Home | History | Annotate | Line # | Download | only in kern
vfs_syscalls.c revision 1.217.2.7.2.2
      1  1.217.2.7.2.2      ghen /*	$NetBSD: vfs_syscalls.c,v 1.217.2.7.2.2 2007/06/23 19:49:58 ghen Exp $	*/
      2           1.31       cgd 
      3           1.31       cgd /*
      4           1.31       cgd  * Copyright (c) 1989, 1993
      5           1.31       cgd  *	The Regents of the University of California.  All rights reserved.
      6           1.31       cgd  * (c) UNIX System Laboratories, Inc.
      7           1.31       cgd  * All or some portions of this file are derived from material licensed
      8           1.31       cgd  * to the University of California by American Telephone and Telegraph
      9           1.31       cgd  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
     10           1.31       cgd  * the permission of UNIX System Laboratories, Inc.
     11           1.31       cgd  *
     12           1.31       cgd  * Redistribution and use in source and binary forms, with or without
     13           1.31       cgd  * modification, are permitted provided that the following conditions
     14           1.31       cgd  * are met:
     15           1.31       cgd  * 1. Redistributions of source code must retain the above copyright
     16           1.31       cgd  *    notice, this list of conditions and the following disclaimer.
     17           1.31       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     18           1.31       cgd  *    notice, this list of conditions and the following disclaimer in the
     19           1.31       cgd  *    documentation and/or other materials provided with the distribution.
     20          1.191       agc  * 3. Neither the name of the University nor the names of its contributors
     21           1.31       cgd  *    may be used to endorse or promote products derived from this software
     22           1.31       cgd  *    without specific prior written permission.
     23           1.31       cgd  *
     24           1.31       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25           1.31       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26           1.31       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27           1.31       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28           1.31       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29           1.31       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30           1.31       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31           1.31       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32           1.31       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33           1.31       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34           1.31       cgd  * SUCH DAMAGE.
     35           1.31       cgd  *
     36          1.113      fvdl  *	@(#)vfs_syscalls.c	8.42 (Berkeley) 7/31/95
     37           1.31       cgd  */
     38          1.173     lukem 
     39          1.173     lukem #include <sys/cdefs.h>
     40  1.217.2.7.2.2      ghen __KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.217.2.7.2.2 2007/06/23 19:49:58 ghen Exp $");
     41          1.111       mrg 
     42          1.121  jonathan #include "opt_compat_netbsd.h"
     43          1.127  christos #include "opt_compat_43.h"
     44          1.192  drochner #include "opt_ktrace.h"
     45      1.217.2.7      tron #include "opt_verified_exec.h"
     46          1.202   hannken #include "fss.h"
     47           1.31       cgd 
     48           1.31       cgd #include <sys/param.h>
     49           1.31       cgd #include <sys/systm.h>
     50           1.31       cgd #include <sys/namei.h>
     51           1.31       cgd #include <sys/filedesc.h>
     52           1.31       cgd #include <sys/kernel.h>
     53           1.31       cgd #include <sys/file.h>
     54           1.31       cgd #include <sys/stat.h>
     55           1.31       cgd #include <sys/vnode.h>
     56           1.31       cgd #include <sys/mount.h>
     57           1.31       cgd #include <sys/proc.h>
     58           1.31       cgd #include <sys/uio.h>
     59           1.31       cgd #include <sys/malloc.h>
     60           1.31       cgd #include <sys/dirent.h>
     61          1.214   thorpej #include <sys/extattr.h>
     62          1.172    simonb #include <sys/sysctl.h>
     63          1.179   thorpej #include <sys/sa.h>
     64           1.35       cgd #include <sys/syscallargs.h>
     65          1.192  drochner #ifdef KTRACE
     66          1.192  drochner #include <sys/ktrace.h>
     67          1.192  drochner #endif
     68      1.217.2.2      tron #ifdef VERIFIED_EXEC
     69      1.217.2.2      tron #include <sys/verified_exec.h>
     70      1.217.2.6      tron #endif /* VERIFIED_EXEC */
     71           1.35       cgd 
     72          1.148      fvdl #include <miscfs/genfs/genfs.h>
     73          1.148      fvdl #include <miscfs/syncfs/syncfs.h>
     74          1.181   thorpej 
     75          1.202   hannken #if NFSS > 0
     76          1.202   hannken #include <dev/fssvar.h>
     77          1.202   hannken #endif
     78          1.202   hannken 
     79          1.181   thorpej MALLOC_DEFINE(M_MOUNT, "mount", "vfs mount struct");
     80          1.110       mrg 
     81          1.205  junyoung static int change_dir(struct nameidata *, struct proc *);
     82          1.205  junyoung static int change_flags(struct vnode *, u_long, struct proc *);
     83          1.205  junyoung static int change_mode(struct vnode *, int, struct proc *p);
     84          1.205  junyoung static int change_owner(struct vnode *, uid_t, gid_t, struct proc *, int);
     85          1.205  junyoung static int change_utimes(struct vnode *vp, const struct timeval *,
     86          1.205  junyoung 	       struct proc *p);
     87          1.205  junyoung static int rename_files(const char *, const char *, struct proc *, int);
     88           1.63  christos 
     89          1.205  junyoung void checkdirs(struct vnode *);
     90           1.31       cgd 
     91          1.150      fvdl int dovfsusermount = 0;
     92          1.150      fvdl 
     93           1.31       cgd /*
     94           1.31       cgd  * Virtual File System System Calls
     95           1.31       cgd  */
     96           1.31       cgd 
     97           1.31       cgd /*
     98           1.31       cgd  * Mount a file system.
     99           1.31       cgd  */
    100           1.99   thorpej 
    101          1.167  jdolecek #if defined(COMPAT_09) || defined(COMPAT_43)
    102           1.99   thorpej /*
    103           1.99   thorpej  * This table is used to maintain compatibility with 4.3BSD
    104           1.99   thorpej  * and NetBSD 0.9 mount syscalls.  Note, the order is important!
    105          1.124   thorpej  *
    106          1.167  jdolecek  * Do not modify this table. It should only contain filesystems
    107          1.167  jdolecek  * supported by NetBSD 0.9 and 4.3BSD.
    108           1.99   thorpej  */
    109          1.167  jdolecek const char * const mountcompatnames[] = {
    110           1.99   thorpej 	NULL,		/* 0 = MOUNT_NONE */
    111          1.167  jdolecek 	MOUNT_FFS,	/* 1 = MOUNT_UFS */
    112           1.99   thorpej 	MOUNT_NFS,	/* 2 */
    113           1.99   thorpej 	MOUNT_MFS,	/* 3 */
    114           1.99   thorpej 	MOUNT_MSDOS,	/* 4 */
    115          1.167  jdolecek 	MOUNT_CD9660,	/* 5 = MOUNT_ISOFS */
    116          1.167  jdolecek 	MOUNT_FDESC,	/* 6 */
    117          1.167  jdolecek 	MOUNT_KERNFS,	/* 7 */
    118          1.167  jdolecek 	NULL,		/* 8 = MOUNT_DEVFS */
    119          1.167  jdolecek 	MOUNT_AFS,	/* 9 */
    120           1.99   thorpej };
    121          1.113      fvdl const int nmountcompatnames = sizeof(mountcompatnames) /
    122           1.99   thorpej     sizeof(mountcompatnames[0]);
    123          1.167  jdolecek #endif /* COMPAT_09 || COMPAT_43 */
    124           1.99   thorpej 
    125           1.31       cgd /* ARGSUSED */
    126           1.63  christos int
    127          1.179   thorpej sys_mount(l, v, retval)
    128          1.179   thorpej 	struct lwp *l;
    129           1.56   thorpej 	void *v;
    130           1.56   thorpej 	register_t *retval;
    131           1.56   thorpej {
    132          1.155  augustss 	struct sys_mount_args /* {
    133           1.74       cgd 		syscallarg(const char *) type;
    134           1.74       cgd 		syscallarg(const char *) path;
    135           1.35       cgd 		syscallarg(int) flags;
    136           1.74       cgd 		syscallarg(void *) data;
    137           1.56   thorpej 	} */ *uap = v;
    138          1.179   thorpej 	struct proc *p = l->l_proc;
    139          1.113      fvdl 	struct vnode *vp;
    140          1.113      fvdl 	struct mount *mp;
    141           1.63  christos 	int error, flag = 0;
    142           1.31       cgd 	char fstypename[MFSNAMELEN];
    143           1.43   mycroft 	struct vattr va;
    144           1.31       cgd 	struct nameidata nd;
    145          1.109   thorpej 	struct vfsops *vfs;
    146           1.31       cgd 
    147      1.217.2.1      tron 	/*
    148      1.217.2.1      tron 	 * if MNT_GETARGS is specified, it should be only flag.
    149      1.217.2.1      tron 	 */
    150      1.217.2.1      tron 
    151      1.217.2.1      tron 	if ((SCARG(uap, flags) & MNT_GETARGS) != 0 &&
    152      1.217.2.1      tron 	    (SCARG(uap, flags) & ~MNT_GETARGS) != 0) {
    153      1.217.2.1      tron 		return EINVAL;
    154      1.217.2.1      tron 	}
    155      1.217.2.1      tron 
    156          1.177  christos 	if (dovfsusermount == 0 && (SCARG(uap, flags) & MNT_GETARGS) == 0 &&
    157          1.177  christos 	    (error = suser(p->p_ucred, &p->p_acflag)))
    158          1.150      fvdl 		return (error);
    159           1.31       cgd 	/*
    160           1.31       cgd 	 * Get vnode to be covered
    161           1.31       cgd 	 */
    162          1.185  christos 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE,
    163          1.190      fvdl 	    SCARG(uap, path), p);
    164           1.63  christos 	if ((error = namei(&nd)) != 0)
    165           1.31       cgd 		return (error);
    166           1.31       cgd 	vp = nd.ni_vp;
    167          1.113      fvdl 	/*
    168          1.113      fvdl 	 * A lookup in VFS_MOUNT might result in an attempt to
    169          1.182  drochner 	 * lock this vnode again, so make the lock recursive.
    170          1.113      fvdl 	 */
    171          1.128      fvdl 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_SETRECURSE);
    172          1.177  christos 	if (SCARG(uap, flags) & (MNT_UPDATE | MNT_GETARGS)) {
    173           1.31       cgd 		if ((vp->v_flag & VROOT) == 0) {
    174           1.31       cgd 			vput(vp);
    175           1.31       cgd 			return (EINVAL);
    176           1.31       cgd 		}
    177           1.31       cgd 		mp = vp->v_mount;
    178           1.31       cgd 		flag = mp->mnt_flag;
    179          1.109   thorpej 		vfs = mp->mnt_op;
    180           1.31       cgd 		/*
    181           1.31       cgd 		 * We only allow the filesystem to be reloaded if it
    182           1.31       cgd 		 * is currently mounted read-only.
    183           1.31       cgd 		 */
    184           1.35       cgd 		if ((SCARG(uap, flags) & MNT_RELOAD) &&
    185           1.31       cgd 		    ((mp->mnt_flag & MNT_RDONLY) == 0)) {
    186           1.31       cgd 			vput(vp);
    187           1.31       cgd 			return (EOPNOTSUPP);	/* Needs translation */
    188           1.31       cgd 		}
    189          1.125       tls 		/*
    190          1.125       tls 		 * In "highly secure" mode, don't let the caller do anything
    191          1.125       tls 		 * but downgrade a filesystem from read-write to read-only.
    192          1.177  christos 		 * (see also below; MNT_UPDATE or MNT_GETARGS is required.)
    193          1.125       tls 		 */
    194          1.125       tls 		if (securelevel >= 2 &&
    195          1.177  christos 		    SCARG(uap, flags) != MNT_GETARGS &&
    196          1.177  christos 		    SCARG(uap, flags) !=
    197          1.125       tls 		    (mp->mnt_flag | MNT_RDONLY |
    198          1.195   thorpej 		     MNT_RELOAD | MNT_FORCE | MNT_UPDATE)) {
    199          1.125       tls 			vput(vp);
    200          1.125       tls 			return (EPERM);
    201          1.125       tls 		}
    202          1.177  christos 		mp->mnt_flag |= SCARG(uap, flags) &
    203          1.177  christos 		    (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_GETARGS);
    204           1.43   mycroft 		/*
    205           1.43   mycroft 		 * Only root, or the user that did the original mount is
    206           1.43   mycroft 		 * permitted to update it.
    207           1.43   mycroft 		 */
    208          1.177  christos 		if ((mp->mnt_flag & MNT_GETARGS) == 0 &&
    209          1.177  christos 		    mp->mnt_stat.f_owner != p->p_ucred->cr_uid &&
    210           1.93     enami 		    (error = suser(p->p_ucred, &p->p_acflag)) != 0) {
    211           1.43   mycroft 			vput(vp);
    212           1.43   mycroft 			return (error);
    213           1.43   mycroft 		}
    214           1.43   mycroft 		/*
    215          1.130    bouyer 		 * Do not allow NFS export by non-root users. For non-root
    216          1.130    bouyer 		 * users, silently enforce MNT_NOSUID and MNT_NODEV, and
    217          1.130    bouyer 		 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
    218           1.43   mycroft 		 */
    219           1.43   mycroft 		if (p->p_ucred->cr_uid != 0) {
    220           1.43   mycroft 			if (SCARG(uap, flags) & MNT_EXPORTED) {
    221           1.43   mycroft 				vput(vp);
    222           1.43   mycroft 				return (EPERM);
    223           1.43   mycroft 			}
    224           1.43   mycroft 			SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
    225          1.130    bouyer 			if (flag & MNT_NOEXEC)
    226          1.130    bouyer 				SCARG(uap, flags) |= MNT_NOEXEC;
    227           1.43   mycroft 		}
    228          1.113      fvdl 		if (vfs_busy(mp, LK_NOWAIT, 0)) {
    229          1.113      fvdl 			vput(vp);
    230          1.113      fvdl 			return (EPERM);
    231          1.205  junyoung 		}
    232           1.31       cgd 		goto update;
    233          1.125       tls 	} else {
    234          1.158     pooka 		if (securelevel >= 2) {
    235          1.158     pooka 			vput(vp);
    236          1.125       tls 			return (EPERM);
    237          1.158     pooka 		}
    238           1.31       cgd 	}
    239           1.43   mycroft 	/*
    240           1.43   mycroft 	 * If the user is not root, ensure that they own the directory
    241           1.43   mycroft 	 * onto which we are attempting to mount.
    242           1.43   mycroft 	 */
    243          1.190      fvdl 	if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) != 0 ||
    244           1.43   mycroft 	    (va.va_uid != p->p_ucred->cr_uid &&
    245           1.93     enami 		(error = suser(p->p_ucred, &p->p_acflag)) != 0)) {
    246           1.43   mycroft 		vput(vp);
    247           1.43   mycroft 		return (error);
    248           1.43   mycroft 	}
    249           1.43   mycroft 	/*
    250          1.130    bouyer 	 * Do not allow NFS export by non-root users. For non-root users,
    251          1.130    bouyer 	 * silently enforce MNT_NOSUID and MNT_NODEV, and MNT_NOEXEC if the
    252          1.130    bouyer 	 * mount point is already MNT_NOEXEC.
    253           1.43   mycroft 	 */
    254           1.43   mycroft 	if (p->p_ucred->cr_uid != 0) {
    255           1.43   mycroft 		if (SCARG(uap, flags) & MNT_EXPORTED) {
    256           1.43   mycroft 			vput(vp);
    257           1.43   mycroft 			return (EPERM);
    258           1.43   mycroft 		}
    259           1.43   mycroft 		SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
    260          1.130    bouyer 		if (vp->v_mount->mnt_flag & MNT_NOEXEC)
    261          1.130    bouyer 			SCARG(uap, flags) |= MNT_NOEXEC;
    262           1.43   mycroft 	}
    263          1.203  jdolecek 	if ((error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) != 0) {
    264          1.203  jdolecek 		vput(vp);
    265           1.31       cgd 		return (error);
    266          1.203  jdolecek 	}
    267           1.31       cgd 	if (vp->v_type != VDIR) {
    268           1.31       cgd 		vput(vp);
    269           1.31       cgd 		return (ENOTDIR);
    270           1.31       cgd 	}
    271           1.63  christos 	error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL);
    272           1.63  christos 	if (error) {
    273           1.54       cgd #if defined(COMPAT_09) || defined(COMPAT_43)
    274           1.54       cgd 		/*
    275           1.54       cgd 		 * Historically filesystem types were identified by number.
    276           1.54       cgd 		 * If we get an integer for the filesystem type instead of a
    277           1.54       cgd 		 * string, we check to see if it matches one of the historic
    278           1.54       cgd 		 * filesystem types.
    279          1.205  junyoung 		 */
    280          1.109   thorpej 		u_long fsindex = (u_long)SCARG(uap, type);
    281           1.99   thorpej 		if (fsindex >= nmountcompatnames ||
    282           1.99   thorpej 		    mountcompatnames[fsindex] == NULL) {
    283           1.54       cgd 			vput(vp);
    284           1.54       cgd 			return (ENODEV);
    285           1.54       cgd 		}
    286           1.99   thorpej 		strncpy(fstypename, mountcompatnames[fsindex], MFSNAMELEN);
    287           1.31       cgd #else
    288           1.31       cgd 		vput(vp);
    289           1.31       cgd 		return (error);
    290           1.31       cgd #endif
    291           1.31       cgd 	}
    292           1.58       gwr #ifdef	COMPAT_10
    293           1.59   mycroft 	/* Accept `ufs' as an alias for `ffs'. */
    294           1.59   mycroft 	if (!strncmp(fstypename, "ufs", MFSNAMELEN))
    295           1.59   mycroft 		strncpy(fstypename, "ffs", MFSNAMELEN);
    296           1.58       gwr #endif
    297          1.109   thorpej 	if ((vfs = vfs_getopsbyname(fstypename)) == NULL) {
    298           1.31       cgd 		vput(vp);
    299           1.31       cgd 		return (ENODEV);
    300           1.31       cgd 	}
    301           1.43   mycroft 	if (vp->v_mountedhere != NULL) {
    302           1.43   mycroft 		vput(vp);
    303           1.43   mycroft 		return (EBUSY);
    304           1.43   mycroft 	}
    305           1.31       cgd 
    306           1.31       cgd 	/*
    307           1.31       cgd 	 * Allocate and initialize the file system.
    308           1.31       cgd 	 */
    309           1.31       cgd 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
    310           1.31       cgd 		M_MOUNT, M_WAITOK);
    311          1.123     perry 	memset((char *)mp, 0, (u_long)sizeof(struct mount));
    312          1.113      fvdl 	lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0);
    313          1.208        pk 	simple_lock_init(&mp->mnt_slock);
    314          1.113      fvdl 	(void)vfs_busy(mp, LK_NOWAIT, 0);
    315          1.109   thorpej 	mp->mnt_op = vfs;
    316          1.109   thorpej 	vfs->vfs_refcount++;
    317          1.129      fvdl 	mp->mnt_vnodecovered = vp;
    318           1.43   mycroft 	mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
    319          1.190      fvdl 	mp->mnt_unmounter = NULL;
    320          1.210   hannken 	mp->mnt_leaf = mp;
    321          1.195   thorpej 
    322          1.195   thorpej 	/*
    323          1.195   thorpej 	 * The underlying file system may refuse the mount for
    324          1.198   thorpej 	 * various reasons.  Allow the user to force it to happen.
    325          1.195   thorpej 	 */
    326          1.198   thorpej 	mp->mnt_flag |= SCARG(uap, flags) & MNT_FORCE;
    327          1.195   thorpej  update:
    328      1.217.2.1      tron 	if ((SCARG(uap, flags) & MNT_GETARGS) == 0) {
    329      1.217.2.1      tron 		/*
    330      1.217.2.1      tron 		 * Set the mount level flags.
    331      1.217.2.1      tron 		 */
    332      1.217.2.1      tron 		if (SCARG(uap, flags) & MNT_RDONLY)
    333      1.217.2.1      tron 			mp->mnt_flag |= MNT_RDONLY;
    334      1.217.2.1      tron 		else if (mp->mnt_flag & MNT_RDONLY)
    335      1.217.2.1      tron 			mp->mnt_iflag |= IMNT_WANTRDWR;
    336      1.217.2.1      tron 		mp->mnt_flag &=
    337      1.217.2.1      tron 		  ~(MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
    338      1.217.2.1      tron 		    MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP |
    339      1.217.2.1      tron 		    MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP);
    340      1.217.2.1      tron 		mp->mnt_flag |= SCARG(uap, flags) &
    341      1.217.2.1      tron 		   (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
    342      1.217.2.1      tron 		    MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOCOREDUMP |
    343      1.217.2.1      tron 		    MNT_NOATIME | MNT_NODEVMTIME | MNT_SYMPERM | MNT_SOFTDEP |
    344      1.217.2.1      tron 		    MNT_IGNORE);
    345      1.217.2.1      tron 	}
    346           1.31       cgd 	/*
    347           1.31       cgd 	 * Mount the filesystem.
    348           1.31       cgd 	 */
    349          1.190      fvdl 	error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p);
    350          1.177  christos 	if (mp->mnt_flag & (MNT_UPDATE | MNT_GETARGS)) {
    351          1.196       dbj 		if (mp->mnt_iflag & IMNT_WANTRDWR)
    352           1.31       cgd 			mp->mnt_flag &= ~MNT_RDONLY;
    353      1.217.2.1      tron 		if (error)
    354          1.177  christos 			mp->mnt_flag = flag;
    355           1.31       cgd 		mp->mnt_flag &=~
    356          1.196       dbj 		    (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_GETARGS);
    357          1.196       dbj 		mp->mnt_iflag &=~ IMNT_WANTRDWR;
    358          1.151   mycroft 		if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0) {
    359          1.148      fvdl 			if (mp->mnt_syncer == NULL)
    360          1.148      fvdl 				error = vfs_allocate_syncvnode(mp);
    361          1.148      fvdl 		} else {
    362          1.160   mycroft 			if (mp->mnt_syncer != NULL)
    363          1.160   mycroft 				vfs_deallocate_syncvnode(mp);
    364          1.148      fvdl 		}
    365          1.113      fvdl 		vfs_unbusy(mp);
    366          1.174     enami 		VOP_UNLOCK(vp, 0);
    367          1.174     enami 		vrele(vp);
    368           1.31       cgd 		return (error);
    369           1.31       cgd 	}
    370           1.31       cgd 	/*
    371           1.31       cgd 	 * Put the new filesystem on the mount list after root.
    372           1.31       cgd 	 */
    373           1.31       cgd 	cache_purge(vp);
    374           1.31       cgd 	if (!error) {
    375          1.195   thorpej 		mp->mnt_flag &=~
    376          1.196       dbj 		    (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_GETARGS);
    377          1.196       dbj 		mp->mnt_iflag &=~ IMNT_WANTRDWR;
    378          1.128      fvdl 		vp->v_mountedhere = mp;
    379          1.113      fvdl 		simple_lock(&mountlist_slock);
    380           1.47   mycroft 		CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
    381          1.113      fvdl 		simple_unlock(&mountlist_slock);
    382           1.43   mycroft 		checkdirs(vp);
    383          1.113      fvdl 		VOP_UNLOCK(vp, 0);
    384          1.151   mycroft 		if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0)
    385          1.148      fvdl 			error = vfs_allocate_syncvnode(mp);
    386          1.113      fvdl 		vfs_unbusy(mp);
    387          1.206  christos 		(void) VFS_STATVFS(mp, &mp->mnt_stat, p);
    388          1.190      fvdl 		if ((error = VFS_START(mp, 0, p)))
    389          1.113      fvdl 			vrele(vp);
    390           1.31       cgd 	} else {
    391          1.128      fvdl 		vp->v_mountedhere = (struct mount *)0;
    392          1.109   thorpej 		vfs->vfs_refcount--;
    393          1.113      fvdl 		vfs_unbusy(mp);
    394          1.184       dsl 		free(mp, M_MOUNT);
    395           1.31       cgd 		vput(vp);
    396           1.31       cgd 	}
    397           1.31       cgd 	return (error);
    398           1.31       cgd }
    399           1.31       cgd 
    400           1.31       cgd /*
    401           1.43   mycroft  * Scan all active processes to see if any of them have a current
    402           1.43   mycroft  * or root directory onto which the new filesystem has just been
    403           1.43   mycroft  * mounted. If so, replace them with the new mount point.
    404           1.43   mycroft  */
    405           1.63  christos void
    406           1.43   mycroft checkdirs(olddp)
    407           1.43   mycroft 	struct vnode *olddp;
    408           1.43   mycroft {
    409          1.134   thorpej 	struct cwdinfo *cwdi;
    410           1.43   mycroft 	struct vnode *newdp;
    411           1.43   mycroft 	struct proc *p;
    412           1.43   mycroft 
    413           1.43   mycroft 	if (olddp->v_usecount == 1)
    414           1.43   mycroft 		return;
    415          1.189   thorpej 	if (VFS_ROOT(olddp->v_mountedhere, &newdp))
    416           1.43   mycroft 		panic("mount: lost mount");
    417          1.144   thorpej 	proclist_lock_read();
    418          1.212      yamt 	PROCLIST_FOREACH(p, &allproc) {
    419          1.134   thorpej 		cwdi = p->p_cwdi;
    420          1.215       dbj 		if (!cwdi)
    421          1.215       dbj 			continue;
    422          1.134   thorpej 		if (cwdi->cwdi_cdir == olddp) {
    423          1.134   thorpej 			vrele(cwdi->cwdi_cdir);
    424           1.43   mycroft 			VREF(newdp);
    425          1.134   thorpej 			cwdi->cwdi_cdir = newdp;
    426           1.43   mycroft 		}
    427          1.134   thorpej 		if (cwdi->cwdi_rdir == olddp) {
    428          1.134   thorpej 			vrele(cwdi->cwdi_rdir);
    429           1.43   mycroft 			VREF(newdp);
    430          1.134   thorpej 			cwdi->cwdi_rdir = newdp;
    431           1.43   mycroft 		}
    432           1.43   mycroft 	}
    433          1.143   thorpej 	proclist_unlock_read();
    434           1.43   mycroft 	if (rootvnode == olddp) {
    435           1.43   mycroft 		vrele(rootvnode);
    436           1.43   mycroft 		VREF(newdp);
    437           1.43   mycroft 		rootvnode = newdp;
    438           1.43   mycroft 	}
    439           1.43   mycroft 	vput(newdp);
    440           1.43   mycroft }
    441           1.43   mycroft 
    442           1.43   mycroft /*
    443           1.31       cgd  * Unmount a file system.
    444           1.31       cgd  *
    445           1.31       cgd  * Note: unmount takes a path to the vnode mounted on as argument,
    446           1.31       cgd  * not special file (as before).
    447           1.31       cgd  */
    448           1.31       cgd /* ARGSUSED */
    449           1.63  christos int
    450          1.179   thorpej sys_unmount(l, v, retval)
    451          1.179   thorpej 	struct lwp *l;
    452           1.56   thorpej 	void *v;
    453           1.56   thorpej 	register_t *retval;
    454           1.56   thorpej {
    455          1.155  augustss 	struct sys_unmount_args /* {
    456           1.74       cgd 		syscallarg(const char *) path;
    457           1.35       cgd 		syscallarg(int) flags;
    458           1.56   thorpej 	} */ *uap = v;
    459          1.179   thorpej 	struct proc *p = l->l_proc;
    460          1.155  augustss 	struct vnode *vp;
    461           1.31       cgd 	struct mount *mp;
    462           1.31       cgd 	int error;
    463           1.31       cgd 	struct nameidata nd;
    464           1.31       cgd 
    465           1.35       cgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
    466          1.190      fvdl 	    SCARG(uap, path), p);
    467           1.63  christos 	if ((error = namei(&nd)) != 0)
    468           1.31       cgd 		return (error);
    469           1.31       cgd 	vp = nd.ni_vp;
    470           1.43   mycroft 	mp = vp->v_mount;
    471           1.31       cgd 
    472           1.31       cgd 	/*
    473           1.43   mycroft 	 * Only root, or the user that did the original mount is
    474           1.43   mycroft 	 * permitted to unmount this filesystem.
    475           1.31       cgd 	 */
    476           1.43   mycroft 	if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) &&
    477           1.93     enami 	    (error = suser(p->p_ucred, &p->p_acflag)) != 0) {
    478           1.31       cgd 		vput(vp);
    479           1.31       cgd 		return (error);
    480           1.31       cgd 	}
    481           1.31       cgd 
    482           1.31       cgd 	/*
    483           1.47   mycroft 	 * Don't allow unmounting the root file system.
    484           1.47   mycroft 	 */
    485           1.47   mycroft 	if (mp->mnt_flag & MNT_ROOTFS) {
    486           1.47   mycroft 		vput(vp);
    487           1.47   mycroft 		return (EINVAL);
    488           1.47   mycroft 	}
    489           1.47   mycroft 
    490           1.47   mycroft 	/*
    491           1.31       cgd 	 * Must be the root of the filesystem
    492           1.31       cgd 	 */
    493           1.31       cgd 	if ((vp->v_flag & VROOT) == 0) {
    494           1.31       cgd 		vput(vp);
    495           1.31       cgd 		return (EINVAL);
    496           1.31       cgd 	}
    497           1.31       cgd 	vput(vp);
    498           1.78      fvdl 
    499          1.165   thorpej 	/*
    500          1.165   thorpej 	 * XXX Freeze syncer.  Must do this before locking the
    501          1.165   thorpej 	 * mount point.  See dounmount() for details.
    502          1.165   thorpej 	 */
    503          1.165   thorpej 	lockmgr(&syncer_lock, LK_EXCLUSIVE, NULL);
    504          1.165   thorpej 
    505          1.165   thorpej 	if (vfs_busy(mp, 0, 0)) {
    506          1.165   thorpej 		lockmgr(&syncer_lock, LK_RELEASE, NULL);
    507           1.78      fvdl 		return (EBUSY);
    508          1.165   thorpej 	}
    509           1.78      fvdl 
    510          1.190      fvdl 	return (dounmount(mp, SCARG(uap, flags), p));
    511           1.31       cgd }
    512           1.31       cgd 
    513           1.31       cgd /*
    514           1.78      fvdl  * Do the actual file system unmount. File system is assumed to have been
    515           1.78      fvdl  * marked busy by the caller.
    516           1.31       cgd  */
    517           1.63  christos int
    518          1.190      fvdl dounmount(mp, flags, p)
    519          1.155  augustss 	struct mount *mp;
    520           1.31       cgd 	int flags;
    521          1.190      fvdl 	struct proc *p;
    522           1.31       cgd {
    523           1.31       cgd 	struct vnode *coveredvp;
    524           1.31       cgd 	int error;
    525          1.140  sommerfe 	int async;
    526          1.162      fvdl 	int used_syncer;
    527           1.31       cgd 
    528          1.113      fvdl 	simple_lock(&mountlist_slock);
    529          1.148      fvdl 	vfs_unbusy(mp);
    530          1.162      fvdl 	used_syncer = (mp->mnt_syncer != NULL);
    531          1.162      fvdl 
    532          1.148      fvdl 	/*
    533          1.165   thorpej 	 * XXX Syncer must be frozen when we get here.  This should really
    534          1.165   thorpej 	 * be done on a per-mountpoint basis, but especially the softdep
    535          1.165   thorpej 	 * code possibly called from the syncer doens't exactly work on a
    536          1.165   thorpej 	 * per-mountpoint basis, so the softdep code would become a maze
    537          1.165   thorpej 	 * of vfs_busy() calls.
    538          1.165   thorpej 	 *
    539          1.165   thorpej 	 * The caller of dounmount() must acquire syncer_lock because
    540          1.165   thorpej 	 * the syncer itself acquires locks in syncer_lock -> vfs_busy
    541          1.165   thorpej 	 * order, and we must preserve that order to avoid deadlock.
    542          1.165   thorpej 	 *
    543          1.165   thorpej 	 * So, if the file system did not use the syncer, now is
    544          1.165   thorpej 	 * the time to release the syncer_lock.
    545          1.148      fvdl 	 */
    546          1.165   thorpej 	if (used_syncer == 0)
    547          1.165   thorpej 		lockmgr(&syncer_lock, LK_RELEASE, NULL);
    548          1.148      fvdl 
    549          1.196       dbj 	mp->mnt_iflag |= IMNT_UNMOUNT;
    550          1.190      fvdl 	mp->mnt_unmounter = p;
    551          1.113      fvdl 	lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock);
    552          1.197   hannken 	vn_start_write(NULL, &mp, V_WAIT);
    553          1.197   hannken 
    554           1.91      fvdl 	if (mp->mnt_flag & MNT_EXPUBLIC)
    555           1.91      fvdl 		vfs_setpublicfs(NULL, NULL, NULL);
    556          1.141  sommerfe 	async = mp->mnt_flag & MNT_ASYNC;
    557          1.151   mycroft 	mp->mnt_flag &= ~MNT_ASYNC;
    558           1.31       cgd 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
    559          1.160   mycroft 	if (mp->mnt_syncer != NULL)
    560          1.160   mycroft 		vfs_deallocate_syncvnode(mp);
    561          1.209   hannken 	error = 0;
    562          1.209   hannken 	if ((mp->mnt_flag & MNT_RDONLY) == 0) {
    563          1.202   hannken #if NFSS > 0
    564          1.209   hannken 		error = fss_umount_hook(mp, (flags & MNT_FORCE));
    565          1.202   hannken #endif
    566          1.209   hannken 		if (error == 0)
    567          1.209   hannken 			error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p);
    568          1.209   hannken 	}
    569          1.209   hannken 	if (error == 0 || (flags & MNT_FORCE))
    570          1.190      fvdl 		error = VFS_UNMOUNT(mp, flags, p);
    571          1.197   hannken 	vn_finished_write(mp, 0);
    572          1.113      fvdl 	simple_lock(&mountlist_slock);
    573           1.31       cgd 	if (error) {
    574          1.151   mycroft 		if ((mp->mnt_flag & (MNT_RDONLY | MNT_ASYNC)) == 0)
    575          1.148      fvdl 			(void) vfs_allocate_syncvnode(mp);
    576          1.196       dbj 		mp->mnt_iflag &= ~IMNT_UNMOUNT;
    577          1.148      fvdl 		mp->mnt_unmounter = NULL;
    578          1.140  sommerfe 		mp->mnt_flag |= async;
    579          1.113      fvdl 		lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE,
    580          1.113      fvdl 		    &mountlist_slock);
    581          1.162      fvdl 		if (used_syncer)
    582          1.162      fvdl 			lockmgr(&syncer_lock, LK_RELEASE, NULL);
    583          1.208        pk 		simple_lock(&mp->mnt_slock);
    584          1.151   mycroft 		while (mp->mnt_wcnt > 0) {
    585          1.184       dsl 			wakeup(mp);
    586          1.208        pk 			ltsleep(&mp->mnt_wcnt, PVFS, "mntwcnt1",
    587          1.208        pk 				0, &mp->mnt_slock);
    588          1.142  sommerfe 		}
    589          1.208        pk 		simple_unlock(&mp->mnt_slock);
    590          1.142  sommerfe 		return (error);
    591          1.113      fvdl 	}
    592          1.113      fvdl 	CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);
    593          1.113      fvdl 	if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {
    594          1.113      fvdl 		coveredvp->v_mountedhere = NULL;
    595          1.113      fvdl 		vrele(coveredvp);
    596          1.113      fvdl 	}
    597          1.113      fvdl 	mp->mnt_op->vfs_refcount--;
    598          1.176      matt 	if (LIST_FIRST(&mp->mnt_vnodelist) != NULL)
    599          1.113      fvdl 		panic("unmount: dangling vnode");
    600          1.196       dbj 	mp->mnt_iflag |= IMNT_GONE;
    601          1.113      fvdl 	lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock);
    602          1.162      fvdl 	if (used_syncer)
    603          1.162      fvdl 		lockmgr(&syncer_lock, LK_RELEASE, NULL);
    604          1.208        pk 	simple_lock(&mp->mnt_slock);
    605          1.208        pk 	while (mp->mnt_wcnt > 0) {
    606          1.184       dsl 		wakeup(mp);
    607          1.208        pk 		ltsleep(&mp->mnt_wcnt, PVFS, "mntwcnt2", 0, &mp->mnt_slock);
    608          1.142  sommerfe 	}
    609          1.208        pk 	simple_unlock(&mp->mnt_slock);
    610          1.184       dsl 	free(mp, M_MOUNT);
    611          1.113      fvdl 	return (0);
    612           1.31       cgd }
    613           1.31       cgd 
    614           1.31       cgd /*
    615           1.31       cgd  * Sync each mounted filesystem.
    616           1.31       cgd  */
    617           1.31       cgd #ifdef DEBUG
    618           1.31       cgd int syncprt = 0;
    619           1.31       cgd struct ctldebug debug0 = { "syncprt", &syncprt };
    620           1.31       cgd #endif
    621           1.31       cgd 
    622           1.31       cgd /* ARGSUSED */
    623           1.63  christos int
    624          1.179   thorpej sys_sync(l, v, retval)
    625          1.179   thorpej 	struct lwp *l;
    626           1.57   mycroft 	void *v;
    627           1.35       cgd 	register_t *retval;
    628           1.31       cgd {
    629          1.155  augustss 	struct mount *mp, *nmp;
    630           1.31       cgd 	int asyncflag;
    631          1.180  christos 	struct proc *p = l == NULL ? &proc0 : l->l_proc;
    632           1.31       cgd 
    633          1.113      fvdl 	simple_lock(&mountlist_slock);
    634           1.77     mikel 	for (mp = mountlist.cqh_last; mp != (void *)&mountlist; mp = nmp) {
    635          1.113      fvdl 		if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock)) {
    636          1.113      fvdl 			nmp = mp->mnt_list.cqe_prev;
    637          1.113      fvdl 			continue;
    638          1.113      fvdl 		}
    639          1.197   hannken 		if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
    640          1.197   hannken 		    vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
    641           1.31       cgd 			asyncflag = mp->mnt_flag & MNT_ASYNC;
    642           1.31       cgd 			mp->mnt_flag &= ~MNT_ASYNC;
    643          1.190      fvdl 			VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
    644           1.31       cgd 			if (asyncflag)
    645          1.113      fvdl 				 mp->mnt_flag |= MNT_ASYNC;
    646          1.197   hannken 			vn_finished_write(mp, 0);
    647           1.31       cgd 		}
    648          1.113      fvdl 		simple_lock(&mountlist_slock);
    649          1.113      fvdl 		nmp = mp->mnt_list.cqe_prev;
    650          1.113      fvdl 		vfs_unbusy(mp);
    651          1.205  junyoung 
    652           1.31       cgd 	}
    653          1.113      fvdl 	simple_unlock(&mountlist_slock);
    654           1.31       cgd #ifdef DEBUG
    655           1.31       cgd 	if (syncprt)
    656           1.31       cgd 		vfs_bufstats();
    657           1.31       cgd #endif /* DEBUG */
    658           1.31       cgd 	return (0);
    659           1.31       cgd }
    660           1.31       cgd 
    661           1.31       cgd /*
    662           1.31       cgd  * Change filesystem quotas.
    663           1.31       cgd  */
    664           1.31       cgd /* ARGSUSED */
    665           1.63  christos int
    666          1.179   thorpej sys_quotactl(l, v, retval)
    667          1.179   thorpej 	struct lwp *l;
    668           1.56   thorpej 	void *v;
    669           1.56   thorpej 	register_t *retval;
    670           1.56   thorpej {
    671          1.155  augustss 	struct sys_quotactl_args /* {
    672           1.74       cgd 		syscallarg(const char *) path;
    673           1.35       cgd 		syscallarg(int) cmd;
    674           1.35       cgd 		syscallarg(int) uid;
    675           1.35       cgd 		syscallarg(caddr_t) arg;
    676           1.56   thorpej 	} */ *uap = v;
    677          1.190      fvdl 	struct proc *p = l->l_proc;
    678          1.155  augustss 	struct mount *mp;
    679           1.31       cgd 	int error;
    680           1.31       cgd 	struct nameidata nd;
    681           1.31       cgd 
    682          1.190      fvdl 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
    683           1.63  christos 	if ((error = namei(&nd)) != 0)
    684           1.31       cgd 		return (error);
    685          1.197   hannken 	error = vn_start_write(nd.ni_vp, &mp, V_WAIT | V_PCATCH);
    686           1.31       cgd 	vrele(nd.ni_vp);
    687          1.197   hannken 	if (error)
    688          1.197   hannken 		return (error);
    689          1.197   hannken 	error = VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
    690          1.197   hannken 	    SCARG(uap, arg), p);
    691          1.197   hannken 	vn_finished_write(mp, 0);
    692          1.197   hannken 	return (error);
    693           1.31       cgd }
    694           1.31       cgd 
    695          1.206  christos int
    696          1.206  christos dostatvfs(struct mount *mp, struct statvfs *sp, struct proc *p, int flags,
    697          1.185  christos     int root)
    698          1.185  christos {
    699          1.190      fvdl 	struct cwdinfo *cwdi = p->p_cwdi;
    700          1.185  christos 	int error = 0;
    701          1.185  christos 
    702          1.185  christos 	/*
    703          1.185  christos 	 * If MNT_NOWAIT or MNT_LAZY is specified, do not
    704          1.204       dbj 	 * refresh the fsstat cache. MNT_WAIT or MNT_LAZY
    705          1.185  christos 	 * overrides MNT_NOWAIT.
    706          1.185  christos 	 */
    707          1.185  christos 	if (flags == MNT_NOWAIT	|| flags == MNT_LAZY ||
    708          1.185  christos 	    (flags != MNT_WAIT && flags != 0)) {
    709          1.185  christos 		memcpy(sp, &mp->mnt_stat, sizeof(*sp));
    710          1.185  christos 		goto done;
    711          1.185  christos 	}
    712          1.205  junyoung 
    713          1.211  jdolecek 	/* Get the filesystem stats now */
    714          1.211  jdolecek 	memset(sp, 0, sizeof(*sp));
    715          1.206  christos 	if ((error = VFS_STATVFS(mp, sp, p)) != 0) {
    716          1.185  christos 		return error;
    717          1.185  christos 	}
    718          1.185  christos 
    719          1.185  christos 	if (cwdi->cwdi_rdir == NULL)
    720          1.185  christos 		(void)memcpy(&mp->mnt_stat, sp, sizeof(mp->mnt_stat));
    721          1.185  christos done:
    722          1.185  christos 	if (cwdi->cwdi_rdir != NULL) {
    723          1.185  christos 		size_t len;
    724          1.185  christos 		char *bp;
    725          1.185  christos 		char *path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
    726          1.185  christos 		if (!path)
    727          1.185  christos 			return ENOMEM;
    728          1.185  christos 
    729          1.185  christos 		bp = path + MAXPATHLEN;
    730          1.185  christos 		*--bp = '\0';
    731          1.185  christos 		error = getcwd_common(cwdi->cwdi_rdir, rootvnode, &bp, path,
    732          1.190      fvdl 		    MAXPATHLEN / 2, 0, p);
    733          1.185  christos 		if (error) {
    734          1.185  christos 			free(path, M_TEMP);
    735          1.185  christos 			return error;
    736          1.185  christos 		}
    737          1.185  christos 		len = strlen(bp);
    738          1.185  christos 		/*
    739          1.185  christos 		 * for mount points that are below our root, we can see
    740          1.185  christos 		 * them, so we fix up the pathname and return them. The
    741          1.185  christos 		 * rest we cannot see, so we don't allow viewing the
    742          1.185  christos 		 * data.
    743          1.185  christos 		 */
    744          1.185  christos 		if (strncmp(bp, sp->f_mntonname, len) == 0) {
    745          1.187    itojun 			strlcpy(sp->f_mntonname, &sp->f_mntonname[len],
    746          1.187    itojun 			    sizeof(sp->f_mntonname));
    747          1.185  christos 			if (sp->f_mntonname[0] == '\0')
    748          1.187    itojun 				(void)strlcpy(sp->f_mntonname, "/",
    749          1.187    itojun 				    sizeof(sp->f_mntonname));
    750          1.185  christos 		} else {
    751          1.185  christos 			if (root)
    752          1.187    itojun 				(void)strlcpy(sp->f_mntonname, "/",
    753          1.187    itojun 				    sizeof(sp->f_mntonname));
    754          1.185  christos 			else
    755          1.185  christos 				error = EPERM;
    756          1.185  christos 		}
    757          1.185  christos 		free(path, M_TEMP);
    758          1.185  christos 	}
    759          1.206  christos 	sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK;
    760          1.185  christos 	return error;
    761          1.185  christos }
    762          1.185  christos 
    763           1.31       cgd /*
    764           1.31       cgd  * Get filesystem statistics.
    765           1.31       cgd  */
    766           1.31       cgd /* ARGSUSED */
    767           1.63  christos int
    768          1.206  christos sys_statvfs1(l, v, retval)
    769          1.179   thorpej 	struct lwp *l;
    770           1.56   thorpej 	void *v;
    771           1.56   thorpej 	register_t *retval;
    772           1.56   thorpej {
    773          1.206  christos 	struct sys_statvfs1_args /* {
    774           1.74       cgd 		syscallarg(const char *) path;
    775          1.206  christos 		syscallarg(struct statvfs *) buf;
    776          1.206  christos 		syscallarg(int) flags;
    777           1.56   thorpej 	} */ *uap = v;
    778          1.190      fvdl 	struct proc *p = l->l_proc;
    779          1.155  augustss 	struct mount *mp;
    780          1.206  christos 	struct statvfs sbuf;
    781           1.31       cgd 	int error;
    782           1.31       cgd 	struct nameidata nd;
    783           1.31       cgd 
    784          1.190      fvdl 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
    785           1.63  christos 	if ((error = namei(&nd)) != 0)
    786          1.185  christos 		return error;
    787           1.31       cgd 	mp = nd.ni_vp->v_mount;
    788           1.31       cgd 	vrele(nd.ni_vp);
    789          1.206  christos 	if ((error = dostatvfs(mp, &sbuf, p, SCARG(uap, flags), 1)) != 0)
    790          1.185  christos 		return error;
    791          1.185  christos 	return copyout(&sbuf, SCARG(uap, buf), sizeof(sbuf));
    792           1.31       cgd }
    793           1.31       cgd 
    794           1.31       cgd /*
    795           1.31       cgd  * Get filesystem statistics.
    796           1.31       cgd  */
    797           1.31       cgd /* ARGSUSED */
    798           1.63  christos int
    799          1.206  christos sys_fstatvfs1(l, v, retval)
    800          1.179   thorpej 	struct lwp *l;
    801           1.56   thorpej 	void *v;
    802           1.56   thorpej 	register_t *retval;
    803           1.56   thorpej {
    804          1.206  christos 	struct sys_fstatvfs1_args /* {
    805           1.35       cgd 		syscallarg(int) fd;
    806          1.206  christos 		syscallarg(struct statvfs *) buf;
    807          1.206  christos 		syscallarg(int) flags;
    808           1.56   thorpej 	} */ *uap = v;
    809          1.179   thorpej 	struct proc *p = l->l_proc;
    810           1.31       cgd 	struct file *fp;
    811           1.31       cgd 	struct mount *mp;
    812          1.206  christos 	struct statvfs sbuf;
    813           1.31       cgd 	int error;
    814           1.31       cgd 
    815          1.135   thorpej 	/* getvnode() will use the descriptor for us */
    816           1.63  christos 	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
    817           1.31       cgd 		return (error);
    818           1.62   mycroft 	mp = ((struct vnode *)fp->f_data)->v_mount;
    819          1.206  christos 	if ((error = dostatvfs(mp, &sbuf, p, SCARG(uap, flags), 1)) != 0)
    820          1.135   thorpej 		goto out;
    821          1.185  christos 	error = copyout(&sbuf, SCARG(uap, buf), sizeof(sbuf));
    822          1.135   thorpej  out:
    823          1.190      fvdl 	FILE_UNUSE(fp, p);
    824          1.185  christos 	return error;
    825           1.31       cgd }
    826           1.31       cgd 
    827          1.185  christos 
    828           1.31       cgd /*
    829           1.31       cgd  * Get statistics on all filesystems.
    830           1.31       cgd  */
    831           1.63  christos int
    832          1.206  christos sys_getvfsstat(l, v, retval)
    833          1.179   thorpej 	struct lwp *l;
    834           1.56   thorpej 	void *v;
    835           1.56   thorpej 	register_t *retval;
    836           1.56   thorpej {
    837          1.206  christos 	struct sys_getvfsstat_args /* {
    838          1.206  christos 		syscallarg(struct statvfs *) buf;
    839          1.206  christos 		syscallarg(size_t) bufsize;
    840           1.35       cgd 		syscallarg(int) flags;
    841           1.56   thorpej 	} */ *uap = v;
    842          1.185  christos 	int root = 0;
    843          1.179   thorpej 	struct proc *p = l->l_proc;
    844          1.155  augustss 	struct mount *mp, *nmp;
    845          1.206  christos 	struct statvfs sbuf;
    846          1.206  christos 	struct statvfs *sfsp;
    847          1.206  christos 	size_t count, maxcount;
    848          1.206  christos 	int error = 0;
    849           1.31       cgd 
    850          1.206  christos 	maxcount = SCARG(uap, bufsize) / sizeof(struct statvfs);
    851          1.206  christos 	sfsp = SCARG(uap, buf);
    852          1.113      fvdl 	simple_lock(&mountlist_slock);
    853          1.113      fvdl 	count = 0;
    854          1.176      matt 	for (mp = CIRCLEQ_FIRST(&mountlist); mp != (void *)&mountlist;
    855          1.176      matt 	     mp = nmp) {
    856          1.113      fvdl 		if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock)) {
    857          1.176      matt 			nmp = CIRCLEQ_NEXT(mp, mnt_list);
    858          1.113      fvdl 			continue;
    859          1.113      fvdl 		}
    860          1.113      fvdl 		if (sfsp && count < maxcount) {
    861          1.206  christos 			error = dostatvfs(mp, &sbuf, p, SCARG(uap, flags), 0);
    862          1.185  christos 			if (error) {
    863          1.186      yamt 				simple_lock(&mountlist_slock);
    864          1.176      matt 				nmp = CIRCLEQ_NEXT(mp, mnt_list);
    865          1.113      fvdl 				vfs_unbusy(mp);
    866           1.31       cgd 				continue;
    867          1.113      fvdl 			}
    868          1.206  christos 			error = copyout(&sbuf, sfsp, sizeof(*sfsp));
    869          1.133   mycroft 			if (error) {
    870          1.133   mycroft 				vfs_unbusy(mp);
    871           1.31       cgd 				return (error);
    872          1.133   mycroft 			}
    873          1.206  christos 			sfsp++;
    874          1.185  christos 			root |= strcmp(sbuf.f_mntonname, "/") == 0;
    875           1.31       cgd 		}
    876           1.31       cgd 		count++;
    877          1.186      yamt 		simple_lock(&mountlist_slock);
    878          1.176      matt 		nmp = CIRCLEQ_NEXT(mp, mnt_list);
    879          1.113      fvdl 		vfs_unbusy(mp);
    880           1.31       cgd 	}
    881          1.113      fvdl 	simple_unlock(&mountlist_slock);
    882          1.185  christos 	if (root == 0 && p->p_cwdi->cwdi_rdir) {
    883          1.185  christos 		/*
    884          1.185  christos 		 * fake a root entry
    885          1.185  christos 		 */
    886          1.206  christos 		if ((error = dostatvfs(p->p_cwdi->cwdi_rdir->v_mount, &sbuf, p,
    887          1.185  christos 		    SCARG(uap, flags), 1)) != 0)
    888          1.185  christos 			return error;
    889          1.185  christos 		if (sfsp)
    890          1.206  christos 			error = copyout(&sbuf, sfsp, sizeof(*sfsp));
    891          1.185  christos 		count++;
    892          1.185  christos 	}
    893           1.31       cgd 	if (sfsp && count > maxcount)
    894           1.31       cgd 		*retval = maxcount;
    895           1.31       cgd 	else
    896           1.31       cgd 		*retval = count;
    897          1.185  christos 	return error;
    898           1.31       cgd }
    899           1.31       cgd 
    900           1.31       cgd /*
    901           1.31       cgd  * Change current working directory to a given file descriptor.
    902           1.31       cgd  */
    903           1.31       cgd /* ARGSUSED */
    904           1.63  christos int
    905          1.179   thorpej sys_fchdir(l, v, retval)
    906          1.179   thorpej 	struct lwp *l;
    907           1.56   thorpej 	void *v;
    908           1.56   thorpej 	register_t *retval;
    909           1.56   thorpej {
    910           1.57   mycroft 	struct sys_fchdir_args /* {
    911           1.35       cgd 		syscallarg(int) fd;
    912           1.56   thorpej 	} */ *uap = v;
    913          1.179   thorpej 	struct proc *p = l->l_proc;
    914          1.134   thorpej 	struct filedesc *fdp = p->p_fd;
    915          1.134   thorpej 	struct cwdinfo *cwdi = p->p_cwdi;
    916           1.43   mycroft 	struct vnode *vp, *tdp;
    917           1.43   mycroft 	struct mount *mp;
    918           1.31       cgd 	struct file *fp;
    919           1.31       cgd 	int error;
    920           1.31       cgd 
    921          1.135   thorpej 	/* getvnode() will use the descriptor for us */
    922           1.63  christos 	if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0)
    923           1.31       cgd 		return (error);
    924           1.62   mycroft 	vp = (struct vnode *)fp->f_data;
    925          1.131  sommerfe 
    926           1.43   mycroft 	VREF(vp);
    927          1.113      fvdl 	vn_lock(vp,  LK_EXCLUSIVE | LK_RETRY);
    928           1.31       cgd 	if (vp->v_type != VDIR)
    929           1.31       cgd 		error = ENOTDIR;
    930           1.31       cgd 	else
    931          1.190      fvdl 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
    932           1.43   mycroft 	while (!error && (mp = vp->v_mountedhere) != NULL) {
    933          1.113      fvdl 		if (vfs_busy(mp, 0, 0))
    934           1.43   mycroft 			continue;
    935          1.189   thorpej 		error = VFS_ROOT(mp, &tdp);
    936          1.113      fvdl 		vfs_unbusy(mp);
    937          1.113      fvdl 		if (error)
    938           1.43   mycroft 			break;
    939           1.43   mycroft 		vput(vp);
    940           1.43   mycroft 		vp = tdp;
    941           1.43   mycroft 	}
    942           1.43   mycroft 	if (error) {
    943          1.113      fvdl 		vput(vp);
    944          1.135   thorpej 		goto out;
    945           1.43   mycroft 	}
    946          1.113      fvdl 	VOP_UNLOCK(vp, 0);
    947          1.131  sommerfe 
    948          1.131  sommerfe 	/*
    949          1.131  sommerfe 	 * Disallow changing to a directory not under the process's
    950          1.131  sommerfe 	 * current root directory (if there is one).
    951          1.131  sommerfe 	 */
    952          1.190      fvdl 	if (cwdi->cwdi_rdir && !vn_isunder(vp, NULL, p)) {
    953          1.131  sommerfe 		vrele(vp);
    954          1.135   thorpej 		error = EPERM;	/* operation not permitted */
    955          1.135   thorpej 		goto out;
    956          1.131  sommerfe 	}
    957          1.205  junyoung 
    958          1.134   thorpej 	vrele(cwdi->cwdi_cdir);
    959          1.134   thorpej 	cwdi->cwdi_cdir = vp;
    960          1.135   thorpej  out:
    961          1.190      fvdl 	FILE_UNUSE(fp, p);
    962          1.135   thorpej 	return (error);
    963           1.31       cgd }
    964           1.31       cgd 
    965           1.31       cgd /*
    966          1.131  sommerfe  * Change this process's notion of the root directory to a given file descriptor.
    967          1.131  sommerfe  */
    968          1.131  sommerfe 
    969          1.131  sommerfe int
    970          1.179   thorpej sys_fchroot(l, v, retval)
    971          1.179   thorpej 	struct lwp *l;
    972          1.131  sommerfe 	void *v;
    973          1.131  sommerfe 	register_t *retval;
    974          1.131  sommerfe {
    975          1.131  sommerfe 	struct sys_fchroot_args *uap = v;
    976          1.179   thorpej 	struct proc *p = l->l_proc;
    977          1.134   thorpej 	struct filedesc *fdp = p->p_fd;
    978          1.134   thorpej 	struct cwdinfo *cwdi = p->p_cwdi;
    979          1.131  sommerfe 	struct vnode	*vp;
    980          1.131  sommerfe 	struct file	*fp;
    981          1.131  sommerfe 	int		 error;
    982          1.131  sommerfe 
    983          1.131  sommerfe 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    984          1.131  sommerfe 		return error;
    985          1.135   thorpej 	/* getvnode() will use the descriptor for us */
    986          1.131  sommerfe 	if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0)
    987          1.131  sommerfe 		return error;
    988          1.131  sommerfe 	vp = (struct vnode *) fp->f_data;
    989          1.131  sommerfe 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    990          1.131  sommerfe 	if (vp->v_type != VDIR)
    991          1.131  sommerfe 		error = ENOTDIR;
    992          1.131  sommerfe 	else
    993          1.190      fvdl 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
    994          1.131  sommerfe 	VOP_UNLOCK(vp, 0);
    995          1.131  sommerfe 	if (error)
    996          1.135   thorpej 		goto out;
    997          1.131  sommerfe 	VREF(vp);
    998          1.131  sommerfe 
    999          1.131  sommerfe 	/*
   1000          1.131  sommerfe 	 * Prevent escaping from chroot by putting the root under
   1001          1.131  sommerfe 	 * the working directory.  Silently chdir to / if we aren't
   1002          1.131  sommerfe 	 * already there.
   1003          1.131  sommerfe 	 */
   1004          1.190      fvdl 	if (!vn_isunder(cwdi->cwdi_cdir, vp, p)) {
   1005          1.131  sommerfe 		/*
   1006          1.131  sommerfe 		 * XXX would be more failsafe to change directory to a
   1007          1.131  sommerfe 		 * deadfs node here instead
   1008          1.131  sommerfe 		 */
   1009          1.134   thorpej 		vrele(cwdi->cwdi_cdir);
   1010          1.131  sommerfe 		VREF(vp);
   1011          1.134   thorpej 		cwdi->cwdi_cdir = vp;
   1012          1.131  sommerfe 	}
   1013          1.205  junyoung 
   1014          1.134   thorpej 	if (cwdi->cwdi_rdir != NULL)
   1015          1.134   thorpej 		vrele(cwdi->cwdi_rdir);
   1016          1.134   thorpej 	cwdi->cwdi_rdir = vp;
   1017          1.135   thorpej  out:
   1018          1.190      fvdl 	FILE_UNUSE(fp, p);
   1019          1.135   thorpej 	return (error);
   1020          1.131  sommerfe }
   1021          1.131  sommerfe 
   1022          1.131  sommerfe 
   1023          1.131  sommerfe 
   1024          1.131  sommerfe /*
   1025           1.31       cgd  * Change current working directory (``.'').
   1026           1.31       cgd  */
   1027           1.31       cgd /* ARGSUSED */
   1028           1.63  christos int
   1029          1.179   thorpej sys_chdir(l, v, retval)
   1030          1.179   thorpej 	struct lwp *l;
   1031           1.56   thorpej 	void *v;
   1032           1.56   thorpej 	register_t *retval;
   1033           1.56   thorpej {
   1034           1.57   mycroft 	struct sys_chdir_args /* {
   1035           1.74       cgd 		syscallarg(const char *) path;
   1036           1.56   thorpej 	} */ *uap = v;
   1037          1.179   thorpej 	struct proc *p = l->l_proc;
   1038          1.134   thorpej 	struct cwdinfo *cwdi = p->p_cwdi;
   1039           1.31       cgd 	int error;
   1040           1.31       cgd 	struct nameidata nd;
   1041           1.31       cgd 
   1042           1.35       cgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
   1043          1.190      fvdl 	    SCARG(uap, path), p);
   1044          1.190      fvdl 	if ((error = change_dir(&nd, p)) != 0)
   1045           1.31       cgd 		return (error);
   1046          1.134   thorpej 	vrele(cwdi->cwdi_cdir);
   1047          1.134   thorpej 	cwdi->cwdi_cdir = nd.ni_vp;
   1048           1.31       cgd 	return (0);
   1049           1.31       cgd }
   1050           1.31       cgd 
   1051           1.31       cgd /*
   1052           1.31       cgd  * Change notion of root (``/'') directory.
   1053           1.31       cgd  */
   1054           1.31       cgd /* ARGSUSED */
   1055           1.63  christos int
   1056          1.179   thorpej sys_chroot(l, v, retval)
   1057          1.179   thorpej 	struct lwp *l;
   1058           1.56   thorpej 	void *v;
   1059           1.56   thorpej 	register_t *retval;
   1060           1.56   thorpej {
   1061           1.57   mycroft 	struct sys_chroot_args /* {
   1062           1.74       cgd 		syscallarg(const char *) path;
   1063           1.56   thorpej 	} */ *uap = v;
   1064          1.179   thorpej 	struct proc *p = l->l_proc;
   1065          1.134   thorpej 	struct cwdinfo *cwdi = p->p_cwdi;
   1066          1.131  sommerfe 	struct vnode *vp;
   1067           1.31       cgd 	int error;
   1068           1.31       cgd 	struct nameidata nd;
   1069           1.31       cgd 
   1070           1.63  christos 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
   1071           1.31       cgd 		return (error);
   1072           1.35       cgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
   1073          1.190      fvdl 	    SCARG(uap, path), p);
   1074          1.190      fvdl 	if ((error = change_dir(&nd, p)) != 0)
   1075           1.31       cgd 		return (error);
   1076          1.134   thorpej 	if (cwdi->cwdi_rdir != NULL)
   1077          1.134   thorpej 		vrele(cwdi->cwdi_rdir);
   1078          1.131  sommerfe 	vp = nd.ni_vp;
   1079          1.134   thorpej 	cwdi->cwdi_rdir = vp;
   1080          1.131  sommerfe 
   1081          1.131  sommerfe 	/*
   1082          1.131  sommerfe 	 * Prevent escaping from chroot by putting the root under
   1083          1.131  sommerfe 	 * the working directory.  Silently chdir to / if we aren't
   1084          1.131  sommerfe 	 * already there.
   1085          1.131  sommerfe 	 */
   1086          1.190      fvdl 	if (!vn_isunder(cwdi->cwdi_cdir, vp, p)) {
   1087          1.131  sommerfe 		/*
   1088          1.131  sommerfe 		 * XXX would be more failsafe to change directory to a
   1089          1.131  sommerfe 		 * deadfs node here instead
   1090          1.131  sommerfe 		 */
   1091          1.134   thorpej 		vrele(cwdi->cwdi_cdir);
   1092          1.131  sommerfe 		VREF(vp);
   1093          1.134   thorpej 		cwdi->cwdi_cdir = vp;
   1094          1.131  sommerfe 	}
   1095          1.205  junyoung 
   1096           1.31       cgd 	return (0);
   1097           1.31       cgd }
   1098           1.31       cgd 
   1099           1.31       cgd /*
   1100           1.31       cgd  * Common routine for chroot and chdir.
   1101           1.31       cgd  */
   1102           1.31       cgd static int
   1103          1.190      fvdl change_dir(ndp, p)
   1104          1.155  augustss 	struct nameidata *ndp;
   1105          1.190      fvdl 	struct proc *p;
   1106           1.31       cgd {
   1107           1.31       cgd 	struct vnode *vp;
   1108           1.31       cgd 	int error;
   1109           1.31       cgd 
   1110           1.63  christos 	if ((error = namei(ndp)) != 0)
   1111           1.31       cgd 		return (error);
   1112           1.31       cgd 	vp = ndp->ni_vp;
   1113           1.31       cgd 	if (vp->v_type != VDIR)
   1114           1.31       cgd 		error = ENOTDIR;
   1115           1.31       cgd 	else
   1116          1.190      fvdl 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
   1117          1.205  junyoung 
   1118           1.31       cgd 	if (error)
   1119          1.113      fvdl 		vput(vp);
   1120          1.113      fvdl 	else
   1121          1.113      fvdl 		VOP_UNLOCK(vp, 0);
   1122           1.31       cgd 	return (error);
   1123           1.31       cgd }
   1124           1.31       cgd 
   1125           1.31       cgd /*
   1126           1.31       cgd  * Check permissions, allocate an open file structure,
   1127           1.31       cgd  * and call the device open routine if any.
   1128           1.31       cgd  */
   1129           1.63  christos int
   1130          1.179   thorpej sys_open(l, v, retval)
   1131          1.179   thorpej 	struct lwp *l;
   1132           1.56   thorpej 	void *v;
   1133           1.56   thorpej 	register_t *retval;
   1134           1.56   thorpej {
   1135          1.155  augustss 	struct sys_open_args /* {
   1136           1.74       cgd 		syscallarg(const char *) path;
   1137           1.35       cgd 		syscallarg(int) flags;
   1138           1.35       cgd 		syscallarg(int) mode;
   1139           1.56   thorpej 	} */ *uap = v;
   1140          1.179   thorpej 	struct proc *p = l->l_proc;
   1141          1.134   thorpej 	struct cwdinfo *cwdi = p->p_cwdi;
   1142          1.135   thorpej 	struct filedesc *fdp = p->p_fd;
   1143          1.135   thorpej 	struct file *fp;
   1144          1.135   thorpej 	struct vnode *vp;
   1145           1.31       cgd 	int flags, cmode;
   1146           1.31       cgd 	int type, indx, error;
   1147           1.31       cgd 	struct flock lf;
   1148           1.31       cgd 	struct nameidata nd;
   1149           1.31       cgd 
   1150          1.104   mycroft 	flags = FFLAGS(SCARG(uap, flags));
   1151          1.104   mycroft 	if ((flags & (FREAD | FWRITE)) == 0)
   1152          1.104   mycroft 		return (EINVAL);
   1153          1.135   thorpej 	/* falloc() will use the file descriptor for us */
   1154          1.135   thorpej 	if ((error = falloc(p, &fp, &indx)) != 0)
   1155           1.31       cgd 		return (error);
   1156          1.134   thorpej 	cmode = ((SCARG(uap, mode) &~ cwdi->cwdi_cmask) & ALLPERMS) &~ S_ISTXT;
   1157          1.190      fvdl 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   1158          1.194  jdolecek 	l->l_dupfd = -indx - 1;			/* XXX check for fdopen */
   1159           1.63  christos 	if ((error = vn_open(&nd, flags, cmode)) != 0) {
   1160          1.190      fvdl 		FILE_UNUSE(fp, p);
   1161          1.200      yamt 		fdp->fd_ofiles[indx] = NULL;
   1162           1.31       cgd 		ffree(fp);
   1163          1.213  christos 		if ((error == EDUPFD || error == EMOVEFD) &&
   1164          1.194  jdolecek 		    l->l_dupfd >= 0 &&			/* XXX from fdopen */
   1165           1.45   mycroft 		    (error =
   1166          1.194  jdolecek 			dupfdopen(p, indx, l->l_dupfd, flags, error)) == 0) {
   1167           1.45   mycroft 			*retval = indx;
   1168           1.45   mycroft 			return (0);
   1169           1.45   mycroft 		}
   1170           1.45   mycroft 		if (error == ERESTART)
   1171           1.44   mycroft 			error = EINTR;
   1172          1.153   thorpej 		fdremove(fdp, indx);
   1173           1.31       cgd 		return (error);
   1174           1.31       cgd 	}
   1175          1.194  jdolecek 	l->l_dupfd = 0;
   1176           1.31       cgd 	vp = nd.ni_vp;
   1177           1.31       cgd 	fp->f_flag = flags & FMASK;
   1178           1.31       cgd 	fp->f_type = DTYPE_VNODE;
   1179           1.31       cgd 	fp->f_ops = &vnops;
   1180          1.184       dsl 	fp->f_data = vp;
   1181           1.31       cgd 	if (flags & (O_EXLOCK | O_SHLOCK)) {
   1182           1.31       cgd 		lf.l_whence = SEEK_SET;
   1183           1.31       cgd 		lf.l_start = 0;
   1184           1.31       cgd 		lf.l_len = 0;
   1185           1.31       cgd 		if (flags & O_EXLOCK)
   1186           1.31       cgd 			lf.l_type = F_WRLCK;
   1187           1.31       cgd 		else
   1188           1.31       cgd 			lf.l_type = F_RDLCK;
   1189           1.31       cgd 		type = F_FLOCK;
   1190           1.31       cgd 		if ((flags & FNONBLOCK) == 0)
   1191           1.31       cgd 			type |= F_WAIT;
   1192          1.113      fvdl 		VOP_UNLOCK(vp, 0);
   1193          1.184       dsl 		error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type);
   1194           1.63  christos 		if (error) {
   1195          1.190      fvdl 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
   1196          1.190      fvdl 			FILE_UNUSE(fp, p);
   1197           1.31       cgd 			ffree(fp);
   1198          1.153   thorpej 			fdremove(fdp, indx);
   1199           1.31       cgd 			return (error);
   1200           1.31       cgd 		}
   1201          1.113      fvdl 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
   1202           1.31       cgd 		fp->f_flag |= FHASLOCK;
   1203           1.31       cgd 	}
   1204          1.113      fvdl 	VOP_UNLOCK(vp, 0);
   1205           1.31       cgd 	*retval = indx;
   1206          1.166   thorpej 	FILE_SET_MATURE(fp);
   1207          1.190      fvdl 	FILE_UNUSE(fp, p);
   1208           1.31       cgd 	return (0);
   1209          1.137  wrstuden }
   1210          1.137  wrstuden 
   1211          1.137  wrstuden /*
   1212          1.137  wrstuden  * Get file handle system call
   1213          1.137  wrstuden  */
   1214          1.137  wrstuden int
   1215          1.179   thorpej sys_getfh(l, v, retval)
   1216          1.179   thorpej 	struct lwp *l;
   1217          1.155  augustss 	void *v;
   1218          1.137  wrstuden 	register_t *retval;
   1219          1.137  wrstuden {
   1220          1.155  augustss 	struct sys_getfh_args /* {
   1221          1.137  wrstuden 		syscallarg(char *) fname;
   1222          1.137  wrstuden 		syscallarg(fhandle_t *) fhp;
   1223          1.137  wrstuden 	} */ *uap = v;
   1224          1.179   thorpej 	struct proc *p = l->l_proc;
   1225          1.155  augustss 	struct vnode *vp;
   1226          1.137  wrstuden 	fhandle_t fh;
   1227          1.137  wrstuden 	int error;
   1228          1.137  wrstuden 	struct nameidata nd;
   1229          1.137  wrstuden 
   1230          1.137  wrstuden 	/*
   1231          1.137  wrstuden 	 * Must be super user
   1232          1.137  wrstuden 	 */
   1233          1.137  wrstuden 	error = suser(p->p_ucred, &p->p_acflag);
   1234          1.137  wrstuden 	if (error)
   1235          1.137  wrstuden 		return (error);
   1236          1.137  wrstuden 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
   1237          1.190      fvdl 	    SCARG(uap, fname), p);
   1238          1.137  wrstuden 	error = namei(&nd);
   1239          1.137  wrstuden 	if (error)
   1240          1.137  wrstuden 		return (error);
   1241          1.137  wrstuden 	vp = nd.ni_vp;
   1242          1.184       dsl 	memset(&fh, 0, sizeof(fh));
   1243          1.206  christos 	fh.fh_fsid = vp->v_mount->mnt_stat.f_fsidx;
   1244          1.137  wrstuden 	error = VFS_VPTOFH(vp, &fh.fh_fid);
   1245          1.137  wrstuden 	vput(vp);
   1246          1.137  wrstuden 	if (error)
   1247          1.137  wrstuden 		return (error);
   1248          1.184       dsl 	error = copyout(&fh, (caddr_t)SCARG(uap, fhp), sizeof (fh));
   1249          1.137  wrstuden 	return (error);
   1250          1.137  wrstuden }
   1251          1.137  wrstuden 
   1252          1.137  wrstuden /*
   1253          1.137  wrstuden  * Open a file given a file handle.
   1254          1.137  wrstuden  *
   1255          1.137  wrstuden  * Check permissions, allocate an open file structure,
   1256          1.137  wrstuden  * and call the device open routine if any.
   1257          1.137  wrstuden  */
   1258          1.137  wrstuden int
   1259          1.179   thorpej sys_fhopen(l, v, retval)
   1260          1.179   thorpej 	struct lwp *l;
   1261          1.137  wrstuden 	void *v;
   1262          1.137  wrstuden 	register_t *retval;
   1263          1.137  wrstuden {
   1264          1.155  augustss 	struct sys_fhopen_args /* {
   1265          1.137  wrstuden 		syscallarg(const fhandle_t *) fhp;
   1266          1.137  wrstuden 		syscallarg(int) flags;
   1267          1.137  wrstuden 	} */ *uap = v;
   1268          1.179   thorpej 	struct proc *p = l->l_proc;
   1269          1.137  wrstuden 	struct filedesc *fdp = p->p_fd;
   1270          1.137  wrstuden 	struct file *fp;
   1271          1.139  wrstuden 	struct vnode *vp = NULL;
   1272          1.137  wrstuden 	struct mount *mp;
   1273          1.137  wrstuden 	struct ucred *cred = p->p_ucred;
   1274          1.137  wrstuden 	int flags;
   1275          1.137  wrstuden 	struct file *nfp;
   1276          1.137  wrstuden 	int type, indx, error=0;
   1277          1.137  wrstuden 	struct flock lf;
   1278          1.137  wrstuden 	struct vattr va;
   1279          1.137  wrstuden 	fhandle_t fh;
   1280          1.137  wrstuden 
   1281          1.137  wrstuden 	/*
   1282          1.137  wrstuden 	 * Must be super user
   1283          1.137  wrstuden 	 */
   1284          1.137  wrstuden 	if ((error = suser(p->p_ucred, &p->p_acflag)))
   1285          1.137  wrstuden 		return (error);
   1286          1.137  wrstuden 
   1287          1.137  wrstuden 	flags = FFLAGS(SCARG(uap, flags));
   1288          1.137  wrstuden 	if ((flags & (FREAD | FWRITE)) == 0)
   1289          1.137  wrstuden 		return (EINVAL);
   1290          1.137  wrstuden 	if ((flags & O_CREAT))
   1291          1.137  wrstuden 		return (EINVAL);
   1292          1.139  wrstuden 	/* falloc() will use the file descriptor for us */
   1293          1.137  wrstuden 	if ((error = falloc(p, &nfp, &indx)) != 0)
   1294          1.137  wrstuden 		return (error);
   1295          1.137  wrstuden 	fp = nfp;
   1296          1.137  wrstuden 	if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
   1297          1.139  wrstuden 		goto bad;
   1298          1.139  wrstuden 
   1299          1.139  wrstuden 	if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) {
   1300          1.139  wrstuden 		error = ESTALE;
   1301          1.139  wrstuden 		goto bad;
   1302          1.139  wrstuden 	}
   1303          1.137  wrstuden 
   1304          1.189   thorpej 	if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)) != 0) {
   1305          1.139  wrstuden 		vp = NULL;	/* most likely unnecessary sanity for bad: */
   1306          1.139  wrstuden 		goto bad;
   1307          1.139  wrstuden 	}
   1308          1.137  wrstuden 
   1309          1.137  wrstuden 	/* Now do an effective vn_open */
   1310          1.137  wrstuden 
   1311          1.137  wrstuden 	if (vp->v_type == VSOCK) {
   1312          1.137  wrstuden 		error = EOPNOTSUPP;
   1313          1.137  wrstuden 		goto bad;
   1314          1.137  wrstuden 	}
   1315          1.137  wrstuden 	if (flags & FREAD) {
   1316          1.190      fvdl 		if ((error = VOP_ACCESS(vp, VREAD, cred, p)) != 0)
   1317          1.137  wrstuden 			goto bad;
   1318          1.137  wrstuden 	}
   1319          1.137  wrstuden 	if (flags & (FWRITE | O_TRUNC)) {
   1320          1.137  wrstuden 		if (vp->v_type == VDIR) {
   1321          1.137  wrstuden 			error = EISDIR;
   1322          1.137  wrstuden 			goto bad;
   1323          1.137  wrstuden 		}
   1324          1.137  wrstuden 		if ((error = vn_writechk(vp)) != 0 ||
   1325          1.190      fvdl 		    (error = VOP_ACCESS(vp, VWRITE, cred, p)) != 0)
   1326          1.137  wrstuden 			goto bad;
   1327          1.137  wrstuden 	}
   1328          1.137  wrstuden 	if (flags & O_TRUNC) {
   1329          1.197   hannken 		if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
   1330          1.197   hannken 			goto bad;
   1331          1.137  wrstuden 		VOP_UNLOCK(vp, 0);			/* XXX */
   1332          1.190      fvdl 		VOP_LEASE(vp, p, cred, LEASE_WRITE);
   1333          1.137  wrstuden 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);   /* XXX */
   1334          1.137  wrstuden 		VATTR_NULL(&va);
   1335          1.137  wrstuden 		va.va_size = 0;
   1336          1.197   hannken 		error = VOP_SETATTR(vp, &va, cred, p);
   1337          1.197   hannken 		vn_finished_write(mp, 0);
   1338          1.197   hannken 		if (error)
   1339          1.137  wrstuden 			goto bad;
   1340          1.137  wrstuden 	}
   1341          1.190      fvdl 	if ((error = VOP_OPEN(vp, flags, cred, p)) != 0)
   1342          1.137  wrstuden 		goto bad;
   1343          1.164       chs 	if (vp->v_type == VREG &&
   1344          1.164       chs 	    uvn_attach(vp, flags & FWRITE ? VM_PROT_WRITE : 0) == NULL) {
   1345          1.164       chs 		error = EIO;
   1346          1.164       chs 		goto bad;
   1347          1.164       chs 	}
   1348          1.137  wrstuden 	if (flags & FWRITE)
   1349          1.137  wrstuden 		vp->v_writecount++;
   1350          1.137  wrstuden 
   1351          1.137  wrstuden 	/* done with modified vn_open, now finish what sys_open does. */
   1352          1.137  wrstuden 
   1353          1.137  wrstuden 	fp->f_flag = flags & FMASK;
   1354          1.137  wrstuden 	fp->f_type = DTYPE_VNODE;
   1355          1.137  wrstuden 	fp->f_ops = &vnops;
   1356          1.184       dsl 	fp->f_data = vp;
   1357          1.137  wrstuden 	if (flags & (O_EXLOCK | O_SHLOCK)) {
   1358          1.137  wrstuden 		lf.l_whence = SEEK_SET;
   1359          1.137  wrstuden 		lf.l_start = 0;
   1360          1.137  wrstuden 		lf.l_len = 0;
   1361          1.137  wrstuden 		if (flags & O_EXLOCK)
   1362          1.137  wrstuden 			lf.l_type = F_WRLCK;
   1363          1.137  wrstuden 		else
   1364          1.137  wrstuden 			lf.l_type = F_RDLCK;
   1365          1.137  wrstuden 		type = F_FLOCK;
   1366          1.137  wrstuden 		if ((flags & FNONBLOCK) == 0)
   1367          1.137  wrstuden 			type |= F_WAIT;
   1368          1.137  wrstuden 		VOP_UNLOCK(vp, 0);
   1369          1.184       dsl 		error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, type);
   1370          1.137  wrstuden 		if (error) {
   1371          1.190      fvdl 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
   1372          1.190      fvdl 			FILE_UNUSE(fp, p);
   1373          1.137  wrstuden 			ffree(fp);
   1374          1.153   thorpej 			fdremove(fdp, indx);
   1375          1.137  wrstuden 			return (error);
   1376          1.137  wrstuden 		}
   1377          1.137  wrstuden 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
   1378          1.137  wrstuden 		fp->f_flag |= FHASLOCK;
   1379          1.137  wrstuden 	}
   1380          1.137  wrstuden 	VOP_UNLOCK(vp, 0);
   1381          1.137  wrstuden 	*retval = indx;
   1382          1.166   thorpej 	FILE_SET_MATURE(fp);
   1383          1.190      fvdl 	FILE_UNUSE(fp, p);
   1384          1.137  wrstuden 	return (0);
   1385          1.139  wrstuden 
   1386          1.137  wrstuden bad:
   1387          1.190      fvdl 	FILE_UNUSE(fp, p);
   1388          1.139  wrstuden 	ffree(fp);
   1389          1.153   thorpej 	fdremove(fdp, indx);
   1390          1.139  wrstuden 	if (vp != NULL)
   1391          1.139  wrstuden 		vput(vp);
   1392          1.137  wrstuden 	return (error);
   1393          1.137  wrstuden }
   1394          1.137  wrstuden 
   1395          1.137  wrstuden /* ARGSUSED */
   1396          1.137  wrstuden int
   1397          1.179   thorpej sys_fhstat(l, v, retval)
   1398          1.179   thorpej 	struct lwp *l;
   1399          1.137  wrstuden 	void *v;
   1400          1.137  wrstuden 	register_t *retval;
   1401          1.137  wrstuden {
   1402          1.155  augustss 	struct sys_fhstat_args /* {
   1403          1.137  wrstuden 		syscallarg(const fhandle_t *) fhp;
   1404          1.137  wrstuden 		syscallarg(struct stat *) sb;
   1405          1.137  wrstuden 	} */ *uap = v;
   1406          1.179   thorpej 	struct proc *p = l->l_proc;
   1407          1.137  wrstuden 	struct stat sb;
   1408          1.137  wrstuden 	int error;
   1409          1.137  wrstuden 	fhandle_t fh;
   1410          1.137  wrstuden 	struct mount *mp;
   1411          1.137  wrstuden 	struct vnode *vp;
   1412          1.137  wrstuden 
   1413          1.137  wrstuden 	/*
   1414          1.137  wrstuden 	 * Must be super user
   1415          1.137  wrstuden 	 */
   1416          1.137  wrstuden 	if ((error = suser(p->p_ucred, &p->p_acflag)))
   1417          1.137  wrstuden 		return (error);
   1418          1.137  wrstuden 
   1419          1.137  wrstuden 	if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
   1420          1.137  wrstuden 		return (error);
   1421          1.137  wrstuden 
   1422          1.137  wrstuden 	if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
   1423          1.137  wrstuden 		return (ESTALE);
   1424          1.189   thorpej 	if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
   1425          1.137  wrstuden 		return (error);
   1426          1.190      fvdl 	error = vn_stat(vp, &sb, p);
   1427          1.137  wrstuden 	vput(vp);
   1428          1.137  wrstuden 	if (error)
   1429          1.137  wrstuden 		return (error);
   1430          1.137  wrstuden 	error = copyout(&sb, SCARG(uap, sb), sizeof(sb));
   1431          1.137  wrstuden 	return (error);
   1432          1.137  wrstuden }
   1433          1.137  wrstuden 
   1434          1.137  wrstuden /* ARGSUSED */
   1435          1.137  wrstuden int
   1436          1.206  christos sys_fhstatvfs1(l, v, retval)
   1437          1.179   thorpej 	struct lwp *l;
   1438          1.137  wrstuden 	void *v;
   1439          1.137  wrstuden 	register_t *retval;
   1440          1.137  wrstuden {
   1441          1.206  christos 	struct sys_fhstatvfs1_args /*
   1442          1.137  wrstuden 		syscallarg(const fhandle_t *) fhp;
   1443          1.206  christos 		syscallarg(struct statvfs *) buf;
   1444          1.206  christos 		syscallarg(int)	flags;
   1445          1.137  wrstuden 	} */ *uap = v;
   1446          1.179   thorpej 	struct proc *p = l->l_proc;
   1447          1.206  christos 	struct statvfs sbuf;
   1448          1.137  wrstuden 	fhandle_t fh;
   1449          1.137  wrstuden 	struct mount *mp;
   1450          1.137  wrstuden 	struct vnode *vp;
   1451          1.137  wrstuden 	int error;
   1452          1.137  wrstuden 
   1453          1.137  wrstuden 	/*
   1454          1.137  wrstuden 	 * Must be super user
   1455          1.137  wrstuden 	 */
   1456          1.206  christos 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
   1457          1.206  christos 		return error;
   1458          1.137  wrstuden 
   1459          1.137  wrstuden 	if ((error = copyin(SCARG(uap, fhp), &fh, sizeof(fhandle_t))) != 0)
   1460          1.206  christos 		return error;
   1461          1.137  wrstuden 
   1462          1.137  wrstuden 	if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
   1463          1.206  christos 		return ESTALE;
   1464          1.189   thorpej 	if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
   1465          1.206  christos 		return error;
   1466          1.206  christos 
   1467          1.137  wrstuden 	mp = vp->v_mount;
   1468          1.206  christos 	if ((error = dostatvfs(mp, &sbuf, p, SCARG(uap, flags), 1)) != 0) {
   1469          1.206  christos 		vput(vp);
   1470          1.206  christos 		return error;
   1471          1.206  christos 	}
   1472          1.137  wrstuden 	vput(vp);
   1473          1.206  christos 	return copyout(&sbuf, SCARG(uap, buf), sizeof(sbuf));
   1474           1.31       cgd }
   1475           1.31       cgd 
   1476           1.31       cgd /*
   1477           1.31       cgd  * Create a special file.
   1478           1.31       cgd  */
   1479           1.31       cgd /* ARGSUSED */
   1480           1.63  christos int
   1481          1.179   thorpej sys_mknod(l, v, retval)
   1482          1.179   thorpej 	struct lwp *l;
   1483           1.56   thorpej 	void *v;
   1484           1.56   thorpej 	register_t *retval;
   1485           1.56   thorpej {
   1486          1.155  augustss 	struct sys_mknod_args /* {
   1487           1.74       cgd 		syscallarg(const char *) path;
   1488           1.35       cgd 		syscallarg(int) mode;
   1489           1.35       cgd 		syscallarg(int) dev;
   1490           1.56   thorpej 	} */ *uap = v;
   1491          1.179   thorpej 	struct proc *p = l->l_proc;
   1492          1.155  augustss 	struct vnode *vp;
   1493          1.197   hannken 	struct mount *mp;
   1494           1.31       cgd 	struct vattr vattr;
   1495           1.31       cgd 	int error;
   1496           1.63  christos 	int whiteout = 0;
   1497           1.31       cgd 	struct nameidata nd;
   1498           1.31       cgd 
   1499           1.63  christos 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
   1500           1.31       cgd 		return (error);
   1501          1.197   hannken restart:
   1502          1.190      fvdl 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
   1503           1.63  christos 	if ((error = namei(&nd)) != 0)
   1504           1.31       cgd 		return (error);
   1505           1.31       cgd 	vp = nd.ni_vp;
   1506           1.43   mycroft 	if (vp != NULL)
   1507           1.31       cgd 		error = EEXIST;
   1508           1.43   mycroft 	else {
   1509           1.43   mycroft 		VATTR_NULL(&vattr);
   1510           1.94     enami 		vattr.va_mode =
   1511          1.134   thorpej 		    (SCARG(uap, mode) & ALLPERMS) &~ p->p_cwdi->cwdi_cmask;
   1512           1.43   mycroft 		vattr.va_rdev = SCARG(uap, dev);
   1513           1.43   mycroft 		whiteout = 0;
   1514           1.43   mycroft 
   1515           1.43   mycroft 		switch (SCARG(uap, mode) & S_IFMT) {
   1516           1.43   mycroft 		case S_IFMT:	/* used by badsect to flag bad sectors */
   1517           1.43   mycroft 			vattr.va_type = VBAD;
   1518           1.43   mycroft 			break;
   1519           1.43   mycroft 		case S_IFCHR:
   1520           1.43   mycroft 			vattr.va_type = VCHR;
   1521           1.43   mycroft 			break;
   1522           1.43   mycroft 		case S_IFBLK:
   1523           1.43   mycroft 			vattr.va_type = VBLK;
   1524           1.43   mycroft 			break;
   1525           1.43   mycroft 		case S_IFWHT:
   1526           1.43   mycroft 			whiteout = 1;
   1527           1.43   mycroft 			break;
   1528           1.43   mycroft 		default:
   1529           1.43   mycroft 			error = EINVAL;
   1530           1.43   mycroft 			break;
   1531           1.43   mycroft 		}
   1532           1.31       cgd 	}
   1533          1.197   hannken 	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
   1534          1.197   hannken 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
   1535          1.197   hannken 		if (nd.ni_dvp == vp)
   1536          1.197   hannken 			vrele(nd.ni_dvp);
   1537          1.197   hannken 		else
   1538          1.197   hannken 			vput(nd.ni_dvp);
   1539          1.197   hannken 		if (vp)
   1540          1.197   hannken 			vrele(vp);
   1541          1.197   hannken 		if ((error = vn_start_write(NULL, &mp,
   1542          1.197   hannken 		    V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
   1543          1.197   hannken 			return (error);
   1544          1.197   hannken 		goto restart;
   1545          1.197   hannken 	}
   1546           1.43   mycroft 	if (!error) {
   1547          1.190      fvdl 		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
   1548           1.43   mycroft 		if (whiteout) {
   1549           1.43   mycroft 			error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
   1550           1.43   mycroft 			if (error)
   1551           1.43   mycroft 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
   1552           1.43   mycroft 			vput(nd.ni_dvp);
   1553           1.43   mycroft 		} else {
   1554           1.43   mycroft 			error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
   1555           1.43   mycroft 						&nd.ni_cnd, &vattr);
   1556          1.168     assar 			if (error == 0)
   1557          1.168     assar 				vput(nd.ni_vp);
   1558           1.43   mycroft 		}
   1559           1.43   mycroft 	} else {
   1560           1.43   mycroft 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
   1561           1.43   mycroft 		if (nd.ni_dvp == vp)
   1562           1.43   mycroft 			vrele(nd.ni_dvp);
   1563           1.43   mycroft 		else
   1564           1.43   mycroft 			vput(nd.ni_dvp);
   1565           1.43   mycroft 		if (vp)
   1566           1.43   mycroft 			vrele(vp);
   1567           1.31       cgd 	}
   1568          1.197   hannken 	vn_finished_write(mp, 0);
   1569           1.31       cgd 	return (error);
   1570           1.31       cgd }
   1571           1.31       cgd 
   1572           1.31       cgd /*
   1573           1.31       cgd  * Create a named pipe.
   1574           1.31       cgd  */
   1575           1.31       cgd /* ARGSUSED */
   1576           1.63  christos int
   1577          1.179   thorpej sys_mkfifo(l, v, retval)
   1578          1.179   thorpej 	struct lwp *l;
   1579           1.56   thorpej 	void *v;
   1580           1.56   thorpej 	register_t *retval;
   1581           1.56   thorpej {
   1582          1.155  augustss 	struct sys_mkfifo_args /* {
   1583           1.74       cgd 		syscallarg(const char *) path;
   1584           1.35       cgd 		syscallarg(int) mode;
   1585           1.56   thorpej 	} */ *uap = v;
   1586          1.179   thorpej 	struct proc *p = l->l_proc;
   1587          1.197   hannken 	struct mount *mp;
   1588           1.31       cgd 	struct vattr vattr;
   1589           1.31       cgd 	int error;
   1590           1.31       cgd 	struct nameidata nd;
   1591           1.31       cgd 
   1592          1.197   hannken restart:
   1593          1.190      fvdl 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
   1594           1.63  christos 	if ((error = namei(&nd)) != 0)
   1595           1.31       cgd 		return (error);
   1596           1.31       cgd 	if (nd.ni_vp != NULL) {
   1597           1.31       cgd 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
   1598           1.31       cgd 		if (nd.ni_dvp == nd.ni_vp)
   1599           1.31       cgd 			vrele(nd.ni_dvp);
   1600           1.31       cgd 		else
   1601           1.31       cgd 			vput(nd.ni_dvp);
   1602           1.31       cgd 		vrele(nd.ni_vp);
   1603           1.31       cgd 		return (EEXIST);
   1604           1.31       cgd 	}
   1605          1.197   hannken 	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
   1606          1.197   hannken 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
   1607          1.197   hannken 		if (nd.ni_dvp == nd.ni_vp)
   1608          1.197   hannken 			vrele(nd.ni_dvp);
   1609          1.197   hannken 		else
   1610          1.197   hannken 			vput(nd.ni_dvp);
   1611          1.197   hannken 		if (nd.ni_vp)
   1612          1.197   hannken 			vrele(nd.ni_vp);
   1613          1.197   hannken 		if ((error = vn_start_write(NULL, &mp,
   1614          1.197   hannken 		    V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
   1615          1.197   hannken 			return (error);
   1616          1.197   hannken 		goto restart;
   1617          1.197   hannken 	}
   1618           1.31       cgd 	VATTR_NULL(&vattr);
   1619           1.31       cgd 	vattr.va_type = VFIFO;
   1620          1.134   thorpej 	vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_cwdi->cwdi_cmask;
   1621          1.190      fvdl 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
   1622          1.168     assar 	error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
   1623          1.168     assar 	if (error == 0)
   1624          1.168     assar 		vput(nd.ni_vp);
   1625          1.197   hannken 	vn_finished_write(mp, 0);
   1626          1.168     assar 	return (error);
   1627           1.31       cgd }
   1628           1.31       cgd 
   1629           1.31       cgd /*
   1630           1.31       cgd  * Make a hard file link.
   1631           1.31       cgd  */
   1632           1.31       cgd /* ARGSUSED */
   1633           1.63  christos int
   1634          1.179   thorpej sys_link(l, v, retval)
   1635          1.179   thorpej 	struct lwp *l;
   1636           1.56   thorpej 	void *v;
   1637           1.56   thorpej 	register_t *retval;
   1638           1.56   thorpej {
   1639          1.155  augustss 	struct sys_link_args /* {
   1640           1.74       cgd 		syscallarg(const char *) path;
   1641           1.74       cgd 		syscallarg(const char *) link;
   1642           1.56   thorpej 	} */ *uap = v;
   1643          1.179   thorpej 	struct proc *p = l->l_proc;
   1644          1.155  augustss 	struct vnode *vp;
   1645          1.197   hannken 	struct mount *mp;
   1646           1.31       cgd 	struct nameidata nd;
   1647           1.31       cgd 	int error;
   1648           1.31       cgd 
   1649          1.190      fvdl 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   1650           1.63  christos 	if ((error = namei(&nd)) != 0)
   1651           1.31       cgd 		return (error);
   1652           1.31       cgd 	vp = nd.ni_vp;
   1653          1.197   hannken 	if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) {
   1654          1.197   hannken 		vrele(vp);
   1655          1.197   hannken 		return (error);
   1656          1.197   hannken 	}
   1657          1.190      fvdl 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
   1658           1.66   mycroft 	if ((error = namei(&nd)) != 0)
   1659           1.66   mycroft 		goto out;
   1660           1.66   mycroft 	if (nd.ni_vp) {
   1661           1.66   mycroft 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
   1662           1.66   mycroft 		if (nd.ni_dvp == nd.ni_vp)
   1663           1.66   mycroft 			vrele(nd.ni_dvp);
   1664           1.66   mycroft 		else
   1665           1.66   mycroft 			vput(nd.ni_dvp);
   1666           1.66   mycroft 		vrele(nd.ni_vp);
   1667           1.66   mycroft 		error = EEXIST;
   1668           1.66   mycroft 		goto out;
   1669           1.31       cgd 	}
   1670          1.190      fvdl 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
   1671          1.190      fvdl 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
   1672           1.66   mycroft 	error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
   1673           1.66   mycroft out:
   1674           1.31       cgd 	vrele(vp);
   1675          1.197   hannken 	vn_finished_write(mp, 0);
   1676           1.31       cgd 	return (error);
   1677           1.31       cgd }
   1678           1.31       cgd 
   1679           1.31       cgd /*
   1680           1.31       cgd  * Make a symbolic link.
   1681           1.31       cgd  */
   1682           1.31       cgd /* ARGSUSED */
   1683           1.63  christos int
   1684          1.179   thorpej sys_symlink(l, v, retval)
   1685          1.179   thorpej 	struct lwp *l;
   1686           1.56   thorpej 	void *v;
   1687           1.56   thorpej 	register_t *retval;
   1688           1.56   thorpej {
   1689          1.155  augustss 	struct sys_symlink_args /* {
   1690           1.74       cgd 		syscallarg(const char *) path;
   1691           1.74       cgd 		syscallarg(const char *) link;
   1692           1.56   thorpej 	} */ *uap = v;
   1693          1.179   thorpej 	struct proc *p = l->l_proc;
   1694          1.197   hannken 	struct mount *mp;
   1695           1.31       cgd 	struct vattr vattr;
   1696           1.31       cgd 	char *path;
   1697           1.31       cgd 	int error;
   1698           1.31       cgd 	struct nameidata nd;
   1699           1.31       cgd 
   1700          1.161   thorpej 	path = PNBUF_GET();
   1701           1.63  christos 	error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL);
   1702           1.63  christos 	if (error)
   1703           1.43   mycroft 		goto out;
   1704          1.197   hannken restart:
   1705          1.190      fvdl 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
   1706           1.63  christos 	if ((error = namei(&nd)) != 0)
   1707           1.43   mycroft 		goto out;
   1708           1.31       cgd 	if (nd.ni_vp) {
   1709           1.31       cgd 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
   1710           1.31       cgd 		if (nd.ni_dvp == nd.ni_vp)
   1711           1.31       cgd 			vrele(nd.ni_dvp);
   1712           1.31       cgd 		else
   1713           1.31       cgd 			vput(nd.ni_dvp);
   1714           1.31       cgd 		vrele(nd.ni_vp);
   1715           1.31       cgd 		error = EEXIST;
   1716           1.43   mycroft 		goto out;
   1717           1.31       cgd 	}
   1718          1.197   hannken 	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
   1719          1.197   hannken 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
   1720          1.197   hannken 		if (nd.ni_dvp == nd.ni_vp)
   1721          1.197   hannken 			vrele(nd.ni_dvp);
   1722          1.197   hannken 		else
   1723          1.197   hannken 			vput(nd.ni_dvp);
   1724          1.197   hannken 		if ((error = vn_start_write(NULL, &mp,
   1725          1.197   hannken 		    V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
   1726          1.197   hannken 			return (error);
   1727          1.197   hannken 		goto restart;
   1728          1.197   hannken 	}
   1729           1.31       cgd 	VATTR_NULL(&vattr);
   1730          1.134   thorpej 	vattr.va_mode = ACCESSPERMS &~ p->p_cwdi->cwdi_cmask;
   1731          1.190      fvdl 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
   1732           1.31       cgd 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
   1733          1.168     assar 	if (error == 0)
   1734          1.168     assar 		vput(nd.ni_vp);
   1735          1.197   hannken 	vn_finished_write(mp, 0);
   1736           1.43   mycroft out:
   1737          1.161   thorpej 	PNBUF_PUT(path);
   1738           1.31       cgd 	return (error);
   1739           1.31       cgd }
   1740           1.31       cgd 
   1741           1.31       cgd /*
   1742           1.43   mycroft  * Delete a whiteout from the filesystem.
   1743           1.43   mycroft  */
   1744           1.43   mycroft /* ARGSUSED */
   1745           1.63  christos int
   1746          1.179   thorpej sys_undelete(l, v, retval)
   1747          1.179   thorpej 	struct lwp *l;
   1748           1.56   thorpej 	void *v;
   1749           1.56   thorpej 	register_t *retval;
   1750           1.56   thorpej {
   1751          1.155  augustss 	struct sys_undelete_args /* {
   1752           1.74       cgd 		syscallarg(const char *) path;
   1753           1.56   thorpej 	} */ *uap = v;
   1754          1.179   thorpej 	struct proc *p = l->l_proc;
   1755           1.43   mycroft 	int error;
   1756          1.197   hannken 	struct mount *mp;
   1757           1.43   mycroft 	struct nameidata nd;
   1758           1.43   mycroft 
   1759          1.197   hannken restart:
   1760           1.43   mycroft 	NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
   1761          1.190      fvdl 	    SCARG(uap, path), p);
   1762           1.43   mycroft 	error = namei(&nd);
   1763           1.43   mycroft 	if (error)
   1764           1.43   mycroft 		return (error);
   1765           1.43   mycroft 
   1766           1.43   mycroft 	if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
   1767           1.43   mycroft 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
   1768           1.43   mycroft 		if (nd.ni_dvp == nd.ni_vp)
   1769           1.43   mycroft 			vrele(nd.ni_dvp);
   1770           1.43   mycroft 		else
   1771           1.43   mycroft 			vput(nd.ni_dvp);
   1772           1.43   mycroft 		if (nd.ni_vp)
   1773           1.43   mycroft 			vrele(nd.ni_vp);
   1774           1.43   mycroft 		return (EEXIST);
   1775           1.43   mycroft 	}
   1776          1.197   hannken 	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
   1777          1.197   hannken 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
   1778          1.197   hannken 		if (nd.ni_dvp == nd.ni_vp)
   1779          1.197   hannken 			vrele(nd.ni_dvp);
   1780          1.197   hannken 		else
   1781          1.197   hannken 			vput(nd.ni_dvp);
   1782          1.197   hannken 		if ((error = vn_start_write(NULL, &mp,
   1783          1.197   hannken 		    V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
   1784          1.197   hannken 			return (error);
   1785          1.197   hannken 		goto restart;
   1786          1.197   hannken 	}
   1787          1.190      fvdl 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
   1788           1.63  christos 	if ((error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE)) != 0)
   1789           1.43   mycroft 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
   1790           1.43   mycroft 	vput(nd.ni_dvp);
   1791          1.197   hannken 	vn_finished_write(mp, 0);
   1792           1.43   mycroft 	return (error);
   1793           1.43   mycroft }
   1794           1.43   mycroft 
   1795           1.43   mycroft /*
   1796           1.31       cgd  * Delete a name from the filesystem.
   1797           1.31       cgd  */
   1798           1.31       cgd /* ARGSUSED */
   1799           1.63  christos int
   1800          1.179   thorpej sys_unlink(l, v, retval)
   1801          1.179   thorpej 	struct lwp *l;
   1802           1.56   thorpej 	void *v;
   1803           1.56   thorpej 	register_t *retval;
   1804           1.56   thorpej {
   1805           1.57   mycroft 	struct sys_unlink_args /* {
   1806           1.74       cgd 		syscallarg(const char *) path;
   1807           1.56   thorpej 	} */ *uap = v;
   1808          1.179   thorpej 	struct proc *p = l->l_proc;
   1809          1.197   hannken 	struct mount *mp;
   1810          1.155  augustss 	struct vnode *vp;
   1811           1.31       cgd 	int error;
   1812           1.31       cgd 	struct nameidata nd;
   1813           1.31       cgd 
   1814          1.197   hannken restart:
   1815           1.67   mycroft 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
   1816          1.190      fvdl 	    SCARG(uap, path), p);
   1817           1.63  christos 	if ((error = namei(&nd)) != 0)
   1818           1.31       cgd 		return (error);
   1819           1.31       cgd 	vp = nd.ni_vp;
   1820           1.31       cgd 
   1821           1.66   mycroft 	/*
   1822           1.66   mycroft 	 * The root of a mounted filesystem cannot be deleted.
   1823           1.66   mycroft 	 */
   1824           1.66   mycroft 	if (vp->v_flag & VROOT) {
   1825           1.43   mycroft 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
   1826           1.43   mycroft 		if (nd.ni_dvp == vp)
   1827           1.43   mycroft 			vrele(nd.ni_dvp);
   1828           1.43   mycroft 		else
   1829           1.43   mycroft 			vput(nd.ni_dvp);
   1830           1.66   mycroft 		vput(vp);
   1831           1.66   mycroft 		error = EBUSY;
   1832           1.66   mycroft 		goto out;
   1833           1.31       cgd 	}
   1834      1.217.2.2      tron 
   1835      1.217.2.2      tron #ifdef VERIFIED_EXEC
   1836      1.217.2.3      tron 	/* Handle remove requests for veriexec entries. */
   1837      1.217.2.2      tron 	if ((error = veriexec_removechk(p, vp, nd.ni_dirp)) != 0) {
   1838      1.217.2.2      tron 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
   1839      1.217.2.2      tron 		if (nd.ni_dvp == vp)
   1840      1.217.2.2      tron 			vrele(nd.ni_dvp);
   1841      1.217.2.2      tron 		else
   1842      1.217.2.2      tron 			vput(nd.ni_dvp);
   1843      1.217.2.2      tron 		vput(vp);
   1844      1.217.2.2      tron 		goto out;
   1845      1.217.2.2      tron 	}
   1846      1.217.2.6      tron #endif /* VERIFIED_EXEC */
   1847  1.217.2.7.2.2      ghen 
   1848          1.197   hannken 	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
   1849          1.197   hannken 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
   1850          1.197   hannken 		if (nd.ni_dvp == vp)
   1851          1.197   hannken 			vrele(nd.ni_dvp);
   1852          1.197   hannken 		else
   1853          1.197   hannken 			vput(nd.ni_dvp);
   1854          1.197   hannken 		vput(vp);
   1855          1.197   hannken 		if ((error = vn_start_write(NULL, &mp,
   1856          1.197   hannken 		    V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
   1857          1.197   hannken 			return (error);
   1858          1.197   hannken 		goto restart;
   1859          1.197   hannken 	}
   1860          1.190      fvdl 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
   1861          1.190      fvdl 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
   1862           1.66   mycroft 	error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
   1863          1.197   hannken 	vn_finished_write(mp, 0);
   1864           1.66   mycroft out:
   1865           1.31       cgd 	return (error);
   1866           1.31       cgd }
   1867           1.31       cgd 
   1868           1.31       cgd /*
   1869           1.31       cgd  * Reposition read/write file offset.
   1870           1.31       cgd  */
   1871           1.63  christos int
   1872          1.179   thorpej sys_lseek(l, v, retval)
   1873          1.179   thorpej 	struct lwp *l;
   1874           1.56   thorpej 	void *v;
   1875           1.56   thorpej 	register_t *retval;
   1876           1.56   thorpej {
   1877          1.155  augustss 	struct sys_lseek_args /* {
   1878           1.35       cgd 		syscallarg(int) fd;
   1879           1.35       cgd 		syscallarg(int) pad;
   1880           1.35       cgd 		syscallarg(off_t) offset;
   1881           1.35       cgd 		syscallarg(int) whence;
   1882           1.56   thorpej 	} */ *uap = v;
   1883          1.179   thorpej 	struct proc *p = l->l_proc;
   1884           1.31       cgd 	struct ucred *cred = p->p_ucred;
   1885          1.155  augustss 	struct filedesc *fdp = p->p_fd;
   1886          1.155  augustss 	struct file *fp;
   1887           1.84    kleink 	struct vnode *vp;
   1888           1.31       cgd 	struct vattr vattr;
   1889          1.155  augustss 	off_t newoff;
   1890           1.31       cgd 	int error;
   1891           1.31       cgd 
   1892          1.166   thorpej 	if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
   1893           1.31       cgd 		return (EBADF);
   1894           1.84    kleink 
   1895          1.135   thorpej 	FILE_USE(fp);
   1896          1.135   thorpej 
   1897           1.84    kleink 	vp = (struct vnode *)fp->f_data;
   1898          1.135   thorpej 	if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
   1899          1.135   thorpej 		error = ESPIPE;
   1900          1.135   thorpej 		goto out;
   1901          1.135   thorpej 	}
   1902           1.84    kleink 
   1903           1.35       cgd 	switch (SCARG(uap, whence)) {
   1904           1.92    kleink 	case SEEK_CUR:
   1905           1.84    kleink 		newoff = fp->f_offset + SCARG(uap, offset);
   1906           1.31       cgd 		break;
   1907           1.92    kleink 	case SEEK_END:
   1908          1.190      fvdl 		error = VOP_GETATTR(vp, &vattr, cred, p);
   1909           1.63  christos 		if (error)
   1910          1.135   thorpej 			goto out;
   1911           1.84    kleink 		newoff = SCARG(uap, offset) + vattr.va_size;
   1912           1.31       cgd 		break;
   1913           1.92    kleink 	case SEEK_SET:
   1914           1.84    kleink 		newoff = SCARG(uap, offset);
   1915           1.31       cgd 		break;
   1916           1.31       cgd 	default:
   1917          1.135   thorpej 		error = EINVAL;
   1918          1.135   thorpej 		goto out;
   1919           1.31       cgd 	}
   1920           1.84    kleink 	if ((error = VOP_SEEK(vp, fp->f_offset, newoff, cred)) != 0)
   1921          1.135   thorpej 		goto out;
   1922           1.84    kleink 
   1923           1.84    kleink 	*(off_t *)retval = fp->f_offset = newoff;
   1924          1.135   thorpej  out:
   1925          1.190      fvdl 	FILE_UNUSE(fp, p);
   1926          1.135   thorpej 	return (error);
   1927          1.120   thorpej }
   1928          1.120   thorpej 
   1929          1.120   thorpej /*
   1930          1.120   thorpej  * Positional read system call.
   1931          1.120   thorpej  */
   1932          1.120   thorpej int
   1933          1.179   thorpej sys_pread(l, v, retval)
   1934          1.179   thorpej 	struct lwp *l;
   1935          1.120   thorpej 	void *v;
   1936          1.120   thorpej 	register_t *retval;
   1937          1.120   thorpej {
   1938          1.120   thorpej 	struct sys_pread_args /* {
   1939          1.120   thorpej 		syscallarg(int) fd;
   1940          1.120   thorpej 		syscallarg(void *) buf;
   1941          1.120   thorpej 		syscallarg(size_t) nbyte;
   1942          1.120   thorpej 		syscallarg(off_t) offset;
   1943          1.120   thorpej 	} */ *uap = v;
   1944          1.179   thorpej 	struct proc *p = l->l_proc;
   1945          1.120   thorpej 	struct filedesc *fdp = p->p_fd;
   1946          1.120   thorpej 	struct file *fp;
   1947          1.120   thorpej 	struct vnode *vp;
   1948          1.120   thorpej 	off_t offset;
   1949          1.120   thorpej 	int error, fd = SCARG(uap, fd);
   1950          1.120   thorpej 
   1951          1.166   thorpej 	if ((fp = fd_getfile(fdp, fd)) == NULL)
   1952          1.166   thorpej 		return (EBADF);
   1953          1.166   thorpej 
   1954          1.183        pk 	if ((fp->f_flag & FREAD) == 0) {
   1955          1.183        pk 		simple_unlock(&fp->f_slock);
   1956          1.120   thorpej 		return (EBADF);
   1957          1.183        pk 	}
   1958          1.120   thorpej 
   1959          1.135   thorpej 	FILE_USE(fp);
   1960          1.135   thorpej 
   1961          1.120   thorpej 	vp = (struct vnode *)fp->f_data;
   1962          1.135   thorpej 	if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
   1963          1.135   thorpej 		error = ESPIPE;
   1964          1.135   thorpej 		goto out;
   1965          1.135   thorpej 	}
   1966          1.120   thorpej 
   1967          1.120   thorpej 	offset = SCARG(uap, offset);
   1968          1.120   thorpej 
   1969          1.120   thorpej 	/*
   1970          1.120   thorpej 	 * XXX This works because no file systems actually
   1971          1.120   thorpej 	 * XXX take any action on the seek operation.
   1972          1.120   thorpej 	 */
   1973          1.120   thorpej 	if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
   1974          1.135   thorpej 		goto out;
   1975          1.120   thorpej 
   1976          1.135   thorpej 	/* dofileread() will unuse the descriptor for us */
   1977          1.190      fvdl 	return (dofileread(p, fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
   1978          1.120   thorpej 	    &offset, 0, retval));
   1979          1.135   thorpej 
   1980          1.135   thorpej  out:
   1981          1.190      fvdl 	FILE_UNUSE(fp, p);
   1982          1.135   thorpej 	return (error);
   1983          1.120   thorpej }
   1984          1.120   thorpej 
   1985          1.120   thorpej /*
   1986          1.120   thorpej  * Positional scatter read system call.
   1987          1.120   thorpej  */
   1988          1.120   thorpej int
   1989          1.179   thorpej sys_preadv(l, v, retval)
   1990          1.179   thorpej 	struct lwp *l;
   1991          1.120   thorpej 	void *v;
   1992          1.120   thorpej 	register_t *retval;
   1993          1.120   thorpej {
   1994          1.120   thorpej 	struct sys_preadv_args /* {
   1995          1.120   thorpej 		syscallarg(int) fd;
   1996          1.120   thorpej 		syscallarg(const struct iovec *) iovp;
   1997          1.120   thorpej 		syscallarg(int) iovcnt;
   1998          1.120   thorpej 		syscallarg(off_t) offset;
   1999          1.120   thorpej 	} */ *uap = v;
   2000          1.179   thorpej 	struct proc *p = l->l_proc;
   2001          1.120   thorpej 	struct filedesc *fdp = p->p_fd;
   2002          1.120   thorpej 	struct file *fp;
   2003          1.120   thorpej 	struct vnode *vp;
   2004          1.120   thorpej 	off_t offset;
   2005          1.120   thorpej 	int error, fd = SCARG(uap, fd);
   2006          1.120   thorpej 
   2007          1.166   thorpej 	if ((fp = fd_getfile(fdp, fd)) == NULL)
   2008          1.166   thorpej 		return (EBADF);
   2009          1.166   thorpej 
   2010          1.183        pk 	if ((fp->f_flag & FREAD) == 0) {
   2011          1.183        pk 		simple_unlock(&fp->f_slock);
   2012          1.120   thorpej 		return (EBADF);
   2013          1.183        pk 	}
   2014          1.120   thorpej 
   2015          1.135   thorpej 	FILE_USE(fp);
   2016          1.135   thorpej 
   2017          1.120   thorpej 	vp = (struct vnode *)fp->f_data;
   2018          1.135   thorpej 	if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
   2019          1.135   thorpej 		error = ESPIPE;
   2020          1.135   thorpej 		goto out;
   2021          1.135   thorpej 	}
   2022          1.120   thorpej 
   2023          1.120   thorpej 	offset = SCARG(uap, offset);
   2024          1.120   thorpej 
   2025          1.120   thorpej 	/*
   2026          1.120   thorpej 	 * XXX This works because no file systems actually
   2027          1.120   thorpej 	 * XXX take any action on the seek operation.
   2028          1.120   thorpej 	 */
   2029          1.120   thorpej 	if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
   2030          1.135   thorpej 		goto out;
   2031          1.120   thorpej 
   2032          1.135   thorpej 	/* dofilereadv() will unuse the descriptor for us */
   2033          1.190      fvdl 	return (dofilereadv(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt),
   2034          1.120   thorpej 	    &offset, 0, retval));
   2035          1.135   thorpej 
   2036          1.135   thorpej  out:
   2037          1.190      fvdl 	FILE_UNUSE(fp, p);
   2038          1.135   thorpej 	return (error);
   2039          1.120   thorpej }
   2040          1.120   thorpej 
   2041          1.120   thorpej /*
   2042          1.120   thorpej  * Positional write system call.
   2043          1.120   thorpej  */
   2044          1.120   thorpej int
   2045          1.179   thorpej sys_pwrite(l, v, retval)
   2046          1.179   thorpej 	struct lwp *l;
   2047          1.120   thorpej 	void *v;
   2048          1.120   thorpej 	register_t *retval;
   2049          1.120   thorpej {
   2050          1.120   thorpej 	struct sys_pwrite_args /* {
   2051          1.120   thorpej 		syscallarg(int) fd;
   2052          1.120   thorpej 		syscallarg(const void *) buf;
   2053          1.120   thorpej 		syscallarg(size_t) nbyte;
   2054          1.120   thorpej 		syscallarg(off_t) offset;
   2055          1.120   thorpej 	} */ *uap = v;
   2056          1.179   thorpej 	struct proc *p = l->l_proc;
   2057          1.120   thorpej 	struct filedesc *fdp = p->p_fd;
   2058          1.120   thorpej 	struct file *fp;
   2059          1.120   thorpej 	struct vnode *vp;
   2060          1.120   thorpej 	off_t offset;
   2061          1.120   thorpej 	int error, fd = SCARG(uap, fd);
   2062          1.120   thorpej 
   2063          1.166   thorpej 	if ((fp = fd_getfile(fdp, fd)) == NULL)
   2064          1.166   thorpej 		return (EBADF);
   2065          1.166   thorpej 
   2066          1.183        pk 	if ((fp->f_flag & FWRITE) == 0) {
   2067          1.183        pk 		simple_unlock(&fp->f_slock);
   2068          1.120   thorpej 		return (EBADF);
   2069          1.183        pk 	}
   2070          1.120   thorpej 
   2071          1.135   thorpej 	FILE_USE(fp);
   2072          1.135   thorpej 
   2073          1.120   thorpej 	vp = (struct vnode *)fp->f_data;
   2074          1.135   thorpej 	if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
   2075          1.135   thorpej 		error = ESPIPE;
   2076          1.135   thorpej 		goto out;
   2077          1.135   thorpej 	}
   2078          1.120   thorpej 
   2079          1.120   thorpej 	offset = SCARG(uap, offset);
   2080          1.120   thorpej 
   2081          1.120   thorpej 	/*
   2082          1.120   thorpej 	 * XXX This works because no file systems actually
   2083          1.120   thorpej 	 * XXX take any action on the seek operation.
   2084          1.120   thorpej 	 */
   2085          1.120   thorpej 	if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
   2086          1.135   thorpej 		goto out;
   2087          1.120   thorpej 
   2088          1.135   thorpej 	/* dofilewrite() will unuse the descriptor for us */
   2089          1.190      fvdl 	return (dofilewrite(p, fd, fp, SCARG(uap, buf), SCARG(uap, nbyte),
   2090          1.120   thorpej 	    &offset, 0, retval));
   2091          1.135   thorpej 
   2092          1.135   thorpej  out:
   2093          1.190      fvdl 	FILE_UNUSE(fp, p);
   2094          1.135   thorpej 	return (error);
   2095          1.120   thorpej }
   2096          1.120   thorpej 
   2097          1.120   thorpej /*
   2098          1.120   thorpej  * Positional gather write system call.
   2099          1.120   thorpej  */
   2100          1.120   thorpej int
   2101          1.179   thorpej sys_pwritev(l, v, retval)
   2102          1.179   thorpej 	struct lwp *l;
   2103          1.120   thorpej 	void *v;
   2104          1.120   thorpej 	register_t *retval;
   2105          1.120   thorpej {
   2106          1.120   thorpej 	struct sys_pwritev_args /* {
   2107          1.120   thorpej 		syscallarg(int) fd;
   2108          1.120   thorpej 		syscallarg(const struct iovec *) iovp;
   2109          1.120   thorpej 		syscallarg(int) iovcnt;
   2110          1.120   thorpej 		syscallarg(off_t) offset;
   2111          1.120   thorpej 	} */ *uap = v;
   2112          1.179   thorpej 	struct proc *p = l->l_proc;
   2113          1.120   thorpej 	struct filedesc *fdp = p->p_fd;
   2114          1.120   thorpej 	struct file *fp;
   2115          1.120   thorpej 	struct vnode *vp;
   2116          1.120   thorpej 	off_t offset;
   2117          1.120   thorpej 	int error, fd = SCARG(uap, fd);
   2118          1.120   thorpej 
   2119          1.166   thorpej 	if ((fp = fd_getfile(fdp, fd)) == NULL)
   2120          1.166   thorpej 		return (EBADF);
   2121          1.166   thorpej 
   2122          1.183        pk 	if ((fp->f_flag & FWRITE) == 0) {
   2123          1.183        pk 		simple_unlock(&fp->f_slock);
   2124          1.120   thorpej 		return (EBADF);
   2125          1.183        pk 	}
   2126          1.120   thorpej 
   2127          1.135   thorpej 	FILE_USE(fp);
   2128          1.135   thorpej 
   2129          1.120   thorpej 	vp = (struct vnode *)fp->f_data;
   2130          1.135   thorpej 	if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
   2131          1.135   thorpej 		error = ESPIPE;
   2132          1.135   thorpej 		goto out;
   2133          1.135   thorpej 	}
   2134          1.120   thorpej 
   2135          1.120   thorpej 	offset = SCARG(uap, offset);
   2136          1.120   thorpej 
   2137          1.120   thorpej 	/*
   2138          1.120   thorpej 	 * XXX This works because no file systems actually
   2139          1.120   thorpej 	 * XXX take any action on the seek operation.
   2140          1.120   thorpej 	 */
   2141          1.120   thorpej 	if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
   2142          1.135   thorpej 		goto out;
   2143          1.120   thorpej 
   2144          1.135   thorpej 	/* dofilewritev() will unuse the descriptor for us */
   2145          1.190      fvdl 	return (dofilewritev(p, fd, fp, SCARG(uap, iovp), SCARG(uap, iovcnt),
   2146          1.120   thorpej 	    &offset, 0, retval));
   2147          1.135   thorpej 
   2148          1.135   thorpej  out:
   2149          1.190      fvdl 	FILE_UNUSE(fp, p);
   2150          1.135   thorpej 	return (error);
   2151           1.31       cgd }
   2152           1.31       cgd 
   2153           1.31       cgd /*
   2154           1.31       cgd  * Check access permissions.
   2155           1.31       cgd  */
   2156           1.63  christos int
   2157          1.179   thorpej sys_access(l, v, retval)
   2158          1.179   thorpej 	struct lwp *l;
   2159           1.56   thorpej 	void *v;
   2160           1.56   thorpej 	register_t *retval;
   2161           1.56   thorpej {
   2162          1.155  augustss 	struct sys_access_args /* {
   2163           1.74       cgd 		syscallarg(const char *) path;
   2164           1.35       cgd 		syscallarg(int) flags;
   2165           1.56   thorpej 	} */ *uap = v;
   2166          1.179   thorpej 	struct proc *p = l->l_proc;
   2167          1.207        pk 	struct ucred *cred;
   2168          1.155  augustss 	struct vnode *vp;
   2169          1.169  christos 	int error, flags;
   2170           1.31       cgd 	struct nameidata nd;
   2171           1.31       cgd 
   2172          1.207        pk 	cred = crdup(p->p_ucred);
   2173           1.31       cgd 	cred->cr_uid = p->p_cred->p_ruid;
   2174           1.53       jtc 	cred->cr_gid = p->p_cred->p_rgid;
   2175           1.35       cgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
   2176          1.190      fvdl 	    SCARG(uap, path), p);
   2177          1.169  christos 	/* Override default credentials */
   2178          1.169  christos 	nd.ni_cnd.cn_cred = cred;
   2179           1.63  christos 	if ((error = namei(&nd)) != 0)
   2180          1.169  christos 		goto out;
   2181           1.31       cgd 	vp = nd.ni_vp;
   2182           1.31       cgd 
   2183           1.31       cgd 	/* Flags == 0 means only check for existence. */
   2184           1.35       cgd 	if (SCARG(uap, flags)) {
   2185           1.31       cgd 		flags = 0;
   2186           1.35       cgd 		if (SCARG(uap, flags) & R_OK)
   2187           1.31       cgd 			flags |= VREAD;
   2188           1.35       cgd 		if (SCARG(uap, flags) & W_OK)
   2189           1.31       cgd 			flags |= VWRITE;
   2190           1.89   mycroft 		if (SCARG(uap, flags) & X_OK)
   2191           1.89   mycroft 			flags |= VEXEC;
   2192          1.138        is 
   2193          1.190      fvdl 		error = VOP_ACCESS(vp, flags, cred, p);
   2194          1.138        is 		if (!error && (flags & VWRITE))
   2195          1.138        is 			error = vn_writechk(vp);
   2196           1.31       cgd 	}
   2197           1.31       cgd 	vput(vp);
   2198          1.169  christos out:
   2199          1.169  christos 	crfree(cred);
   2200           1.31       cgd 	return (error);
   2201           1.31       cgd }
   2202           1.31       cgd 
   2203           1.31       cgd /*
   2204           1.31       cgd  * Get file status; this version follows links.
   2205           1.31       cgd  */
   2206           1.31       cgd /* ARGSUSED */
   2207           1.63  christos int
   2208          1.179   thorpej sys___stat13(l, v, retval)
   2209          1.179   thorpej 	struct lwp *l;
   2210           1.56   thorpej 	void *v;
   2211           1.56   thorpej 	register_t *retval;
   2212           1.56   thorpej {
   2213          1.155  augustss 	struct sys___stat13_args /* {
   2214           1.74       cgd 		syscallarg(const char *) path;
   2215           1.35       cgd 		syscallarg(struct stat *) ub;
   2216           1.56   thorpej 	} */ *uap = v;
   2217          1.190      fvdl 	struct proc *p = l->l_proc;
   2218           1.31       cgd 	struct stat sb;
   2219           1.31       cgd 	int error;
   2220           1.31       cgd 	struct nameidata nd;
   2221           1.31       cgd 
   2222           1.35       cgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
   2223          1.190      fvdl 	    SCARG(uap, path), p);
   2224           1.63  christos 	if ((error = namei(&nd)) != 0)
   2225           1.31       cgd 		return (error);
   2226          1.190      fvdl 	error = vn_stat(nd.ni_vp, &sb, p);
   2227           1.31       cgd 	vput(nd.ni_vp);
   2228           1.31       cgd 	if (error)
   2229           1.31       cgd 		return (error);
   2230          1.122     perry 	error = copyout(&sb, SCARG(uap, ub), sizeof(sb));
   2231           1.31       cgd 	return (error);
   2232           1.31       cgd }
   2233           1.31       cgd 
   2234           1.31       cgd /*
   2235           1.31       cgd  * Get file status; this version does not follow links.
   2236           1.31       cgd  */
   2237           1.31       cgd /* ARGSUSED */
   2238           1.63  christos int
   2239          1.179   thorpej sys___lstat13(l, v, retval)
   2240          1.179   thorpej 	struct lwp *l;
   2241           1.56   thorpej 	void *v;
   2242           1.56   thorpej 	register_t *retval;
   2243           1.56   thorpej {
   2244          1.155  augustss 	struct sys___lstat13_args /* {
   2245           1.74       cgd 		syscallarg(const char *) path;
   2246           1.35       cgd 		syscallarg(struct stat *) ub;
   2247           1.56   thorpej 	} */ *uap = v;
   2248          1.190      fvdl 	struct proc *p = l->l_proc;
   2249           1.65   mycroft 	struct stat sb;
   2250           1.31       cgd 	int error;
   2251           1.31       cgd 	struct nameidata nd;
   2252           1.31       cgd 
   2253           1.65   mycroft 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
   2254          1.190      fvdl 	    SCARG(uap, path), p);
   2255           1.63  christos 	if ((error = namei(&nd)) != 0)
   2256           1.31       cgd 		return (error);
   2257          1.190      fvdl 	error = vn_stat(nd.ni_vp, &sb, p);
   2258           1.65   mycroft 	vput(nd.ni_vp);
   2259           1.64       jtc 	if (error)
   2260           1.64       jtc 		return (error);
   2261          1.122     perry 	error = copyout(&sb, SCARG(uap, ub), sizeof(sb));
   2262           1.31       cgd 	return (error);
   2263           1.31       cgd }
   2264           1.31       cgd 
   2265           1.31       cgd /*
   2266           1.31       cgd  * Get configurable pathname variables.
   2267           1.31       cgd  */
   2268           1.31       cgd /* ARGSUSED */
   2269           1.63  christos int
   2270          1.179   thorpej sys_pathconf(l, v, retval)
   2271          1.179   thorpej 	struct lwp *l;
   2272           1.56   thorpej 	void *v;
   2273           1.56   thorpej 	register_t *retval;
   2274           1.56   thorpej {
   2275          1.155  augustss 	struct sys_pathconf_args /* {
   2276           1.74       cgd 		syscallarg(const char *) path;
   2277           1.35       cgd 		syscallarg(int) name;
   2278           1.56   thorpej 	} */ *uap = v;
   2279          1.190      fvdl 	struct proc *p = l->l_proc;
   2280           1.31       cgd 	int error;
   2281           1.31       cgd 	struct nameidata nd;
   2282           1.31       cgd 
   2283           1.35       cgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
   2284          1.190      fvdl 	    SCARG(uap, path), p);
   2285           1.63  christos 	if ((error = namei(&nd)) != 0)
   2286           1.31       cgd 		return (error);
   2287           1.35       cgd 	error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
   2288           1.31       cgd 	vput(nd.ni_vp);
   2289           1.31       cgd 	return (error);
   2290           1.31       cgd }
   2291           1.31       cgd 
   2292           1.31       cgd /*
   2293           1.31       cgd  * Return target name of a symbolic link.
   2294           1.31       cgd  */
   2295           1.31       cgd /* ARGSUSED */
   2296           1.63  christos int
   2297          1.179   thorpej sys_readlink(l, v, retval)
   2298          1.179   thorpej 	struct lwp *l;
   2299           1.56   thorpej 	void *v;
   2300           1.56   thorpej 	register_t *retval;
   2301           1.56   thorpej {
   2302          1.155  augustss 	struct sys_readlink_args /* {
   2303           1.74       cgd 		syscallarg(const char *) path;
   2304           1.35       cgd 		syscallarg(char *) buf;
   2305          1.115    kleink 		syscallarg(size_t) count;
   2306           1.56   thorpej 	} */ *uap = v;
   2307          1.179   thorpej 	struct proc *p = l->l_proc;
   2308          1.155  augustss 	struct vnode *vp;
   2309           1.31       cgd 	struct iovec aiov;
   2310           1.31       cgd 	struct uio auio;
   2311           1.31       cgd 	int error;
   2312           1.31       cgd 	struct nameidata nd;
   2313           1.31       cgd 
   2314           1.35       cgd 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
   2315          1.190      fvdl 	    SCARG(uap, path), p);
   2316           1.63  christos 	if ((error = namei(&nd)) != 0)
   2317           1.31       cgd 		return (error);
   2318           1.31       cgd 	vp = nd.ni_vp;
   2319           1.31       cgd 	if (vp->v_type != VLNK)
   2320           1.31       cgd 		error = EINVAL;
   2321          1.106     enami 	else if (!(vp->v_mount->mnt_flag & MNT_SYMPERM) ||
   2322          1.190      fvdl 	    (error = VOP_ACCESS(vp, VREAD, p->p_ucred, p)) == 0) {
   2323           1.35       cgd 		aiov.iov_base = SCARG(uap, buf);
   2324           1.35       cgd 		aiov.iov_len = SCARG(uap, count);
   2325           1.31       cgd 		auio.uio_iov = &aiov;
   2326           1.31       cgd 		auio.uio_iovcnt = 1;
   2327           1.31       cgd 		auio.uio_offset = 0;
   2328           1.31       cgd 		auio.uio_rw = UIO_READ;
   2329           1.31       cgd 		auio.uio_segflg = UIO_USERSPACE;
   2330          1.190      fvdl 		auio.uio_procp = p;
   2331           1.35       cgd 		auio.uio_resid = SCARG(uap, count);
   2332           1.31       cgd 		error = VOP_READLINK(vp, &auio, p->p_ucred);
   2333           1.31       cgd 	}
   2334           1.31       cgd 	vput(vp);
   2335           1.35       cgd 	*retval = SCARG(uap, count) - auio.uio_resid;
   2336           1.31       cgd 	return (error);
   2337           1.31       cgd }
   2338           1.31       cgd 
   2339           1.31       cgd /*
   2340           1.31       cgd  * Change flags of a file given a path name.
   2341           1.31       cgd  */
   2342           1.31       cgd /* ARGSUSED */
   2343           1.63  christos int
   2344          1.179   thorpej sys_chflags(l, v, retval)
   2345          1.179   thorpej 	struct lwp *l;
   2346           1.56   thorpej 	void *v;
   2347           1.56   thorpej 	register_t *retval;
   2348           1.56   thorpej {
   2349          1.155  augustss 	struct sys_chflags_args /* {
   2350           1.74       cgd 		syscallarg(const char *) path;
   2351           1.74       cgd 		syscallarg(u_long) flags;
   2352           1.56   thorpej 	} */ *uap = v;
   2353          1.190      fvdl 	struct proc *p = l->l_proc;
   2354          1.155  augustss 	struct vnode *vp;
   2355           1.31       cgd 	int error;
   2356           1.31       cgd 	struct nameidata nd;
   2357           1.31       cgd 
   2358          1.190      fvdl 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   2359           1.63  christos 	if ((error = namei(&nd)) != 0)
   2360           1.31       cgd 		return (error);
   2361           1.31       cgd 	vp = nd.ni_vp;
   2362          1.190      fvdl 	error = change_flags(vp, SCARG(uap, flags), p);
   2363           1.31       cgd 	vput(vp);
   2364           1.31       cgd 	return (error);
   2365           1.31       cgd }
   2366           1.31       cgd 
   2367           1.31       cgd /*
   2368           1.31       cgd  * Change flags of a file given a file descriptor.
   2369           1.31       cgd  */
   2370           1.31       cgd /* ARGSUSED */
   2371           1.63  christos int
   2372          1.179   thorpej sys_fchflags(l, v, retval)
   2373          1.179   thorpej 	struct lwp *l;
   2374           1.56   thorpej 	void *v;
   2375           1.56   thorpej 	register_t *retval;
   2376           1.56   thorpej {
   2377          1.155  augustss 	struct sys_fchflags_args /* {
   2378           1.35       cgd 		syscallarg(int) fd;
   2379           1.74       cgd 		syscallarg(u_long) flags;
   2380           1.56   thorpej 	} */ *uap = v;
   2381          1.179   thorpej 	struct proc *p = l->l_proc;
   2382           1.31       cgd 	struct vnode *vp;
   2383           1.31       cgd 	struct file *fp;
   2384           1.31       cgd 	int error;
   2385           1.31       cgd 
   2386          1.135   thorpej 	/* getvnode() will use the descriptor for us */
   2387           1.63  christos 	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
   2388           1.31       cgd 		return (error);
   2389           1.62   mycroft 	vp = (struct vnode *)fp->f_data;
   2390          1.190      fvdl 	error = change_flags(vp, SCARG(uap, flags), p);
   2391          1.113      fvdl 	VOP_UNLOCK(vp, 0);
   2392          1.190      fvdl 	FILE_UNUSE(fp, p);
   2393          1.156       mrg 	return (error);
   2394          1.156       mrg }
   2395          1.156       mrg 
   2396          1.156       mrg /*
   2397          1.163     enami  * Change flags of a file given a path name; this version does
   2398          1.156       mrg  * not follow links.
   2399          1.156       mrg  */
   2400          1.156       mrg int
   2401          1.179   thorpej sys_lchflags(l, v, retval)
   2402          1.179   thorpej 	struct lwp *l;
   2403          1.156       mrg 	void *v;
   2404          1.156       mrg 	register_t *retval;
   2405          1.156       mrg {
   2406          1.163     enami 	struct sys_lchflags_args /* {
   2407          1.156       mrg 		syscallarg(const char *) path;
   2408          1.156       mrg 		syscallarg(u_long) flags;
   2409          1.156       mrg 	} */ *uap = v;
   2410          1.190      fvdl 	struct proc *p = l->l_proc;
   2411          1.163     enami 	struct vnode *vp;
   2412          1.156       mrg 	int error;
   2413          1.156       mrg 	struct nameidata nd;
   2414          1.156       mrg 
   2415          1.190      fvdl 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   2416          1.156       mrg 	if ((error = namei(&nd)) != 0)
   2417          1.156       mrg 		return (error);
   2418          1.156       mrg 	vp = nd.ni_vp;
   2419          1.190      fvdl 	error = change_flags(vp, SCARG(uap, flags), p);
   2420          1.163     enami 	vput(vp);
   2421          1.163     enami 	return (error);
   2422          1.163     enami }
   2423          1.163     enami 
   2424          1.163     enami /*
   2425          1.163     enami  * Common routine to change flags of a file.
   2426          1.163     enami  */
   2427          1.163     enami int
   2428          1.190      fvdl change_flags(vp, flags, p)
   2429          1.163     enami 	struct vnode *vp;
   2430          1.163     enami 	u_long flags;
   2431          1.190      fvdl 	struct proc *p;
   2432          1.163     enami {
   2433          1.197   hannken 	struct mount *mp;
   2434          1.163     enami 	struct vattr vattr;
   2435          1.163     enami 	int error;
   2436          1.163     enami 
   2437          1.197   hannken 	if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
   2438          1.197   hannken 		return (error);
   2439          1.190      fvdl 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
   2440          1.156       mrg 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
   2441          1.163     enami 	/*
   2442          1.163     enami 	 * Non-superusers cannot change the flags on devices, even if they
   2443          1.163     enami 	 * own them.
   2444          1.163     enami 	 */
   2445          1.163     enami 	if (suser(p->p_ucred, &p->p_acflag) != 0) {
   2446          1.190      fvdl 		if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0)
   2447          1.156       mrg 			goto out;
   2448          1.156       mrg 		if (vattr.va_type == VCHR || vattr.va_type == VBLK) {
   2449          1.156       mrg 			error = EINVAL;
   2450          1.156       mrg 			goto out;
   2451          1.156       mrg 		}
   2452          1.156       mrg 	}
   2453          1.156       mrg 	VATTR_NULL(&vattr);
   2454          1.163     enami 	vattr.va_flags = flags;
   2455          1.190      fvdl 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
   2456          1.156       mrg out:
   2457          1.197   hannken 	vn_finished_write(mp, 0);
   2458           1.31       cgd 	return (error);
   2459           1.31       cgd }
   2460           1.31       cgd 
   2461           1.31       cgd /*
   2462           1.98     enami  * Change mode of a file given path name; this version follows links.
   2463           1.31       cgd  */
   2464           1.31       cgd /* ARGSUSED */
   2465           1.63  christos int
   2466          1.179   thorpej sys_chmod(l, v, retval)
   2467          1.179   thorpej 	struct lwp *l;
   2468           1.56   thorpej 	void *v;
   2469           1.56   thorpej 	register_t *retval;
   2470           1.56   thorpej {
   2471          1.155  augustss 	struct sys_chmod_args /* {
   2472           1.74       cgd 		syscallarg(const char *) path;
   2473           1.35       cgd 		syscallarg(int) mode;
   2474           1.56   thorpej 	} */ *uap = v;
   2475          1.190      fvdl 	struct proc *p = l->l_proc;
   2476           1.31       cgd 	int error;
   2477           1.31       cgd 	struct nameidata nd;
   2478           1.31       cgd 
   2479          1.190      fvdl 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   2480           1.63  christos 	if ((error = namei(&nd)) != 0)
   2481           1.31       cgd 		return (error);
   2482           1.97     enami 
   2483          1.190      fvdl 	error = change_mode(nd.ni_vp, SCARG(uap, mode), p);
   2484           1.97     enami 
   2485           1.97     enami 	vrele(nd.ni_vp);
   2486           1.31       cgd 	return (error);
   2487           1.31       cgd }
   2488           1.31       cgd 
   2489           1.31       cgd /*
   2490           1.31       cgd  * Change mode of a file given a file descriptor.
   2491           1.31       cgd  */
   2492           1.31       cgd /* ARGSUSED */
   2493           1.63  christos int
   2494          1.179   thorpej sys_fchmod(l, v, retval)
   2495          1.179   thorpej 	struct lwp *l;
   2496           1.56   thorpej 	void *v;
   2497           1.56   thorpej 	register_t *retval;
   2498           1.56   thorpej {
   2499          1.155  augustss 	struct sys_fchmod_args /* {
   2500           1.35       cgd 		syscallarg(int) fd;
   2501           1.35       cgd 		syscallarg(int) mode;
   2502           1.56   thorpej 	} */ *uap = v;
   2503          1.179   thorpej 	struct proc *p = l->l_proc;
   2504           1.31       cgd 	struct file *fp;
   2505           1.31       cgd 	int error;
   2506           1.31       cgd 
   2507          1.135   thorpej 	/* getvnode() will use the descriptor for us */
   2508           1.63  christos 	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
   2509           1.31       cgd 		return (error);
   2510           1.97     enami 
   2511          1.190      fvdl 	error = change_mode((struct vnode *)fp->f_data, SCARG(uap, mode), p);
   2512          1.190      fvdl 	FILE_UNUSE(fp, p);
   2513          1.135   thorpej 	return (error);
   2514           1.97     enami }
   2515           1.97     enami 
   2516           1.97     enami /*
   2517           1.98     enami  * Change mode of a file given path name; this version does not follow links.
   2518           1.98     enami  */
   2519           1.98     enami /* ARGSUSED */
   2520           1.98     enami int
   2521          1.179   thorpej sys_lchmod(l, v, retval)
   2522          1.179   thorpej 	struct lwp *l;
   2523           1.98     enami 	void *v;
   2524           1.98     enami 	register_t *retval;
   2525           1.98     enami {
   2526          1.155  augustss 	struct sys_lchmod_args /* {
   2527           1.98     enami 		syscallarg(const char *) path;
   2528           1.98     enami 		syscallarg(int) mode;
   2529           1.98     enami 	} */ *uap = v;
   2530          1.190      fvdl 	struct proc *p = l->l_proc;
   2531           1.98     enami 	int error;
   2532           1.98     enami 	struct nameidata nd;
   2533           1.98     enami 
   2534          1.190      fvdl 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   2535           1.98     enami 	if ((error = namei(&nd)) != 0)
   2536           1.98     enami 		return (error);
   2537           1.98     enami 
   2538          1.190      fvdl 	error = change_mode(nd.ni_vp, SCARG(uap, mode), p);
   2539           1.98     enami 
   2540           1.98     enami 	vrele(nd.ni_vp);
   2541           1.98     enami 	return (error);
   2542           1.98     enami }
   2543           1.98     enami 
   2544           1.98     enami /*
   2545           1.97     enami  * Common routine to set mode given a vnode.
   2546           1.97     enami  */
   2547           1.97     enami static int
   2548          1.190      fvdl change_mode(vp, mode, p)
   2549           1.97     enami 	struct vnode *vp;
   2550           1.97     enami 	int mode;
   2551          1.190      fvdl 	struct proc *p;
   2552           1.97     enami {
   2553          1.197   hannken 	struct mount *mp;
   2554           1.97     enami 	struct vattr vattr;
   2555           1.97     enami 	int error;
   2556           1.97     enami 
   2557          1.197   hannken 	if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
   2558          1.197   hannken 		return (error);
   2559          1.190      fvdl 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
   2560          1.113      fvdl 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
   2561          1.113      fvdl 	VATTR_NULL(&vattr);
   2562          1.113      fvdl 	vattr.va_mode = mode & ALLPERMS;
   2563          1.190      fvdl 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
   2564          1.113      fvdl 	VOP_UNLOCK(vp, 0);
   2565          1.197   hannken 	vn_finished_write(mp, 0);
   2566           1.31       cgd 	return (error);
   2567           1.31       cgd }
   2568           1.31       cgd 
   2569           1.31       cgd /*
   2570           1.98     enami  * Set ownership given a path name; this version follows links.
   2571           1.31       cgd  */
   2572           1.31       cgd /* ARGSUSED */
   2573           1.63  christos int
   2574          1.179   thorpej sys_chown(l, v, retval)
   2575          1.179   thorpej 	struct lwp *l;
   2576           1.56   thorpej 	void *v;
   2577           1.56   thorpej 	register_t *retval;
   2578           1.56   thorpej {
   2579          1.155  augustss 	struct sys_chown_args /* {
   2580           1.74       cgd 		syscallarg(const char *) path;
   2581           1.74       cgd 		syscallarg(uid_t) uid;
   2582           1.74       cgd 		syscallarg(gid_t) gid;
   2583           1.56   thorpej 	} */ *uap = v;
   2584          1.190      fvdl 	struct proc *p = l->l_proc;
   2585           1.31       cgd 	int error;
   2586           1.31       cgd 	struct nameidata nd;
   2587           1.31       cgd 
   2588          1.190      fvdl 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   2589           1.63  christos 	if ((error = namei(&nd)) != 0)
   2590           1.31       cgd 		return (error);
   2591           1.86    kleink 
   2592          1.190      fvdl 	error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), p, 0);
   2593          1.112    kleink 
   2594          1.112    kleink 	vrele(nd.ni_vp);
   2595          1.112    kleink 	return (error);
   2596          1.112    kleink }
   2597          1.112    kleink 
   2598          1.112    kleink /*
   2599          1.112    kleink  * Set ownership given a path name; this version follows links.
   2600          1.112    kleink  * Provides POSIX semantics.
   2601          1.112    kleink  */
   2602          1.112    kleink /* ARGSUSED */
   2603          1.112    kleink int
   2604          1.179   thorpej sys___posix_chown(l, v, retval)
   2605          1.179   thorpej 	struct lwp *l;
   2606          1.112    kleink 	void *v;
   2607          1.112    kleink 	register_t *retval;
   2608          1.112    kleink {
   2609          1.155  augustss 	struct sys_chown_args /* {
   2610          1.112    kleink 		syscallarg(const char *) path;
   2611          1.112    kleink 		syscallarg(uid_t) uid;
   2612          1.112    kleink 		syscallarg(gid_t) gid;
   2613          1.112    kleink 	} */ *uap = v;
   2614          1.190      fvdl 	struct proc *p = l->l_proc;
   2615          1.112    kleink 	int error;
   2616          1.112    kleink 	struct nameidata nd;
   2617          1.112    kleink 
   2618          1.190      fvdl 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   2619          1.112    kleink 	if ((error = namei(&nd)) != 0)
   2620          1.112    kleink 		return (error);
   2621          1.112    kleink 
   2622          1.190      fvdl 	error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), p, 1);
   2623           1.86    kleink 
   2624           1.86    kleink 	vrele(nd.ni_vp);
   2625           1.31       cgd 	return (error);
   2626           1.31       cgd }
   2627           1.31       cgd 
   2628           1.31       cgd /*
   2629           1.31       cgd  * Set ownership given a file descriptor.
   2630           1.31       cgd  */
   2631           1.31       cgd /* ARGSUSED */
   2632           1.63  christos int
   2633          1.179   thorpej sys_fchown(l, v, retval)
   2634          1.179   thorpej 	struct lwp *l;
   2635           1.56   thorpej 	void *v;
   2636           1.56   thorpej 	register_t *retval;
   2637           1.56   thorpej {
   2638          1.155  augustss 	struct sys_fchown_args /* {
   2639           1.35       cgd 		syscallarg(int) fd;
   2640           1.74       cgd 		syscallarg(uid_t) uid;
   2641           1.74       cgd 		syscallarg(gid_t) gid;
   2642           1.56   thorpej 	} */ *uap = v;
   2643          1.179   thorpej 	struct proc *p = l->l_proc;
   2644           1.71   mycroft 	int error;
   2645           1.31       cgd 	struct file *fp;
   2646           1.31       cgd 
   2647          1.135   thorpej 	/* getvnode() will use the descriptor for us */
   2648           1.63  christos 	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
   2649           1.31       cgd 		return (error);
   2650           1.86    kleink 
   2651          1.135   thorpej 	error = change_owner((struct vnode *)fp->f_data, SCARG(uap, uid),
   2652          1.190      fvdl 	    SCARG(uap, gid), p, 0);
   2653          1.190      fvdl 	FILE_UNUSE(fp, p);
   2654          1.135   thorpej 	return (error);
   2655          1.112    kleink }
   2656          1.112    kleink 
   2657          1.112    kleink /*
   2658          1.112    kleink  * Set ownership given a file descriptor, providing POSIX/XPG semantics.
   2659          1.112    kleink  */
   2660          1.112    kleink /* ARGSUSED */
   2661          1.112    kleink int
   2662          1.179   thorpej sys___posix_fchown(l, v, retval)
   2663          1.179   thorpej 	struct lwp *l;
   2664          1.112    kleink 	void *v;
   2665          1.112    kleink 	register_t *retval;
   2666          1.112    kleink {
   2667          1.155  augustss 	struct sys_fchown_args /* {
   2668          1.112    kleink 		syscallarg(int) fd;
   2669          1.112    kleink 		syscallarg(uid_t) uid;
   2670          1.112    kleink 		syscallarg(gid_t) gid;
   2671          1.112    kleink 	} */ *uap = v;
   2672          1.179   thorpej 	struct proc *p = l->l_proc;
   2673          1.112    kleink 	int error;
   2674          1.112    kleink 	struct file *fp;
   2675          1.112    kleink 
   2676          1.135   thorpej 	/* getvnode() will use the descriptor for us */
   2677          1.112    kleink 	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
   2678          1.112    kleink 		return (error);
   2679          1.112    kleink 
   2680          1.135   thorpej 	error = change_owner((struct vnode *)fp->f_data, SCARG(uap, uid),
   2681          1.190      fvdl 	    SCARG(uap, gid), p, 1);
   2682          1.190      fvdl 	FILE_UNUSE(fp, p);
   2683          1.135   thorpej 	return (error);
   2684           1.86    kleink }
   2685           1.86    kleink 
   2686           1.86    kleink /*
   2687           1.98     enami  * Set ownership given a path name; this version does not follow links.
   2688           1.98     enami  */
   2689           1.98     enami /* ARGSUSED */
   2690           1.98     enami int
   2691          1.179   thorpej sys_lchown(l, v, retval)
   2692          1.179   thorpej 	struct lwp *l;
   2693           1.98     enami 	void *v;
   2694           1.98     enami 	register_t *retval;
   2695           1.98     enami {
   2696          1.155  augustss 	struct sys_lchown_args /* {
   2697           1.98     enami 		syscallarg(const char *) path;
   2698           1.98     enami 		syscallarg(uid_t) uid;
   2699           1.98     enami 		syscallarg(gid_t) gid;
   2700           1.98     enami 	} */ *uap = v;
   2701          1.190      fvdl 	struct proc *p = l->l_proc;
   2702           1.98     enami 	int error;
   2703           1.98     enami 	struct nameidata nd;
   2704           1.98     enami 
   2705          1.190      fvdl 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   2706           1.98     enami 	if ((error = namei(&nd)) != 0)
   2707           1.98     enami 		return (error);
   2708           1.98     enami 
   2709          1.190      fvdl 	error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), p, 0);
   2710          1.112    kleink 
   2711          1.112    kleink 	vrele(nd.ni_vp);
   2712          1.112    kleink 	return (error);
   2713          1.112    kleink }
   2714          1.112    kleink 
   2715          1.112    kleink /*
   2716          1.112    kleink  * Set ownership given a path name; this version does not follow links.
   2717          1.112    kleink  * Provides POSIX/XPG semantics.
   2718          1.112    kleink  */
   2719          1.112    kleink /* ARGSUSED */
   2720          1.112    kleink int
   2721          1.179   thorpej sys___posix_lchown(l, v, retval)
   2722          1.179   thorpej 	struct lwp *l;
   2723          1.112    kleink 	void *v;
   2724          1.112    kleink 	register_t *retval;
   2725          1.112    kleink {
   2726          1.155  augustss 	struct sys_lchown_args /* {
   2727          1.112    kleink 		syscallarg(const char *) path;
   2728          1.112    kleink 		syscallarg(uid_t) uid;
   2729          1.112    kleink 		syscallarg(gid_t) gid;
   2730          1.112    kleink 	} */ *uap = v;
   2731          1.190      fvdl 	struct proc *p = l->l_proc;
   2732          1.112    kleink 	int error;
   2733          1.112    kleink 	struct nameidata nd;
   2734          1.112    kleink 
   2735          1.190      fvdl 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   2736          1.112    kleink 	if ((error = namei(&nd)) != 0)
   2737          1.112    kleink 		return (error);
   2738          1.112    kleink 
   2739          1.190      fvdl 	error = change_owner(nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid), p, 1);
   2740           1.98     enami 
   2741           1.98     enami 	vrele(nd.ni_vp);
   2742           1.98     enami 	return (error);
   2743           1.98     enami }
   2744           1.98     enami 
   2745           1.98     enami /*
   2746          1.205  junyoung  * Common routine to set ownership given a vnode.
   2747           1.86    kleink  */
   2748           1.86    kleink static int
   2749          1.190      fvdl change_owner(vp, uid, gid, p, posix_semantics)
   2750          1.155  augustss 	struct vnode *vp;
   2751           1.86    kleink 	uid_t uid;
   2752           1.86    kleink 	gid_t gid;
   2753          1.190      fvdl 	struct proc *p;
   2754          1.112    kleink 	int posix_semantics;
   2755           1.86    kleink {
   2756          1.197   hannken 	struct mount *mp;
   2757           1.86    kleink 	struct vattr vattr;
   2758          1.112    kleink 	mode_t newmode;
   2759           1.86    kleink 	int error;
   2760           1.86    kleink 
   2761          1.197   hannken 	if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
   2762          1.197   hannken 		return (error);
   2763          1.190      fvdl 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
   2764          1.113      fvdl 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
   2765          1.190      fvdl 	if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0)
   2766           1.86    kleink 		goto out;
   2767           1.86    kleink 
   2768          1.175   thorpej #define CHANGED(x) ((int)(x) != -1)
   2769          1.112    kleink 	newmode = vattr.va_mode;
   2770          1.112    kleink 	if (posix_semantics) {
   2771          1.112    kleink 		/*
   2772          1.114    kleink 		 * POSIX/XPG semantics: if the caller is not the super-user,
   2773          1.114    kleink 		 * clear set-user-id and set-group-id bits.  Both POSIX and
   2774          1.114    kleink 		 * the XPG consider the behaviour for calls by the super-user
   2775          1.114    kleink 		 * implementation-defined; we leave the set-user-id and set-
   2776          1.114    kleink 		 * group-id settings intact in that case.
   2777          1.112    kleink 		 */
   2778          1.112    kleink 		if (suser(p->p_ucred, NULL) != 0)
   2779          1.112    kleink 			newmode &= ~(S_ISUID | S_ISGID);
   2780          1.112    kleink 	} else {
   2781          1.112    kleink 		/*
   2782          1.112    kleink 		 * NetBSD semantics: when changing owner and/or group,
   2783          1.112    kleink 		 * clear the respective bit(s).
   2784          1.112    kleink 		 */
   2785          1.112    kleink 		if (CHANGED(uid))
   2786          1.112    kleink 			newmode &= ~S_ISUID;
   2787          1.112    kleink 		if (CHANGED(gid))
   2788          1.112    kleink 			newmode &= ~S_ISGID;
   2789          1.112    kleink 	}
   2790          1.112    kleink 	/* Update va_mode iff altered. */
   2791          1.112    kleink 	if (vattr.va_mode == newmode)
   2792          1.112    kleink 		newmode = VNOVAL;
   2793          1.205  junyoung 
   2794           1.86    kleink 	VATTR_NULL(&vattr);
   2795          1.175   thorpej 	vattr.va_uid = CHANGED(uid) ? uid : (uid_t)VNOVAL;
   2796          1.175   thorpej 	vattr.va_gid = CHANGED(gid) ? gid : (gid_t)VNOVAL;
   2797           1.86    kleink 	vattr.va_mode = newmode;
   2798          1.190      fvdl 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
   2799          1.112    kleink #undef CHANGED
   2800          1.205  junyoung 
   2801           1.86    kleink out:
   2802          1.113      fvdl 	VOP_UNLOCK(vp, 0);
   2803          1.197   hannken 	vn_finished_write(mp, 0);
   2804           1.31       cgd 	return (error);
   2805           1.31       cgd }
   2806           1.31       cgd 
   2807           1.31       cgd /*
   2808           1.98     enami  * Set the access and modification times given a path name; this
   2809           1.98     enami  * version follows links.
   2810           1.31       cgd  */
   2811           1.31       cgd /* ARGSUSED */
   2812           1.63  christos int
   2813          1.179   thorpej sys_utimes(l, v, retval)
   2814          1.179   thorpej 	struct lwp *l;
   2815           1.56   thorpej 	void *v;
   2816           1.56   thorpej 	register_t *retval;
   2817           1.56   thorpej {
   2818          1.155  augustss 	struct sys_utimes_args /* {
   2819           1.74       cgd 		syscallarg(const char *) path;
   2820           1.74       cgd 		syscallarg(const struct timeval *) tptr;
   2821           1.56   thorpej 	} */ *uap = v;
   2822          1.190      fvdl 	struct proc *p = l->l_proc;
   2823           1.31       cgd 	int error;
   2824           1.31       cgd 	struct nameidata nd;
   2825           1.31       cgd 
   2826          1.190      fvdl 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   2827           1.96     enami 	if ((error = namei(&nd)) != 0)
   2828           1.96     enami 		return (error);
   2829           1.97     enami 
   2830          1.190      fvdl 	error = change_utimes(nd.ni_vp, SCARG(uap, tptr), p);
   2831           1.97     enami 
   2832           1.97     enami 	vrele(nd.ni_vp);
   2833           1.71   mycroft 	return (error);
   2834           1.71   mycroft }
   2835           1.71   mycroft 
   2836           1.71   mycroft /*
   2837           1.71   mycroft  * Set the access and modification times given a file descriptor.
   2838           1.71   mycroft  */
   2839           1.71   mycroft /* ARGSUSED */
   2840           1.71   mycroft int
   2841          1.179   thorpej sys_futimes(l, v, retval)
   2842          1.179   thorpej 	struct lwp *l;
   2843           1.71   mycroft 	void *v;
   2844           1.71   mycroft 	register_t *retval;
   2845           1.71   mycroft {
   2846          1.155  augustss 	struct sys_futimes_args /* {
   2847           1.71   mycroft 		syscallarg(int) fd;
   2848           1.74       cgd 		syscallarg(const struct timeval *) tptr;
   2849           1.71   mycroft 	} */ *uap = v;
   2850          1.179   thorpej 	struct proc *p = l->l_proc;
   2851           1.71   mycroft 	int error;
   2852           1.71   mycroft 	struct file *fp;
   2853           1.71   mycroft 
   2854          1.135   thorpej 	/* getvnode() will use the descriptor for us */
   2855           1.96     enami 	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
   2856           1.96     enami 		return (error);
   2857           1.97     enami 
   2858          1.190      fvdl 	error = change_utimes((struct vnode *)fp->f_data, SCARG(uap, tptr), p);
   2859          1.190      fvdl 	FILE_UNUSE(fp, p);
   2860          1.135   thorpej 	return (error);
   2861           1.98     enami }
   2862           1.98     enami 
   2863           1.98     enami /*
   2864           1.98     enami  * Set the access and modification times given a path name; this
   2865           1.98     enami  * version does not follow links.
   2866           1.98     enami  */
   2867           1.98     enami /* ARGSUSED */
   2868           1.98     enami int
   2869          1.179   thorpej sys_lutimes(l, v, retval)
   2870          1.179   thorpej 	struct lwp *l;
   2871           1.98     enami 	void *v;
   2872           1.98     enami 	register_t *retval;
   2873           1.98     enami {
   2874          1.155  augustss 	struct sys_lutimes_args /* {
   2875           1.98     enami 		syscallarg(const char *) path;
   2876           1.98     enami 		syscallarg(const struct timeval *) tptr;
   2877           1.98     enami 	} */ *uap = v;
   2878          1.190      fvdl 	struct proc *p = l->l_proc;
   2879           1.98     enami 	int error;
   2880           1.98     enami 	struct nameidata nd;
   2881           1.98     enami 
   2882          1.190      fvdl 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   2883           1.98     enami 	if ((error = namei(&nd)) != 0)
   2884           1.98     enami 		return (error);
   2885           1.98     enami 
   2886          1.190      fvdl 	error = change_utimes(nd.ni_vp, SCARG(uap, tptr), p);
   2887           1.98     enami 
   2888           1.98     enami 	vrele(nd.ni_vp);
   2889           1.98     enami 	return (error);
   2890           1.97     enami }
   2891           1.97     enami 
   2892           1.97     enami /*
   2893           1.97     enami  * Common routine to set access and modification times given a vnode.
   2894           1.97     enami  */
   2895           1.97     enami static int
   2896          1.190      fvdl change_utimes(vp, tptr, p)
   2897           1.97     enami 	struct vnode *vp;
   2898           1.97     enami 	const struct timeval *tptr;
   2899          1.190      fvdl 	struct proc *p;
   2900           1.97     enami {
   2901           1.97     enami 	struct timeval tv[2];
   2902          1.197   hannken 	struct mount *mp;
   2903           1.97     enami 	struct vattr vattr;
   2904           1.97     enami 	int error;
   2905           1.97     enami 
   2906          1.197   hannken 	if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
   2907          1.197   hannken 		return (error);
   2908           1.71   mycroft 	VATTR_NULL(&vattr);
   2909           1.97     enami 	if (tptr == NULL) {
   2910           1.71   mycroft 		microtime(&tv[0]);
   2911           1.71   mycroft 		tv[1] = tv[0];
   2912           1.71   mycroft 		vattr.va_vaflags |= VA_UTIMES_NULL;
   2913           1.71   mycroft 	} else {
   2914          1.122     perry 		error = copyin(tptr, tv, sizeof(tv));
   2915           1.71   mycroft 		if (error)
   2916          1.197   hannken 			goto out;
   2917           1.71   mycroft 	}
   2918          1.190      fvdl 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
   2919          1.113      fvdl 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
   2920          1.113      fvdl 	vattr.va_atime.tv_sec = tv[0].tv_sec;
   2921          1.113      fvdl 	vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000;
   2922          1.113      fvdl 	vattr.va_mtime.tv_sec = tv[1].tv_sec;
   2923          1.113      fvdl 	vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000;
   2924          1.190      fvdl 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
   2925          1.113      fvdl 	VOP_UNLOCK(vp, 0);
   2926          1.197   hannken out:
   2927          1.197   hannken 	vn_finished_write(mp, 0);
   2928           1.31       cgd 	return (error);
   2929           1.31       cgd }
   2930           1.31       cgd 
   2931           1.31       cgd /*
   2932           1.31       cgd  * Truncate a file given its path name.
   2933           1.31       cgd  */
   2934           1.31       cgd /* ARGSUSED */
   2935           1.63  christos int
   2936          1.179   thorpej sys_truncate(l, v, retval)
   2937          1.179   thorpej 	struct lwp *l;
   2938           1.56   thorpej 	void *v;
   2939           1.56   thorpej 	register_t *retval;
   2940           1.56   thorpej {
   2941          1.155  augustss 	struct sys_truncate_args /* {
   2942           1.74       cgd 		syscallarg(const char *) path;
   2943           1.35       cgd 		syscallarg(int) pad;
   2944           1.35       cgd 		syscallarg(off_t) length;
   2945           1.56   thorpej 	} */ *uap = v;
   2946          1.179   thorpej 	struct proc *p = l->l_proc;
   2947          1.155  augustss 	struct vnode *vp;
   2948          1.197   hannken 	struct mount *mp;
   2949           1.31       cgd 	struct vattr vattr;
   2950           1.31       cgd 	int error;
   2951           1.31       cgd 	struct nameidata nd;
   2952           1.31       cgd 
   2953          1.190      fvdl 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   2954           1.63  christos 	if ((error = namei(&nd)) != 0)
   2955           1.31       cgd 		return (error);
   2956           1.31       cgd 	vp = nd.ni_vp;
   2957          1.197   hannken 	if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) {
   2958          1.197   hannken 		vrele(vp);
   2959          1.197   hannken 		return (error);
   2960          1.197   hannken 	}
   2961          1.190      fvdl 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
   2962          1.113      fvdl 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
   2963           1.31       cgd 	if (vp->v_type == VDIR)
   2964           1.31       cgd 		error = EISDIR;
   2965           1.31       cgd 	else if ((error = vn_writechk(vp)) == 0 &&
   2966          1.190      fvdl 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
   2967           1.31       cgd 		VATTR_NULL(&vattr);
   2968           1.35       cgd 		vattr.va_size = SCARG(uap, length);
   2969          1.190      fvdl 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
   2970           1.31       cgd 	}
   2971           1.31       cgd 	vput(vp);
   2972          1.197   hannken 	vn_finished_write(mp, 0);
   2973           1.31       cgd 	return (error);
   2974           1.31       cgd }
   2975           1.31       cgd 
   2976           1.31       cgd /*
   2977           1.31       cgd  * Truncate a file given a file descriptor.
   2978           1.31       cgd  */
   2979           1.31       cgd /* ARGSUSED */
   2980           1.63  christos int
   2981          1.179   thorpej sys_ftruncate(l, v, retval)
   2982          1.179   thorpej 	struct lwp *l;
   2983           1.56   thorpej 	void *v;
   2984           1.56   thorpej 	register_t *retval;
   2985           1.56   thorpej {
   2986          1.155  augustss 	struct sys_ftruncate_args /* {
   2987           1.35       cgd 		syscallarg(int) fd;
   2988           1.35       cgd 		syscallarg(int) pad;
   2989           1.35       cgd 		syscallarg(off_t) length;
   2990           1.56   thorpej 	} */ *uap = v;
   2991          1.179   thorpej 	struct proc *p = l->l_proc;
   2992          1.197   hannken 	struct mount *mp;
   2993           1.31       cgd 	struct vattr vattr;
   2994           1.31       cgd 	struct vnode *vp;
   2995           1.31       cgd 	struct file *fp;
   2996           1.31       cgd 	int error;
   2997           1.31       cgd 
   2998          1.135   thorpej 	/* getvnode() will use the descriptor for us */
   2999           1.63  christos 	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
   3000           1.31       cgd 		return (error);
   3001          1.135   thorpej 	if ((fp->f_flag & FWRITE) == 0) {
   3002          1.135   thorpej 		error = EINVAL;
   3003          1.135   thorpej 		goto out;
   3004          1.135   thorpej 	}
   3005           1.62   mycroft 	vp = (struct vnode *)fp->f_data;
   3006          1.197   hannken 	if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) {
   3007          1.197   hannken 		FILE_UNUSE(fp, p);
   3008          1.197   hannken 		return (error);
   3009          1.197   hannken 	}
   3010          1.190      fvdl 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
   3011          1.113      fvdl 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
   3012           1.31       cgd 	if (vp->v_type == VDIR)
   3013           1.31       cgd 		error = EISDIR;
   3014           1.31       cgd 	else if ((error = vn_writechk(vp)) == 0) {
   3015           1.31       cgd 		VATTR_NULL(&vattr);
   3016           1.35       cgd 		vattr.va_size = SCARG(uap, length);
   3017          1.190      fvdl 		error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
   3018           1.31       cgd 	}
   3019          1.113      fvdl 	VOP_UNLOCK(vp, 0);
   3020          1.197   hannken 	vn_finished_write(mp, 0);
   3021          1.135   thorpej  out:
   3022          1.190      fvdl 	FILE_UNUSE(fp, p);
   3023           1.31       cgd 	return (error);
   3024           1.31       cgd }
   3025           1.31       cgd 
   3026           1.31       cgd /*
   3027           1.31       cgd  * Sync an open file.
   3028           1.31       cgd  */
   3029           1.31       cgd /* ARGSUSED */
   3030           1.63  christos int
   3031          1.179   thorpej sys_fsync(l, v, retval)
   3032          1.179   thorpej 	struct lwp *l;
   3033           1.56   thorpej 	void *v;
   3034           1.56   thorpej 	register_t *retval;
   3035           1.56   thorpej {
   3036           1.57   mycroft 	struct sys_fsync_args /* {
   3037           1.35       cgd 		syscallarg(int) fd;
   3038           1.56   thorpej 	} */ *uap = v;
   3039          1.179   thorpej 	struct proc *p = l->l_proc;
   3040          1.155  augustss 	struct vnode *vp;
   3041          1.197   hannken 	struct mount *mp;
   3042           1.31       cgd 	struct file *fp;
   3043           1.31       cgd 	int error;
   3044           1.31       cgd 
   3045          1.135   thorpej 	/* getvnode() will use the descriptor for us */
   3046           1.63  christos 	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
   3047           1.31       cgd 		return (error);
   3048           1.62   mycroft 	vp = (struct vnode *)fp->f_data;
   3049          1.197   hannken 	if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0) {
   3050          1.197   hannken 		FILE_UNUSE(fp, p);
   3051          1.197   hannken 		return (error);
   3052          1.197   hannken 	}
   3053          1.113      fvdl 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
   3054          1.190      fvdl 	error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT, 0, 0, p);
   3055          1.148      fvdl 	if (error == 0 && bioops.io_fsync != NULL &&
   3056          1.148      fvdl 	    vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP))
   3057          1.216  wrstuden 		(*bioops.io_fsync)(vp, 0);
   3058          1.113      fvdl 	VOP_UNLOCK(vp, 0);
   3059          1.197   hannken 	vn_finished_write(mp, 0);
   3060          1.201   thorpej 	FILE_UNUSE(fp, p);
   3061          1.201   thorpej 	return (error);
   3062          1.201   thorpej }
   3063          1.201   thorpej 
   3064          1.201   thorpej /*
   3065          1.201   thorpej  * Sync a range of file data.  API modeled after that found in AIX.
   3066          1.201   thorpej  *
   3067          1.201   thorpej  * FDATASYNC indicates that we need only save enough metadata to be able
   3068          1.201   thorpej  * to re-read the written data.  Note we duplicate AIX's requirement that
   3069          1.201   thorpej  * the file be open for writing.
   3070          1.201   thorpej  */
   3071          1.201   thorpej /* ARGSUSED */
   3072          1.201   thorpej int
   3073          1.201   thorpej sys_fsync_range(l, v, retval)
   3074          1.201   thorpej 	struct lwp *l;
   3075          1.201   thorpej 	void *v;
   3076          1.201   thorpej 	register_t *retval;
   3077          1.201   thorpej {
   3078          1.201   thorpej 	struct sys_fsync_range_args /* {
   3079          1.201   thorpej 		syscallarg(int) fd;
   3080          1.201   thorpej 		syscallarg(int) flags;
   3081          1.201   thorpej 		syscallarg(off_t) start;
   3082          1.201   thorpej 		syscallarg(int) length;
   3083          1.201   thorpej 	} */ *uap = v;
   3084          1.201   thorpej 	struct proc *p = l->l_proc;
   3085          1.201   thorpej 	struct vnode *vp;
   3086          1.201   thorpej 	struct file *fp;
   3087          1.201   thorpej 	int flags, nflags;
   3088          1.201   thorpej 	off_t s, e, len;
   3089          1.201   thorpej 	int error;
   3090          1.201   thorpej 
   3091          1.201   thorpej 	/* getvnode() will use the descriptor for us */
   3092          1.201   thorpej 	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
   3093          1.201   thorpej 		return (error);
   3094          1.201   thorpej 
   3095          1.201   thorpej 	if ((fp->f_flag & FWRITE) == 0) {
   3096  1.217.2.7.2.1    bouyer 		error = EBADF;
   3097  1.217.2.7.2.1    bouyer 		goto out;
   3098          1.201   thorpej 	}
   3099          1.201   thorpej 
   3100          1.201   thorpej 	flags = SCARG(uap, flags);
   3101          1.201   thorpej 	if (((flags & (FDATASYNC | FFILESYNC)) == 0) ||
   3102          1.201   thorpej 	    ((~flags & (FDATASYNC | FFILESYNC)) == 0)) {
   3103  1.217.2.7.2.1    bouyer 		error = EINVAL;
   3104  1.217.2.7.2.1    bouyer 		goto out;
   3105          1.201   thorpej 	}
   3106          1.201   thorpej 	/* Now set up the flags for value(s) to pass to VOP_FSYNC() */
   3107          1.201   thorpej 	if (flags & FDATASYNC)
   3108          1.201   thorpej 		nflags = FSYNC_DATAONLY | FSYNC_WAIT;
   3109          1.201   thorpej 	else
   3110          1.201   thorpej 		nflags = FSYNC_WAIT;
   3111          1.216  wrstuden 	if (flags & FDISKSYNC)
   3112          1.216  wrstuden 		nflags |= FSYNC_CACHE;
   3113          1.201   thorpej 
   3114          1.201   thorpej 	len = SCARG(uap, length);
   3115          1.201   thorpej 	/* If length == 0, we do the whole file, and s = l = 0 will do that */
   3116          1.201   thorpej 	if (len) {
   3117          1.201   thorpej 		s = SCARG(uap, start);
   3118          1.201   thorpej 		e = s + len;
   3119          1.201   thorpej 		if (e < s) {
   3120          1.201   thorpej 			FILE_UNUSE(fp, p);
   3121  1.217.2.7.2.1    bouyer 			error = EINVAL;
   3122  1.217.2.7.2.1    bouyer 			goto out;
   3123          1.201   thorpej 		}
   3124          1.201   thorpej 	} else {
   3125          1.201   thorpej 		e = 0;
   3126          1.201   thorpej 		s = 0;
   3127          1.201   thorpej 	}
   3128          1.201   thorpej 
   3129          1.201   thorpej 	vp = (struct vnode *)fp->f_data;
   3130          1.201   thorpej 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
   3131          1.201   thorpej 	error = VOP_FSYNC(vp, fp->f_cred, nflags, s, e, p);
   3132          1.201   thorpej 
   3133          1.201   thorpej 	if (error == 0 && bioops.io_fsync != NULL &&
   3134          1.201   thorpej 	    vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP))
   3135          1.216  wrstuden 		(*bioops.io_fsync)(vp, nflags);
   3136          1.201   thorpej 
   3137          1.201   thorpej 	VOP_UNLOCK(vp, 0);
   3138  1.217.2.7.2.1    bouyer out:
   3139          1.190      fvdl 	FILE_UNUSE(fp, p);
   3140           1.31       cgd 	return (error);
   3141           1.31       cgd }
   3142           1.31       cgd 
   3143           1.31       cgd /*
   3144          1.117    kleink  * Sync the data of an open file.
   3145          1.117    kleink  */
   3146          1.117    kleink /* ARGSUSED */
   3147          1.117    kleink int
   3148          1.179   thorpej sys_fdatasync(l, v, retval)
   3149          1.179   thorpej 	struct lwp *l;
   3150          1.117    kleink 	void *v;
   3151          1.117    kleink 	register_t *retval;
   3152          1.117    kleink {
   3153          1.117    kleink 	struct sys_fdatasync_args /* {
   3154          1.117    kleink 		syscallarg(int) fd;
   3155          1.117    kleink 	} */ *uap = v;
   3156          1.179   thorpej 	struct proc *p = l->l_proc;
   3157          1.117    kleink 	struct vnode *vp;
   3158          1.117    kleink 	struct file *fp;
   3159          1.117    kleink 	int error;
   3160          1.117    kleink 
   3161          1.135   thorpej 	/* getvnode() will use the descriptor for us */
   3162          1.117    kleink 	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
   3163          1.117    kleink 		return (error);
   3164          1.199    kleink 	if ((fp->f_flag & FWRITE) == 0) {
   3165          1.199    kleink 		FILE_UNUSE(fp, p);
   3166          1.199    kleink 		return (EBADF);
   3167          1.199    kleink 	}
   3168          1.117    kleink 	vp = (struct vnode *)fp->f_data;
   3169          1.117    kleink 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
   3170          1.190      fvdl 	error = VOP_FSYNC(vp, fp->f_cred, FSYNC_WAIT|FSYNC_DATAONLY, 0, 0, p);
   3171          1.117    kleink 	VOP_UNLOCK(vp, 0);
   3172          1.190      fvdl 	FILE_UNUSE(fp, p);
   3173          1.117    kleink 	return (error);
   3174          1.117    kleink }
   3175          1.117    kleink 
   3176          1.117    kleink /*
   3177           1.90    kleink  * Rename files, (standard) BSD semantics frontend.
   3178           1.31       cgd  */
   3179           1.31       cgd /* ARGSUSED */
   3180           1.63  christos int
   3181          1.179   thorpej sys_rename(l, v, retval)
   3182          1.179   thorpej 	struct lwp *l;
   3183           1.56   thorpej 	void *v;
   3184           1.56   thorpej 	register_t *retval;
   3185           1.56   thorpej {
   3186          1.155  augustss 	struct sys_rename_args /* {
   3187           1.74       cgd 		syscallarg(const char *) from;
   3188           1.74       cgd 		syscallarg(const char *) to;
   3189           1.56   thorpej 	} */ *uap = v;
   3190          1.190      fvdl 	struct proc *p = l->l_proc;
   3191           1.90    kleink 
   3192          1.190      fvdl 	return (rename_files(SCARG(uap, from), SCARG(uap, to), p, 0));
   3193           1.90    kleink }
   3194           1.90    kleink 
   3195           1.90    kleink /*
   3196           1.90    kleink  * Rename files, POSIX semantics frontend.
   3197           1.90    kleink  */
   3198           1.90    kleink /* ARGSUSED */
   3199           1.90    kleink int
   3200          1.179   thorpej sys___posix_rename(l, v, retval)
   3201          1.179   thorpej 	struct lwp *l;
   3202           1.90    kleink 	void *v;
   3203           1.90    kleink 	register_t *retval;
   3204           1.90    kleink {
   3205          1.155  augustss 	struct sys___posix_rename_args /* {
   3206           1.90    kleink 		syscallarg(const char *) from;
   3207           1.90    kleink 		syscallarg(const char *) to;
   3208           1.90    kleink 	} */ *uap = v;
   3209          1.190      fvdl 	struct proc *p = l->l_proc;
   3210           1.90    kleink 
   3211          1.190      fvdl 	return (rename_files(SCARG(uap, from), SCARG(uap, to), p, 1));
   3212           1.90    kleink }
   3213           1.90    kleink 
   3214           1.90    kleink /*
   3215           1.90    kleink  * Rename files.  Source and destination must either both be directories,
   3216           1.90    kleink  * or both not be directories.  If target is a directory, it must be empty.
   3217           1.90    kleink  * If `from' and `to' refer to the same object, the value of the `retain'
   3218           1.90    kleink  * argument is used to determine whether `from' will be
   3219           1.90    kleink  *
   3220           1.90    kleink  * (retain == 0)	deleted unless `from' and `to' refer to the same
   3221           1.90    kleink  *			object in the file system's name space (BSD).
   3222           1.90    kleink  * (retain == 1)	always retained (POSIX).
   3223           1.90    kleink  */
   3224           1.90    kleink static int
   3225          1.190      fvdl rename_files(from, to, p, retain)
   3226           1.90    kleink 	const char *from, *to;
   3227          1.190      fvdl 	struct proc *p;
   3228           1.90    kleink 	int retain;
   3229           1.90    kleink {
   3230          1.197   hannken 	struct mount *mp = NULL;
   3231          1.155  augustss 	struct vnode *tvp, *fvp, *tdvp;
   3232           1.31       cgd 	struct nameidata fromnd, tond;
   3233           1.31       cgd 	int error;
   3234           1.31       cgd 
   3235           1.31       cgd 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
   3236          1.190      fvdl 	    from, p);
   3237           1.63  christos 	if ((error = namei(&fromnd)) != 0)
   3238           1.31       cgd 		return (error);
   3239           1.31       cgd 	fvp = fromnd.ni_vp;
   3240          1.197   hannken 	error = vn_start_write(fvp, &mp, V_WAIT | V_PCATCH);
   3241          1.197   hannken 	if (error != 0) {
   3242          1.197   hannken 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
   3243          1.197   hannken 		vrele(fromnd.ni_dvp);
   3244          1.197   hannken 		vrele(fvp);
   3245          1.197   hannken 		if (fromnd.ni_startdir)
   3246          1.197   hannken 			vrele(fromnd.ni_startdir);
   3247          1.197   hannken 		PNBUF_PUT(fromnd.ni_cnd.cn_pnbuf);
   3248          1.197   hannken 		return (error);
   3249          1.197   hannken 	}
   3250          1.193  christos 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART |
   3251          1.193  christos 	    (fvp->v_type == VDIR ? CREATEDIR : 0), UIO_USERSPACE, to, p);
   3252           1.63  christos 	if ((error = namei(&tond)) != 0) {
   3253           1.31       cgd 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
   3254           1.31       cgd 		vrele(fromnd.ni_dvp);
   3255           1.31       cgd 		vrele(fvp);
   3256           1.31       cgd 		goto out1;
   3257           1.31       cgd 	}
   3258           1.31       cgd 	tdvp = tond.ni_dvp;
   3259           1.31       cgd 	tvp = tond.ni_vp;
   3260           1.90    kleink 
   3261           1.31       cgd 	if (tvp != NULL) {
   3262           1.31       cgd 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
   3263           1.31       cgd 			error = ENOTDIR;
   3264           1.31       cgd 			goto out;
   3265           1.31       cgd 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
   3266           1.31       cgd 			error = EISDIR;
   3267           1.31       cgd 			goto out;
   3268           1.31       cgd 		}
   3269           1.31       cgd 	}
   3270           1.90    kleink 
   3271           1.31       cgd 	if (fvp == tdvp)
   3272           1.31       cgd 		error = EINVAL;
   3273           1.90    kleink 
   3274           1.82    kleink 	/*
   3275           1.90    kleink 	 * Source and destination refer to the same object.
   3276           1.82    kleink 	 */
   3277           1.90    kleink 	if (fvp == tvp) {
   3278           1.90    kleink 		if (retain)
   3279           1.90    kleink 			error = -1;
   3280           1.90    kleink 		else if (fromnd.ni_dvp == tdvp &&
   3281           1.90    kleink 		    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
   3282          1.123     perry 		    !memcmp(fromnd.ni_cnd.cn_nameptr,
   3283           1.90    kleink 		          tond.ni_cnd.cn_nameptr,
   3284           1.90    kleink 		          fromnd.ni_cnd.cn_namelen))
   3285           1.82    kleink 		error = -1;
   3286           1.90    kleink 	}
   3287           1.90    kleink 
   3288      1.217.2.6      tron #ifdef VERIFIED_EXEC
   3289      1.217.2.6      tron 	if (!error)
   3290  1.217.2.7.2.2      ghen 		error = veriexec_renamechk(fvp, tvp, fromnd.ni_dirp,
   3291  1.217.2.7.2.2      ghen 					   tond.ni_dirp);
   3292      1.217.2.6      tron #endif /* VERIFIED_EXEC */
   3293      1.217.2.6      tron 
   3294           1.31       cgd out:
   3295           1.31       cgd 	if (!error) {
   3296          1.190      fvdl 		VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE);
   3297           1.31       cgd 		if (fromnd.ni_dvp != tdvp)
   3298          1.190      fvdl 			VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
   3299           1.75      fvdl 		if (tvp) {
   3300          1.190      fvdl 			VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE);
   3301           1.75      fvdl 		}
   3302           1.31       cgd 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
   3303           1.31       cgd 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
   3304           1.31       cgd 	} else {
   3305           1.31       cgd 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
   3306           1.31       cgd 		if (tdvp == tvp)
   3307           1.31       cgd 			vrele(tdvp);
   3308           1.31       cgd 		else
   3309           1.31       cgd 			vput(tdvp);
   3310           1.31       cgd 		if (tvp)
   3311           1.31       cgd 			vput(tvp);
   3312           1.31       cgd 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
   3313           1.31       cgd 		vrele(fromnd.ni_dvp);
   3314           1.31       cgd 		vrele(fvp);
   3315           1.31       cgd 	}
   3316           1.31       cgd 	vrele(tond.ni_startdir);
   3317          1.161   thorpej 	PNBUF_PUT(tond.ni_cnd.cn_pnbuf);
   3318           1.31       cgd out1:
   3319          1.197   hannken 	vn_finished_write(mp, 0);
   3320           1.31       cgd 	if (fromnd.ni_startdir)
   3321           1.31       cgd 		vrele(fromnd.ni_startdir);
   3322          1.161   thorpej 	PNBUF_PUT(fromnd.ni_cnd.cn_pnbuf);
   3323           1.80    kleink 	return (error == -1 ? 0 : error);
   3324           1.31       cgd }
   3325           1.31       cgd 
   3326           1.31       cgd /*
   3327           1.31       cgd  * Make a directory file.
   3328           1.31       cgd  */
   3329           1.31       cgd /* ARGSUSED */
   3330           1.63  christos int
   3331          1.179   thorpej sys_mkdir(l, v, retval)
   3332          1.179   thorpej 	struct lwp *l;
   3333           1.56   thorpej 	void *v;
   3334           1.56   thorpej 	register_t *retval;
   3335           1.56   thorpej {
   3336          1.155  augustss 	struct sys_mkdir_args /* {
   3337           1.74       cgd 		syscallarg(const char *) path;
   3338           1.35       cgd 		syscallarg(int) mode;
   3339           1.56   thorpej 	} */ *uap = v;
   3340          1.179   thorpej 	struct proc *p = l->l_proc;
   3341          1.197   hannken 	struct mount *mp;
   3342          1.155  augustss 	struct vnode *vp;
   3343           1.31       cgd 	struct vattr vattr;
   3344           1.31       cgd 	int error;
   3345           1.31       cgd 	struct nameidata nd;
   3346           1.31       cgd 
   3347          1.197   hannken restart:
   3348          1.193  christos 	NDINIT(&nd, CREATE, LOCKPARENT | CREATEDIR, UIO_USERSPACE,
   3349          1.193  christos 	    SCARG(uap, path), p);
   3350           1.63  christos 	if ((error = namei(&nd)) != 0)
   3351           1.31       cgd 		return (error);
   3352           1.31       cgd 	vp = nd.ni_vp;
   3353           1.31       cgd 	if (vp != NULL) {
   3354           1.31       cgd 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
   3355           1.31       cgd 		if (nd.ni_dvp == vp)
   3356           1.31       cgd 			vrele(nd.ni_dvp);
   3357           1.31       cgd 		else
   3358           1.31       cgd 			vput(nd.ni_dvp);
   3359           1.31       cgd 		vrele(vp);
   3360           1.31       cgd 		return (EEXIST);
   3361           1.31       cgd 	}
   3362          1.197   hannken 	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
   3363          1.197   hannken 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
   3364          1.197   hannken 		if (nd.ni_dvp == vp)
   3365          1.197   hannken 			vrele(nd.ni_dvp);
   3366          1.197   hannken 		else
   3367          1.197   hannken 			vput(nd.ni_dvp);
   3368          1.197   hannken 		if ((error = vn_start_write(NULL, &mp,
   3369          1.197   hannken 		    V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
   3370          1.197   hannken 			return (error);
   3371          1.197   hannken 		goto restart;
   3372          1.197   hannken 	}
   3373           1.31       cgd 	VATTR_NULL(&vattr);
   3374           1.31       cgd 	vattr.va_type = VDIR;
   3375          1.134   thorpej 	vattr.va_mode =
   3376          1.134   thorpej 	    (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_cwdi->cwdi_cmask;
   3377          1.190      fvdl 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
   3378           1.31       cgd 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
   3379           1.31       cgd 	if (!error)
   3380           1.31       cgd 		vput(nd.ni_vp);
   3381          1.197   hannken 	vn_finished_write(mp, 0);
   3382           1.31       cgd 	return (error);
   3383           1.31       cgd }
   3384           1.31       cgd 
   3385           1.31       cgd /*
   3386           1.31       cgd  * Remove a directory file.
   3387           1.31       cgd  */
   3388           1.31       cgd /* ARGSUSED */
   3389           1.63  christos int
   3390          1.179   thorpej sys_rmdir(l, v, retval)
   3391          1.179   thorpej 	struct lwp *l;
   3392           1.56   thorpej 	void *v;
   3393           1.56   thorpej 	register_t *retval;
   3394           1.56   thorpej {
   3395           1.57   mycroft 	struct sys_rmdir_args /* {
   3396           1.74       cgd 		syscallarg(const char *) path;
   3397           1.56   thorpej 	} */ *uap = v;
   3398          1.179   thorpej 	struct proc *p = l->l_proc;
   3399          1.197   hannken 	struct mount *mp;
   3400          1.155  augustss 	struct vnode *vp;
   3401           1.31       cgd 	int error;
   3402           1.31       cgd 	struct nameidata nd;
   3403           1.31       cgd 
   3404          1.197   hannken restart:
   3405           1.35       cgd 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
   3406          1.190      fvdl 	    SCARG(uap, path), p);
   3407           1.63  christos 	if ((error = namei(&nd)) != 0)
   3408           1.31       cgd 		return (error);
   3409           1.31       cgd 	vp = nd.ni_vp;
   3410           1.31       cgd 	if (vp->v_type != VDIR) {
   3411           1.31       cgd 		error = ENOTDIR;
   3412           1.31       cgd 		goto out;
   3413           1.31       cgd 	}
   3414           1.31       cgd 	/*
   3415           1.31       cgd 	 * No rmdir "." please.
   3416           1.31       cgd 	 */
   3417           1.31       cgd 	if (nd.ni_dvp == vp) {
   3418           1.31       cgd 		error = EINVAL;
   3419           1.31       cgd 		goto out;
   3420           1.31       cgd 	}
   3421           1.31       cgd 	/*
   3422           1.31       cgd 	 * The root of a mounted filesystem cannot be deleted.
   3423           1.31       cgd 	 */
   3424          1.197   hannken 	if (vp->v_flag & VROOT) {
   3425           1.31       cgd 		error = EBUSY;
   3426          1.197   hannken 		goto out;
   3427          1.197   hannken 	}
   3428          1.197   hannken 	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
   3429           1.31       cgd 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
   3430           1.31       cgd 		if (nd.ni_dvp == vp)
   3431           1.31       cgd 			vrele(nd.ni_dvp);
   3432           1.31       cgd 		else
   3433           1.31       cgd 			vput(nd.ni_dvp);
   3434           1.31       cgd 		vput(vp);
   3435          1.197   hannken 		if ((error = vn_start_write(NULL, &mp,
   3436          1.197   hannken 		    V_WAIT | V_SLEEPONLY | V_PCATCH)) != 0)
   3437          1.197   hannken 			return (error);
   3438          1.197   hannken 		goto restart;
   3439           1.31       cgd 	}
   3440          1.197   hannken 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
   3441          1.197   hannken 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
   3442          1.197   hannken 	error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
   3443          1.197   hannken 	vn_finished_write(mp, 0);
   3444          1.197   hannken 	return (error);
   3445          1.197   hannken 
   3446          1.197   hannken out:
   3447          1.197   hannken 	VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
   3448          1.197   hannken 	if (nd.ni_dvp == vp)
   3449          1.197   hannken 		vrele(nd.ni_dvp);
   3450          1.197   hannken 	else
   3451          1.197   hannken 		vput(nd.ni_dvp);
   3452          1.197   hannken 	vput(vp);
   3453           1.31       cgd 	return (error);
   3454           1.31       cgd }
   3455           1.31       cgd 
   3456           1.31       cgd /*
   3457           1.31       cgd  * Read a block of directory entries in a file system independent format.
   3458           1.31       cgd  */
   3459           1.63  christos int
   3460          1.179   thorpej sys_getdents(l, v, retval)
   3461          1.179   thorpej 	struct lwp *l;
   3462           1.56   thorpej 	void *v;
   3463           1.56   thorpej 	register_t *retval;
   3464           1.56   thorpej {
   3465          1.155  augustss 	struct sys_getdents_args /* {
   3466           1.35       cgd 		syscallarg(int) fd;
   3467           1.35       cgd 		syscallarg(char *) buf;
   3468          1.101      fvdl 		syscallarg(size_t) count;
   3469           1.56   thorpej 	} */ *uap = v;
   3470          1.179   thorpej 	struct proc *p = l->l_proc;
   3471           1.31       cgd 	struct file *fp;
   3472          1.101      fvdl 	int error, done;
   3473           1.31       cgd 
   3474          1.135   thorpej 	/* getvnode() will use the descriptor for us */
   3475           1.63  christos 	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
   3476           1.31       cgd 		return (error);
   3477          1.135   thorpej 	if ((fp->f_flag & FREAD) == 0) {
   3478          1.135   thorpej 		error = EBADF;
   3479          1.135   thorpej 		goto out;
   3480          1.135   thorpej 	}
   3481          1.101      fvdl 	error = vn_readdir(fp, SCARG(uap, buf), UIO_USERSPACE,
   3482          1.190      fvdl 			SCARG(uap, count), &done, p, 0, 0);
   3483          1.192  drochner #ifdef KTRACE
   3484          1.192  drochner 	if (!error && KTRPOINT(p, KTR_GENIO)) {
   3485          1.192  drochner 		struct iovec iov;
   3486          1.192  drochner 		iov.iov_base = SCARG(uap, buf);
   3487          1.192  drochner 		iov.iov_len = done;
   3488          1.192  drochner 		ktrgenio(p, SCARG(uap, fd), UIO_READ, &iov, done, 0);
   3489          1.192  drochner 	}
   3490          1.192  drochner #endif
   3491          1.101      fvdl 	*retval = done;
   3492          1.135   thorpej  out:
   3493          1.190      fvdl 	FILE_UNUSE(fp, p);
   3494           1.31       cgd 	return (error);
   3495           1.31       cgd }
   3496           1.31       cgd 
   3497           1.31       cgd /*
   3498           1.31       cgd  * Set the mode mask for creation of filesystem nodes.
   3499           1.31       cgd  */
   3500           1.56   thorpej int
   3501          1.179   thorpej sys_umask(l, v, retval)
   3502          1.179   thorpej 	struct lwp *l;
   3503           1.56   thorpej 	void *v;
   3504           1.56   thorpej 	register_t *retval;
   3505           1.56   thorpej {
   3506           1.57   mycroft 	struct sys_umask_args /* {
   3507          1.103   mycroft 		syscallarg(mode_t) newmask;
   3508           1.56   thorpej 	} */ *uap = v;
   3509          1.179   thorpej 	struct proc *p = l->l_proc;
   3510          1.134   thorpej 	struct cwdinfo *cwdi;
   3511           1.31       cgd 
   3512          1.134   thorpej 	cwdi = p->p_cwdi;
   3513          1.134   thorpej 	*retval = cwdi->cwdi_cmask;
   3514          1.134   thorpej 	cwdi->cwdi_cmask = SCARG(uap, newmask) & ALLPERMS;
   3515           1.31       cgd 	return (0);
   3516           1.31       cgd }
   3517           1.31       cgd 
   3518           1.31       cgd /*
   3519           1.31       cgd  * Void all references to file by ripping underlying filesystem
   3520           1.31       cgd  * away from vnode.
   3521           1.31       cgd  */
   3522           1.31       cgd /* ARGSUSED */
   3523           1.63  christos int
   3524          1.179   thorpej sys_revoke(l, v, retval)
   3525          1.179   thorpej 	struct lwp *l;
   3526           1.56   thorpej 	void *v;
   3527           1.56   thorpej 	register_t *retval;
   3528           1.56   thorpej {
   3529          1.155  augustss 	struct sys_revoke_args /* {
   3530           1.74       cgd 		syscallarg(const char *) path;
   3531           1.56   thorpej 	} */ *uap = v;
   3532          1.179   thorpej 	struct proc *p = l->l_proc;
   3533          1.197   hannken 	struct mount *mp;
   3534          1.155  augustss 	struct vnode *vp;
   3535           1.31       cgd 	struct vattr vattr;
   3536           1.31       cgd 	int error;
   3537           1.31       cgd 	struct nameidata nd;
   3538           1.31       cgd 
   3539          1.190      fvdl 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   3540           1.63  christos 	if ((error = namei(&nd)) != 0)
   3541           1.31       cgd 		return (error);
   3542           1.31       cgd 	vp = nd.ni_vp;
   3543          1.190      fvdl 	if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) != 0)
   3544           1.31       cgd 		goto out;
   3545           1.31       cgd 	if (p->p_ucred->cr_uid != vattr.va_uid &&
   3546           1.93     enami 	    (error = suser(p->p_ucred, &p->p_acflag)) != 0)
   3547           1.31       cgd 		goto out;
   3548          1.197   hannken 	if ((error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH)) != 0)
   3549          1.197   hannken 		goto out;
   3550          1.145  wrstuden 	if (vp->v_usecount > 1 || (vp->v_flag & (VALIASED | VLAYER)))
   3551          1.113      fvdl 		VOP_REVOKE(vp, REVOKEALL);
   3552          1.197   hannken 	vn_finished_write(mp, 0);
   3553           1.31       cgd out:
   3554           1.31       cgd 	vrele(vp);
   3555           1.31       cgd 	return (error);
   3556           1.31       cgd }
   3557           1.31       cgd 
   3558           1.31       cgd /*
   3559           1.31       cgd  * Convert a user file descriptor to a kernel file entry.
   3560           1.31       cgd  */
   3561           1.60   mycroft int
   3562           1.62   mycroft getvnode(fdp, fd, fpp)
   3563           1.31       cgd 	struct filedesc *fdp;
   3564           1.60   mycroft 	int fd;
   3565           1.31       cgd 	struct file **fpp;
   3566           1.31       cgd {
   3567           1.60   mycroft 	struct vnode *vp;
   3568           1.31       cgd 	struct file *fp;
   3569           1.31       cgd 
   3570          1.166   thorpej 	if ((fp = fd_getfile(fdp, fd)) == NULL)
   3571           1.31       cgd 		return (EBADF);
   3572          1.135   thorpej 
   3573          1.135   thorpej 	FILE_USE(fp);
   3574          1.135   thorpej 
   3575          1.135   thorpej 	if (fp->f_type != DTYPE_VNODE) {
   3576          1.135   thorpej 		FILE_UNUSE(fp, NULL);
   3577           1.31       cgd 		return (EINVAL);
   3578          1.135   thorpej 	}
   3579          1.135   thorpej 
   3580           1.60   mycroft 	vp = (struct vnode *)fp->f_data;
   3581          1.135   thorpej 	if (vp->v_type == VBAD) {
   3582          1.135   thorpej 		FILE_UNUSE(fp, NULL);
   3583           1.60   mycroft 		return (EBADF);
   3584          1.135   thorpej 	}
   3585          1.135   thorpej 
   3586           1.31       cgd 	*fpp = fp;
   3587           1.31       cgd 	return (0);
   3588           1.31       cgd }
   3589          1.214   thorpej 
   3590          1.214   thorpej /*
   3591          1.214   thorpej  * Push extended attribute configuration information into the VFS.
   3592          1.214   thorpej  *
   3593          1.214   thorpej  * NOTE: Not all file systems that support extended attributes will
   3594          1.214   thorpej  * require the use of this system call.
   3595          1.214   thorpej  */
   3596          1.214   thorpej int
   3597          1.214   thorpej sys_extattrctl(struct lwp *l, void *v, register_t *retval)
   3598          1.214   thorpej {
   3599          1.214   thorpej 	struct sys_extattrctl_args /* {
   3600          1.214   thorpej 		syscallarg(const char *) path;
   3601          1.214   thorpej 		syscallarg(int) cmd;
   3602          1.214   thorpej 		syscallarg(const char *) filename;
   3603          1.214   thorpej 		syscallarg(int) attrnamespace;
   3604          1.214   thorpej 		syscallarg(const char *) attrname;
   3605          1.214   thorpej 	} */ *uap = v;
   3606          1.214   thorpej 	struct proc *p = l->l_proc;
   3607          1.214   thorpej 	struct vnode *vp;
   3608          1.214   thorpej 	struct nameidata nd;
   3609          1.214   thorpej 	struct mount *mp;
   3610          1.214   thorpej 	char attrname[EXTATTR_MAXNAMELEN];
   3611          1.214   thorpej 	int error;
   3612          1.214   thorpej 
   3613          1.214   thorpej 	if (SCARG(uap, attrname) != NULL) {
   3614          1.214   thorpej 		error = copyinstr(SCARG(uap, attrname), attrname,
   3615          1.214   thorpej 		    sizeof(attrname), NULL);
   3616          1.214   thorpej 		if (error)
   3617          1.214   thorpej 			return (error);
   3618          1.214   thorpej 	}
   3619          1.214   thorpej 
   3620          1.214   thorpej 	vp = NULL;
   3621          1.214   thorpej 	if (SCARG(uap, filename) != NULL) {
   3622          1.214   thorpej 		NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
   3623          1.214   thorpej 		    SCARG(uap, filename), p);
   3624          1.214   thorpej 		error = namei(&nd);
   3625          1.214   thorpej 		if (error)
   3626          1.214   thorpej 			return (error);
   3627          1.214   thorpej 		vp = nd.ni_vp;
   3628          1.214   thorpej 	}
   3629          1.214   thorpej 
   3630          1.214   thorpej 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   3631          1.214   thorpej 	error = namei(&nd);
   3632          1.214   thorpej 	if (error) {
   3633          1.214   thorpej 		if (vp != NULL)
   3634          1.214   thorpej 			vput(vp);
   3635          1.214   thorpej 		return (error);
   3636          1.214   thorpej 	}
   3637          1.214   thorpej 
   3638          1.214   thorpej 	error = vn_start_write(nd.ni_vp, &mp, V_WAIT | V_PCATCH);
   3639          1.214   thorpej 	if (error) {
   3640          1.214   thorpej 		if (vp != NULL)
   3641          1.214   thorpej 			vput(vp);
   3642          1.214   thorpej 		return (error);
   3643          1.214   thorpej 	}
   3644          1.214   thorpej 
   3645          1.214   thorpej 	error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), vp,
   3646          1.214   thorpej 	    SCARG(uap, attrnamespace),
   3647          1.214   thorpej 	    SCARG(uap, attrname) != NULL ? attrname : NULL, p);
   3648          1.217     perry 
   3649          1.214   thorpej 	vn_finished_write(mp, 0);
   3650          1.214   thorpej 
   3651          1.214   thorpej 	if (vp != NULL)
   3652          1.214   thorpej 		vrele(vp);
   3653          1.217     perry 
   3654          1.214   thorpej 	return (error);
   3655          1.214   thorpej }
   3656          1.214   thorpej 
   3657          1.214   thorpej /*
   3658          1.214   thorpej  * Set a named extended attribute on a file or directory.
   3659          1.214   thorpej  */
   3660          1.214   thorpej static int
   3661          1.214   thorpej extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
   3662          1.214   thorpej     const void *data, size_t nbytes, struct proc *p, register_t *retval)
   3663          1.214   thorpej {
   3664          1.214   thorpej 	struct mount *mp;
   3665          1.214   thorpej 	struct uio auio;
   3666          1.214   thorpej 	struct iovec aiov;
   3667          1.214   thorpej 	ssize_t cnt;
   3668          1.214   thorpej 	int error;
   3669          1.214   thorpej 
   3670          1.214   thorpej 	error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH);
   3671          1.214   thorpej 	if (error)
   3672          1.214   thorpej 		return (error);
   3673          1.214   thorpej 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
   3674          1.214   thorpej 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
   3675          1.214   thorpej 
   3676          1.214   thorpej 	aiov.iov_base = (caddr_t) data;		/* XXX kills const */
   3677          1.214   thorpej 	aiov.iov_len = nbytes;
   3678          1.214   thorpej 	auio.uio_iov = &aiov;
   3679          1.214   thorpej 	auio.uio_iovcnt = 1;
   3680          1.214   thorpej 	auio.uio_offset = 0;
   3681          1.214   thorpej 	if (nbytes > INT_MAX) {
   3682          1.214   thorpej 		error = EINVAL;
   3683          1.214   thorpej 		goto done;
   3684          1.214   thorpej 	}
   3685          1.214   thorpej 	auio.uio_resid = nbytes;
   3686          1.214   thorpej 	auio.uio_rw = UIO_WRITE;
   3687          1.214   thorpej 	auio.uio_segflg = UIO_USERSPACE;
   3688          1.214   thorpej 	auio.uio_procp = p;
   3689          1.214   thorpej 	cnt = nbytes;
   3690          1.214   thorpej 
   3691          1.214   thorpej 	error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
   3692          1.214   thorpej 	    p->p_ucred, p);
   3693          1.214   thorpej 	cnt -= auio.uio_resid;
   3694          1.214   thorpej 	retval[0] = cnt;
   3695          1.214   thorpej 
   3696          1.214   thorpej  done:
   3697          1.214   thorpej 	VOP_UNLOCK(vp, 0);
   3698          1.214   thorpej 	vn_finished_write(mp, 0);
   3699          1.214   thorpej 	return (error);
   3700          1.214   thorpej }
   3701          1.214   thorpej 
   3702          1.214   thorpej int
   3703          1.214   thorpej sys_extattr_set_fd(struct lwp *l, void *v, register_t *retval)
   3704          1.214   thorpej {
   3705          1.214   thorpej 	struct sys_extattr_set_fd_args /* {
   3706          1.214   thorpej 		syscallarg(int) fd;
   3707          1.214   thorpej 		syscallarg(int) attrnamespace;
   3708          1.214   thorpej 		syscallarg(const char *) attrname;
   3709          1.214   thorpej 		syscallarg(const void *) data;
   3710          1.214   thorpej 		syscallarg(size_t) nbytes;
   3711          1.214   thorpej 	} */ *uap = v;
   3712          1.214   thorpej 	struct proc *p = l->l_proc;
   3713          1.214   thorpej 	struct file *fp;
   3714          1.214   thorpej 	struct vnode *vp;
   3715          1.214   thorpej 	char attrname[EXTATTR_MAXNAMELEN];
   3716          1.214   thorpej 	int error;
   3717          1.214   thorpej 
   3718          1.214   thorpej 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
   3719          1.214   thorpej 	    NULL);
   3720          1.214   thorpej 	if (error)
   3721          1.214   thorpej 		return (error);
   3722          1.217     perry 
   3723          1.214   thorpej 	error = getvnode(p->p_fd, SCARG(uap, fd), &fp);
   3724          1.214   thorpej 	if (error)
   3725          1.214   thorpej 		return (error);
   3726          1.214   thorpej 	vp = (struct vnode *) fp->f_data;
   3727          1.214   thorpej 
   3728          1.214   thorpej 	error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname,
   3729          1.214   thorpej 	    SCARG(uap, data), SCARG(uap, nbytes), p, retval);
   3730          1.214   thorpej 
   3731          1.214   thorpej 	FILE_UNUSE(fp, p);
   3732          1.214   thorpej 	return (error);
   3733          1.214   thorpej }
   3734          1.214   thorpej 
   3735          1.214   thorpej int
   3736          1.214   thorpej sys_extattr_set_file(struct lwp *l, void *v, register_t *retval)
   3737          1.214   thorpej {
   3738          1.214   thorpej 	struct sys_extattr_set_file_args /* {
   3739          1.214   thorpej 		syscallarg(const char *) path;
   3740          1.214   thorpej 		syscallarg(int) attrnamespace;
   3741          1.214   thorpej 		syscallarg(const char *) attrname;
   3742          1.214   thorpej 		syscallarg(const void *) data;
   3743          1.214   thorpej 		syscallarg(size_t) nbytes;
   3744          1.214   thorpej 	} */ *uap = v;
   3745          1.214   thorpej 	struct proc *p = l->l_proc;
   3746          1.214   thorpej 	struct nameidata nd;
   3747          1.214   thorpej 	char attrname[EXTATTR_MAXNAMELEN];
   3748          1.214   thorpej 	int error;
   3749          1.214   thorpej 
   3750          1.214   thorpej 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
   3751          1.214   thorpej 	    NULL);
   3752          1.214   thorpej 	if (error)
   3753          1.214   thorpej 		return (error);
   3754          1.217     perry 
   3755          1.214   thorpej 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   3756          1.214   thorpej 	error = namei(&nd);
   3757          1.214   thorpej 	if (error)
   3758          1.214   thorpej 		return (error);
   3759          1.217     perry 
   3760          1.214   thorpej 	error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
   3761          1.214   thorpej 	    SCARG(uap, data), SCARG(uap, nbytes), p, retval);
   3762          1.214   thorpej 
   3763          1.214   thorpej 	vrele(nd.ni_vp);
   3764          1.214   thorpej 	return (error);
   3765          1.214   thorpej }
   3766          1.214   thorpej 
   3767          1.214   thorpej int
   3768          1.214   thorpej sys_extattr_set_link(struct lwp *l, void *v, register_t *retval)
   3769          1.214   thorpej {
   3770          1.214   thorpej 	struct sys_extattr_set_link_args /* {
   3771          1.214   thorpej 		syscallarg(const char *) path;
   3772          1.214   thorpej 		syscallarg(int) attrnamespace;
   3773          1.214   thorpej 		syscallarg(const char *) attrname;
   3774          1.214   thorpej 		syscallarg(const void *) data;
   3775          1.214   thorpej 		syscallarg(size_t) nbytes;
   3776          1.214   thorpej 	} */ *uap = v;
   3777          1.214   thorpej 	struct proc *p = l->l_proc;
   3778          1.214   thorpej 	struct nameidata nd;
   3779          1.214   thorpej 	char attrname[EXTATTR_MAXNAMELEN];
   3780          1.214   thorpej 	int error;
   3781          1.214   thorpej 
   3782          1.214   thorpej 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
   3783          1.214   thorpej 	    NULL);
   3784          1.214   thorpej 	if (error)
   3785          1.214   thorpej 		return (error);
   3786          1.217     perry 
   3787          1.214   thorpej 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   3788          1.214   thorpej 	error = namei(&nd);
   3789          1.214   thorpej 	if (error)
   3790          1.214   thorpej 		return (error);
   3791          1.217     perry 
   3792          1.214   thorpej 	error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
   3793          1.214   thorpej 	    SCARG(uap, data), SCARG(uap, nbytes), p, retval);
   3794          1.214   thorpej 
   3795          1.214   thorpej 	vrele(nd.ni_vp);
   3796          1.214   thorpej 	return (error);
   3797          1.214   thorpej }
   3798          1.214   thorpej 
   3799          1.214   thorpej /*
   3800          1.214   thorpej  * Get a named extended attribute on a file or directory.
   3801          1.214   thorpej  */
   3802          1.214   thorpej static int
   3803          1.214   thorpej extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
   3804          1.214   thorpej     void *data, size_t nbytes, struct proc *p, register_t *retval)
   3805          1.214   thorpej {
   3806          1.214   thorpej 	struct uio auio, *auiop;
   3807          1.214   thorpej 	struct iovec aiov;
   3808          1.214   thorpej 	ssize_t cnt;
   3809          1.214   thorpej 	size_t size, *sizep;
   3810          1.214   thorpej 	int error;
   3811          1.214   thorpej 
   3812          1.214   thorpej 	VOP_LEASE(vp, p, p->p_ucred, LEASE_READ);
   3813          1.214   thorpej 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
   3814          1.214   thorpej 
   3815          1.214   thorpej 	/*
   3816          1.214   thorpej 	 * Slightly unusual semantics: if the user provides a NULL data
   3817          1.214   thorpej 	 * pointer, they don't want to receive the data, just the maximum
   3818          1.214   thorpej 	 * read length.
   3819          1.214   thorpej 	 */
   3820          1.214   thorpej 	auiop = NULL;
   3821          1.214   thorpej 	sizep = NULL;
   3822          1.214   thorpej 	cnt = 0;
   3823          1.214   thorpej 	if (data != NULL) {
   3824          1.214   thorpej 		aiov.iov_base = data;
   3825          1.214   thorpej 		aiov.iov_len = nbytes;
   3826          1.214   thorpej 		auio.uio_iov = &aiov;
   3827          1.214   thorpej 		auio.uio_offset = 0;
   3828          1.214   thorpej 		if (nbytes > INT_MAX) {
   3829          1.214   thorpej 			error = EINVAL;
   3830          1.214   thorpej 			goto done;
   3831          1.214   thorpej 		}
   3832          1.214   thorpej 		auio.uio_resid = nbytes;
   3833          1.214   thorpej 		auio.uio_rw = UIO_READ;
   3834          1.214   thorpej 		auio.uio_segflg = UIO_USERSPACE;
   3835          1.214   thorpej 		auio.uio_procp = p;
   3836          1.214   thorpej 		auiop = &auio;
   3837          1.214   thorpej 		cnt = nbytes;
   3838          1.214   thorpej 	} else
   3839          1.214   thorpej 		sizep = &size;
   3840          1.217     perry 
   3841          1.214   thorpej 	error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep,
   3842          1.214   thorpej 	    p->p_ucred, p);
   3843          1.217     perry 
   3844          1.214   thorpej 	if (auiop != NULL) {
   3845          1.214   thorpej 		cnt -= auio.uio_resid;
   3846          1.214   thorpej 		retval[0] = cnt;
   3847          1.214   thorpej 	} else
   3848          1.214   thorpej 		retval[0] = size;
   3849          1.214   thorpej 
   3850          1.214   thorpej  done:
   3851          1.214   thorpej 	VOP_UNLOCK(vp, 0);
   3852          1.214   thorpej 	return (error);
   3853          1.214   thorpej }
   3854          1.214   thorpej 
   3855          1.214   thorpej int
   3856          1.214   thorpej sys_extattr_get_fd(struct lwp *l, void *v, register_t *retval)
   3857          1.214   thorpej {
   3858          1.214   thorpej 	struct sys_extattr_get_fd_args /* {
   3859          1.214   thorpej 		syscallarg(int) fd;
   3860          1.214   thorpej 		syscallarg(int) attrnamespace;
   3861          1.214   thorpej 		syscallarg(const char *) attrname;
   3862          1.214   thorpej 		syscallarg(void *) data;
   3863          1.214   thorpej 		syscallarg(size_t) nbytes;
   3864          1.214   thorpej 	} */ *uap = v;
   3865          1.214   thorpej 	struct proc *p = l->l_proc;
   3866          1.214   thorpej 	struct file *fp;
   3867          1.214   thorpej 	struct vnode *vp;
   3868          1.214   thorpej 	char attrname[EXTATTR_MAXNAMELEN];
   3869          1.214   thorpej 	int error;
   3870          1.214   thorpej 
   3871          1.214   thorpej 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
   3872          1.214   thorpej 	    NULL);
   3873          1.214   thorpej 	if (error)
   3874          1.214   thorpej 		return (error);
   3875          1.217     perry 
   3876          1.214   thorpej 	error = getvnode(p->p_fd, SCARG(uap, fd), &fp);
   3877          1.214   thorpej 	if (error)
   3878          1.214   thorpej 		return (error);
   3879          1.214   thorpej 	vp = (struct vnode *) fp->f_data;
   3880          1.214   thorpej 
   3881          1.214   thorpej 	error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname,
   3882          1.214   thorpej 	    SCARG(uap, data), SCARG(uap, nbytes), p, retval);
   3883          1.214   thorpej 
   3884          1.214   thorpej 	FILE_UNUSE(fp, p);
   3885          1.214   thorpej 	return (error);
   3886          1.214   thorpej }
   3887          1.214   thorpej 
   3888          1.214   thorpej int
   3889          1.214   thorpej sys_extattr_get_file(struct lwp *l, void *v, register_t *retval)
   3890          1.214   thorpej {
   3891          1.214   thorpej 	struct sys_extattr_get_file_args /* {
   3892          1.214   thorpej 		syscallarg(const char *) path;
   3893          1.214   thorpej 		syscallarg(int) attrnamespace;
   3894          1.214   thorpej 		syscallarg(const char *) attrname;
   3895          1.214   thorpej 		syscallarg(void *) data;
   3896          1.214   thorpej 		syscallarg(size_t) nbytes;
   3897          1.214   thorpej 	} */ *uap = v;
   3898          1.214   thorpej 	struct proc *p = l->l_proc;
   3899          1.214   thorpej 	struct nameidata nd;
   3900          1.214   thorpej 	char attrname[EXTATTR_MAXNAMELEN];
   3901          1.214   thorpej 	int error;
   3902          1.214   thorpej 
   3903          1.214   thorpej 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
   3904          1.214   thorpej 	    NULL);
   3905          1.214   thorpej 	if (error)
   3906          1.214   thorpej 		return (error);
   3907          1.217     perry 
   3908          1.214   thorpej 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   3909          1.214   thorpej 	error = namei(&nd);
   3910          1.214   thorpej 	if (error)
   3911          1.214   thorpej 		return (error);
   3912          1.217     perry 
   3913          1.214   thorpej 	error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
   3914          1.214   thorpej 	    SCARG(uap, data), SCARG(uap, nbytes), p, retval);
   3915          1.214   thorpej 
   3916          1.214   thorpej 	vrele(nd.ni_vp);
   3917          1.214   thorpej 	return (error);
   3918          1.214   thorpej }
   3919          1.214   thorpej 
   3920          1.214   thorpej int
   3921          1.214   thorpej sys_extattr_get_link(struct lwp *l, void *v, register_t *retval)
   3922          1.214   thorpej {
   3923          1.214   thorpej 	struct sys_extattr_get_link_args /* {
   3924          1.214   thorpej 		syscallarg(const char *) path;
   3925          1.214   thorpej 		syscallarg(int) attrnamespace;
   3926          1.214   thorpej 		syscallarg(const char *) attrname;
   3927          1.214   thorpej 		syscallarg(void *) data;
   3928          1.214   thorpej 		syscallarg(size_t) nbytes;
   3929          1.214   thorpej 	} */ *uap = v;
   3930          1.214   thorpej 	struct proc *p = l->l_proc;
   3931          1.214   thorpej 	struct nameidata nd;
   3932          1.214   thorpej 	char attrname[EXTATTR_MAXNAMELEN];
   3933          1.214   thorpej 	int error;
   3934          1.214   thorpej 
   3935          1.214   thorpej 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
   3936          1.214   thorpej 	    NULL);
   3937          1.214   thorpej 	if (error)
   3938          1.214   thorpej 		return (error);
   3939          1.217     perry 
   3940          1.214   thorpej 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   3941          1.214   thorpej 	error = namei(&nd);
   3942          1.214   thorpej 	if (error)
   3943          1.214   thorpej 		return (error);
   3944          1.217     perry 
   3945          1.214   thorpej 	error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
   3946          1.214   thorpej 	    SCARG(uap, data), SCARG(uap, nbytes), p, retval);
   3947          1.214   thorpej 
   3948          1.214   thorpej 	vrele(nd.ni_vp);
   3949          1.214   thorpej 	return (error);
   3950          1.214   thorpej }
   3951          1.214   thorpej 
   3952          1.214   thorpej /*
   3953          1.214   thorpej  * Delete a named extended attribute on a file or directory.
   3954          1.214   thorpej  */
   3955          1.214   thorpej static int
   3956          1.214   thorpej extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
   3957          1.214   thorpej     struct proc *p)
   3958          1.214   thorpej {
   3959          1.214   thorpej 	struct mount *mp;
   3960          1.214   thorpej 	int error;
   3961          1.214   thorpej 
   3962          1.214   thorpej 	error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH);
   3963          1.214   thorpej 	if (error)
   3964          1.214   thorpej 		return (error);
   3965          1.214   thorpej 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
   3966          1.214   thorpej 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
   3967          1.214   thorpej 
   3968          1.214   thorpej 	error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, p->p_ucred, p);
   3969          1.214   thorpej 	if (error == EOPNOTSUPP)
   3970          1.214   thorpej 		error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
   3971          1.214   thorpej 		    p->p_ucred, p);
   3972          1.217     perry 
   3973          1.214   thorpej 	VOP_UNLOCK(vp, 0);
   3974          1.214   thorpej 	vn_finished_write(mp, 0);
   3975          1.214   thorpej 	return (error);
   3976          1.214   thorpej }
   3977          1.214   thorpej 
   3978          1.214   thorpej int
   3979          1.214   thorpej sys_extattr_delete_fd(struct lwp *l, void *v, register_t *retval)
   3980          1.214   thorpej {
   3981          1.214   thorpej 	struct sys_extattr_delete_fd_args /* {
   3982          1.214   thorpej 		syscallarg(int) fd;
   3983          1.214   thorpej 		syscallarg(int) attrnamespace;
   3984          1.214   thorpej 		syscallarg(const char *) attrname;
   3985          1.214   thorpej 	} */ *uap = v;
   3986          1.214   thorpej 	struct proc *p = l->l_proc;
   3987          1.214   thorpej 	struct file *fp;
   3988          1.214   thorpej 	struct vnode *vp;
   3989          1.214   thorpej 	char attrname[EXTATTR_MAXNAMELEN];
   3990          1.214   thorpej 	int error;
   3991          1.214   thorpej 
   3992          1.214   thorpej 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
   3993          1.214   thorpej 	    NULL);
   3994          1.214   thorpej 	if (error)
   3995          1.214   thorpej 		return (error);
   3996          1.217     perry 
   3997          1.214   thorpej 	error = getvnode(p->p_fd, SCARG(uap, fd), &fp);
   3998          1.214   thorpej 	if (error)
   3999          1.214   thorpej 		return (error);
   4000          1.214   thorpej 	vp = (struct vnode *) fp->f_data;
   4001          1.214   thorpej 
   4002          1.214   thorpej 	error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, p);
   4003          1.214   thorpej 
   4004          1.214   thorpej 	FILE_UNUSE(fp, p);
   4005          1.214   thorpej 	return (error);
   4006          1.214   thorpej }
   4007          1.214   thorpej 
   4008          1.214   thorpej int
   4009          1.214   thorpej sys_extattr_delete_file(struct lwp *l, void *v, register_t *retval)
   4010          1.214   thorpej {
   4011          1.214   thorpej 	struct sys_extattr_delete_file_args /* {
   4012          1.214   thorpej 		syscallarg(const char *) path;
   4013          1.214   thorpej 		syscallarg(int) attrnamespace;
   4014          1.214   thorpej 		syscallarg(const char *) attrname;
   4015          1.214   thorpej 	} */ *uap = v;
   4016          1.214   thorpej 	struct proc *p = l->l_proc;
   4017          1.214   thorpej 	struct nameidata nd;
   4018          1.214   thorpej 	char attrname[EXTATTR_MAXNAMELEN];
   4019          1.214   thorpej 	int error;
   4020          1.214   thorpej 
   4021          1.214   thorpej 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
   4022          1.214   thorpej 	    NULL);
   4023          1.214   thorpej 	if (error)
   4024          1.214   thorpej 		return (error);
   4025          1.217     perry 
   4026          1.214   thorpej 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   4027          1.214   thorpej 	error = namei(&nd);
   4028          1.214   thorpej 	if (error)
   4029          1.214   thorpej 		return (error);
   4030          1.217     perry 
   4031          1.214   thorpej 	error = extattr_delete_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
   4032          1.214   thorpej 	    p);
   4033          1.214   thorpej 
   4034          1.214   thorpej 	vrele(nd.ni_vp);
   4035          1.214   thorpej 	return (error);
   4036          1.214   thorpej }
   4037          1.214   thorpej 
   4038          1.214   thorpej int
   4039          1.214   thorpej sys_extattr_delete_link(struct lwp *l, void *v, register_t *retval)
   4040          1.214   thorpej {
   4041          1.214   thorpej 	struct sys_extattr_delete_link_args /* {
   4042          1.214   thorpej 		syscallarg(const char *) path;
   4043          1.214   thorpej 		syscallarg(int) attrnamespace;
   4044          1.214   thorpej 		syscallarg(const char *) attrname;
   4045          1.214   thorpej 	} */ *uap = v;
   4046          1.214   thorpej 	struct proc *p = l->l_proc;
   4047          1.214   thorpej 	struct nameidata nd;
   4048          1.214   thorpej 	char attrname[EXTATTR_MAXNAMELEN];
   4049          1.214   thorpej 	int error;
   4050          1.214   thorpej 
   4051          1.214   thorpej 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
   4052          1.214   thorpej 	    NULL);
   4053          1.214   thorpej 	if (error)
   4054          1.214   thorpej 		return (error);
   4055          1.217     perry 
   4056          1.214   thorpej 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   4057          1.214   thorpej 	error = namei(&nd);
   4058          1.214   thorpej 	if (error)
   4059          1.214   thorpej 		return (error);
   4060          1.217     perry 
   4061          1.214   thorpej 	error = extattr_delete_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
   4062          1.214   thorpej 	    p);
   4063          1.214   thorpej 
   4064          1.214   thorpej 	vrele(nd.ni_vp);
   4065          1.214   thorpej 	return (error);
   4066          1.214   thorpej }
   4067          1.214   thorpej 
   4068          1.214   thorpej /*
   4069          1.214   thorpej  * Retrieve a list of extended attributes on a file or directory.
   4070          1.214   thorpej  */
   4071          1.214   thorpej static int
   4072          1.214   thorpej extattr_list_vp(struct vnode *vp, int attrnamespace, void *data, size_t nbytes,
   4073          1.214   thorpej     struct proc *p, register_t *retval)
   4074          1.214   thorpej {
   4075          1.214   thorpej 	struct uio auio, *auiop;
   4076          1.214   thorpej 	size_t size, *sizep;
   4077          1.214   thorpej 	struct iovec aiov;
   4078          1.214   thorpej 	ssize_t cnt;
   4079          1.214   thorpej 	int error;
   4080          1.214   thorpej 
   4081          1.214   thorpej 	VOP_LEASE(vp, p, p->p_ucred, LEASE_READ);
   4082          1.214   thorpej 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
   4083          1.214   thorpej 
   4084          1.214   thorpej 	auiop = NULL;
   4085          1.214   thorpej 	sizep = NULL;
   4086          1.214   thorpej 	cnt = 0;
   4087          1.214   thorpej 	if (data != NULL) {
   4088          1.214   thorpej 		aiov.iov_base = data;
   4089          1.214   thorpej 		aiov.iov_len = nbytes;
   4090          1.214   thorpej 		auio.uio_iov = &aiov;
   4091          1.214   thorpej 		auio.uio_offset = 0;
   4092          1.214   thorpej 		if (nbytes > INT_MAX) {
   4093          1.214   thorpej 			error = EINVAL;
   4094          1.214   thorpej 			goto done;
   4095          1.214   thorpej 		}
   4096          1.214   thorpej 		auio.uio_resid = nbytes;
   4097          1.214   thorpej 		auio.uio_rw = UIO_READ;
   4098          1.214   thorpej 		auio.uio_segflg = UIO_USERSPACE;
   4099          1.214   thorpej 		auio.uio_procp = p;
   4100          1.214   thorpej 		auiop = &auio;
   4101          1.214   thorpej 		cnt = nbytes;
   4102          1.214   thorpej 	} else
   4103          1.214   thorpej 		sizep = &size;
   4104          1.217     perry 
   4105          1.214   thorpej 	error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep,
   4106          1.214   thorpej 	    p->p_ucred, p);
   4107          1.217     perry 
   4108          1.214   thorpej 	if (auiop != NULL) {
   4109          1.214   thorpej 		cnt -= auio.uio_resid;
   4110          1.214   thorpej 		retval[0] = cnt;
   4111          1.214   thorpej 	} else
   4112          1.214   thorpej 		retval[0] = size;
   4113          1.217     perry 
   4114          1.214   thorpej  done:
   4115          1.214   thorpej 	VOP_UNLOCK(vp, 0);
   4116          1.214   thorpej 	return (error);
   4117          1.214   thorpej }
   4118          1.214   thorpej 
   4119          1.214   thorpej int
   4120          1.214   thorpej sys_extattr_list_fd(struct lwp *l, void *v, register_t *retval)
   4121          1.214   thorpej {
   4122          1.214   thorpej 	struct sys_extattr_list_fd_args /* {
   4123          1.214   thorpej 		syscallarg(int) fd;
   4124          1.214   thorpej 		syscallarg(int) attrnamespace;
   4125          1.214   thorpej 		syscallarg(void *) data;
   4126          1.214   thorpej 		syscallarg(size_t) nbytes;
   4127          1.214   thorpej 	} */ *uap = v;
   4128          1.214   thorpej 	struct proc *p = l->l_proc;
   4129          1.214   thorpej 	struct file *fp;
   4130          1.214   thorpej 	struct vnode *vp;
   4131          1.214   thorpej 	int error;
   4132          1.214   thorpej 
   4133          1.214   thorpej 	error = getvnode(p->p_fd, SCARG(uap, fd), &fp);
   4134          1.214   thorpej 	if (error)
   4135          1.214   thorpej 		return (error);
   4136          1.214   thorpej 	vp = (struct vnode *) fp->f_data;
   4137          1.214   thorpej 
   4138          1.214   thorpej 	error = extattr_list_vp(vp, SCARG(uap, attrnamespace),
   4139          1.214   thorpej 	    SCARG(uap, data), SCARG(uap, nbytes), p, retval);
   4140          1.214   thorpej 
   4141          1.214   thorpej 	FILE_UNUSE(fp, p);
   4142          1.214   thorpej 	return (error);
   4143          1.214   thorpej }
   4144          1.214   thorpej 
   4145          1.214   thorpej int
   4146          1.214   thorpej sys_extattr_list_file(struct lwp *l, void *v, register_t *retval)
   4147          1.214   thorpej {
   4148          1.214   thorpej 	struct sys_extattr_list_file_args /* {
   4149          1.214   thorpej 		syscallarg(const char *) path;
   4150          1.214   thorpej 		syscallarg(int) attrnamespace;
   4151          1.214   thorpej 		syscallarg(void *) data;
   4152          1.214   thorpej 		syscallarg(size_t) nbytes;
   4153          1.214   thorpej 	} */ *uap = v;
   4154          1.214   thorpej 	struct proc *p = l->l_proc;
   4155          1.214   thorpej 	struct nameidata nd;
   4156          1.214   thorpej 	int error;
   4157          1.214   thorpej 
   4158          1.214   thorpej 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   4159          1.214   thorpej 	error = namei(&nd);
   4160          1.214   thorpej 	if (error)
   4161          1.214   thorpej 		return (error);
   4162          1.217     perry 
   4163          1.214   thorpej 	error = extattr_list_vp(nd.ni_vp, SCARG(uap, attrnamespace),
   4164          1.214   thorpej 	    SCARG(uap, data), SCARG(uap, nbytes), p, retval);
   4165          1.214   thorpej 
   4166          1.214   thorpej 	vrele(nd.ni_vp);
   4167          1.214   thorpej 	return (error);
   4168          1.214   thorpej }
   4169          1.214   thorpej 
   4170          1.214   thorpej int
   4171          1.214   thorpej sys_extattr_list_link(struct lwp *l, void *v, register_t *retval)
   4172          1.214   thorpej {
   4173          1.214   thorpej 	struct sys_extattr_list_link_args /* {
   4174          1.214   thorpej 		syscallarg(const char *) path;
   4175          1.214   thorpej 		syscallarg(int) attrnamespace;
   4176          1.214   thorpej 		syscallarg(void *) data;
   4177          1.214   thorpej 		syscallarg(size_t) nbytes;
   4178          1.214   thorpej 	} */ *uap = v;
   4179          1.214   thorpej 	struct proc *p = l->l_proc;
   4180          1.214   thorpej 	struct nameidata nd;
   4181          1.214   thorpej 	int error;
   4182          1.214   thorpej 
   4183          1.214   thorpej 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
   4184          1.214   thorpej 	error = namei(&nd);
   4185          1.214   thorpej 	if (error)
   4186          1.214   thorpej 		return (error);
   4187          1.214   thorpej 
   4188          1.214   thorpej 	error = extattr_list_vp(nd.ni_vp, SCARG(uap, attrnamespace),
   4189          1.214   thorpej 	    SCARG(uap, data), SCARG(uap, nbytes), p, retval);
   4190          1.214   thorpej 
   4191          1.214   thorpej 	vrele(nd.ni_vp);
   4192          1.214   thorpej 	return (error);
   4193          1.214   thorpej }
   4194