xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 69409)
123405Smckusick /*
263428Sbostic  * Copyright (c) 1989, 1993
363428Sbostic  *	The Regents of the University of California.  All rights reserved.
465771Sbostic  * (c) UNIX System Laboratories, Inc.
565771Sbostic  * All or some portions of this file are derived from material licensed
665771Sbostic  * to the University of California by American Telephone and Telegraph
765771Sbostic  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
865771Sbostic  * the permission of UNIX System Laboratories, Inc.
923405Smckusick  *
1044459Sbostic  * %sccs.include.redist.c%
1137741Smckusick  *
12*69409Smckusick  *	@(#)vfs_syscalls.c	8.37 (Berkeley) 05/14/95
1323405Smckusick  */
1437Sbill 
1556517Sbostic #include <sys/param.h>
1656517Sbostic #include <sys/systm.h>
1756517Sbostic #include <sys/namei.h>
1856517Sbostic #include <sys/filedesc.h>
1956517Sbostic #include <sys/kernel.h>
2056517Sbostic #include <sys/file.h>
2156517Sbostic #include <sys/stat.h>
2256517Sbostic #include <sys/vnode.h>
2356517Sbostic #include <sys/mount.h>
2456517Sbostic #include <sys/proc.h>
2556517Sbostic #include <sys/uio.h>
2656517Sbostic #include <sys/malloc.h>
2756517Sbostic #include <sys/dirent.h>
2856517Sbostic 
2968318Scgd #include <sys/syscallargs.h>
3068318Scgd 
3153468Smckusick #include <vm/vm.h>
3259875Smckusick #include <sys/sysctl.h>
3337Sbill 
3464410Sbostic static int change_dir __P((struct nameidata *ndp, struct proc *p));
3568318Scgd static void checkdirs __P((struct vnode *olddp));
3664410Sbostic 
3737741Smckusick /*
3837741Smckusick  * Virtual File System System Calls
3937741Smckusick  */
4012756Ssam 
419167Ssam /*
4264410Sbostic  * Mount a file system.
439167Ssam  */
4442441Smckusick /* ARGSUSED */
4568318Scgd int
4642441Smckusick mount(p, uap, retval)
4745914Smckusick 	struct proc *p;
4868318Scgd 	register struct mount_args /* {
4968663Smckusick 		syscallarg(char *) type;
5068318Scgd 		syscallarg(char *) path;
5168318Scgd 		syscallarg(int) flags;
5268318Scgd 		syscallarg(caddr_t) data;
5368318Scgd 	} */ *uap;
5468318Scgd 	register_t *retval;
5542441Smckusick {
5668663Smckusick 	struct vnode *vp;
5768663Smckusick 	struct mount *mp;
5868663Smckusick 	struct vfsconf *vfsp;
5940111Smckusick 	int error, flag;
6067532Smckusick 	struct vattr va;
6168663Smckusick 	u_long fstypenum;
6247540Skarels 	struct nameidata nd;
6368663Smckusick 	char fstypename[MFSNAMELEN];
646254Sroot 
6537741Smckusick 	/*
6637741Smckusick 	 * Get vnode to be covered
6737741Smckusick 	 */
6868318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
6968318Scgd 	    SCARG(uap, path), p);
7052322Smckusick 	if (error = namei(&nd))
7147540Skarels 		return (error);
7252322Smckusick 	vp = nd.ni_vp;
7368318Scgd 	if (SCARG(uap, flags) & MNT_UPDATE) {
7439335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
7539335Smckusick 			vput(vp);
7647540Skarels 			return (EINVAL);
7739335Smckusick 		}
7839335Smckusick 		mp = vp->v_mount;
7957047Smckusick 		flag = mp->mnt_flag;
8039335Smckusick 		/*
8157047Smckusick 		 * We only allow the filesystem to be reloaded if it
8257047Smckusick 		 * is currently mounted read-only.
8339335Smckusick 		 */
8468318Scgd 		if ((SCARG(uap, flags) & MNT_RELOAD) &&
8557047Smckusick 		    ((mp->mnt_flag & MNT_RDONLY) == 0)) {
8639335Smckusick 			vput(vp);
8747540Skarels 			return (EOPNOTSUPP);	/* Needs translation */
8839335Smckusick 		}
8957047Smckusick 		mp->mnt_flag |=
9068318Scgd 		    SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
9167532Smckusick 		/*
9267532Smckusick 		 * Only root, or the user that did the original mount is
9367532Smckusick 		 * permitted to update it.
9467532Smckusick 		 */
9567532Smckusick 		if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid &&
9667532Smckusick 		    (error = suser(p->p_ucred, &p->p_acflag))) {
9767532Smckusick 			vput(vp);
9867532Smckusick 			return (error);
9967532Smckusick 		}
10067532Smckusick 		/*
10167532Smckusick 		 * Do not allow NFS export by non-root users. Silently
10267532Smckusick 		 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
10367532Smckusick 		 */
10467532Smckusick 		if (p->p_ucred->cr_uid != 0) {
10568318Scgd 			if (SCARG(uap, flags) & MNT_EXPORTED) {
10667532Smckusick 				vput(vp);
10767532Smckusick 				return (EPERM);
10867532Smckusick 			}
10968318Scgd 			SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
11067532Smckusick 		}
111*69409Smckusick 		VOP_UNLOCK(vp, 0, p);
11239335Smckusick 		goto update;
11339335Smckusick 	}
11467532Smckusick 	/*
11567532Smckusick 	 * If the user is not root, ensure that they own the directory
11667532Smckusick 	 * onto which we are attempting to mount.
11767532Smckusick 	 */
11867532Smckusick 	if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) ||
11967532Smckusick 	    (va.va_uid != p->p_ucred->cr_uid &&
12067532Smckusick 	     (error = suser(p->p_ucred, &p->p_acflag)))) {
12167532Smckusick 		vput(vp);
12267532Smckusick 		return (error);
12367532Smckusick 	}
12467532Smckusick 	/*
12567532Smckusick 	 * Do not allow NFS export by non-root users. Silently
12667532Smckusick 	 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
12767532Smckusick 	 */
12867532Smckusick 	if (p->p_ucred->cr_uid != 0) {
12968318Scgd 		if (SCARG(uap, flags) & MNT_EXPORTED) {
13067532Smckusick 			vput(vp);
13167532Smckusick 			return (EPERM);
13267532Smckusick 		}
13368318Scgd 		SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
13467532Smckusick 	}
13557793Smckusick 	if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0))
13654441Smckusick 		return (error);
13737741Smckusick 	if (vp->v_type != VDIR) {
13837741Smckusick 		vput(vp);
13947540Skarels 		return (ENOTDIR);
14037741Smckusick 	}
14168663Smckusick #ifdef COMPAT_43
14268663Smckusick 	/*
14368663Smckusick 	 * Historically filesystem types were identified by number. If we
14468663Smckusick 	 * get an integer for the filesystem type instead of a string, we
14568663Smckusick 	 * check to see if it matches one of the historic filesystem types.
14668663Smckusick 	 */
14768663Smckusick 	fstypenum = (u_long)SCARG(uap, type);
14868663Smckusick 	if (fstypenum < maxvfsconf) {
14968663Smckusick 		for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
15068663Smckusick 			if (vfsp->vfc_typenum == fstypenum)
15168663Smckusick 				break;
15268663Smckusick 		if (vfsp == NULL) {
15368663Smckusick 			vput(vp);
15468663Smckusick 			return (ENODEV);
15568663Smckusick 		}
15668663Smckusick 		strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN);
15768663Smckusick 	} else
15868663Smckusick #endif /* COMPAT_43 */
15968663Smckusick 	if (error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL)) {
16037741Smckusick 		vput(vp);
16168663Smckusick 		return (error);
16268663Smckusick 	}
16368663Smckusick 	for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
16468663Smckusick 		if (!strcmp(vfsp->vfc_name, fstypename))
16568663Smckusick 			break;
16668663Smckusick 	if (vfsp == NULL) {
16768663Smckusick 		vput(vp);
16847540Skarels 		return (ENODEV);
16937741Smckusick 	}
17067969Spendry 	if (vp->v_mountedhere != NULL) {
17167961Smckusick 		vput(vp);
17267961Smckusick 		return (EBUSY);
17367961Smckusick 	}
17437741Smckusick 
17537741Smckusick 	/*
17668663Smckusick 	 * Allocate and initialize the filesystem.
17737741Smckusick 	 */
17837741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
17937741Smckusick 		M_MOUNT, M_WAITOK);
18054172Smckusick 	bzero((char *)mp, (u_long)sizeof(struct mount));
18168663Smckusick 	mp->mnt_op = vfsp->vfc_vfsops;
18239335Smckusick 	if (error = vfs_lock(mp)) {
18339335Smckusick 		free((caddr_t)mp, M_MOUNT);
18439335Smckusick 		vput(vp);
18547540Skarels 		return (error);
18639335Smckusick 	}
18768663Smckusick 	mp->mnt_vfc = vfsp;
18868663Smckusick 	vfsp->vfc_refcount++;
18968663Smckusick 	mp->mnt_stat.f_type = vfsp->vfc_typenum;
19068663Smckusick 	mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
19168663Smckusick 	strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
19239335Smckusick 	vp->v_mountedhere = mp;
19341400Smckusick 	mp->mnt_vnodecovered = vp;
19467532Smckusick 	mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
19539335Smckusick update:
19639335Smckusick 	/*
19739335Smckusick 	 * Set the mount level flags.
19839335Smckusick 	 */
19968318Scgd 	if (SCARG(uap, flags) & MNT_RDONLY)
20041400Smckusick 		mp->mnt_flag |= MNT_RDONLY;
20157047Smckusick 	else if (mp->mnt_flag & MNT_RDONLY)
20257047Smckusick 		mp->mnt_flag |= MNT_WANTRDWR;
20365613Smckusick 	mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
20465613Smckusick 	    MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);
20568318Scgd 	mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC |
20668318Scgd 	    MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);
20739335Smckusick 	/*
20839335Smckusick 	 * Mount the filesystem.
20939335Smckusick 	 */
21068318Scgd 	error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p);
21141400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
21239335Smckusick 		vrele(vp);
21357047Smckusick 		if (mp->mnt_flag & MNT_WANTRDWR)
21457047Smckusick 			mp->mnt_flag &= ~MNT_RDONLY;
21557047Smckusick 		mp->mnt_flag &=~
21657047Smckusick 		    (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
21740111Smckusick 		if (error)
21841400Smckusick 			mp->mnt_flag = flag;
21947540Skarels 		return (error);
22039335Smckusick 	}
22140110Smckusick 	/*
22240110Smckusick 	 * Put the new filesystem on the mount list after root.
22340110Smckusick 	 */
22437741Smckusick 	cache_purge(vp);
22537741Smckusick 	if (!error) {
22669325Smckusick 		CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
22767974Smckusick 		checkdirs(vp);
228*69409Smckusick 		VOP_UNLOCK(vp, 0, p);
22937741Smckusick 		vfs_unlock(mp);
23048026Smckusick 		error = VFS_START(mp, 0, p);
23137741Smckusick 	} else {
23265259Smckusick 		mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
23368663Smckusick 		mp->mnt_vfc->vfc_refcount--;
23465259Smckusick 		vfs_unlock(mp);
23537741Smckusick 		free((caddr_t)mp, M_MOUNT);
23639335Smckusick 		vput(vp);
23737741Smckusick 	}
23847540Skarels 	return (error);
2396254Sroot }
2406254Sroot 
2419167Ssam /*
24267974Smckusick  * Scan all active processes to see if any of them have a current
24367974Smckusick  * or root directory onto which the new filesystem has just been
24467974Smckusick  * mounted. If so, replace them with the new mount point.
24567974Smckusick  */
24668318Scgd static void
24767974Smckusick checkdirs(olddp)
24867974Smckusick 	struct vnode *olddp;
24967974Smckusick {
25067974Smckusick 	struct filedesc *fdp;
25167974Smckusick 	struct vnode *newdp;
25267974Smckusick 	struct proc *p;
25367974Smckusick 
25467974Smckusick 	if (olddp->v_usecount == 1)
25567974Smckusick 		return;
25667974Smckusick 	if (VFS_ROOT(olddp->v_mountedhere, &newdp))
25767974Smckusick 		panic("mount: lost mount");
25867974Smckusick 	for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
25967974Smckusick 		fdp = p->p_fd;
26067974Smckusick 		if (fdp->fd_cdir == olddp) {
26167974Smckusick 			vrele(fdp->fd_cdir);
26267974Smckusick 			VREF(newdp);
26367974Smckusick 			fdp->fd_cdir = newdp;
26467974Smckusick 		}
26567974Smckusick 		if (fdp->fd_rdir == olddp) {
26667974Smckusick 			vrele(fdp->fd_rdir);
26767974Smckusick 			VREF(newdp);
26867974Smckusick 			fdp->fd_rdir = newdp;
26967974Smckusick 		}
27067974Smckusick 	}
27167974Smckusick 	if (rootvnode == olddp) {
27267974Smckusick 		vrele(rootvnode);
27367974Smckusick 		VREF(newdp);
27467974Smckusick 		rootvnode = newdp;
27567974Smckusick 	}
27667974Smckusick 	vput(newdp);
27767974Smckusick }
27867974Smckusick 
27967974Smckusick /*
28064410Sbostic  * Unmount a file system.
28137741Smckusick  *
28237741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
28337741Smckusick  * not special file (as before).
2849167Ssam  */
28542441Smckusick /* ARGSUSED */
28668318Scgd int
28742441Smckusick unmount(p, uap, retval)
28845914Smckusick 	struct proc *p;
28968318Scgd 	register struct unmount_args /* {
29068318Scgd 		syscallarg(char *) path;
29168318Scgd 		syscallarg(int) flags;
29268318Scgd 	} */ *uap;
29368318Scgd 	register_t *retval;
29442441Smckusick {
29537741Smckusick 	register struct vnode *vp;
29639356Smckusick 	struct mount *mp;
29737741Smckusick 	int error;
29847540Skarels 	struct nameidata nd;
2996254Sroot 
30068318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
30168318Scgd 	    SCARG(uap, path), p);
30252322Smckusick 	if (error = namei(&nd))
30347540Skarels 		return (error);
30452322Smckusick 	vp = nd.ni_vp;
30567532Smckusick 	mp = vp->v_mount;
30666172Spendry 
30737741Smckusick 	/*
30867532Smckusick 	 * Only root, or the user that did the original mount is
30967532Smckusick 	 * permitted to unmount this filesystem.
31066172Spendry 	 */
31167532Smckusick 	if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) &&
31266172Spendry 	    (error = suser(p->p_ucred, &p->p_acflag))) {
31366172Spendry 		vput(vp);
31466172Spendry 		return (error);
31566172Spendry 	}
31666172Spendry 
31766172Spendry 	/*
31869334Smckusick 	 * Don't allow unmounting the root file system.
31969334Smckusick 	 */
32069334Smckusick 	if (mp->mnt_flag & MNT_ROOTFS) {
32169334Smckusick 		vput(vp);
32269334Smckusick 		return (EINVAL);
32369334Smckusick 	}
32469334Smckusick 
32569334Smckusick 	/*
32637741Smckusick 	 * Must be the root of the filesystem
32737741Smckusick 	 */
32837741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
32937741Smckusick 		vput(vp);
33047540Skarels 		return (EINVAL);
33137741Smckusick 	}
33237741Smckusick 	vput(vp);
33368318Scgd 	return (dounmount(mp, SCARG(uap, flags), p));
33439356Smckusick }
33539356Smckusick 
33639356Smckusick /*
33764410Sbostic  * Do the actual file system unmount.
33839356Smckusick  */
33968318Scgd int
34048026Smckusick dounmount(mp, flags, p)
34139356Smckusick 	register struct mount *mp;
34239356Smckusick 	int flags;
34348026Smckusick 	struct proc *p;
34439356Smckusick {
34539356Smckusick 	struct vnode *coveredvp;
34639356Smckusick 	int error;
34739356Smckusick 
34841400Smckusick 	coveredvp = mp->mnt_vnodecovered;
34941298Smckusick 	if (vfs_busy(mp))
35041298Smckusick 		return (EBUSY);
35141400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
35237741Smckusick 	if (error = vfs_lock(mp))
35339356Smckusick 		return (error);
35437741Smckusick 
35565859Smckusick 	mp->mnt_flag &=~ MNT_ASYNC;
35645738Smckusick 	vnode_pager_umount(mp);	/* release cached vnodes */
35737741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
35869357Spendry 	if (((mp->mnt_flag & MNT_RDONLY) ||
35969357Spendry 	     (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) ||
36054441Smckusick 	    (flags & MNT_FORCE))
36148026Smckusick 		error = VFS_UNMOUNT(mp, flags, p);
36241400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
36341298Smckusick 	vfs_unbusy(mp);
36437741Smckusick 	if (error) {
36537741Smckusick 		vfs_unlock(mp);
36637741Smckusick 	} else {
36769325Smckusick 		CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);
36869325Smckusick 		if (coveredvp != NULLVP) {
36969325Smckusick 			vrele(coveredvp);
37069325Smckusick 			mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
37169325Smckusick 		}
37268663Smckusick 		mp->mnt_vfc->vfc_refcount--;
37365259Smckusick 		vfs_unlock(mp);
37465259Smckusick 		if (mp->mnt_vnodelist.lh_first != NULL)
37552287Smckusick 			panic("unmount: dangling vnode");
37637741Smckusick 		free((caddr_t)mp, M_MOUNT);
37737741Smckusick 	}
37839356Smckusick 	return (error);
3796254Sroot }
3806254Sroot 
3819167Ssam /*
38237741Smckusick  * Sync each mounted filesystem.
3839167Ssam  */
38467403Smckusick #ifdef DEBUG
38556352Smckusick int syncprt = 0;
38659875Smckusick struct ctldebug debug0 = { "syncprt", &syncprt };
38756352Smckusick #endif
38856352Smckusick 
38939491Smckusick /* ARGSUSED */
39068318Scgd int
39142441Smckusick sync(p, uap, retval)
39245914Smckusick 	struct proc *p;
39368318Scgd 	void *uap;
39468318Scgd 	register_t *retval;
3956254Sroot {
39665259Smckusick 	register struct mount *mp, *nmp;
39765859Smckusick 	int asyncflag;
39837741Smckusick 
39969325Smckusick 	for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
40067678Smckusick 		/*
40167678Smckusick 		 * Get the next pointer in case we hang on vfs_busy
40267678Smckusick 		 * while we are being unmounted.
40367678Smckusick 		 */
40469325Smckusick 		nmp = mp->mnt_list.cqe_next;
40540343Smckusick 		/*
40640343Smckusick 		 * The lock check below is to avoid races with mount
40740343Smckusick 		 * and unmount.
40840343Smckusick 		 */
40941400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
41041298Smckusick 		    !vfs_busy(mp)) {
41165859Smckusick 			asyncflag = mp->mnt_flag & MNT_ASYNC;
41265859Smckusick 			mp->mnt_flag &= ~MNT_ASYNC;
41354441Smckusick 			VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
41465859Smckusick 			if (asyncflag)
41565859Smckusick 				mp->mnt_flag |= MNT_ASYNC;
41667678Smckusick 			/*
41767678Smckusick 			 * Get the next pointer again, as the next filesystem
41867678Smckusick 			 * might have been unmounted while we were sync'ing.
41967678Smckusick 			 */
42069325Smckusick 			nmp = mp->mnt_list.cqe_next;
42165259Smckusick 			vfs_unbusy(mp);
42265259Smckusick 		}
42365259Smckusick 	}
42456352Smckusick #ifdef DIAGNOSTIC
42556352Smckusick 	if (syncprt)
42656352Smckusick 		vfs_bufstats();
42756352Smckusick #endif /* DIAGNOSTIC */
42847688Skarels 	return (0);
42937741Smckusick }
43037741Smckusick 
43137741Smckusick /*
43264410Sbostic  * Change filesystem quotas.
43341298Smckusick  */
43442441Smckusick /* ARGSUSED */
43568318Scgd int
43642441Smckusick quotactl(p, uap, retval)
43745914Smckusick 	struct proc *p;
43868318Scgd 	register struct quotactl_args /* {
43968318Scgd 		syscallarg(char *) path;
44068318Scgd 		syscallarg(int) cmd;
44168318Scgd 		syscallarg(int) uid;
44268318Scgd 		syscallarg(caddr_t) arg;
44368318Scgd 	} */ *uap;
44468318Scgd 	register_t *retval;
44542441Smckusick {
44641298Smckusick 	register struct mount *mp;
44741298Smckusick 	int error;
44847540Skarels 	struct nameidata nd;
44941298Smckusick 
45068318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
45152322Smckusick 	if (error = namei(&nd))
45247540Skarels 		return (error);
45352322Smckusick 	mp = nd.ni_vp->v_mount;
45452322Smckusick 	vrele(nd.ni_vp);
45568318Scgd 	return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
45668318Scgd 	    SCARG(uap, arg), p));
45741298Smckusick }
45841298Smckusick 
45941298Smckusick /*
46049365Smckusick  * Get filesystem statistics.
46137741Smckusick  */
46242441Smckusick /* ARGSUSED */
46368318Scgd int
46442441Smckusick statfs(p, uap, retval)
46545914Smckusick 	struct proc *p;
46668318Scgd 	register struct statfs_args /* {
46768318Scgd 		syscallarg(char *) path;
46868318Scgd 		syscallarg(struct statfs *) buf;
46968318Scgd 	} */ *uap;
47068318Scgd 	register_t *retval;
47142441Smckusick {
47239464Smckusick 	register struct mount *mp;
47340343Smckusick 	register struct statfs *sp;
47437741Smckusick 	int error;
47547540Skarels 	struct nameidata nd;
47637741Smckusick 
47768318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
47852322Smckusick 	if (error = namei(&nd))
47947540Skarels 		return (error);
48052322Smckusick 	mp = nd.ni_vp->v_mount;
48141400Smckusick 	sp = &mp->mnt_stat;
48252322Smckusick 	vrele(nd.ni_vp);
48348026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
48447540Skarels 		return (error);
48541400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
48668318Scgd 	return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
48737741Smckusick }
48837741Smckusick 
48942441Smckusick /*
49049365Smckusick  * Get filesystem statistics.
49142441Smckusick  */
49242441Smckusick /* ARGSUSED */
49368318Scgd int
49442441Smckusick fstatfs(p, uap, retval)
49545914Smckusick 	struct proc *p;
49668318Scgd 	register struct fstatfs_args /* {
49768318Scgd 		syscallarg(int) fd;
49868318Scgd 		syscallarg(struct statfs *) buf;
49968318Scgd 	} */ *uap;
50068318Scgd 	register_t *retval;
50142441Smckusick {
50237741Smckusick 	struct file *fp;
50339464Smckusick 	struct mount *mp;
50440343Smckusick 	register struct statfs *sp;
50537741Smckusick 	int error;
50637741Smckusick 
50768318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
50847540Skarels 		return (error);
50939464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
51041400Smckusick 	sp = &mp->mnt_stat;
51148026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
51247540Skarels 		return (error);
51341400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
51468318Scgd 	return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
51537741Smckusick }
51637741Smckusick 
51737741Smckusick /*
51849365Smckusick  * Get statistics on all filesystems.
51938270Smckusick  */
52068318Scgd int
52142441Smckusick getfsstat(p, uap, retval)
52245914Smckusick 	struct proc *p;
52368318Scgd 	register struct getfsstat_args /* {
52468318Scgd 		syscallarg(struct statfs *) buf;
52568318Scgd 		syscallarg(long) bufsize;
52668318Scgd 		syscallarg(int) flags;
52768318Scgd 	} */ *uap;
52868318Scgd 	register_t *retval;
52942441Smckusick {
53065259Smckusick 	register struct mount *mp, *nmp;
53140343Smckusick 	register struct statfs *sp;
53239606Smckusick 	caddr_t sfsp;
53338270Smckusick 	long count, maxcount, error;
53438270Smckusick 
53568318Scgd 	maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
53668318Scgd 	sfsp = (caddr_t)SCARG(uap, buf);
53769325Smckusick 	count = 0;
53869325Smckusick 	for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
53969325Smckusick 		nmp = mp->mnt_list.cqe_next;
54041400Smckusick 		if (sfsp && count < maxcount &&
54141400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
54241400Smckusick 			sp = &mp->mnt_stat;
54340343Smckusick 			/*
54440343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
54540343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
54640343Smckusick 			 */
54768318Scgd 			if (((SCARG(uap, flags) & MNT_NOWAIT) == 0 ||
54868318Scgd 			    (SCARG(uap, flags) & MNT_WAIT)) &&
54965259Smckusick 			    (error = VFS_STATFS(mp, sp, p)))
55039607Smckusick 				continue;
55141400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
55240343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
55347540Skarels 				return (error);
55440343Smckusick 			sfsp += sizeof(*sp);
55538270Smckusick 		}
55639606Smckusick 		count++;
55765259Smckusick 	}
55838270Smckusick 	if (sfsp && count > maxcount)
55942441Smckusick 		*retval = maxcount;
56038270Smckusick 	else
56142441Smckusick 		*retval = count;
56247540Skarels 	return (0);
56338270Smckusick }
56438270Smckusick 
56538270Smckusick /*
56638259Smckusick  * Change current working directory to a given file descriptor.
56738259Smckusick  */
56842441Smckusick /* ARGSUSED */
56968318Scgd int
57042441Smckusick fchdir(p, uap, retval)
57145914Smckusick 	struct proc *p;
57268318Scgd 	struct fchdir_args /* {
57368318Scgd 		syscallarg(int) fd;
57468318Scgd 	} */ *uap;
57568318Scgd 	register_t *retval;
57638259Smckusick {
57745914Smckusick 	register struct filedesc *fdp = p->p_fd;
57867974Smckusick 	struct vnode *vp, *tdp;
57967974Smckusick 	struct mount *mp;
58038259Smckusick 	struct file *fp;
58138259Smckusick 	int error;
58238259Smckusick 
58368318Scgd 	if (error = getvnode(fdp, SCARG(uap, fd), &fp))
58447540Skarels 		return (error);
58538259Smckusick 	vp = (struct vnode *)fp->f_data;
58667974Smckusick 	VREF(vp);
587*69409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
58838259Smckusick 	if (vp->v_type != VDIR)
58938259Smckusick 		error = ENOTDIR;
59038259Smckusick 	else
59148026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
59267974Smckusick 	while (!error && (mp = vp->v_mountedhere) != NULL) {
59367974Smckusick 		if (mp->mnt_flag & MNT_MLOCK) {
59467974Smckusick 			mp->mnt_flag |= MNT_MWAIT;
59567974Smckusick 			sleep((caddr_t)mp, PVFS);
59667974Smckusick 			continue;
59767974Smckusick 		}
59867974Smckusick 		if (error = VFS_ROOT(mp, &tdp))
59967974Smckusick 			break;
60067974Smckusick 		vput(vp);
60167974Smckusick 		vp = tdp;
60267974Smckusick 	}
603*69409Smckusick 	VOP_UNLOCK(vp, 0, p);
60467974Smckusick 	if (error) {
60567974Smckusick 		vrele(vp);
60647540Skarels 		return (error);
60767974Smckusick 	}
60845914Smckusick 	vrele(fdp->fd_cdir);
60945914Smckusick 	fdp->fd_cdir = vp;
61047540Skarels 	return (0);
61138259Smckusick }
61238259Smckusick 
61338259Smckusick /*
61437741Smckusick  * Change current working directory (``.'').
61537741Smckusick  */
61642441Smckusick /* ARGSUSED */
61768318Scgd int
61842441Smckusick chdir(p, uap, retval)
61945914Smckusick 	struct proc *p;
62068318Scgd 	struct chdir_args /* {
62168318Scgd 		syscallarg(char *) path;
62268318Scgd 	} */ *uap;
62368318Scgd 	register_t *retval;
62437741Smckusick {
62545914Smckusick 	register struct filedesc *fdp = p->p_fd;
62637741Smckusick 	int error;
62747540Skarels 	struct nameidata nd;
6286254Sroot 
62968318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
63068318Scgd 	    SCARG(uap, path), p);
63164410Sbostic 	if (error = change_dir(&nd, p))
63247540Skarels 		return (error);
63345914Smckusick 	vrele(fdp->fd_cdir);
63452322Smckusick 	fdp->fd_cdir = nd.ni_vp;
63547540Skarels 	return (0);
63637741Smckusick }
6376254Sroot 
63837741Smckusick /*
63937741Smckusick  * Change notion of root (``/'') directory.
64037741Smckusick  */
64142441Smckusick /* ARGSUSED */
64268318Scgd int
64342441Smckusick chroot(p, uap, retval)
64445914Smckusick 	struct proc *p;
64568318Scgd 	struct chroot_args /* {
64668318Scgd 		syscallarg(char *) path;
64768318Scgd 	} */ *uap;
64868318Scgd 	register_t *retval;
64937741Smckusick {
65045914Smckusick 	register struct filedesc *fdp = p->p_fd;
65137741Smckusick 	int error;
65247540Skarels 	struct nameidata nd;
65337741Smckusick 
65447540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
65547540Skarels 		return (error);
65668318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
65768318Scgd 	    SCARG(uap, path), p);
65864410Sbostic 	if (error = change_dir(&nd, p))
65947540Skarels 		return (error);
66045914Smckusick 	if (fdp->fd_rdir != NULL)
66145914Smckusick 		vrele(fdp->fd_rdir);
66252322Smckusick 	fdp->fd_rdir = nd.ni_vp;
66347540Skarels 	return (0);
6646254Sroot }
6656254Sroot 
66637Sbill /*
66737741Smckusick  * Common routine for chroot and chdir.
66837741Smckusick  */
66964410Sbostic static int
67064410Sbostic change_dir(ndp, p)
67152322Smckusick 	register struct nameidata *ndp;
67247540Skarels 	struct proc *p;
67337741Smckusick {
67437741Smckusick 	struct vnode *vp;
67537741Smckusick 	int error;
67637741Smckusick 
67752322Smckusick 	if (error = namei(ndp))
67837741Smckusick 		return (error);
67937741Smckusick 	vp = ndp->ni_vp;
68037741Smckusick 	if (vp->v_type != VDIR)
68137741Smckusick 		error = ENOTDIR;
68237741Smckusick 	else
68348026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
684*69409Smckusick 	VOP_UNLOCK(vp, 0, p);
68537741Smckusick 	if (error)
68637741Smckusick 		vrele(vp);
68737741Smckusick 	return (error);
68837741Smckusick }
68937741Smckusick 
69037741Smckusick /*
69142441Smckusick  * Check permissions, allocate an open file structure,
69242441Smckusick  * and call the device open routine if any.
6936254Sroot  */
69468318Scgd int
69542441Smckusick open(p, uap, retval)
69645914Smckusick 	struct proc *p;
69768318Scgd 	register struct open_args /* {
69868318Scgd 		syscallarg(char *) path;
69968318Scgd 		syscallarg(int) flags;
70068318Scgd 		syscallarg(int) mode;
70168318Scgd 	} */ *uap;
70268318Scgd 	register_t *retval;
7036254Sroot {
70445914Smckusick 	register struct filedesc *fdp = p->p_fd;
70542441Smckusick 	register struct file *fp;
70650111Smckusick 	register struct vnode *vp;
70764410Sbostic 	int flags, cmode;
70837741Smckusick 	struct file *nfp;
70949945Smckusick 	int type, indx, error;
71049945Smckusick 	struct flock lf;
71147540Skarels 	struct nameidata nd;
71237741Smckusick 	extern struct fileops vnops;
7136254Sroot 
71445914Smckusick 	if (error = falloc(p, &nfp, &indx))
71547540Skarels 		return (error);
71637741Smckusick 	fp = nfp;
71768318Scgd 	flags = FFLAGS(SCARG(uap, flags));
71868318Scgd 	cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
71968318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
72045202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
72164410Sbostic 	if (error = vn_open(&nd, flags, cmode)) {
72249980Smckusick 		ffree(fp);
72354723Smckusick 		if ((error == ENODEV || error == ENXIO) &&
72468318Scgd 		    p->p_dupfd >= 0 &&			/* XXX from fdopen */
72564410Sbostic 		    (error =
72668318Scgd 			dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
72742441Smckusick 			*retval = indx;
72847540Skarels 			return (0);
72942441Smckusick 		}
73040884Smckusick 		if (error == ERESTART)
73140884Smckusick 			error = EINTR;
73247688Skarels 		fdp->fd_ofiles[indx] = NULL;
73347540Skarels 		return (error);
73412756Ssam 	}
73553828Spendry 	p->p_dupfd = 0;
73652322Smckusick 	vp = nd.ni_vp;
73764410Sbostic 	fp->f_flag = flags & FMASK;
73854348Smckusick 	fp->f_type = DTYPE_VNODE;
73954348Smckusick 	fp->f_ops = &vnops;
74054348Smckusick 	fp->f_data = (caddr_t)vp;
74164410Sbostic 	if (flags & (O_EXLOCK | O_SHLOCK)) {
74249945Smckusick 		lf.l_whence = SEEK_SET;
74349945Smckusick 		lf.l_start = 0;
74449945Smckusick 		lf.l_len = 0;
74564410Sbostic 		if (flags & O_EXLOCK)
74649945Smckusick 			lf.l_type = F_WRLCK;
74749945Smckusick 		else
74849945Smckusick 			lf.l_type = F_RDLCK;
74949945Smckusick 		type = F_FLOCK;
75064410Sbostic 		if ((flags & FNONBLOCK) == 0)
75149945Smckusick 			type |= F_WAIT;
752*69409Smckusick 		VOP_UNLOCK(vp, 0, p);
75350111Smckusick 		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
75450111Smckusick 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
75549980Smckusick 			ffree(fp);
75649945Smckusick 			fdp->fd_ofiles[indx] = NULL;
75749945Smckusick 			return (error);
75849945Smckusick 		}
759*69409Smckusick 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
76049949Smckusick 		fp->f_flag |= FHASLOCK;
76149945Smckusick 	}
762*69409Smckusick 	VOP_UNLOCK(vp, 0, p);
76342441Smckusick 	*retval = indx;
76447540Skarels 	return (0);
7656254Sroot }
7666254Sroot 
76742955Smckusick #ifdef COMPAT_43
7686254Sroot /*
76964410Sbostic  * Create a file.
7706254Sroot  */
77168318Scgd int
77268318Scgd compat_43_creat(p, uap, retval)
77342441Smckusick 	struct proc *p;
77468318Scgd 	register struct compat_43_creat_args /* {
77568318Scgd 		syscallarg(char *) path;
77668318Scgd 		syscallarg(int) mode;
77768318Scgd 	} */ *uap;
77868318Scgd 	register_t *retval;
7796254Sroot {
78068318Scgd 	struct open_args /* {
78168318Scgd 		syscallarg(char *) path;
78268318Scgd 		syscallarg(int) flags;
78368318Scgd 		syscallarg(int) mode;
78468318Scgd 	} */ nuap;
78542441Smckusick 
78668318Scgd 	SCARG(&nuap, path) = SCARG(uap, path);
78768318Scgd 	SCARG(&nuap, mode) = SCARG(uap, mode);
78868318Scgd 	SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
78968318Scgd 	return (open(p, &nuap, retval));
79042441Smckusick }
79142955Smckusick #endif /* COMPAT_43 */
79242441Smckusick 
79342441Smckusick /*
79464410Sbostic  * Create a special file.
79542441Smckusick  */
79642441Smckusick /* ARGSUSED */
79768318Scgd int
79842441Smckusick mknod(p, uap, retval)
79945914Smckusick 	struct proc *p;
80068318Scgd 	register struct mknod_args /* {
80168318Scgd 		syscallarg(char *) path;
80268318Scgd 		syscallarg(int) mode;
80368318Scgd 		syscallarg(int) dev;
80468318Scgd 	} */ *uap;
80568318Scgd 	register_t *retval;
80642441Smckusick {
80737741Smckusick 	register struct vnode *vp;
80837741Smckusick 	struct vattr vattr;
80937741Smckusick 	int error;
81067575Spendry 	int whiteout;
81147540Skarels 	struct nameidata nd;
8126254Sroot 
81347540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
81447540Skarels 		return (error);
81568318Scgd 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
81652322Smckusick 	if (error = namei(&nd))
81747540Skarels 		return (error);
81852322Smckusick 	vp = nd.ni_vp;
81964585Sbostic 	if (vp != NULL)
82037741Smckusick 		error = EEXIST;
82164585Sbostic 	else {
82264585Sbostic 		VATTR_NULL(&vattr);
82368318Scgd 		vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
82468318Scgd 		vattr.va_rdev = SCARG(uap, dev);
82567575Spendry 		whiteout = 0;
82664585Sbostic 
82768318Scgd 		switch (SCARG(uap, mode) & S_IFMT) {
82864585Sbostic 		case S_IFMT:	/* used by badsect to flag bad sectors */
82964585Sbostic 			vattr.va_type = VBAD;
83064585Sbostic 			break;
83164585Sbostic 		case S_IFCHR:
83264585Sbostic 			vattr.va_type = VCHR;
83364585Sbostic 			break;
83464585Sbostic 		case S_IFBLK:
83564585Sbostic 			vattr.va_type = VBLK;
83664585Sbostic 			break;
83767575Spendry 		case S_IFWHT:
83867575Spendry 			whiteout = 1;
83967575Spendry 			break;
84064585Sbostic 		default:
84164585Sbostic 			error = EINVAL;
84264585Sbostic 			break;
84364585Sbostic 		}
8446254Sroot 	}
84567747Spendry 	if (!error) {
84667654Smckusick 		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
84767747Spendry 		if (whiteout) {
84867747Spendry 			error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
84967747Spendry 			if (error)
85067747Spendry 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
85167747Spendry 			vput(nd.ni_dvp);
85267747Spendry 		} else {
85367747Spendry 			error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
85467747Spendry 						&nd.ni_cnd, &vattr);
85567747Spendry 		}
85642465Smckusick 	} else {
85752322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
85852322Smckusick 		if (nd.ni_dvp == vp)
85952322Smckusick 			vrele(nd.ni_dvp);
86043344Smckusick 		else
86152322Smckusick 			vput(nd.ni_dvp);
86242465Smckusick 		if (vp)
86342465Smckusick 			vrele(vp);
86442465Smckusick 	}
86547540Skarels 	return (error);
8666254Sroot }
8676254Sroot 
8686254Sroot /*
86968318Scgd  * Create a named pipe.
87040285Smckusick  */
87142441Smckusick /* ARGSUSED */
87268318Scgd int
87342441Smckusick mkfifo(p, uap, retval)
87445914Smckusick 	struct proc *p;
87568318Scgd 	register struct mkfifo_args /* {
87668318Scgd 		syscallarg(char *) path;
87768318Scgd 		syscallarg(int) mode;
87868318Scgd 	} */ *uap;
87968318Scgd 	register_t *retval;
88042441Smckusick {
88140285Smckusick 	struct vattr vattr;
88240285Smckusick 	int error;
88347540Skarels 	struct nameidata nd;
88440285Smckusick 
88540285Smckusick #ifndef FIFO
88647540Skarels 	return (EOPNOTSUPP);
88740285Smckusick #else
88868318Scgd 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
88952322Smckusick 	if (error = namei(&nd))
89047540Skarels 		return (error);
89152322Smckusick 	if (nd.ni_vp != NULL) {
89252322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
89352322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
89452322Smckusick 			vrele(nd.ni_dvp);
89543344Smckusick 		else
89652322Smckusick 			vput(nd.ni_dvp);
89752322Smckusick 		vrele(nd.ni_vp);
89847540Skarels 		return (EEXIST);
89940285Smckusick 	}
90045785Sbostic 	VATTR_NULL(&vattr);
90145785Sbostic 	vattr.va_type = VFIFO;
90268318Scgd 	vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
90367654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
90452322Smckusick 	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
90540285Smckusick #endif /* FIFO */
90640285Smckusick }
90740285Smckusick 
90840285Smckusick /*
90964410Sbostic  * Make a hard file link.
9106254Sroot  */
91142441Smckusick /* ARGSUSED */
91268318Scgd int
91342441Smckusick link(p, uap, retval)
91445914Smckusick 	struct proc *p;
91568318Scgd 	register struct link_args /* {
91668318Scgd 		syscallarg(char *) path;
91768318Scgd 		syscallarg(char *) link;
91868318Scgd 	} */ *uap;
91968318Scgd 	register_t *retval;
92042441Smckusick {
92164410Sbostic 	register struct vnode *vp;
92264410Sbostic 	struct nameidata nd;
92337741Smckusick 	int error;
9246254Sroot 
92568318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
92652322Smckusick 	if (error = namei(&nd))
92747540Skarels 		return (error);
92852322Smckusick 	vp = nd.ni_vp;
92964585Sbostic 	if (vp->v_type != VDIR ||
93064585Sbostic 	    (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
93164585Sbostic 		nd.ni_cnd.cn_nameiop = CREATE;
93264585Sbostic 		nd.ni_cnd.cn_flags = LOCKPARENT;
93368318Scgd 		nd.ni_dirp = SCARG(uap, link);
93464585Sbostic 		if ((error = namei(&nd)) == 0) {
93564585Sbostic 			if (nd.ni_vp != NULL)
93664585Sbostic 				error = EEXIST;
93764585Sbostic 			if (!error) {
93867654Smckusick 				VOP_LEASE(nd.ni_dvp, p, p->p_ucred,
93967654Smckusick 				    LEASE_WRITE);
94067654Smckusick 				VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
94168538Smckusick 				error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd);
94264585Sbostic 			} else {
94364585Sbostic 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
94464585Sbostic 				if (nd.ni_dvp == nd.ni_vp)
94564585Sbostic 					vrele(nd.ni_dvp);
94664585Sbostic 				else
94764585Sbostic 					vput(nd.ni_dvp);
94864585Sbostic 				if (nd.ni_vp)
94964585Sbostic 					vrele(nd.ni_vp);
95064585Sbostic 			}
95164585Sbostic 		}
95242465Smckusick 	}
95364585Sbostic 	vrele(vp);
95447540Skarels 	return (error);
9556254Sroot }
9566254Sroot 
9576254Sroot /*
95849365Smckusick  * Make a symbolic link.
9596254Sroot  */
96042441Smckusick /* ARGSUSED */
96168318Scgd int
96242441Smckusick symlink(p, uap, retval)
96345914Smckusick 	struct proc *p;
96468318Scgd 	register struct symlink_args /* {
96568318Scgd 		syscallarg(char *) path;
96668318Scgd 		syscallarg(char *) link;
96768318Scgd 	} */ *uap;
96868318Scgd 	register_t *retval;
96942441Smckusick {
97037741Smckusick 	struct vattr vattr;
97164410Sbostic 	char *path;
97237741Smckusick 	int error;
97347540Skarels 	struct nameidata nd;
9746254Sroot 
97564410Sbostic 	MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
97668318Scgd 	if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL))
97742465Smckusick 		goto out;
97868318Scgd 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
97952322Smckusick 	if (error = namei(&nd))
98042465Smckusick 		goto out;
98152322Smckusick 	if (nd.ni_vp) {
98252322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
98352322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
98452322Smckusick 			vrele(nd.ni_dvp);
98543344Smckusick 		else
98652322Smckusick 			vput(nd.ni_dvp);
98752322Smckusick 		vrele(nd.ni_vp);
98837741Smckusick 		error = EEXIST;
98937741Smckusick 		goto out;
9906254Sroot 	}
99141362Smckusick 	VATTR_NULL(&vattr);
99264410Sbostic 	vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
99367654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
99464410Sbostic 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
99537741Smckusick out:
99664410Sbostic 	FREE(path, M_NAMEI);
99747540Skarels 	return (error);
9986254Sroot }
9996254Sroot 
10006254Sroot /*
100167518Spendry  * Delete a whiteout from the filesystem.
100267518Spendry  */
100367518Spendry /* ARGSUSED */
100468318Scgd int
100567845Smckusick undelete(p, uap, retval)
100667518Spendry 	struct proc *p;
100768318Scgd 	register struct undelete_args /* {
100868318Scgd 		syscallarg(char *) path;
100968318Scgd 	} */ *uap;
101068318Scgd 	register_t *retval;
101167518Spendry {
101267518Spendry 	int error;
101367518Spendry 	struct nameidata nd;
101467518Spendry 
101568318Scgd 	NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
101668318Scgd 	    SCARG(uap, path), p);
101767575Spendry 	error = namei(&nd);
101867575Spendry 	if (error)
101967518Spendry 		return (error);
102067575Spendry 
102167575Spendry 	if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
102267518Spendry 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
102367518Spendry 		if (nd.ni_dvp == nd.ni_vp)
102467518Spendry 			vrele(nd.ni_dvp);
102567518Spendry 		else
102667518Spendry 			vput(nd.ni_dvp);
102767518Spendry 		if (nd.ni_vp)
102867518Spendry 			vrele(nd.ni_vp);
102967518Spendry 		return (EEXIST);
103067518Spendry 	}
103167575Spendry 
103267654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
103367747Spendry 	if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE))
103467575Spendry 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
103567518Spendry 	vput(nd.ni_dvp);
103667518Spendry 	return (error);
103767518Spendry }
103867518Spendry 
103967518Spendry /*
104049365Smckusick  * Delete a name from the filesystem.
10416254Sroot  */
104242441Smckusick /* ARGSUSED */
104368318Scgd int
104442441Smckusick unlink(p, uap, retval)
104545914Smckusick 	struct proc *p;
104668318Scgd 	struct unlink_args /* {
104768318Scgd 		syscallarg(char *) path;
104868318Scgd 	} */ *uap;
104968318Scgd 	register_t *retval;
10506254Sroot {
105137741Smckusick 	register struct vnode *vp;
105237741Smckusick 	int error;
105347540Skarels 	struct nameidata nd;
10546254Sroot 
105568318Scgd 	NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
105652322Smckusick 	if (error = namei(&nd))
105747540Skarels 		return (error);
105852322Smckusick 	vp = nd.ni_vp;
105967654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1060*69409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
106164410Sbostic 
106264585Sbostic 	if (vp->v_type != VDIR ||
106364585Sbostic 	    (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
106464585Sbostic 		/*
106564585Sbostic 		 * The root of a mounted filesystem cannot be deleted.
106664585Sbostic 		 */
106764585Sbostic 		if (vp->v_flag & VROOT)
106864585Sbostic 			error = EBUSY;
106964585Sbostic 		else
107064585Sbostic 			(void)vnode_pager_uncache(vp);
107164585Sbostic 	}
107264585Sbostic 
107364585Sbostic 	if (!error) {
107467654Smckusick 		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
107552322Smckusick 		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
107642465Smckusick 	} else {
107752322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
107852322Smckusick 		if (nd.ni_dvp == vp)
107952322Smckusick 			vrele(nd.ni_dvp);
108043344Smckusick 		else
108152322Smckusick 			vput(nd.ni_dvp);
108267575Spendry 		if (vp != NULLVP)
108367575Spendry 			vput(vp);
108442465Smckusick 	}
108547540Skarels 	return (error);
10866254Sroot }
10876254Sroot 
108864410Sbostic /*
108964410Sbostic  * Reposition read/write file offset.
109064410Sbostic  */
109168318Scgd int
109260414Smckusick lseek(p, uap, retval)
109353468Smckusick 	struct proc *p;
109468318Scgd 	register struct lseek_args /* {
109568318Scgd 		syscallarg(int) fd;
109668318Scgd 		syscallarg(int) pad;
109768318Scgd 		syscallarg(off_t) offset;
109868318Scgd 		syscallarg(int) whence;
109968318Scgd 	} */ *uap;
110068318Scgd 	register_t *retval;
110142441Smckusick {
110247540Skarels 	struct ucred *cred = p->p_ucred;
110345914Smckusick 	register struct filedesc *fdp = p->p_fd;
110442441Smckusick 	register struct file *fp;
110537741Smckusick 	struct vattr vattr;
110637741Smckusick 	int error;
11076254Sroot 
110868318Scgd 	if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
110968318Scgd 	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
111047540Skarels 		return (EBADF);
111137741Smckusick 	if (fp->f_type != DTYPE_VNODE)
111247540Skarels 		return (ESPIPE);
111368318Scgd 	switch (SCARG(uap, whence)) {
111413878Ssam 	case L_INCR:
111568318Scgd 		fp->f_offset += SCARG(uap, offset);
111613878Ssam 		break;
111713878Ssam 	case L_XTND:
111864410Sbostic 		if (error =
111964410Sbostic 		    VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p))
112047540Skarels 			return (error);
112168318Scgd 		fp->f_offset = SCARG(uap, offset) + vattr.va_size;
112213878Ssam 		break;
112313878Ssam 	case L_SET:
112468318Scgd 		fp->f_offset = SCARG(uap, offset);
112513878Ssam 		break;
112613878Ssam 	default:
112747540Skarels 		return (EINVAL);
112813878Ssam 	}
112954916Storek 	*(off_t *)retval = fp->f_offset;
113047540Skarels 	return (0);
11316254Sroot }
11326254Sroot 
113360414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
11346254Sroot /*
113564410Sbostic  * Reposition read/write file offset.
113660036Smckusick  */
113768318Scgd int
113868318Scgd compat_43_lseek(p, uap, retval)
113960036Smckusick 	struct proc *p;
114068318Scgd 	register struct compat_43_lseek_args /* {
114168318Scgd 		syscallarg(int) fd;
114268318Scgd 		syscallarg(long) offset;
114368318Scgd 		syscallarg(int) whence;
114468318Scgd 	} */ *uap;
114568318Scgd 	register_t *retval;
114660036Smckusick {
114768318Scgd 	struct lseek_args /* {
114868318Scgd 		syscallarg(int) fd;
114968318Scgd 		syscallarg(int) pad;
115068318Scgd 		syscallarg(off_t) offset;
115168318Scgd 		syscallarg(int) whence;
115268318Scgd 	} */ nuap;
115360036Smckusick 	off_t qret;
115460036Smckusick 	int error;
115560036Smckusick 
115668318Scgd 	SCARG(&nuap, fd) = SCARG(uap, fd);
115768318Scgd 	SCARG(&nuap, offset) = SCARG(uap, offset);
115868318Scgd 	SCARG(&nuap, whence) = SCARG(uap, whence);
115960428Smckusick 	error = lseek(p, &nuap, &qret);
116060036Smckusick 	*(long *)retval = qret;
116160036Smckusick 	return (error);
116260036Smckusick }
116360414Smckusick #endif /* COMPAT_43 */
116460036Smckusick 
116560036Smckusick /*
116649365Smckusick  * Check access permissions.
11676254Sroot  */
116868318Scgd int
116963427Sbostic access(p, uap, retval)
117045914Smckusick 	struct proc *p;
117168318Scgd 	register struct access_args /* {
117268318Scgd 		syscallarg(char *) path;
117368318Scgd 		syscallarg(int) flags;
117468318Scgd 	} */ *uap;
117568318Scgd 	register_t *retval;
117642441Smckusick {
117747540Skarels 	register struct ucred *cred = p->p_ucred;
117837741Smckusick 	register struct vnode *vp;
117964585Sbostic 	int error, flags, t_gid, t_uid;
118047540Skarels 	struct nameidata nd;
11816254Sroot 
118264585Sbostic 	t_uid = cred->cr_uid;
118364585Sbostic 	t_gid = cred->cr_groups[0];
118447540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
118547540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
118668318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
118768318Scgd 	    SCARG(uap, path), p);
118852322Smckusick 	if (error = namei(&nd))
118937741Smckusick 		goto out1;
119052322Smckusick 	vp = nd.ni_vp;
119164410Sbostic 
119264410Sbostic 	/* Flags == 0 means only check for existence. */
119368318Scgd 	if (SCARG(uap, flags)) {
119464410Sbostic 		flags = 0;
119568318Scgd 		if (SCARG(uap, flags) & R_OK)
119664410Sbostic 			flags |= VREAD;
119768318Scgd 		if (SCARG(uap, flags) & W_OK)
119864410Sbostic 			flags |= VWRITE;
119968318Scgd 		if (SCARG(uap, flags) & X_OK)
120064410Sbostic 			flags |= VEXEC;
120164410Sbostic 		if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
120264410Sbostic 			error = VOP_ACCESS(vp, flags, cred, p);
12036254Sroot 	}
120437741Smckusick 	vput(vp);
120537741Smckusick out1:
120664585Sbostic 	cred->cr_uid = t_uid;
120764585Sbostic 	cred->cr_groups[0] = t_gid;
120847540Skarels 	return (error);
12096254Sroot }
12106254Sroot 
121154348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
12126254Sroot /*
121364410Sbostic  * Get file status; this version follows links.
121437Sbill  */
121542441Smckusick /* ARGSUSED */
121668318Scgd int
121768318Scgd compat_43_stat(p, uap, retval)
121845914Smckusick 	struct proc *p;
121968318Scgd 	register struct compat_43_stat_args /* {
122068318Scgd 		syscallarg(char *) path;
122168318Scgd 		syscallarg(struct ostat *) ub;
122268318Scgd 	} */ *uap;
122368318Scgd 	register_t *retval;
122453468Smckusick {
122553468Smckusick 	struct stat sb;
122653468Smckusick 	struct ostat osb;
122753468Smckusick 	int error;
122853468Smckusick 	struct nameidata nd;
122953468Smckusick 
123068318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
123168318Scgd 	    SCARG(uap, path), p);
123253468Smckusick 	if (error = namei(&nd))
123353468Smckusick 		return (error);
123453468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
123553468Smckusick 	vput(nd.ni_vp);
123653468Smckusick 	if (error)
123753468Smckusick 		return (error);
123853468Smckusick 	cvtstat(&sb, &osb);
123968318Scgd 	error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
124053468Smckusick 	return (error);
124153468Smckusick }
124253468Smckusick 
124353468Smckusick /*
124464410Sbostic  * Get file status; this version does not follow links.
124553468Smckusick  */
124653468Smckusick /* ARGSUSED */
124768318Scgd int
124868318Scgd compat_43_lstat(p, uap, retval)
124953468Smckusick 	struct proc *p;
125068318Scgd 	register struct compat_43_lstat_args /* {
125168318Scgd 		syscallarg(char *) path;
125268318Scgd 		syscallarg(struct ostat *) ub;
125368318Scgd 	} */ *uap;
125468318Scgd 	register_t *retval;
125553468Smckusick {
125667748Smckusick 	struct vnode *vp, *dvp;
125767748Smckusick 	struct stat sb, sb1;
125853468Smckusick 	struct ostat osb;
125953468Smckusick 	int error;
126053468Smckusick 	struct nameidata nd;
126153468Smckusick 
126267748Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
126368318Scgd 	    SCARG(uap, path), p);
126453468Smckusick 	if (error = namei(&nd))
126553468Smckusick 		return (error);
126667748Smckusick 	/*
126767748Smckusick 	 * For symbolic links, always return the attributes of its
126867748Smckusick 	 * containing directory, except for mode, size, and links.
126967748Smckusick 	 */
127067748Smckusick 	vp = nd.ni_vp;
127167748Smckusick 	dvp = nd.ni_dvp;
127267748Smckusick 	if (vp->v_type != VLNK) {
127367748Smckusick 		if (dvp == vp)
127467748Smckusick 			vrele(dvp);
127567748Smckusick 		else
127667748Smckusick 			vput(dvp);
127767748Smckusick 		error = vn_stat(vp, &sb, p);
127867748Smckusick 		vput(vp);
127967748Smckusick 		if (error)
128067748Smckusick 			return (error);
128167748Smckusick 	} else {
128267748Smckusick 		error = vn_stat(dvp, &sb, p);
128367748Smckusick 		vput(dvp);
128467748Smckusick 		if (error) {
128567748Smckusick 			vput(vp);
128667748Smckusick 			return (error);
128767748Smckusick 		}
128867748Smckusick 		error = vn_stat(vp, &sb1, p);
128967748Smckusick 		vput(vp);
129067748Smckusick 		if (error)
129167748Smckusick 			return (error);
129267748Smckusick 		sb.st_mode &= ~S_IFDIR;
129367748Smckusick 		sb.st_mode |= S_IFLNK;
129467748Smckusick 		sb.st_nlink = sb1.st_nlink;
129567748Smckusick 		sb.st_size = sb1.st_size;
129667748Smckusick 		sb.st_blocks = sb1.st_blocks;
129767748Smckusick 	}
129853468Smckusick 	cvtstat(&sb, &osb);
129968318Scgd 	error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
130053468Smckusick 	return (error);
130153468Smckusick }
130253468Smckusick 
130353468Smckusick /*
130464410Sbostic  * Convert from an old to a new stat structure.
130553468Smckusick  */
130668318Scgd void
130753468Smckusick cvtstat(st, ost)
130853468Smckusick 	struct stat *st;
130953468Smckusick 	struct ostat *ost;
131053468Smckusick {
131153468Smckusick 
131253468Smckusick 	ost->st_dev = st->st_dev;
131353468Smckusick 	ost->st_ino = st->st_ino;
131453468Smckusick 	ost->st_mode = st->st_mode;
131553468Smckusick 	ost->st_nlink = st->st_nlink;
131653468Smckusick 	ost->st_uid = st->st_uid;
131753468Smckusick 	ost->st_gid = st->st_gid;
131853468Smckusick 	ost->st_rdev = st->st_rdev;
131953468Smckusick 	if (st->st_size < (quad_t)1 << 32)
132053468Smckusick 		ost->st_size = st->st_size;
132153468Smckusick 	else
132253468Smckusick 		ost->st_size = -2;
132353468Smckusick 	ost->st_atime = st->st_atime;
132453468Smckusick 	ost->st_mtime = st->st_mtime;
132553468Smckusick 	ost->st_ctime = st->st_ctime;
132653468Smckusick 	ost->st_blksize = st->st_blksize;
132753468Smckusick 	ost->st_blocks = st->st_blocks;
132853468Smckusick 	ost->st_flags = st->st_flags;
132953468Smckusick 	ost->st_gen = st->st_gen;
133053468Smckusick }
133154348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
133253468Smckusick 
133353468Smckusick /*
133464410Sbostic  * Get file status; this version follows links.
133553468Smckusick  */
133653468Smckusick /* ARGSUSED */
133768318Scgd int
133853759Smckusick stat(p, uap, retval)
133953468Smckusick 	struct proc *p;
134068318Scgd 	register struct stat_args /* {
134168318Scgd 		syscallarg(char *) path;
134268318Scgd 		syscallarg(struct stat *) ub;
134368318Scgd 	} */ *uap;
134468318Scgd 	register_t *retval;
134537Sbill {
134642441Smckusick 	struct stat sb;
134742441Smckusick 	int error;
134847540Skarels 	struct nameidata nd;
134937Sbill 
135068318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
135168318Scgd 	    SCARG(uap, path), p);
135252322Smckusick 	if (error = namei(&nd))
135347540Skarels 		return (error);
135452322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
135552322Smckusick 	vput(nd.ni_vp);
135642441Smckusick 	if (error)
135747540Skarels 		return (error);
135868318Scgd 	error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
135947540Skarels 	return (error);
136037Sbill }
136137Sbill 
136237Sbill /*
136364410Sbostic  * Get file status; this version does not follow links.
13645992Swnj  */
136542441Smckusick /* ARGSUSED */
136668318Scgd int
136753759Smckusick lstat(p, uap, retval)
136845914Smckusick 	struct proc *p;
136968318Scgd 	register struct lstat_args /* {
137068318Scgd 		syscallarg(char *) path;
137168318Scgd 		syscallarg(struct stat *) ub;
137268318Scgd 	} */ *uap;
137368318Scgd 	register_t *retval;
137442441Smckusick {
137537741Smckusick 	int error;
137659373Smckusick 	struct vnode *vp, *dvp;
137759373Smckusick 	struct stat sb, sb1;
137847540Skarels 	struct nameidata nd;
13795992Swnj 
138059373Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
138168318Scgd 	    SCARG(uap, path), p);
138252322Smckusick 	if (error = namei(&nd))
138347540Skarels 		return (error);
138459373Smckusick 	/*
138568579Smckusick 	 * For symbolic links, always return the attributes of its containing
138668579Smckusick 	 * directory, except for mode, size, inode number, and links.
138759373Smckusick 	 */
138859373Smckusick 	vp = nd.ni_vp;
138959373Smckusick 	dvp = nd.ni_dvp;
139059373Smckusick 	if (vp->v_type != VLNK) {
139159373Smckusick 		if (dvp == vp)
139259373Smckusick 			vrele(dvp);
139359373Smckusick 		else
139459373Smckusick 			vput(dvp);
139559373Smckusick 		error = vn_stat(vp, &sb, p);
139659373Smckusick 		vput(vp);
139759373Smckusick 		if (error)
139859373Smckusick 			return (error);
139959373Smckusick 	} else {
140059373Smckusick 		error = vn_stat(dvp, &sb, p);
140159373Smckusick 		vput(dvp);
140259373Smckusick 		if (error) {
140359373Smckusick 			vput(vp);
140459373Smckusick 			return (error);
140559373Smckusick 		}
140659373Smckusick 		error = vn_stat(vp, &sb1, p);
140759373Smckusick 		vput(vp);
140859373Smckusick 		if (error)
140959373Smckusick 			return (error);
141059373Smckusick 		sb.st_mode &= ~S_IFDIR;
141159373Smckusick 		sb.st_mode |= S_IFLNK;
141259373Smckusick 		sb.st_nlink = sb1.st_nlink;
141359373Smckusick 		sb.st_size = sb1.st_size;
141459373Smckusick 		sb.st_blocks = sb1.st_blocks;
141568579Smckusick 		sb.st_ino = sb1.st_ino;
141659373Smckusick 	}
141768318Scgd 	error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
141847540Skarels 	return (error);
14195992Swnj }
14205992Swnj 
14215992Swnj /*
142264410Sbostic  * Get configurable pathname variables.
142360414Smckusick  */
142460414Smckusick /* ARGSUSED */
142568318Scgd int
142660414Smckusick pathconf(p, uap, retval)
142760414Smckusick 	struct proc *p;
142868318Scgd 	register struct pathconf_args /* {
142968318Scgd 		syscallarg(char *) path;
143068318Scgd 		syscallarg(int) name;
143168318Scgd 	} */ *uap;
143268318Scgd 	register_t *retval;
143360414Smckusick {
143460414Smckusick 	int error;
143560414Smckusick 	struct nameidata nd;
143660414Smckusick 
143768318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
143868318Scgd 	    SCARG(uap, path), p);
143960414Smckusick 	if (error = namei(&nd))
144060414Smckusick 		return (error);
144168318Scgd 	error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
144260414Smckusick 	vput(nd.ni_vp);
144360414Smckusick 	return (error);
144460414Smckusick }
144560414Smckusick 
144660414Smckusick /*
144749365Smckusick  * Return target name of a symbolic link.
144837Sbill  */
144942441Smckusick /* ARGSUSED */
145068318Scgd int
145142441Smckusick readlink(p, uap, retval)
145245914Smckusick 	struct proc *p;
145368318Scgd 	register struct readlink_args /* {
145468318Scgd 		syscallarg(char *) path;
145568318Scgd 		syscallarg(char *) buf;
145668318Scgd 		syscallarg(int) count;
145768318Scgd 	} */ *uap;
145868318Scgd 	register_t *retval;
145942441Smckusick {
146037741Smckusick 	register struct vnode *vp;
146137741Smckusick 	struct iovec aiov;
146237741Smckusick 	struct uio auio;
146337741Smckusick 	int error;
146447540Skarels 	struct nameidata nd;
14655992Swnj 
146668318Scgd 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
146768318Scgd 	    SCARG(uap, path), p);
146852322Smckusick 	if (error = namei(&nd))
146947540Skarels 		return (error);
147052322Smckusick 	vp = nd.ni_vp;
147164410Sbostic 	if (vp->v_type != VLNK)
147237741Smckusick 		error = EINVAL;
147364410Sbostic 	else {
147468318Scgd 		aiov.iov_base = SCARG(uap, buf);
147568318Scgd 		aiov.iov_len = SCARG(uap, count);
147664410Sbostic 		auio.uio_iov = &aiov;
147764410Sbostic 		auio.uio_iovcnt = 1;
147864410Sbostic 		auio.uio_offset = 0;
147964410Sbostic 		auio.uio_rw = UIO_READ;
148064410Sbostic 		auio.uio_segflg = UIO_USERSPACE;
148164410Sbostic 		auio.uio_procp = p;
148268318Scgd 		auio.uio_resid = SCARG(uap, count);
148364410Sbostic 		error = VOP_READLINK(vp, &auio, p->p_ucred);
14845992Swnj 	}
148537741Smckusick 	vput(vp);
148668318Scgd 	*retval = SCARG(uap, count) - auio.uio_resid;
148747540Skarels 	return (error);
14885992Swnj }
14895992Swnj 
14909167Ssam /*
149164410Sbostic  * Change flags of a file given a path name.
149238259Smckusick  */
149342441Smckusick /* ARGSUSED */
149468318Scgd int
149542441Smckusick chflags(p, uap, retval)
149645914Smckusick 	struct proc *p;
149768318Scgd 	register struct chflags_args /* {
149868318Scgd 		syscallarg(char *) path;
149968318Scgd 		syscallarg(int) flags;
150068318Scgd 	} */ *uap;
150168318Scgd 	register_t *retval;
150242441Smckusick {
150338259Smckusick 	register struct vnode *vp;
150438259Smckusick 	struct vattr vattr;
150538259Smckusick 	int error;
150647540Skarels 	struct nameidata nd;
150738259Smckusick 
150868318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
150952322Smckusick 	if (error = namei(&nd))
151047540Skarels 		return (error);
151152322Smckusick 	vp = nd.ni_vp;
151267654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1513*69409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
151464410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
151538259Smckusick 		error = EROFS;
151664410Sbostic 	else {
151764410Sbostic 		VATTR_NULL(&vattr);
151868318Scgd 		vattr.va_flags = SCARG(uap, flags);
151964410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
152038259Smckusick 	}
152138259Smckusick 	vput(vp);
152247540Skarels 	return (error);
152338259Smckusick }
152438259Smckusick 
152538259Smckusick /*
152638259Smckusick  * Change flags of a file given a file descriptor.
152738259Smckusick  */
152842441Smckusick /* ARGSUSED */
152968318Scgd int
153042441Smckusick fchflags(p, uap, retval)
153145914Smckusick 	struct proc *p;
153268318Scgd 	register struct fchflags_args /* {
153368318Scgd 		syscallarg(int) fd;
153468318Scgd 		syscallarg(int) flags;
153568318Scgd 	} */ *uap;
153668318Scgd 	register_t *retval;
153742441Smckusick {
153838259Smckusick 	struct vattr vattr;
153938259Smckusick 	struct vnode *vp;
154038259Smckusick 	struct file *fp;
154138259Smckusick 	int error;
154238259Smckusick 
154368318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
154447540Skarels 		return (error);
154538259Smckusick 	vp = (struct vnode *)fp->f_data;
154667654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1547*69409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
154864410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
154938259Smckusick 		error = EROFS;
155064410Sbostic 	else {
155164410Sbostic 		VATTR_NULL(&vattr);
155268318Scgd 		vattr.va_flags = SCARG(uap, flags);
155364410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
155438259Smckusick 	}
1555*69409Smckusick 	VOP_UNLOCK(vp, 0, p);
155647540Skarels 	return (error);
155738259Smckusick }
155838259Smckusick 
155938259Smckusick /*
15609167Ssam  * Change mode of a file given path name.
15619167Ssam  */
156242441Smckusick /* ARGSUSED */
156368318Scgd int
156442441Smckusick chmod(p, uap, retval)
156545914Smckusick 	struct proc *p;
156668318Scgd 	register struct chmod_args /* {
156768318Scgd 		syscallarg(char *) path;
156868318Scgd 		syscallarg(int) mode;
156968318Scgd 	} */ *uap;
157068318Scgd 	register_t *retval;
157142441Smckusick {
157237741Smckusick 	register struct vnode *vp;
157337741Smckusick 	struct vattr vattr;
157437741Smckusick 	int error;
157547540Skarels 	struct nameidata nd;
15765992Swnj 
157768318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
157852322Smckusick 	if (error = namei(&nd))
157947540Skarels 		return (error);
158052322Smckusick 	vp = nd.ni_vp;
158167654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1582*69409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
158364410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
158437741Smckusick 		error = EROFS;
158564410Sbostic 	else {
158664410Sbostic 		VATTR_NULL(&vattr);
158768318Scgd 		vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
158864410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
158937741Smckusick 	}
159037741Smckusick 	vput(vp);
159147540Skarels 	return (error);
15927701Ssam }
15937439Sroot 
15949167Ssam /*
15959167Ssam  * Change mode of a file given a file descriptor.
15969167Ssam  */
159742441Smckusick /* ARGSUSED */
159868318Scgd int
159942441Smckusick fchmod(p, uap, retval)
160045914Smckusick 	struct proc *p;
160168318Scgd 	register struct fchmod_args /* {
160268318Scgd 		syscallarg(int) fd;
160368318Scgd 		syscallarg(int) mode;
160468318Scgd 	} */ *uap;
160568318Scgd 	register_t *retval;
160642441Smckusick {
160737741Smckusick 	struct vattr vattr;
160837741Smckusick 	struct vnode *vp;
160937741Smckusick 	struct file *fp;
161037741Smckusick 	int error;
16117701Ssam 
161268318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
161347540Skarels 		return (error);
161437741Smckusick 	vp = (struct vnode *)fp->f_data;
161567654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1616*69409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
161764410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
161837741Smckusick 		error = EROFS;
161964410Sbostic 	else {
162064410Sbostic 		VATTR_NULL(&vattr);
162168318Scgd 		vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
162264410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
16237439Sroot 	}
1624*69409Smckusick 	VOP_UNLOCK(vp, 0, p);
162547540Skarels 	return (error);
16265992Swnj }
16275992Swnj 
16289167Ssam /*
16299167Ssam  * Set ownership given a path name.
16309167Ssam  */
163142441Smckusick /* ARGSUSED */
163268318Scgd int
163342441Smckusick chown(p, uap, retval)
163445914Smckusick 	struct proc *p;
163568318Scgd 	register struct chown_args /* {
163668318Scgd 		syscallarg(char *) path;
163768318Scgd 		syscallarg(int) uid;
163868318Scgd 		syscallarg(int) gid;
163968318Scgd 	} */ *uap;
164068318Scgd 	register_t *retval;
164142441Smckusick {
164237741Smckusick 	register struct vnode *vp;
164337741Smckusick 	struct vattr vattr;
164437741Smckusick 	int error;
164547540Skarels 	struct nameidata nd;
164637Sbill 
164768318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
164852322Smckusick 	if (error = namei(&nd))
164947540Skarels 		return (error);
165052322Smckusick 	vp = nd.ni_vp;
165167654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1652*69409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
165364410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
165437741Smckusick 		error = EROFS;
165564410Sbostic 	else {
165664410Sbostic 		VATTR_NULL(&vattr);
165768318Scgd 		vattr.va_uid = SCARG(uap, uid);
165868318Scgd 		vattr.va_gid = SCARG(uap, gid);
165964410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
166037741Smckusick 	}
166137741Smckusick 	vput(vp);
166247540Skarels 	return (error);
16637701Ssam }
16647439Sroot 
16659167Ssam /*
16669167Ssam  * Set ownership given a file descriptor.
16679167Ssam  */
166842441Smckusick /* ARGSUSED */
166968318Scgd int
167042441Smckusick fchown(p, uap, retval)
167145914Smckusick 	struct proc *p;
167268318Scgd 	register struct fchown_args /* {
167368318Scgd 		syscallarg(int) fd;
167468318Scgd 		syscallarg(int) uid;
167568318Scgd 		syscallarg(int) gid;
167668318Scgd 	} */ *uap;
167768318Scgd 	register_t *retval;
167842441Smckusick {
167937741Smckusick 	struct vattr vattr;
168037741Smckusick 	struct vnode *vp;
168137741Smckusick 	struct file *fp;
168237741Smckusick 	int error;
16837701Ssam 
168468318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
168547540Skarels 		return (error);
168637741Smckusick 	vp = (struct vnode *)fp->f_data;
168767654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1688*69409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
168964410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
169037741Smckusick 		error = EROFS;
169164410Sbostic 	else {
169264410Sbostic 		VATTR_NULL(&vattr);
169368318Scgd 		vattr.va_uid = SCARG(uap, uid);
169468318Scgd 		vattr.va_gid = SCARG(uap, gid);
169564410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
169637741Smckusick 	}
1697*69409Smckusick 	VOP_UNLOCK(vp, 0, p);
169847540Skarels 	return (error);
16997701Ssam }
17007701Ssam 
170142441Smckusick /*
170242441Smckusick  * Set the access and modification times of a file.
170342441Smckusick  */
170442441Smckusick /* ARGSUSED */
170568318Scgd int
170642441Smckusick utimes(p, uap, retval)
170745914Smckusick 	struct proc *p;
170868318Scgd 	register struct utimes_args /* {
170968318Scgd 		syscallarg(char *) path;
171068318Scgd 		syscallarg(struct timeval *) tptr;
171168318Scgd 	} */ *uap;
171268318Scgd 	register_t *retval;
171342441Smckusick {
171437741Smckusick 	register struct vnode *vp;
171511811Ssam 	struct timeval tv[2];
171637741Smckusick 	struct vattr vattr;
171758840Storek 	int error;
171847540Skarels 	struct nameidata nd;
171911811Ssam 
172058505Sbostic 	VATTR_NULL(&vattr);
172168318Scgd 	if (SCARG(uap, tptr) == NULL) {
172258505Sbostic 		microtime(&tv[0]);
172358505Sbostic 		tv[1] = tv[0];
172458548Sbostic 		vattr.va_vaflags |= VA_UTIMES_NULL;
172568318Scgd 	} else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv,
172668318Scgd 	    sizeof (tv)))
172758505Sbostic   		return (error);
172868318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
172952322Smckusick 	if (error = namei(&nd))
173047540Skarels 		return (error);
173152322Smckusick 	vp = nd.ni_vp;
173267654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1733*69409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
173464410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
173537741Smckusick 		error = EROFS;
173664410Sbostic 	else {
173764410Sbostic 		vattr.va_atime.ts_sec = tv[0].tv_sec;
173864410Sbostic 		vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
173964410Sbostic 		vattr.va_mtime.ts_sec = tv[1].tv_sec;
174064410Sbostic 		vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
174164410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
174221015Smckusick 	}
174337741Smckusick 	vput(vp);
174447540Skarels 	return (error);
174511811Ssam }
174611811Ssam 
174764410Sbostic /*
174864410Sbostic  * Truncate a file given its path name.
174964410Sbostic  */
175053468Smckusick /* ARGSUSED */
175168318Scgd int
175260414Smckusick truncate(p, uap, retval)
175353468Smckusick 	struct proc *p;
175468318Scgd 	register struct truncate_args /* {
175568318Scgd 		syscallarg(char *) path;
175668318Scgd 		syscallarg(int) pad;
175768318Scgd 		syscallarg(off_t) length;
175868318Scgd 	} */ *uap;
175968318Scgd 	register_t *retval;
176053468Smckusick {
176137741Smckusick 	register struct vnode *vp;
176237741Smckusick 	struct vattr vattr;
176337741Smckusick 	int error;
176447540Skarels 	struct nameidata nd;
17657701Ssam 
176668318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
176752322Smckusick 	if (error = namei(&nd))
176847540Skarels 		return (error);
176952322Smckusick 	vp = nd.ni_vp;
177067654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1771*69409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
177264410Sbostic 	if (vp->v_type == VDIR)
177337741Smckusick 		error = EISDIR;
177464410Sbostic 	else if ((error = vn_writechk(vp)) == 0 &&
177564410Sbostic 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
177664410Sbostic 		VATTR_NULL(&vattr);
177768318Scgd 		vattr.va_size = SCARG(uap, length);
177864410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
17797701Ssam 	}
178037741Smckusick 	vput(vp);
178147540Skarels 	return (error);
17827701Ssam }
17837701Ssam 
178464410Sbostic /*
178564410Sbostic  * Truncate a file given a file descriptor.
178664410Sbostic  */
178742441Smckusick /* ARGSUSED */
178868318Scgd int
178960414Smckusick ftruncate(p, uap, retval)
179045914Smckusick 	struct proc *p;
179168318Scgd 	register struct ftruncate_args /* {
179268318Scgd 		syscallarg(int) fd;
179368318Scgd 		syscallarg(int) pad;
179468318Scgd 		syscallarg(off_t) length;
179568318Scgd 	} */ *uap;
179668318Scgd 	register_t *retval;
179742441Smckusick {
179837741Smckusick 	struct vattr vattr;
179937741Smckusick 	struct vnode *vp;
18007701Ssam 	struct file *fp;
180137741Smckusick 	int error;
18027701Ssam 
180368318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
180447540Skarels 		return (error);
180537741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
180647540Skarels 		return (EINVAL);
180737741Smckusick 	vp = (struct vnode *)fp->f_data;
180867654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1809*69409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
181064410Sbostic 	if (vp->v_type == VDIR)
181137741Smckusick 		error = EISDIR;
181264410Sbostic 	else if ((error = vn_writechk(vp)) == 0) {
181364410Sbostic 		VATTR_NULL(&vattr);
181468318Scgd 		vattr.va_size = SCARG(uap, length);
181564410Sbostic 		error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
18167701Ssam 	}
1817*69409Smckusick 	VOP_UNLOCK(vp, 0, p);
181847540Skarels 	return (error);
18197701Ssam }
18207701Ssam 
182154863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
18229167Ssam /*
182354863Storek  * Truncate a file given its path name.
182454863Storek  */
182554863Storek /* ARGSUSED */
182668318Scgd int
182768318Scgd compat_43_truncate(p, uap, retval)
182854863Storek 	struct proc *p;
182968318Scgd 	register struct compat_43_truncate_args /* {
183068318Scgd 		syscallarg(char *) path;
183168318Scgd 		syscallarg(long) length;
183268318Scgd 	} */ *uap;
183368318Scgd 	register_t *retval;
183454863Storek {
183568318Scgd 	struct truncate_args /* {
183668318Scgd 		syscallarg(char *) path;
183768318Scgd 		syscallarg(int) pad;
183868318Scgd 		syscallarg(off_t) length;
183968318Scgd 	} */ nuap;
184054863Storek 
184168318Scgd 	SCARG(&nuap, path) = SCARG(uap, path);
184268318Scgd 	SCARG(&nuap, length) = SCARG(uap, length);
184360428Smckusick 	return (truncate(p, &nuap, retval));
184454863Storek }
184554863Storek 
184654863Storek /*
184754863Storek  * Truncate a file given a file descriptor.
184854863Storek  */
184954863Storek /* ARGSUSED */
185068318Scgd int
185168318Scgd compat_43_ftruncate(p, uap, retval)
185254863Storek 	struct proc *p;
185368318Scgd 	register struct compat_43_ftruncate_args /* {
185468318Scgd 		syscallarg(int) fd;
185568318Scgd 		syscallarg(long) length;
185668318Scgd 	} */ *uap;
185768318Scgd 	register_t *retval;
185854863Storek {
185968318Scgd 	struct ftruncate_args /* {
186068318Scgd 		syscallarg(int) fd;
186168318Scgd 		syscallarg(int) pad;
186268318Scgd 		syscallarg(off_t) length;
186368318Scgd 	} */ nuap;
186454863Storek 
186568318Scgd 	SCARG(&nuap, fd) = SCARG(uap, fd);
186668318Scgd 	SCARG(&nuap, length) = SCARG(uap, length);
186760428Smckusick 	return (ftruncate(p, &nuap, retval));
186854863Storek }
186954863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */
187054863Storek 
187154863Storek /*
187264410Sbostic  * Sync an open file.
18739167Ssam  */
187442441Smckusick /* ARGSUSED */
187568318Scgd int
187642441Smckusick fsync(p, uap, retval)
187745914Smckusick 	struct proc *p;
187868318Scgd 	struct fsync_args /* {
187968318Scgd 		syscallarg(int) fd;
188068318Scgd 	} */ *uap;
188168318Scgd 	register_t *retval;
18829167Ssam {
188339592Smckusick 	register struct vnode *vp;
18849167Ssam 	struct file *fp;
188537741Smckusick 	int error;
18869167Ssam 
188768318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
188847540Skarels 		return (error);
188939592Smckusick 	vp = (struct vnode *)fp->f_data;
1890*69409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
189154441Smckusick 	error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
1892*69409Smckusick 	VOP_UNLOCK(vp, 0, p);
189347540Skarels 	return (error);
18949167Ssam }
18959167Ssam 
18969167Ssam /*
189764410Sbostic  * Rename files.  Source and destination must either both be directories,
189864410Sbostic  * or both not be directories.  If target is a directory, it must be empty.
18999167Ssam  */
190042441Smckusick /* ARGSUSED */
190168318Scgd int
190242441Smckusick rename(p, uap, retval)
190345914Smckusick 	struct proc *p;
190468318Scgd 	register struct rename_args /* {
190568318Scgd 		syscallarg(char *) from;
190668318Scgd 		syscallarg(char *) to;
190768318Scgd 	} */ *uap;
190868318Scgd 	register_t *retval;
190942441Smckusick {
191037741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
191149735Smckusick 	struct nameidata fromnd, tond;
191237741Smckusick 	int error;
19137701Ssam 
191452322Smckusick 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
191568318Scgd 	    SCARG(uap, from), p);
191652322Smckusick 	if (error = namei(&fromnd))
191747540Skarels 		return (error);
191849735Smckusick 	fvp = fromnd.ni_vp;
191952322Smckusick 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
192068318Scgd 	    UIO_USERSPACE, SCARG(uap, to), p);
192152322Smckusick 	if (error = namei(&tond)) {
192252230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
192349735Smckusick 		vrele(fromnd.ni_dvp);
192442465Smckusick 		vrele(fvp);
192542465Smckusick 		goto out1;
192642465Smckusick 	}
192737741Smckusick 	tdvp = tond.ni_dvp;
192837741Smckusick 	tvp = tond.ni_vp;
192937741Smckusick 	if (tvp != NULL) {
193037741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
193139242Sbostic 			error = ENOTDIR;
193237741Smckusick 			goto out;
193337741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
193439242Sbostic 			error = EISDIR;
193537741Smckusick 			goto out;
19369167Ssam 		}
19379167Ssam 	}
193839286Smckusick 	if (fvp == tdvp)
193937741Smckusick 		error = EINVAL;
194039286Smckusick 	/*
194149735Smckusick 	 * If source is the same as the destination (that is the
194249735Smckusick 	 * same inode number with the same name in the same directory),
194339286Smckusick 	 * then there is nothing to do.
194439286Smckusick 	 */
194549735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
194652322Smckusick 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
194752322Smckusick 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
194852322Smckusick 	      fromnd.ni_cnd.cn_namelen))
194939286Smckusick 		error = -1;
195037741Smckusick out:
195142465Smckusick 	if (!error) {
195267654Smckusick 		VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE);
195352192Smckusick 		if (fromnd.ni_dvp != tdvp)
195467654Smckusick 			VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
195552192Smckusick 		if (tvp)
195667654Smckusick 			VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE);
195752230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
195852230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
195942465Smckusick 	} else {
196052230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
196143344Smckusick 		if (tdvp == tvp)
196243344Smckusick 			vrele(tdvp);
196343344Smckusick 		else
196443344Smckusick 			vput(tdvp);
196542465Smckusick 		if (tvp)
196642465Smckusick 			vput(tvp);
196752230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
196849735Smckusick 		vrele(fromnd.ni_dvp);
196942465Smckusick 		vrele(fvp);
19709167Ssam 	}
197149735Smckusick 	vrele(tond.ni_startdir);
197252322Smckusick 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
197337741Smckusick out1:
197466801Smckusick 	if (fromnd.ni_startdir)
197566801Smckusick 		vrele(fromnd.ni_startdir);
197652322Smckusick 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
197739286Smckusick 	if (error == -1)
197847540Skarels 		return (0);
197947540Skarels 	return (error);
19807701Ssam }
19817701Ssam 
19827535Sroot /*
198364410Sbostic  * Make a directory file.
198412756Ssam  */
198542441Smckusick /* ARGSUSED */
198668318Scgd int
198742441Smckusick mkdir(p, uap, retval)
198845914Smckusick 	struct proc *p;
198968318Scgd 	register struct mkdir_args /* {
199068318Scgd 		syscallarg(char *) path;
199168318Scgd 		syscallarg(int) mode;
199268318Scgd 	} */ *uap;
199368318Scgd 	register_t *retval;
199442441Smckusick {
199537741Smckusick 	register struct vnode *vp;
199637741Smckusick 	struct vattr vattr;
199737741Smckusick 	int error;
199847540Skarels 	struct nameidata nd;
199912756Ssam 
200068318Scgd 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
200152322Smckusick 	if (error = namei(&nd))
200247540Skarels 		return (error);
200352322Smckusick 	vp = nd.ni_vp;
200437741Smckusick 	if (vp != NULL) {
200552322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
200652322Smckusick 		if (nd.ni_dvp == vp)
200752322Smckusick 			vrele(nd.ni_dvp);
200843344Smckusick 		else
200952322Smckusick 			vput(nd.ni_dvp);
201042465Smckusick 		vrele(vp);
201147540Skarels 		return (EEXIST);
201212756Ssam 	}
201341362Smckusick 	VATTR_NULL(&vattr);
201437741Smckusick 	vattr.va_type = VDIR;
201568318Scgd 	vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask;
201667654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
201752322Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
201838145Smckusick 	if (!error)
201952322Smckusick 		vput(nd.ni_vp);
202047540Skarels 	return (error);
202112756Ssam }
202212756Ssam 
202312756Ssam /*
202464410Sbostic  * Remove a directory file.
202512756Ssam  */
202642441Smckusick /* ARGSUSED */
202768318Scgd int
202842441Smckusick rmdir(p, uap, retval)
202945914Smckusick 	struct proc *p;
203068318Scgd 	struct rmdir_args /* {
203168318Scgd 		syscallarg(char *) path;
203268318Scgd 	} */ *uap;
203368318Scgd 	register_t *retval;
203412756Ssam {
203537741Smckusick 	register struct vnode *vp;
203637741Smckusick 	int error;
203747540Skarels 	struct nameidata nd;
203812756Ssam 
203968318Scgd 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
204068318Scgd 	    SCARG(uap, path), p);
204152322Smckusick 	if (error = namei(&nd))
204247540Skarels 		return (error);
204352322Smckusick 	vp = nd.ni_vp;
204437741Smckusick 	if (vp->v_type != VDIR) {
204537741Smckusick 		error = ENOTDIR;
204612756Ssam 		goto out;
204712756Ssam 	}
204812756Ssam 	/*
204937741Smckusick 	 * No rmdir "." please.
205012756Ssam 	 */
205152322Smckusick 	if (nd.ni_dvp == vp) {
205237741Smckusick 		error = EINVAL;
205312756Ssam 		goto out;
205412756Ssam 	}
205512756Ssam 	/*
205649365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
205712756Ssam 	 */
205837741Smckusick 	if (vp->v_flag & VROOT)
205937741Smckusick 		error = EBUSY;
206012756Ssam out:
206142465Smckusick 	if (!error) {
206267654Smckusick 		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
206367654Smckusick 		VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
206452322Smckusick 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
206542465Smckusick 	} else {
206652322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
206752322Smckusick 		if (nd.ni_dvp == vp)
206852322Smckusick 			vrele(nd.ni_dvp);
206943344Smckusick 		else
207052322Smckusick 			vput(nd.ni_dvp);
207142465Smckusick 		vput(vp);
207242465Smckusick 	}
207347540Skarels 	return (error);
207412756Ssam }
207512756Ssam 
207654620Smckusick #ifdef COMPAT_43
207737741Smckusick /*
207849365Smckusick  * Read a block of directory entries in a file system independent format.
207937741Smckusick  */
208068318Scgd int
208168318Scgd compat_43_getdirentries(p, uap, retval)
208254620Smckusick 	struct proc *p;
208368318Scgd 	register struct compat_43_getdirentries_args /* {
208468318Scgd 		syscallarg(int) fd;
208568318Scgd 		syscallarg(char *) buf;
208668318Scgd 		syscallarg(u_int) count;
208768318Scgd 		syscallarg(long *) basep;
208868318Scgd 	} */ *uap;
208968318Scgd 	register_t *retval;
209054620Smckusick {
209154620Smckusick 	register struct vnode *vp;
209254620Smckusick 	struct file *fp;
209354620Smckusick 	struct uio auio, kuio;
209454620Smckusick 	struct iovec aiov, kiov;
209554620Smckusick 	struct dirent *dp, *edp;
209654620Smckusick 	caddr_t dirbuf;
209767362Smckusick 	int error, eofflag, readcnt;
209854969Smckusick 	long loff;
209954620Smckusick 
210068318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
210154620Smckusick 		return (error);
210254620Smckusick 	if ((fp->f_flag & FREAD) == 0)
210354620Smckusick 		return (EBADF);
210454620Smckusick 	vp = (struct vnode *)fp->f_data;
210567362Smckusick unionread:
210654620Smckusick 	if (vp->v_type != VDIR)
210754620Smckusick 		return (EINVAL);
210868318Scgd 	aiov.iov_base = SCARG(uap, buf);
210968318Scgd 	aiov.iov_len = SCARG(uap, count);
211054620Smckusick 	auio.uio_iov = &aiov;
211154620Smckusick 	auio.uio_iovcnt = 1;
211254620Smckusick 	auio.uio_rw = UIO_READ;
211354620Smckusick 	auio.uio_segflg = UIO_USERSPACE;
211454620Smckusick 	auio.uio_procp = p;
211568318Scgd 	auio.uio_resid = SCARG(uap, count);
2116*69409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
211754969Smckusick 	loff = auio.uio_offset = fp->f_offset;
211854620Smckusick #	if (BYTE_ORDER != LITTLE_ENDIAN)
211956339Smckusick 		if (vp->v_mount->mnt_maxsymlinklen <= 0) {
212067362Smckusick 			error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
212168663Smckusick 			    (int *)0, (u_long *)0);
212256339Smckusick 			fp->f_offset = auio.uio_offset;
212356339Smckusick 		} else
212454620Smckusick #	endif
212554620Smckusick 	{
212654620Smckusick 		kuio = auio;
212754620Smckusick 		kuio.uio_iov = &kiov;
212854620Smckusick 		kuio.uio_segflg = UIO_SYSSPACE;
212968318Scgd 		kiov.iov_len = SCARG(uap, count);
213068318Scgd 		MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK);
213154620Smckusick 		kiov.iov_base = dirbuf;
213267362Smckusick 		error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
213368663Smckusick 			    (int *)0, (u_long *)0);
213456339Smckusick 		fp->f_offset = kuio.uio_offset;
213554620Smckusick 		if (error == 0) {
213668318Scgd 			readcnt = SCARG(uap, count) - kuio.uio_resid;
213754620Smckusick 			edp = (struct dirent *)&dirbuf[readcnt];
213854620Smckusick 			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
213954620Smckusick #				if (BYTE_ORDER == LITTLE_ENDIAN)
214054969Smckusick 					/*
214155009Smckusick 					 * The expected low byte of
214255009Smckusick 					 * dp->d_namlen is our dp->d_type.
214355009Smckusick 					 * The high MBZ byte of dp->d_namlen
214455009Smckusick 					 * is our dp->d_namlen.
214554969Smckusick 					 */
214655009Smckusick 					dp->d_type = dp->d_namlen;
214755009Smckusick 					dp->d_namlen = 0;
214855009Smckusick #				else
214955009Smckusick 					/*
215055009Smckusick 					 * The dp->d_type is the high byte
215155009Smckusick 					 * of the expected dp->d_namlen,
215255009Smckusick 					 * so must be zero'ed.
215355009Smckusick 					 */
215455009Smckusick 					dp->d_type = 0;
215554620Smckusick #				endif
215654620Smckusick 				if (dp->d_reclen > 0) {
215754620Smckusick 					dp = (struct dirent *)
215854620Smckusick 					    ((char *)dp + dp->d_reclen);
215954620Smckusick 				} else {
216054620Smckusick 					error = EIO;
216154620Smckusick 					break;
216254620Smckusick 				}
216354620Smckusick 			}
216454620Smckusick 			if (dp >= edp)
216554620Smckusick 				error = uiomove(dirbuf, readcnt, &auio);
216654620Smckusick 		}
216754620Smckusick 		FREE(dirbuf, M_TEMP);
216854620Smckusick 	}
2169*69409Smckusick 	VOP_UNLOCK(vp, 0, p);
217054620Smckusick 	if (error)
217154620Smckusick 		return (error);
217267362Smckusick 
217367362Smckusick #ifdef UNION
217467362Smckusick {
217567362Smckusick 	extern int (**union_vnodeop_p)();
217668079Spendry 	extern struct vnode *union_dircache __P((struct vnode *));
217767362Smckusick 
217868318Scgd 	if ((SCARG(uap, count) == auio.uio_resid) &&
217967362Smckusick 	    (vp->v_op == union_vnodeop_p)) {
218067362Smckusick 		struct vnode *lvp;
218167362Smckusick 
218268079Spendry 		lvp = union_dircache(vp);
218367362Smckusick 		if (lvp != NULLVP) {
218467575Spendry 			struct vattr va;
218567575Spendry 
218667575Spendry 			/*
218767575Spendry 			 * If the directory is opaque,
218867575Spendry 			 * then don't show lower entries
218967575Spendry 			 */
219067575Spendry 			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
219167575Spendry 			if (va.va_flags & OPAQUE) {
219268079Spendry 				vput(lvp);
219367575Spendry 				lvp = NULL;
219467575Spendry 			}
219567575Spendry 		}
219667575Spendry 
219767575Spendry 		if (lvp != NULLVP) {
219867362Smckusick 			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
2199*69409Smckusick 			VOP_UNLOCK(lvp, 0, p);
220067362Smckusick 
220167362Smckusick 			if (error) {
220267362Smckusick 				vrele(lvp);
220367362Smckusick 				return (error);
220467362Smckusick 			}
220567362Smckusick 			fp->f_data = (caddr_t) lvp;
220667362Smckusick 			fp->f_offset = 0;
220767362Smckusick 			error = vn_close(vp, FREAD, fp->f_cred, p);
220867362Smckusick 			if (error)
220967362Smckusick 				return (error);
221067362Smckusick 			vp = lvp;
221167362Smckusick 			goto unionread;
221267362Smckusick 		}
221367362Smckusick 	}
221467362Smckusick }
221567362Smckusick #endif /* UNION */
221667362Smckusick 
221768318Scgd 	if ((SCARG(uap, count) == auio.uio_resid) &&
221867362Smckusick 	    (vp->v_flag & VROOT) &&
221967362Smckusick 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
222067362Smckusick 		struct vnode *tvp = vp;
222167362Smckusick 		vp = vp->v_mount->mnt_vnodecovered;
222267362Smckusick 		VREF(vp);
222367362Smckusick 		fp->f_data = (caddr_t) vp;
222467362Smckusick 		fp->f_offset = 0;
222567362Smckusick 		vrele(tvp);
222667362Smckusick 		goto unionread;
222767362Smckusick 	}
222868318Scgd 	error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
222968318Scgd 	    sizeof(long));
223068318Scgd 	*retval = SCARG(uap, count) - auio.uio_resid;
223154620Smckusick 	return (error);
223254620Smckusick }
223367362Smckusick #endif /* COMPAT_43 */
223454620Smckusick 
223554620Smckusick /*
223654620Smckusick  * Read a block of directory entries in a file system independent format.
223754620Smckusick  */
223868318Scgd int
223942441Smckusick getdirentries(p, uap, retval)
224045914Smckusick 	struct proc *p;
224168318Scgd 	register struct getdirentries_args /* {
224268318Scgd 		syscallarg(int) fd;
224368318Scgd 		syscallarg(char *) buf;
224468318Scgd 		syscallarg(u_int) count;
224568318Scgd 		syscallarg(long *) basep;
224668318Scgd 	} */ *uap;
224768318Scgd 	register_t *retval;
224842441Smckusick {
224939592Smckusick 	register struct vnode *vp;
225016540Ssam 	struct file *fp;
225137741Smckusick 	struct uio auio;
225237741Smckusick 	struct iovec aiov;
225354969Smckusick 	long loff;
225467362Smckusick 	int error, eofflag;
225512756Ssam 
225668318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
225747540Skarels 		return (error);
225837741Smckusick 	if ((fp->f_flag & FREAD) == 0)
225947540Skarels 		return (EBADF);
226039592Smckusick 	vp = (struct vnode *)fp->f_data;
226155451Spendry unionread:
226239592Smckusick 	if (vp->v_type != VDIR)
226347540Skarels 		return (EINVAL);
226468318Scgd 	aiov.iov_base = SCARG(uap, buf);
226568318Scgd 	aiov.iov_len = SCARG(uap, count);
226637741Smckusick 	auio.uio_iov = &aiov;
226737741Smckusick 	auio.uio_iovcnt = 1;
226837741Smckusick 	auio.uio_rw = UIO_READ;
226937741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
227048026Smckusick 	auio.uio_procp = p;
227168318Scgd 	auio.uio_resid = SCARG(uap, count);
2272*69409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
227354969Smckusick 	loff = auio.uio_offset = fp->f_offset;
227468663Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
227568663Smckusick 			    (int *)0, (u_long *)0);
227639592Smckusick 	fp->f_offset = auio.uio_offset;
2277*69409Smckusick 	VOP_UNLOCK(vp, 0, p);
227839592Smckusick 	if (error)
227947540Skarels 		return (error);
228066095Spendry 
228166095Spendry #ifdef UNION
228266095Spendry {
228366095Spendry 	extern int (**union_vnodeop_p)();
228468079Spendry 	extern struct vnode *union_dircache __P((struct vnode *));
228566095Spendry 
228668318Scgd 	if ((SCARG(uap, count) == auio.uio_resid) &&
228766095Spendry 	    (vp->v_op == union_vnodeop_p)) {
228867122Spendry 		struct vnode *lvp;
228966095Spendry 
229068079Spendry 		lvp = union_dircache(vp);
229167122Spendry 		if (lvp != NULLVP) {
229267575Spendry 			struct vattr va;
229367575Spendry 
229467575Spendry 			/*
229567575Spendry 			 * If the directory is opaque,
229667575Spendry 			 * then don't show lower entries
229767575Spendry 			 */
229867575Spendry 			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
229967575Spendry 			if (va.va_flags & OPAQUE) {
230068079Spendry 				vput(lvp);
230167575Spendry 				lvp = NULL;
230267575Spendry 			}
230367575Spendry 		}
230467575Spendry 
230567575Spendry 		if (lvp != NULLVP) {
230667362Smckusick 			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
2307*69409Smckusick 			VOP_UNLOCK(lvp, 0, p);
230866095Spendry 
230966095Spendry 			if (error) {
231067122Spendry 				vrele(lvp);
231166095Spendry 				return (error);
231266095Spendry 			}
231367122Spendry 			fp->f_data = (caddr_t) lvp;
231466095Spendry 			fp->f_offset = 0;
231567122Spendry 			error = vn_close(vp, FREAD, fp->f_cred, p);
231666095Spendry 			if (error)
231766095Spendry 				return (error);
231867122Spendry 			vp = lvp;
231966095Spendry 			goto unionread;
232066095Spendry 		}
232166095Spendry 	}
232266095Spendry }
232368318Scgd #endif /* UNION */
232466095Spendry 
232568318Scgd 	if ((SCARG(uap, count) == auio.uio_resid) &&
232655451Spendry 	    (vp->v_flag & VROOT) &&
232755451Spendry 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
232855451Spendry 		struct vnode *tvp = vp;
232955451Spendry 		vp = vp->v_mount->mnt_vnodecovered;
233055451Spendry 		VREF(vp);
233155451Spendry 		fp->f_data = (caddr_t) vp;
233255451Spendry 		fp->f_offset = 0;
233355451Spendry 		vrele(tvp);
233455451Spendry 		goto unionread;
233555451Spendry 	}
233668318Scgd 	error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
233768318Scgd 	    sizeof(long));
233868318Scgd 	*retval = SCARG(uap, count) - auio.uio_resid;
233947540Skarels 	return (error);
234012756Ssam }
234112756Ssam 
234212756Ssam /*
234349365Smckusick  * Set the mode mask for creation of filesystem nodes.
234412756Ssam  */
234568318Scgd int
234642441Smckusick umask(p, uap, retval)
234745914Smckusick 	struct proc *p;
234868318Scgd 	struct umask_args /* {
234968318Scgd 		syscallarg(int) newmask;
235068318Scgd 	} */ *uap;
235168318Scgd 	register_t *retval;
235212756Ssam {
235364410Sbostic 	register struct filedesc *fdp;
235412756Ssam 
235564410Sbostic 	fdp = p->p_fd;
235645914Smckusick 	*retval = fdp->fd_cmask;
235768318Scgd 	fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS;
235847540Skarels 	return (0);
235912756Ssam }
236037741Smckusick 
236139566Smarc /*
236239566Smarc  * Void all references to file by ripping underlying filesystem
236339566Smarc  * away from vnode.
236439566Smarc  */
236542441Smckusick /* ARGSUSED */
236668318Scgd int
236742441Smckusick revoke(p, uap, retval)
236845914Smckusick 	struct proc *p;
236968318Scgd 	register struct revoke_args /* {
237068318Scgd 		syscallarg(char *) path;
237168318Scgd 	} */ *uap;
237268318Scgd 	register_t *retval;
237342441Smckusick {
237439566Smarc 	register struct vnode *vp;
237539566Smarc 	struct vattr vattr;
237639566Smarc 	int error;
237747540Skarels 	struct nameidata nd;
237839566Smarc 
237968318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
238052322Smckusick 	if (error = namei(&nd))
238147540Skarels 		return (error);
238252322Smckusick 	vp = nd.ni_vp;
238348026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
238439566Smarc 		goto out;
238547540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
238647540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
238739566Smarc 		goto out;
238839805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
238968423Smckusick 		VOP_REVOKE(vp, REVOKEALL);
239039566Smarc out:
239139566Smarc 	vrele(vp);
239247540Skarels 	return (error);
239339566Smarc }
239439566Smarc 
239549365Smckusick /*
239649365Smckusick  * Convert a user file descriptor to a kernel file entry.
239749365Smckusick  */
239868318Scgd int
239964410Sbostic getvnode(fdp, fd, fpp)
240045914Smckusick 	struct filedesc *fdp;
240137741Smckusick 	struct file **fpp;
240264410Sbostic 	int fd;
240337741Smckusick {
240437741Smckusick 	struct file *fp;
240537741Smckusick 
240664410Sbostic 	if ((u_int)fd >= fdp->fd_nfiles ||
240764410Sbostic 	    (fp = fdp->fd_ofiles[fd]) == NULL)
240837741Smckusick 		return (EBADF);
240937741Smckusick 	if (fp->f_type != DTYPE_VNODE)
241037741Smckusick 		return (EINVAL);
241137741Smckusick 	*fpp = fp;
241237741Smckusick 	return (0);
241337741Smckusick }
2414