xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 69903)
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*69903Smckusick  *	@(#)vfs_syscalls.c	8.41 (Berkeley) 06/15/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
mount(p,uap,retval)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 		}
11169578Smckusick 		if (vfs_busy(mp, LK_NOWAIT, 0, p)) {
11269578Smckusick 			vput(vp);
11369578Smckusick 			return (EBUSY);
11469578Smckusick 		}
11569409Smckusick 		VOP_UNLOCK(vp, 0, p);
11639335Smckusick 		goto update;
11739335Smckusick 	}
11867532Smckusick 	/*
11967532Smckusick 	 * If the user is not root, ensure that they own the directory
12067532Smckusick 	 * onto which we are attempting to mount.
12167532Smckusick 	 */
12267532Smckusick 	if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) ||
12367532Smckusick 	    (va.va_uid != p->p_ucred->cr_uid &&
12467532Smckusick 	     (error = suser(p->p_ucred, &p->p_acflag)))) {
12567532Smckusick 		vput(vp);
12667532Smckusick 		return (error);
12767532Smckusick 	}
12867532Smckusick 	/*
12967532Smckusick 	 * Do not allow NFS export by non-root users. Silently
13067532Smckusick 	 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
13167532Smckusick 	 */
13267532Smckusick 	if (p->p_ucred->cr_uid != 0) {
13368318Scgd 		if (SCARG(uap, flags) & MNT_EXPORTED) {
13467532Smckusick 			vput(vp);
13567532Smckusick 			return (EPERM);
13667532Smckusick 		}
13768318Scgd 		SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
13867532Smckusick 	}
13957793Smckusick 	if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0))
14054441Smckusick 		return (error);
14137741Smckusick 	if (vp->v_type != VDIR) {
14237741Smckusick 		vput(vp);
14347540Skarels 		return (ENOTDIR);
14437741Smckusick 	}
14568663Smckusick #ifdef COMPAT_43
14668663Smckusick 	/*
14768663Smckusick 	 * Historically filesystem types were identified by number. If we
14868663Smckusick 	 * get an integer for the filesystem type instead of a string, we
14968663Smckusick 	 * check to see if it matches one of the historic filesystem types.
15068663Smckusick 	 */
15168663Smckusick 	fstypenum = (u_long)SCARG(uap, type);
15268663Smckusick 	if (fstypenum < maxvfsconf) {
15368663Smckusick 		for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
15468663Smckusick 			if (vfsp->vfc_typenum == fstypenum)
15568663Smckusick 				break;
15668663Smckusick 		if (vfsp == NULL) {
15768663Smckusick 			vput(vp);
15868663Smckusick 			return (ENODEV);
15968663Smckusick 		}
16068663Smckusick 		strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN);
16168663Smckusick 	} else
16268663Smckusick #endif /* COMPAT_43 */
16368663Smckusick 	if (error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL)) {
16437741Smckusick 		vput(vp);
16568663Smckusick 		return (error);
16668663Smckusick 	}
16768663Smckusick 	for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
16868663Smckusick 		if (!strcmp(vfsp->vfc_name, fstypename))
16968663Smckusick 			break;
17068663Smckusick 	if (vfsp == NULL) {
17168663Smckusick 		vput(vp);
17247540Skarels 		return (ENODEV);
17337741Smckusick 	}
17467969Spendry 	if (vp->v_mountedhere != NULL) {
17567961Smckusick 		vput(vp);
17667961Smckusick 		return (EBUSY);
17767961Smckusick 	}
17837741Smckusick 
17937741Smckusick 	/*
18068663Smckusick 	 * Allocate and initialize the filesystem.
18137741Smckusick 	 */
18237741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
18337741Smckusick 		M_MOUNT, M_WAITOK);
18454172Smckusick 	bzero((char *)mp, (u_long)sizeof(struct mount));
18569578Smckusick 	lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0);
18669578Smckusick 	(void)vfs_busy(mp, LK_NOWAIT, 0, p);
18768663Smckusick 	mp->mnt_op = vfsp->vfc_vfsops;
18868663Smckusick 	mp->mnt_vfc = vfsp;
18968663Smckusick 	vfsp->vfc_refcount++;
19068663Smckusick 	mp->mnt_stat.f_type = vfsp->vfc_typenum;
19168663Smckusick 	mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
19268663Smckusick 	strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
19339335Smckusick 	vp->v_mountedhere = mp;
19441400Smckusick 	mp->mnt_vnodecovered = vp;
19567532Smckusick 	mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
19639335Smckusick update:
19739335Smckusick 	/*
19839335Smckusick 	 * Set the mount level flags.
19939335Smckusick 	 */
20068318Scgd 	if (SCARG(uap, flags) & MNT_RDONLY)
20141400Smckusick 		mp->mnt_flag |= MNT_RDONLY;
20257047Smckusick 	else if (mp->mnt_flag & MNT_RDONLY)
20357047Smckusick 		mp->mnt_flag |= MNT_WANTRDWR;
20465613Smckusick 	mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
20565613Smckusick 	    MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);
20668318Scgd 	mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC |
20768318Scgd 	    MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);
20839335Smckusick 	/*
20939335Smckusick 	 * Mount the filesystem.
21039335Smckusick 	 */
21168318Scgd 	error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p);
21241400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
21339335Smckusick 		vrele(vp);
21457047Smckusick 		if (mp->mnt_flag & MNT_WANTRDWR)
21557047Smckusick 			mp->mnt_flag &= ~MNT_RDONLY;
21657047Smckusick 		mp->mnt_flag &=~
21757047Smckusick 		    (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
21840111Smckusick 		if (error)
21941400Smckusick 			mp->mnt_flag = flag;
22069578Smckusick 		vfs_unbusy(mp, p);
22147540Skarels 		return (error);
22239335Smckusick 	}
22340110Smckusick 	/*
22440110Smckusick 	 * Put the new filesystem on the mount list after root.
22540110Smckusick 	 */
22637741Smckusick 	cache_purge(vp);
22737741Smckusick 	if (!error) {
22869578Smckusick 		simple_lock(&mountlist_slock);
22969325Smckusick 		CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
23069578Smckusick 		simple_unlock(&mountlist_slock);
23167974Smckusick 		checkdirs(vp);
23269409Smckusick 		VOP_UNLOCK(vp, 0, p);
23369578Smckusick 		vfs_unbusy(mp, p);
23469578Smckusick 		if (error = VFS_START(mp, 0, p))
23569578Smckusick 			vrele(vp);
23637741Smckusick 	} else {
23765259Smckusick 		mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
23868663Smckusick 		mp->mnt_vfc->vfc_refcount--;
23969578Smckusick 		vfs_unbusy(mp, p);
24037741Smckusick 		free((caddr_t)mp, M_MOUNT);
24139335Smckusick 		vput(vp);
24237741Smckusick 	}
24347540Skarels 	return (error);
2446254Sroot }
2456254Sroot 
2469167Ssam /*
24767974Smckusick  * Scan all active processes to see if any of them have a current
24867974Smckusick  * or root directory onto which the new filesystem has just been
24967974Smckusick  * mounted. If so, replace them with the new mount point.
25067974Smckusick  */
25168318Scgd static void
checkdirs(olddp)25267974Smckusick checkdirs(olddp)
25367974Smckusick 	struct vnode *olddp;
25467974Smckusick {
25567974Smckusick 	struct filedesc *fdp;
25667974Smckusick 	struct vnode *newdp;
25767974Smckusick 	struct proc *p;
25867974Smckusick 
25967974Smckusick 	if (olddp->v_usecount == 1)
26067974Smckusick 		return;
26167974Smckusick 	if (VFS_ROOT(olddp->v_mountedhere, &newdp))
26267974Smckusick 		panic("mount: lost mount");
26367974Smckusick 	for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
26467974Smckusick 		fdp = p->p_fd;
26567974Smckusick 		if (fdp->fd_cdir == olddp) {
26667974Smckusick 			vrele(fdp->fd_cdir);
26767974Smckusick 			VREF(newdp);
26867974Smckusick 			fdp->fd_cdir = newdp;
26967974Smckusick 		}
27067974Smckusick 		if (fdp->fd_rdir == olddp) {
27167974Smckusick 			vrele(fdp->fd_rdir);
27267974Smckusick 			VREF(newdp);
27367974Smckusick 			fdp->fd_rdir = newdp;
27467974Smckusick 		}
27567974Smckusick 	}
27667974Smckusick 	if (rootvnode == olddp) {
27767974Smckusick 		vrele(rootvnode);
27867974Smckusick 		VREF(newdp);
27967974Smckusick 		rootvnode = newdp;
28067974Smckusick 	}
28167974Smckusick 	vput(newdp);
28267974Smckusick }
28367974Smckusick 
28467974Smckusick /*
28564410Sbostic  * Unmount a file system.
28637741Smckusick  *
28737741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
28837741Smckusick  * not special file (as before).
2899167Ssam  */
29042441Smckusick /* ARGSUSED */
29168318Scgd int
unmount(p,uap,retval)29242441Smckusick unmount(p, uap, retval)
29345914Smckusick 	struct proc *p;
29468318Scgd 	register struct unmount_args /* {
29568318Scgd 		syscallarg(char *) path;
29668318Scgd 		syscallarg(int) flags;
29768318Scgd 	} */ *uap;
29868318Scgd 	register_t *retval;
29942441Smckusick {
30037741Smckusick 	register struct vnode *vp;
30139356Smckusick 	struct mount *mp;
30237741Smckusick 	int error;
30347540Skarels 	struct nameidata nd;
3046254Sroot 
30568318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
30668318Scgd 	    SCARG(uap, path), p);
30752322Smckusick 	if (error = namei(&nd))
30847540Skarels 		return (error);
30952322Smckusick 	vp = nd.ni_vp;
31067532Smckusick 	mp = vp->v_mount;
31166172Spendry 
31237741Smckusick 	/*
31367532Smckusick 	 * Only root, or the user that did the original mount is
31467532Smckusick 	 * permitted to unmount this filesystem.
31566172Spendry 	 */
31667532Smckusick 	if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) &&
31766172Spendry 	    (error = suser(p->p_ucred, &p->p_acflag))) {
31866172Spendry 		vput(vp);
31966172Spendry 		return (error);
32066172Spendry 	}
32166172Spendry 
32266172Spendry 	/*
32369334Smckusick 	 * Don't allow unmounting the root file system.
32469334Smckusick 	 */
32569334Smckusick 	if (mp->mnt_flag & MNT_ROOTFS) {
32669334Smckusick 		vput(vp);
32769334Smckusick 		return (EINVAL);
32869334Smckusick 	}
32969334Smckusick 
33069334Smckusick 	/*
33137741Smckusick 	 * Must be the root of the filesystem
33237741Smckusick 	 */
33337741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
33437741Smckusick 		vput(vp);
33547540Skarels 		return (EINVAL);
33637741Smckusick 	}
33737741Smckusick 	vput(vp);
33868318Scgd 	return (dounmount(mp, SCARG(uap, flags), p));
33939356Smckusick }
34039356Smckusick 
34139356Smckusick /*
34264410Sbostic  * Do the actual file system unmount.
34339356Smckusick  */
34468318Scgd int
dounmount(mp,flags,p)34548026Smckusick dounmount(mp, flags, p)
34639356Smckusick 	register struct mount *mp;
34739356Smckusick 	int flags;
34848026Smckusick 	struct proc *p;
34939356Smckusick {
35039356Smckusick 	struct vnode *coveredvp;
35139356Smckusick 	int error;
35239356Smckusick 
35369578Smckusick 	simple_lock(&mountlist_slock);
35441400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
35569578Smckusick 	lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock, p);
35665859Smckusick 	mp->mnt_flag &=~ MNT_ASYNC;
35745738Smckusick 	vnode_pager_umount(mp);	/* release cached vnodes */
35837741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
35969357Spendry 	if (((mp->mnt_flag & MNT_RDONLY) ||
36069357Spendry 	     (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) ||
36154441Smckusick 	    (flags & MNT_FORCE))
36248026Smckusick 		error = VFS_UNMOUNT(mp, flags, p);
36369578Smckusick 	simple_lock(&mountlist_slock);
36437741Smckusick 	if (error) {
36569578Smckusick 		mp->mnt_flag &= ~MNT_UNMOUNT;
36669578Smckusick 		lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE,
36769578Smckusick 		    &mountlist_slock, p);
36869578Smckusick 		return (error);
36937741Smckusick 	}
37069578Smckusick 	CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);
37169578Smckusick 	if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {
37269578Smckusick 		coveredvp->v_mountedhere = (struct mount *)0;
37369578Smckusick 		vrele(coveredvp);
37469578Smckusick 	}
37569578Smckusick 	mp->mnt_vfc->vfc_refcount--;
37669578Smckusick 	if (mp->mnt_vnodelist.lh_first != NULL)
37769578Smckusick 		panic("unmount: dangling vnode");
37869578Smckusick 	lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock, p);
37969578Smckusick 	if (mp->mnt_flag & MNT_MWAIT)
38069578Smckusick 		wakeup((caddr_t)mp);
38169578Smckusick 	free((caddr_t)mp, M_MOUNT);
38269578Smckusick 	return (0);
3836254Sroot }
3846254Sroot 
3859167Ssam /*
38637741Smckusick  * Sync each mounted filesystem.
3879167Ssam  */
38867403Smckusick #ifdef DEBUG
38956352Smckusick int syncprt = 0;
39059875Smckusick struct ctldebug debug0 = { "syncprt", &syncprt };
39156352Smckusick #endif
39256352Smckusick 
39339491Smckusick /* ARGSUSED */
39468318Scgd int
sync(p,uap,retval)39542441Smckusick sync(p, uap, retval)
39645914Smckusick 	struct proc *p;
39768318Scgd 	void *uap;
39868318Scgd 	register_t *retval;
3996254Sroot {
40065259Smckusick 	register struct mount *mp, *nmp;
40165859Smckusick 	int asyncflag;
40237741Smckusick 
40369578Smckusick 	simple_lock(&mountlist_slock);
40469325Smckusick 	for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
40569578Smckusick 		if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
40669578Smckusick 			nmp = mp->mnt_list.cqe_next;
40769578Smckusick 			continue;
40869578Smckusick 		}
40969578Smckusick 		if ((mp->mnt_flag & MNT_RDONLY) == 0) {
41065859Smckusick 			asyncflag = mp->mnt_flag & MNT_ASYNC;
41165859Smckusick 			mp->mnt_flag &= ~MNT_ASYNC;
41254441Smckusick 			VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
41365859Smckusick 			if (asyncflag)
41465859Smckusick 				mp->mnt_flag |= MNT_ASYNC;
41565259Smckusick 		}
41669578Smckusick 		simple_lock(&mountlist_slock);
41769578Smckusick 		nmp = mp->mnt_list.cqe_next;
41869578Smckusick 		vfs_unbusy(mp, p);
41965259Smckusick 	}
42069578Smckusick 	simple_unlock(&mountlist_slock);
42156352Smckusick #ifdef DIAGNOSTIC
42256352Smckusick 	if (syncprt)
42356352Smckusick 		vfs_bufstats();
42456352Smckusick #endif /* DIAGNOSTIC */
42547688Skarels 	return (0);
42637741Smckusick }
42737741Smckusick 
42837741Smckusick /*
42964410Sbostic  * Change filesystem quotas.
43041298Smckusick  */
43142441Smckusick /* ARGSUSED */
43268318Scgd int
quotactl(p,uap,retval)43342441Smckusick quotactl(p, uap, retval)
43445914Smckusick 	struct proc *p;
43568318Scgd 	register struct quotactl_args /* {
43668318Scgd 		syscallarg(char *) path;
43768318Scgd 		syscallarg(int) cmd;
43868318Scgd 		syscallarg(int) uid;
43968318Scgd 		syscallarg(caddr_t) arg;
44068318Scgd 	} */ *uap;
44168318Scgd 	register_t *retval;
44242441Smckusick {
44341298Smckusick 	register struct mount *mp;
44441298Smckusick 	int error;
44547540Skarels 	struct nameidata nd;
44641298Smckusick 
44768318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
44852322Smckusick 	if (error = namei(&nd))
44947540Skarels 		return (error);
45052322Smckusick 	mp = nd.ni_vp->v_mount;
45152322Smckusick 	vrele(nd.ni_vp);
45268318Scgd 	return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
45368318Scgd 	    SCARG(uap, arg), p));
45441298Smckusick }
45541298Smckusick 
45641298Smckusick /*
45749365Smckusick  * Get filesystem statistics.
45837741Smckusick  */
45942441Smckusick /* ARGSUSED */
46068318Scgd int
statfs(p,uap,retval)46142441Smckusick statfs(p, uap, retval)
46245914Smckusick 	struct proc *p;
46368318Scgd 	register struct statfs_args /* {
46468318Scgd 		syscallarg(char *) path;
46568318Scgd 		syscallarg(struct statfs *) buf;
46668318Scgd 	} */ *uap;
46768318Scgd 	register_t *retval;
46842441Smckusick {
46939464Smckusick 	register struct mount *mp;
47040343Smckusick 	register struct statfs *sp;
47137741Smckusick 	int error;
47247540Skarels 	struct nameidata nd;
47337741Smckusick 
47468318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
47552322Smckusick 	if (error = namei(&nd))
47647540Skarels 		return (error);
47752322Smckusick 	mp = nd.ni_vp->v_mount;
47841400Smckusick 	sp = &mp->mnt_stat;
47952322Smckusick 	vrele(nd.ni_vp);
48048026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
48147540Skarels 		return (error);
48241400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
48368318Scgd 	return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
48437741Smckusick }
48537741Smckusick 
48642441Smckusick /*
48749365Smckusick  * Get filesystem statistics.
48842441Smckusick  */
48942441Smckusick /* ARGSUSED */
49068318Scgd int
fstatfs(p,uap,retval)49142441Smckusick fstatfs(p, uap, retval)
49245914Smckusick 	struct proc *p;
49368318Scgd 	register struct fstatfs_args /* {
49468318Scgd 		syscallarg(int) fd;
49568318Scgd 		syscallarg(struct statfs *) buf;
49668318Scgd 	} */ *uap;
49768318Scgd 	register_t *retval;
49842441Smckusick {
49937741Smckusick 	struct file *fp;
50039464Smckusick 	struct mount *mp;
50140343Smckusick 	register struct statfs *sp;
50237741Smckusick 	int error;
50337741Smckusick 
50468318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
50547540Skarels 		return (error);
50639464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
50741400Smckusick 	sp = &mp->mnt_stat;
50848026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
50947540Skarels 		return (error);
51041400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
51168318Scgd 	return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
51237741Smckusick }
51337741Smckusick 
51437741Smckusick /*
51549365Smckusick  * Get statistics on all filesystems.
51638270Smckusick  */
51768318Scgd int
getfsstat(p,uap,retval)51842441Smckusick getfsstat(p, uap, retval)
51945914Smckusick 	struct proc *p;
52068318Scgd 	register struct getfsstat_args /* {
52168318Scgd 		syscallarg(struct statfs *) buf;
52268318Scgd 		syscallarg(long) bufsize;
52368318Scgd 		syscallarg(int) flags;
52468318Scgd 	} */ *uap;
52568318Scgd 	register_t *retval;
52642441Smckusick {
52765259Smckusick 	register struct mount *mp, *nmp;
52840343Smckusick 	register struct statfs *sp;
52939606Smckusick 	caddr_t sfsp;
53038270Smckusick 	long count, maxcount, error;
53138270Smckusick 
53268318Scgd 	maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
53368318Scgd 	sfsp = (caddr_t)SCARG(uap, buf);
53469325Smckusick 	count = 0;
53569578Smckusick 	simple_lock(&mountlist_slock);
53669325Smckusick 	for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
53769578Smckusick 		if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
53869578Smckusick 			nmp = mp->mnt_list.cqe_next;
53969578Smckusick 			continue;
54069578Smckusick 		}
54169578Smckusick 		if (sfsp && count < maxcount) {
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)) &&
549*69903Smckusick 			    (error = VFS_STATFS(mp, sp, p))) {
550*69903Smckusick 				simple_lock(&mountlist_slock);
551*69903Smckusick 				nmp = mp->mnt_list.cqe_next;
552*69903Smckusick 				vfs_unbusy(mp, p);
55339607Smckusick 				continue;
554*69903Smckusick 			}
55541400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
55640343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
55747540Skarels 				return (error);
55840343Smckusick 			sfsp += sizeof(*sp);
55938270Smckusick 		}
56039606Smckusick 		count++;
56169578Smckusick 		simple_lock(&mountlist_slock);
56269578Smckusick 		nmp = mp->mnt_list.cqe_next;
56369578Smckusick 		vfs_unbusy(mp, p);
56465259Smckusick 	}
56569578Smckusick 	simple_unlock(&mountlist_slock);
56638270Smckusick 	if (sfsp && count > maxcount)
56742441Smckusick 		*retval = maxcount;
56838270Smckusick 	else
56942441Smckusick 		*retval = count;
57047540Skarels 	return (0);
57138270Smckusick }
57238270Smckusick 
57338270Smckusick /*
57438259Smckusick  * Change current working directory to a given file descriptor.
57538259Smckusick  */
57642441Smckusick /* ARGSUSED */
57768318Scgd int
fchdir(p,uap,retval)57842441Smckusick fchdir(p, uap, retval)
57945914Smckusick 	struct proc *p;
58068318Scgd 	struct fchdir_args /* {
58168318Scgd 		syscallarg(int) fd;
58268318Scgd 	} */ *uap;
58368318Scgd 	register_t *retval;
58438259Smckusick {
58545914Smckusick 	register struct filedesc *fdp = p->p_fd;
58667974Smckusick 	struct vnode *vp, *tdp;
58767974Smckusick 	struct mount *mp;
58838259Smckusick 	struct file *fp;
58938259Smckusick 	int error;
59038259Smckusick 
59168318Scgd 	if (error = getvnode(fdp, SCARG(uap, fd), &fp))
59247540Skarels 		return (error);
59338259Smckusick 	vp = (struct vnode *)fp->f_data;
59467974Smckusick 	VREF(vp);
59569409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
59638259Smckusick 	if (vp->v_type != VDIR)
59738259Smckusick 		error = ENOTDIR;
59838259Smckusick 	else
59948026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
60067974Smckusick 	while (!error && (mp = vp->v_mountedhere) != NULL) {
60169578Smckusick 		if (vfs_busy(mp, 0, 0, p))
60267974Smckusick 			continue;
60369578Smckusick 		error = VFS_ROOT(mp, &tdp);
60469578Smckusick 		vfs_unbusy(mp, p);
60569578Smckusick 		if (error)
60667974Smckusick 			break;
60767974Smckusick 		vput(vp);
60867974Smckusick 		vp = tdp;
60967974Smckusick 	}
61067974Smckusick 	if (error) {
61169547Spendry 		vput(vp);
61247540Skarels 		return (error);
61367974Smckusick 	}
61469547Spendry 	VOP_UNLOCK(vp, 0, p);
61545914Smckusick 	vrele(fdp->fd_cdir);
61645914Smckusick 	fdp->fd_cdir = vp;
61747540Skarels 	return (0);
61838259Smckusick }
61938259Smckusick 
62038259Smckusick /*
62137741Smckusick  * Change current working directory (``.'').
62237741Smckusick  */
62342441Smckusick /* ARGSUSED */
62468318Scgd int
chdir(p,uap,retval)62542441Smckusick chdir(p, uap, retval)
62645914Smckusick 	struct proc *p;
62768318Scgd 	struct chdir_args /* {
62868318Scgd 		syscallarg(char *) path;
62968318Scgd 	} */ *uap;
63068318Scgd 	register_t *retval;
63137741Smckusick {
63245914Smckusick 	register struct filedesc *fdp = p->p_fd;
63337741Smckusick 	int error;
63447540Skarels 	struct nameidata nd;
6356254Sroot 
63668318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
63768318Scgd 	    SCARG(uap, path), p);
63864410Sbostic 	if (error = change_dir(&nd, p))
63947540Skarels 		return (error);
64045914Smckusick 	vrele(fdp->fd_cdir);
64152322Smckusick 	fdp->fd_cdir = nd.ni_vp;
64247540Skarels 	return (0);
64337741Smckusick }
6446254Sroot 
64537741Smckusick /*
64637741Smckusick  * Change notion of root (``/'') directory.
64737741Smckusick  */
64842441Smckusick /* ARGSUSED */
64968318Scgd int
chroot(p,uap,retval)65042441Smckusick chroot(p, uap, retval)
65145914Smckusick 	struct proc *p;
65268318Scgd 	struct chroot_args /* {
65368318Scgd 		syscallarg(char *) path;
65468318Scgd 	} */ *uap;
65568318Scgd 	register_t *retval;
65637741Smckusick {
65745914Smckusick 	register struct filedesc *fdp = p->p_fd;
65837741Smckusick 	int error;
65947540Skarels 	struct nameidata nd;
66037741Smckusick 
66147540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
66247540Skarels 		return (error);
66368318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
66468318Scgd 	    SCARG(uap, path), p);
66564410Sbostic 	if (error = change_dir(&nd, p))
66647540Skarels 		return (error);
66745914Smckusick 	if (fdp->fd_rdir != NULL)
66845914Smckusick 		vrele(fdp->fd_rdir);
66952322Smckusick 	fdp->fd_rdir = nd.ni_vp;
67047540Skarels 	return (0);
6716254Sroot }
6726254Sroot 
67337Sbill /*
67437741Smckusick  * Common routine for chroot and chdir.
67537741Smckusick  */
67664410Sbostic static int
change_dir(ndp,p)67764410Sbostic change_dir(ndp, p)
67852322Smckusick 	register struct nameidata *ndp;
67947540Skarels 	struct proc *p;
68037741Smckusick {
68137741Smckusick 	struct vnode *vp;
68237741Smckusick 	int error;
68337741Smckusick 
68452322Smckusick 	if (error = namei(ndp))
68537741Smckusick 		return (error);
68637741Smckusick 	vp = ndp->ni_vp;
68737741Smckusick 	if (vp->v_type != VDIR)
68837741Smckusick 		error = ENOTDIR;
68937741Smckusick 	else
69048026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
69137741Smckusick 	if (error)
69269547Spendry 		vput(vp);
69369547Spendry 	else
69469547Spendry 		VOP_UNLOCK(vp, 0, p);
69537741Smckusick 	return (error);
69637741Smckusick }
69737741Smckusick 
69837741Smckusick /*
69942441Smckusick  * Check permissions, allocate an open file structure,
70042441Smckusick  * and call the device open routine if any.
7016254Sroot  */
70268318Scgd int
open(p,uap,retval)70342441Smckusick open(p, uap, retval)
70445914Smckusick 	struct proc *p;
70568318Scgd 	register struct open_args /* {
70668318Scgd 		syscallarg(char *) path;
70768318Scgd 		syscallarg(int) flags;
70868318Scgd 		syscallarg(int) mode;
70968318Scgd 	} */ *uap;
71068318Scgd 	register_t *retval;
7116254Sroot {
71245914Smckusick 	register struct filedesc *fdp = p->p_fd;
71342441Smckusick 	register struct file *fp;
71450111Smckusick 	register struct vnode *vp;
71564410Sbostic 	int flags, cmode;
71637741Smckusick 	struct file *nfp;
71749945Smckusick 	int type, indx, error;
71849945Smckusick 	struct flock lf;
71947540Skarels 	struct nameidata nd;
72037741Smckusick 	extern struct fileops vnops;
7216254Sroot 
72245914Smckusick 	if (error = falloc(p, &nfp, &indx))
72347540Skarels 		return (error);
72437741Smckusick 	fp = nfp;
72568318Scgd 	flags = FFLAGS(SCARG(uap, flags));
72668318Scgd 	cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
72768318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
72845202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
72964410Sbostic 	if (error = vn_open(&nd, flags, cmode)) {
73049980Smckusick 		ffree(fp);
73154723Smckusick 		if ((error == ENODEV || error == ENXIO) &&
73268318Scgd 		    p->p_dupfd >= 0 &&			/* XXX from fdopen */
73364410Sbostic 		    (error =
73468318Scgd 			dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
73542441Smckusick 			*retval = indx;
73647540Skarels 			return (0);
73742441Smckusick 		}
73840884Smckusick 		if (error == ERESTART)
73940884Smckusick 			error = EINTR;
74047688Skarels 		fdp->fd_ofiles[indx] = NULL;
74147540Skarels 		return (error);
74212756Ssam 	}
74353828Spendry 	p->p_dupfd = 0;
74452322Smckusick 	vp = nd.ni_vp;
74564410Sbostic 	fp->f_flag = flags & FMASK;
74654348Smckusick 	fp->f_type = DTYPE_VNODE;
74754348Smckusick 	fp->f_ops = &vnops;
74854348Smckusick 	fp->f_data = (caddr_t)vp;
74964410Sbostic 	if (flags & (O_EXLOCK | O_SHLOCK)) {
75049945Smckusick 		lf.l_whence = SEEK_SET;
75149945Smckusick 		lf.l_start = 0;
75249945Smckusick 		lf.l_len = 0;
75364410Sbostic 		if (flags & O_EXLOCK)
75449945Smckusick 			lf.l_type = F_WRLCK;
75549945Smckusick 		else
75649945Smckusick 			lf.l_type = F_RDLCK;
75749945Smckusick 		type = F_FLOCK;
75864410Sbostic 		if ((flags & FNONBLOCK) == 0)
75949945Smckusick 			type |= F_WAIT;
76069409Smckusick 		VOP_UNLOCK(vp, 0, p);
76150111Smckusick 		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
76250111Smckusick 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
76349980Smckusick 			ffree(fp);
76449945Smckusick 			fdp->fd_ofiles[indx] = NULL;
76549945Smckusick 			return (error);
76649945Smckusick 		}
76769409Smckusick 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
76849949Smckusick 		fp->f_flag |= FHASLOCK;
76949945Smckusick 	}
77069409Smckusick 	VOP_UNLOCK(vp, 0, p);
77142441Smckusick 	*retval = indx;
77247540Skarels 	return (0);
7736254Sroot }
7746254Sroot 
77542955Smckusick #ifdef COMPAT_43
7766254Sroot /*
77764410Sbostic  * Create a file.
7786254Sroot  */
77968318Scgd int
compat_43_creat(p,uap,retval)78068318Scgd compat_43_creat(p, uap, retval)
78142441Smckusick 	struct proc *p;
78268318Scgd 	register struct compat_43_creat_args /* {
78368318Scgd 		syscallarg(char *) path;
78468318Scgd 		syscallarg(int) mode;
78568318Scgd 	} */ *uap;
78668318Scgd 	register_t *retval;
7876254Sroot {
78868318Scgd 	struct open_args /* {
78968318Scgd 		syscallarg(char *) path;
79068318Scgd 		syscallarg(int) flags;
79168318Scgd 		syscallarg(int) mode;
79268318Scgd 	} */ nuap;
79342441Smckusick 
79468318Scgd 	SCARG(&nuap, path) = SCARG(uap, path);
79568318Scgd 	SCARG(&nuap, mode) = SCARG(uap, mode);
79668318Scgd 	SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
79768318Scgd 	return (open(p, &nuap, retval));
79842441Smckusick }
79942955Smckusick #endif /* COMPAT_43 */
80042441Smckusick 
80142441Smckusick /*
80264410Sbostic  * Create a special file.
80342441Smckusick  */
80442441Smckusick /* ARGSUSED */
80568318Scgd int
mknod(p,uap,retval)80642441Smckusick mknod(p, uap, retval)
80745914Smckusick 	struct proc *p;
80868318Scgd 	register struct mknod_args /* {
80968318Scgd 		syscallarg(char *) path;
81068318Scgd 		syscallarg(int) mode;
81168318Scgd 		syscallarg(int) dev;
81268318Scgd 	} */ *uap;
81368318Scgd 	register_t *retval;
81442441Smckusick {
81537741Smckusick 	register struct vnode *vp;
81637741Smckusick 	struct vattr vattr;
81737741Smckusick 	int error;
81867575Spendry 	int whiteout;
81947540Skarels 	struct nameidata nd;
8206254Sroot 
82147540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
82247540Skarels 		return (error);
82368318Scgd 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
82452322Smckusick 	if (error = namei(&nd))
82547540Skarels 		return (error);
82652322Smckusick 	vp = nd.ni_vp;
82764585Sbostic 	if (vp != NULL)
82837741Smckusick 		error = EEXIST;
82964585Sbostic 	else {
83064585Sbostic 		VATTR_NULL(&vattr);
83168318Scgd 		vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
83268318Scgd 		vattr.va_rdev = SCARG(uap, dev);
83367575Spendry 		whiteout = 0;
83464585Sbostic 
83568318Scgd 		switch (SCARG(uap, mode) & S_IFMT) {
83664585Sbostic 		case S_IFMT:	/* used by badsect to flag bad sectors */
83764585Sbostic 			vattr.va_type = VBAD;
83864585Sbostic 			break;
83964585Sbostic 		case S_IFCHR:
84064585Sbostic 			vattr.va_type = VCHR;
84164585Sbostic 			break;
84264585Sbostic 		case S_IFBLK:
84364585Sbostic 			vattr.va_type = VBLK;
84464585Sbostic 			break;
84567575Spendry 		case S_IFWHT:
84667575Spendry 			whiteout = 1;
84767575Spendry 			break;
84864585Sbostic 		default:
84964585Sbostic 			error = EINVAL;
85064585Sbostic 			break;
85164585Sbostic 		}
8526254Sroot 	}
85367747Spendry 	if (!error) {
85467654Smckusick 		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
85567747Spendry 		if (whiteout) {
85667747Spendry 			error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
85767747Spendry 			if (error)
85867747Spendry 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
85967747Spendry 			vput(nd.ni_dvp);
86067747Spendry 		} else {
86167747Spendry 			error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
86267747Spendry 						&nd.ni_cnd, &vattr);
86367747Spendry 		}
86442465Smckusick 	} else {
86552322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
86652322Smckusick 		if (nd.ni_dvp == vp)
86752322Smckusick 			vrele(nd.ni_dvp);
86843344Smckusick 		else
86952322Smckusick 			vput(nd.ni_dvp);
87042465Smckusick 		if (vp)
87142465Smckusick 			vrele(vp);
87242465Smckusick 	}
87347540Skarels 	return (error);
8746254Sroot }
8756254Sroot 
8766254Sroot /*
87768318Scgd  * Create a named pipe.
87840285Smckusick  */
87942441Smckusick /* ARGSUSED */
88068318Scgd int
mkfifo(p,uap,retval)88142441Smckusick mkfifo(p, uap, retval)
88245914Smckusick 	struct proc *p;
88368318Scgd 	register struct mkfifo_args /* {
88468318Scgd 		syscallarg(char *) path;
88568318Scgd 		syscallarg(int) mode;
88668318Scgd 	} */ *uap;
88768318Scgd 	register_t *retval;
88842441Smckusick {
88940285Smckusick 	struct vattr vattr;
89040285Smckusick 	int error;
89147540Skarels 	struct nameidata nd;
89240285Smckusick 
89340285Smckusick #ifndef FIFO
89447540Skarels 	return (EOPNOTSUPP);
89540285Smckusick #else
89668318Scgd 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
89752322Smckusick 	if (error = namei(&nd))
89847540Skarels 		return (error);
89952322Smckusick 	if (nd.ni_vp != NULL) {
90052322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
90152322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
90252322Smckusick 			vrele(nd.ni_dvp);
90343344Smckusick 		else
90452322Smckusick 			vput(nd.ni_dvp);
90552322Smckusick 		vrele(nd.ni_vp);
90647540Skarels 		return (EEXIST);
90740285Smckusick 	}
90845785Sbostic 	VATTR_NULL(&vattr);
90945785Sbostic 	vattr.va_type = VFIFO;
91068318Scgd 	vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
91167654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
91252322Smckusick 	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
91340285Smckusick #endif /* FIFO */
91440285Smckusick }
91540285Smckusick 
91640285Smckusick /*
91764410Sbostic  * Make a hard file link.
9186254Sroot  */
91942441Smckusick /* ARGSUSED */
92068318Scgd int
link(p,uap,retval)92142441Smckusick link(p, uap, retval)
92245914Smckusick 	struct proc *p;
92368318Scgd 	register struct link_args /* {
92468318Scgd 		syscallarg(char *) path;
92568318Scgd 		syscallarg(char *) link;
92668318Scgd 	} */ *uap;
92768318Scgd 	register_t *retval;
92842441Smckusick {
92964410Sbostic 	register struct vnode *vp;
93064410Sbostic 	struct nameidata nd;
93137741Smckusick 	int error;
9326254Sroot 
93368318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
93452322Smckusick 	if (error = namei(&nd))
93547540Skarels 		return (error);
93652322Smckusick 	vp = nd.ni_vp;
93764585Sbostic 	if (vp->v_type != VDIR ||
93864585Sbostic 	    (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
93964585Sbostic 		nd.ni_cnd.cn_nameiop = CREATE;
94064585Sbostic 		nd.ni_cnd.cn_flags = LOCKPARENT;
94168318Scgd 		nd.ni_dirp = SCARG(uap, link);
94264585Sbostic 		if ((error = namei(&nd)) == 0) {
94364585Sbostic 			if (nd.ni_vp != NULL)
94464585Sbostic 				error = EEXIST;
94564585Sbostic 			if (!error) {
94667654Smckusick 				VOP_LEASE(nd.ni_dvp, p, p->p_ucred,
94767654Smckusick 				    LEASE_WRITE);
94867654Smckusick 				VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
94968538Smckusick 				error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd);
95064585Sbostic 			} else {
95164585Sbostic 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
95264585Sbostic 				if (nd.ni_dvp == nd.ni_vp)
95364585Sbostic 					vrele(nd.ni_dvp);
95464585Sbostic 				else
95564585Sbostic 					vput(nd.ni_dvp);
95664585Sbostic 				if (nd.ni_vp)
95764585Sbostic 					vrele(nd.ni_vp);
95864585Sbostic 			}
95964585Sbostic 		}
96042465Smckusick 	}
96164585Sbostic 	vrele(vp);
96247540Skarels 	return (error);
9636254Sroot }
9646254Sroot 
9656254Sroot /*
96649365Smckusick  * Make a symbolic link.
9676254Sroot  */
96842441Smckusick /* ARGSUSED */
96968318Scgd int
symlink(p,uap,retval)97042441Smckusick symlink(p, uap, retval)
97145914Smckusick 	struct proc *p;
97268318Scgd 	register struct symlink_args /* {
97368318Scgd 		syscallarg(char *) path;
97468318Scgd 		syscallarg(char *) link;
97568318Scgd 	} */ *uap;
97668318Scgd 	register_t *retval;
97742441Smckusick {
97837741Smckusick 	struct vattr vattr;
97964410Sbostic 	char *path;
98037741Smckusick 	int error;
98147540Skarels 	struct nameidata nd;
9826254Sroot 
98364410Sbostic 	MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
98468318Scgd 	if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL))
98542465Smckusick 		goto out;
98668318Scgd 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
98752322Smckusick 	if (error = namei(&nd))
98842465Smckusick 		goto out;
98952322Smckusick 	if (nd.ni_vp) {
99052322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
99152322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
99252322Smckusick 			vrele(nd.ni_dvp);
99343344Smckusick 		else
99452322Smckusick 			vput(nd.ni_dvp);
99552322Smckusick 		vrele(nd.ni_vp);
99637741Smckusick 		error = EEXIST;
99737741Smckusick 		goto out;
9986254Sroot 	}
99941362Smckusick 	VATTR_NULL(&vattr);
100064410Sbostic 	vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
100167654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
100264410Sbostic 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
100337741Smckusick out:
100464410Sbostic 	FREE(path, M_NAMEI);
100547540Skarels 	return (error);
10066254Sroot }
10076254Sroot 
10086254Sroot /*
100967518Spendry  * Delete a whiteout from the filesystem.
101067518Spendry  */
101167518Spendry /* ARGSUSED */
101268318Scgd int
undelete(p,uap,retval)101367845Smckusick undelete(p, uap, retval)
101467518Spendry 	struct proc *p;
101568318Scgd 	register struct undelete_args /* {
101668318Scgd 		syscallarg(char *) path;
101768318Scgd 	} */ *uap;
101868318Scgd 	register_t *retval;
101967518Spendry {
102067518Spendry 	int error;
102167518Spendry 	struct nameidata nd;
102267518Spendry 
102368318Scgd 	NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
102468318Scgd 	    SCARG(uap, path), p);
102567575Spendry 	error = namei(&nd);
102667575Spendry 	if (error)
102767518Spendry 		return (error);
102867575Spendry 
102967575Spendry 	if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
103067518Spendry 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
103167518Spendry 		if (nd.ni_dvp == nd.ni_vp)
103267518Spendry 			vrele(nd.ni_dvp);
103367518Spendry 		else
103467518Spendry 			vput(nd.ni_dvp);
103567518Spendry 		if (nd.ni_vp)
103667518Spendry 			vrele(nd.ni_vp);
103767518Spendry 		return (EEXIST);
103867518Spendry 	}
103967575Spendry 
104067654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
104167747Spendry 	if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE))
104267575Spendry 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
104367518Spendry 	vput(nd.ni_dvp);
104467518Spendry 	return (error);
104567518Spendry }
104667518Spendry 
104767518Spendry /*
104849365Smckusick  * Delete a name from the filesystem.
10496254Sroot  */
105042441Smckusick /* ARGSUSED */
105168318Scgd int
unlink(p,uap,retval)105242441Smckusick unlink(p, uap, retval)
105345914Smckusick 	struct proc *p;
105468318Scgd 	struct unlink_args /* {
105568318Scgd 		syscallarg(char *) path;
105668318Scgd 	} */ *uap;
105768318Scgd 	register_t *retval;
10586254Sroot {
105937741Smckusick 	register struct vnode *vp;
106037741Smckusick 	int error;
106147540Skarels 	struct nameidata nd;
10626254Sroot 
106368318Scgd 	NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
106452322Smckusick 	if (error = namei(&nd))
106547540Skarels 		return (error);
106652322Smckusick 	vp = nd.ni_vp;
106767654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
106869409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
106964410Sbostic 
107064585Sbostic 	if (vp->v_type != VDIR ||
107164585Sbostic 	    (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
107264585Sbostic 		/*
107364585Sbostic 		 * The root of a mounted filesystem cannot be deleted.
107464585Sbostic 		 */
107564585Sbostic 		if (vp->v_flag & VROOT)
107664585Sbostic 			error = EBUSY;
107764585Sbostic 		else
107864585Sbostic 			(void)vnode_pager_uncache(vp);
107964585Sbostic 	}
108064585Sbostic 
108164585Sbostic 	if (!error) {
108267654Smckusick 		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
108352322Smckusick 		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
108442465Smckusick 	} else {
108552322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
108652322Smckusick 		if (nd.ni_dvp == vp)
108752322Smckusick 			vrele(nd.ni_dvp);
108843344Smckusick 		else
108952322Smckusick 			vput(nd.ni_dvp);
109067575Spendry 		if (vp != NULLVP)
109167575Spendry 			vput(vp);
109242465Smckusick 	}
109347540Skarels 	return (error);
10946254Sroot }
10956254Sroot 
109664410Sbostic /*
109764410Sbostic  * Reposition read/write file offset.
109864410Sbostic  */
109968318Scgd int
lseek(p,uap,retval)110060414Smckusick lseek(p, uap, retval)
110153468Smckusick 	struct proc *p;
110268318Scgd 	register struct lseek_args /* {
110368318Scgd 		syscallarg(int) fd;
110468318Scgd 		syscallarg(int) pad;
110568318Scgd 		syscallarg(off_t) offset;
110668318Scgd 		syscallarg(int) whence;
110768318Scgd 	} */ *uap;
110868318Scgd 	register_t *retval;
110942441Smckusick {
111047540Skarels 	struct ucred *cred = p->p_ucred;
111145914Smckusick 	register struct filedesc *fdp = p->p_fd;
111242441Smckusick 	register struct file *fp;
111337741Smckusick 	struct vattr vattr;
111437741Smckusick 	int error;
11156254Sroot 
111668318Scgd 	if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
111768318Scgd 	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
111847540Skarels 		return (EBADF);
111937741Smckusick 	if (fp->f_type != DTYPE_VNODE)
112047540Skarels 		return (ESPIPE);
112168318Scgd 	switch (SCARG(uap, whence)) {
112213878Ssam 	case L_INCR:
112368318Scgd 		fp->f_offset += SCARG(uap, offset);
112413878Ssam 		break;
112513878Ssam 	case L_XTND:
112664410Sbostic 		if (error =
112764410Sbostic 		    VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p))
112847540Skarels 			return (error);
112968318Scgd 		fp->f_offset = SCARG(uap, offset) + vattr.va_size;
113013878Ssam 		break;
113113878Ssam 	case L_SET:
113268318Scgd 		fp->f_offset = SCARG(uap, offset);
113313878Ssam 		break;
113413878Ssam 	default:
113547540Skarels 		return (EINVAL);
113613878Ssam 	}
113754916Storek 	*(off_t *)retval = fp->f_offset;
113847540Skarels 	return (0);
11396254Sroot }
11406254Sroot 
114160414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
11426254Sroot /*
114364410Sbostic  * Reposition read/write file offset.
114460036Smckusick  */
114568318Scgd int
compat_43_lseek(p,uap,retval)114668318Scgd compat_43_lseek(p, uap, retval)
114760036Smckusick 	struct proc *p;
114868318Scgd 	register struct compat_43_lseek_args /* {
114968318Scgd 		syscallarg(int) fd;
115068318Scgd 		syscallarg(long) offset;
115168318Scgd 		syscallarg(int) whence;
115268318Scgd 	} */ *uap;
115368318Scgd 	register_t *retval;
115460036Smckusick {
115568318Scgd 	struct lseek_args /* {
115668318Scgd 		syscallarg(int) fd;
115768318Scgd 		syscallarg(int) pad;
115868318Scgd 		syscallarg(off_t) offset;
115968318Scgd 		syscallarg(int) whence;
116068318Scgd 	} */ nuap;
116160036Smckusick 	off_t qret;
116260036Smckusick 	int error;
116360036Smckusick 
116468318Scgd 	SCARG(&nuap, fd) = SCARG(uap, fd);
116568318Scgd 	SCARG(&nuap, offset) = SCARG(uap, offset);
116668318Scgd 	SCARG(&nuap, whence) = SCARG(uap, whence);
116760428Smckusick 	error = lseek(p, &nuap, &qret);
116860036Smckusick 	*(long *)retval = qret;
116960036Smckusick 	return (error);
117060036Smckusick }
117160414Smckusick #endif /* COMPAT_43 */
117260036Smckusick 
117360036Smckusick /*
117449365Smckusick  * Check access permissions.
11756254Sroot  */
117668318Scgd int
access(p,uap,retval)117763427Sbostic access(p, uap, retval)
117845914Smckusick 	struct proc *p;
117968318Scgd 	register struct access_args /* {
118068318Scgd 		syscallarg(char *) path;
118168318Scgd 		syscallarg(int) flags;
118268318Scgd 	} */ *uap;
118368318Scgd 	register_t *retval;
118442441Smckusick {
118547540Skarels 	register struct ucred *cred = p->p_ucred;
118637741Smckusick 	register struct vnode *vp;
118764585Sbostic 	int error, flags, t_gid, t_uid;
118847540Skarels 	struct nameidata nd;
11896254Sroot 
119064585Sbostic 	t_uid = cred->cr_uid;
119164585Sbostic 	t_gid = cred->cr_groups[0];
119247540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
119347540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
119468318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
119568318Scgd 	    SCARG(uap, path), p);
119652322Smckusick 	if (error = namei(&nd))
119737741Smckusick 		goto out1;
119852322Smckusick 	vp = nd.ni_vp;
119964410Sbostic 
120064410Sbostic 	/* Flags == 0 means only check for existence. */
120168318Scgd 	if (SCARG(uap, flags)) {
120264410Sbostic 		flags = 0;
120368318Scgd 		if (SCARG(uap, flags) & R_OK)
120464410Sbostic 			flags |= VREAD;
120568318Scgd 		if (SCARG(uap, flags) & W_OK)
120664410Sbostic 			flags |= VWRITE;
120768318Scgd 		if (SCARG(uap, flags) & X_OK)
120864410Sbostic 			flags |= VEXEC;
120964410Sbostic 		if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
121064410Sbostic 			error = VOP_ACCESS(vp, flags, cred, p);
12116254Sroot 	}
121237741Smckusick 	vput(vp);
121337741Smckusick out1:
121464585Sbostic 	cred->cr_uid = t_uid;
121564585Sbostic 	cred->cr_groups[0] = t_gid;
121647540Skarels 	return (error);
12176254Sroot }
12186254Sroot 
121954348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
12206254Sroot /*
122164410Sbostic  * Get file status; this version follows links.
122237Sbill  */
122342441Smckusick /* ARGSUSED */
122468318Scgd int
compat_43_stat(p,uap,retval)122568318Scgd compat_43_stat(p, uap, retval)
122645914Smckusick 	struct proc *p;
122768318Scgd 	register struct compat_43_stat_args /* {
122868318Scgd 		syscallarg(char *) path;
122968318Scgd 		syscallarg(struct ostat *) ub;
123068318Scgd 	} */ *uap;
123168318Scgd 	register_t *retval;
123253468Smckusick {
123353468Smckusick 	struct stat sb;
123453468Smckusick 	struct ostat osb;
123553468Smckusick 	int error;
123653468Smckusick 	struct nameidata nd;
123753468Smckusick 
123868318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
123968318Scgd 	    SCARG(uap, path), p);
124053468Smckusick 	if (error = namei(&nd))
124153468Smckusick 		return (error);
124253468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
124353468Smckusick 	vput(nd.ni_vp);
124453468Smckusick 	if (error)
124553468Smckusick 		return (error);
124653468Smckusick 	cvtstat(&sb, &osb);
124768318Scgd 	error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
124853468Smckusick 	return (error);
124953468Smckusick }
125053468Smckusick 
125153468Smckusick /*
125264410Sbostic  * Get file status; this version does not follow links.
125353468Smckusick  */
125453468Smckusick /* ARGSUSED */
125568318Scgd int
compat_43_lstat(p,uap,retval)125668318Scgd compat_43_lstat(p, uap, retval)
125753468Smckusick 	struct proc *p;
125868318Scgd 	register struct compat_43_lstat_args /* {
125968318Scgd 		syscallarg(char *) path;
126068318Scgd 		syscallarg(struct ostat *) ub;
126168318Scgd 	} */ *uap;
126268318Scgd 	register_t *retval;
126353468Smckusick {
126467748Smckusick 	struct vnode *vp, *dvp;
126567748Smckusick 	struct stat sb, sb1;
126653468Smckusick 	struct ostat osb;
126753468Smckusick 	int error;
126853468Smckusick 	struct nameidata nd;
126953468Smckusick 
127067748Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
127168318Scgd 	    SCARG(uap, path), p);
127253468Smckusick 	if (error = namei(&nd))
127353468Smckusick 		return (error);
127467748Smckusick 	/*
127567748Smckusick 	 * For symbolic links, always return the attributes of its
127667748Smckusick 	 * containing directory, except for mode, size, and links.
127767748Smckusick 	 */
127867748Smckusick 	vp = nd.ni_vp;
127967748Smckusick 	dvp = nd.ni_dvp;
128067748Smckusick 	if (vp->v_type != VLNK) {
128167748Smckusick 		if (dvp == vp)
128267748Smckusick 			vrele(dvp);
128367748Smckusick 		else
128467748Smckusick 			vput(dvp);
128567748Smckusick 		error = vn_stat(vp, &sb, p);
128667748Smckusick 		vput(vp);
128767748Smckusick 		if (error)
128867748Smckusick 			return (error);
128967748Smckusick 	} else {
129067748Smckusick 		error = vn_stat(dvp, &sb, p);
129167748Smckusick 		vput(dvp);
129267748Smckusick 		if (error) {
129367748Smckusick 			vput(vp);
129467748Smckusick 			return (error);
129567748Smckusick 		}
129667748Smckusick 		error = vn_stat(vp, &sb1, p);
129767748Smckusick 		vput(vp);
129867748Smckusick 		if (error)
129967748Smckusick 			return (error);
130067748Smckusick 		sb.st_mode &= ~S_IFDIR;
130167748Smckusick 		sb.st_mode |= S_IFLNK;
130267748Smckusick 		sb.st_nlink = sb1.st_nlink;
130367748Smckusick 		sb.st_size = sb1.st_size;
130467748Smckusick 		sb.st_blocks = sb1.st_blocks;
130567748Smckusick 	}
130653468Smckusick 	cvtstat(&sb, &osb);
130768318Scgd 	error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
130853468Smckusick 	return (error);
130953468Smckusick }
131053468Smckusick 
131153468Smckusick /*
131264410Sbostic  * Convert from an old to a new stat structure.
131353468Smckusick  */
131468318Scgd void
cvtstat(st,ost)131553468Smckusick cvtstat(st, ost)
131653468Smckusick 	struct stat *st;
131753468Smckusick 	struct ostat *ost;
131853468Smckusick {
131953468Smckusick 
132053468Smckusick 	ost->st_dev = st->st_dev;
132153468Smckusick 	ost->st_ino = st->st_ino;
132253468Smckusick 	ost->st_mode = st->st_mode;
132353468Smckusick 	ost->st_nlink = st->st_nlink;
132453468Smckusick 	ost->st_uid = st->st_uid;
132553468Smckusick 	ost->st_gid = st->st_gid;
132653468Smckusick 	ost->st_rdev = st->st_rdev;
132753468Smckusick 	if (st->st_size < (quad_t)1 << 32)
132853468Smckusick 		ost->st_size = st->st_size;
132953468Smckusick 	else
133053468Smckusick 		ost->st_size = -2;
133153468Smckusick 	ost->st_atime = st->st_atime;
133253468Smckusick 	ost->st_mtime = st->st_mtime;
133353468Smckusick 	ost->st_ctime = st->st_ctime;
133453468Smckusick 	ost->st_blksize = st->st_blksize;
133553468Smckusick 	ost->st_blocks = st->st_blocks;
133653468Smckusick 	ost->st_flags = st->st_flags;
133753468Smckusick 	ost->st_gen = st->st_gen;
133853468Smckusick }
133954348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
134053468Smckusick 
134153468Smckusick /*
134264410Sbostic  * Get file status; this version follows links.
134353468Smckusick  */
134453468Smckusick /* ARGSUSED */
134568318Scgd int
stat(p,uap,retval)134653759Smckusick stat(p, uap, retval)
134753468Smckusick 	struct proc *p;
134868318Scgd 	register struct stat_args /* {
134968318Scgd 		syscallarg(char *) path;
135068318Scgd 		syscallarg(struct stat *) ub;
135168318Scgd 	} */ *uap;
135268318Scgd 	register_t *retval;
135337Sbill {
135442441Smckusick 	struct stat sb;
135542441Smckusick 	int error;
135647540Skarels 	struct nameidata nd;
135737Sbill 
135868318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
135968318Scgd 	    SCARG(uap, path), p);
136052322Smckusick 	if (error = namei(&nd))
136147540Skarels 		return (error);
136252322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
136352322Smckusick 	vput(nd.ni_vp);
136442441Smckusick 	if (error)
136547540Skarels 		return (error);
136668318Scgd 	error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
136747540Skarels 	return (error);
136837Sbill }
136937Sbill 
137037Sbill /*
137164410Sbostic  * Get file status; this version does not follow links.
13725992Swnj  */
137342441Smckusick /* ARGSUSED */
137468318Scgd int
lstat(p,uap,retval)137553759Smckusick lstat(p, uap, retval)
137645914Smckusick 	struct proc *p;
137768318Scgd 	register struct lstat_args /* {
137868318Scgd 		syscallarg(char *) path;
137968318Scgd 		syscallarg(struct stat *) ub;
138068318Scgd 	} */ *uap;
138168318Scgd 	register_t *retval;
138242441Smckusick {
138337741Smckusick 	int error;
138459373Smckusick 	struct vnode *vp, *dvp;
138559373Smckusick 	struct stat sb, sb1;
138647540Skarels 	struct nameidata nd;
13875992Swnj 
138859373Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
138968318Scgd 	    SCARG(uap, path), p);
139052322Smckusick 	if (error = namei(&nd))
139147540Skarels 		return (error);
139259373Smckusick 	/*
139368579Smckusick 	 * For symbolic links, always return the attributes of its containing
139468579Smckusick 	 * directory, except for mode, size, inode number, and links.
139559373Smckusick 	 */
139659373Smckusick 	vp = nd.ni_vp;
139759373Smckusick 	dvp = nd.ni_dvp;
139859373Smckusick 	if (vp->v_type != VLNK) {
139959373Smckusick 		if (dvp == vp)
140059373Smckusick 			vrele(dvp);
140159373Smckusick 		else
140259373Smckusick 			vput(dvp);
140359373Smckusick 		error = vn_stat(vp, &sb, p);
140459373Smckusick 		vput(vp);
140559373Smckusick 		if (error)
140659373Smckusick 			return (error);
140759373Smckusick 	} else {
140859373Smckusick 		error = vn_stat(dvp, &sb, p);
140959373Smckusick 		vput(dvp);
141059373Smckusick 		if (error) {
141159373Smckusick 			vput(vp);
141259373Smckusick 			return (error);
141359373Smckusick 		}
141459373Smckusick 		error = vn_stat(vp, &sb1, p);
141559373Smckusick 		vput(vp);
141659373Smckusick 		if (error)
141759373Smckusick 			return (error);
141859373Smckusick 		sb.st_mode &= ~S_IFDIR;
141959373Smckusick 		sb.st_mode |= S_IFLNK;
142059373Smckusick 		sb.st_nlink = sb1.st_nlink;
142159373Smckusick 		sb.st_size = sb1.st_size;
142259373Smckusick 		sb.st_blocks = sb1.st_blocks;
142368579Smckusick 		sb.st_ino = sb1.st_ino;
142459373Smckusick 	}
142568318Scgd 	error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
142647540Skarels 	return (error);
14275992Swnj }
14285992Swnj 
14295992Swnj /*
143064410Sbostic  * Get configurable pathname variables.
143160414Smckusick  */
143260414Smckusick /* ARGSUSED */
143368318Scgd int
pathconf(p,uap,retval)143460414Smckusick pathconf(p, uap, retval)
143560414Smckusick 	struct proc *p;
143668318Scgd 	register struct pathconf_args /* {
143768318Scgd 		syscallarg(char *) path;
143868318Scgd 		syscallarg(int) name;
143968318Scgd 	} */ *uap;
144068318Scgd 	register_t *retval;
144160414Smckusick {
144260414Smckusick 	int error;
144360414Smckusick 	struct nameidata nd;
144460414Smckusick 
144568318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
144668318Scgd 	    SCARG(uap, path), p);
144760414Smckusick 	if (error = namei(&nd))
144860414Smckusick 		return (error);
144968318Scgd 	error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
145060414Smckusick 	vput(nd.ni_vp);
145160414Smckusick 	return (error);
145260414Smckusick }
145360414Smckusick 
145460414Smckusick /*
145549365Smckusick  * Return target name of a symbolic link.
145637Sbill  */
145742441Smckusick /* ARGSUSED */
145868318Scgd int
readlink(p,uap,retval)145942441Smckusick readlink(p, uap, retval)
146045914Smckusick 	struct proc *p;
146168318Scgd 	register struct readlink_args /* {
146268318Scgd 		syscallarg(char *) path;
146368318Scgd 		syscallarg(char *) buf;
146468318Scgd 		syscallarg(int) count;
146568318Scgd 	} */ *uap;
146668318Scgd 	register_t *retval;
146742441Smckusick {
146837741Smckusick 	register struct vnode *vp;
146937741Smckusick 	struct iovec aiov;
147037741Smckusick 	struct uio auio;
147137741Smckusick 	int error;
147247540Skarels 	struct nameidata nd;
14735992Swnj 
147468318Scgd 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
147568318Scgd 	    SCARG(uap, path), p);
147652322Smckusick 	if (error = namei(&nd))
147747540Skarels 		return (error);
147852322Smckusick 	vp = nd.ni_vp;
147964410Sbostic 	if (vp->v_type != VLNK)
148037741Smckusick 		error = EINVAL;
148164410Sbostic 	else {
148268318Scgd 		aiov.iov_base = SCARG(uap, buf);
148368318Scgd 		aiov.iov_len = SCARG(uap, count);
148464410Sbostic 		auio.uio_iov = &aiov;
148564410Sbostic 		auio.uio_iovcnt = 1;
148664410Sbostic 		auio.uio_offset = 0;
148764410Sbostic 		auio.uio_rw = UIO_READ;
148864410Sbostic 		auio.uio_segflg = UIO_USERSPACE;
148964410Sbostic 		auio.uio_procp = p;
149068318Scgd 		auio.uio_resid = SCARG(uap, count);
149164410Sbostic 		error = VOP_READLINK(vp, &auio, p->p_ucred);
14925992Swnj 	}
149337741Smckusick 	vput(vp);
149468318Scgd 	*retval = SCARG(uap, count) - auio.uio_resid;
149547540Skarels 	return (error);
14965992Swnj }
14975992Swnj 
14989167Ssam /*
149964410Sbostic  * Change flags of a file given a path name.
150038259Smckusick  */
150142441Smckusick /* ARGSUSED */
150268318Scgd int
chflags(p,uap,retval)150342441Smckusick chflags(p, uap, retval)
150445914Smckusick 	struct proc *p;
150568318Scgd 	register struct chflags_args /* {
150668318Scgd 		syscallarg(char *) path;
150768318Scgd 		syscallarg(int) flags;
150868318Scgd 	} */ *uap;
150968318Scgd 	register_t *retval;
151042441Smckusick {
151138259Smckusick 	register struct vnode *vp;
151238259Smckusick 	struct vattr vattr;
151338259Smckusick 	int error;
151447540Skarels 	struct nameidata nd;
151538259Smckusick 
151668318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
151752322Smckusick 	if (error = namei(&nd))
151847540Skarels 		return (error);
151952322Smckusick 	vp = nd.ni_vp;
152067654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
152169409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
152269738Smckusick 	VATTR_NULL(&vattr);
152369738Smckusick 	vattr.va_flags = SCARG(uap, flags);
152469738Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
152538259Smckusick 	vput(vp);
152647540Skarels 	return (error);
152738259Smckusick }
152838259Smckusick 
152938259Smckusick /*
153038259Smckusick  * Change flags of a file given a file descriptor.
153138259Smckusick  */
153242441Smckusick /* ARGSUSED */
153368318Scgd int
fchflags(p,uap,retval)153442441Smckusick fchflags(p, uap, retval)
153545914Smckusick 	struct proc *p;
153668318Scgd 	register struct fchflags_args /* {
153768318Scgd 		syscallarg(int) fd;
153868318Scgd 		syscallarg(int) flags;
153968318Scgd 	} */ *uap;
154068318Scgd 	register_t *retval;
154142441Smckusick {
154238259Smckusick 	struct vattr vattr;
154338259Smckusick 	struct vnode *vp;
154438259Smckusick 	struct file *fp;
154538259Smckusick 	int error;
154638259Smckusick 
154768318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
154847540Skarels 		return (error);
154938259Smckusick 	vp = (struct vnode *)fp->f_data;
155067654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
155169409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
155269738Smckusick 	VATTR_NULL(&vattr);
155369738Smckusick 	vattr.va_flags = SCARG(uap, flags);
155469738Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
155569409Smckusick 	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
chmod(p,uap,retval)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);
158269409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
158369738Smckusick 	VATTR_NULL(&vattr);
158469738Smckusick 	vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
158569738Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
158637741Smckusick 	vput(vp);
158747540Skarels 	return (error);
15887701Ssam }
15897439Sroot 
15909167Ssam /*
15919167Ssam  * Change mode of a file given a file descriptor.
15929167Ssam  */
159342441Smckusick /* ARGSUSED */
159468318Scgd int
fchmod(p,uap,retval)159542441Smckusick fchmod(p, uap, retval)
159645914Smckusick 	struct proc *p;
159768318Scgd 	register struct fchmod_args /* {
159868318Scgd 		syscallarg(int) fd;
159968318Scgd 		syscallarg(int) mode;
160068318Scgd 	} */ *uap;
160168318Scgd 	register_t *retval;
160242441Smckusick {
160337741Smckusick 	struct vattr vattr;
160437741Smckusick 	struct vnode *vp;
160537741Smckusick 	struct file *fp;
160637741Smckusick 	int error;
16077701Ssam 
160868318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
160947540Skarels 		return (error);
161037741Smckusick 	vp = (struct vnode *)fp->f_data;
161167654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
161269409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
161369738Smckusick 	VATTR_NULL(&vattr);
161469738Smckusick 	vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
161569738Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
161669409Smckusick 	VOP_UNLOCK(vp, 0, p);
161747540Skarels 	return (error);
16185992Swnj }
16195992Swnj 
16209167Ssam /*
16219167Ssam  * Set ownership given a path name.
16229167Ssam  */
162342441Smckusick /* ARGSUSED */
162468318Scgd int
chown(p,uap,retval)162542441Smckusick chown(p, uap, retval)
162645914Smckusick 	struct proc *p;
162768318Scgd 	register struct chown_args /* {
162868318Scgd 		syscallarg(char *) path;
162968318Scgd 		syscallarg(int) uid;
163068318Scgd 		syscallarg(int) gid;
163168318Scgd 	} */ *uap;
163268318Scgd 	register_t *retval;
163342441Smckusick {
163437741Smckusick 	register struct vnode *vp;
163537741Smckusick 	struct vattr vattr;
163637741Smckusick 	int error;
163747540Skarels 	struct nameidata nd;
163837Sbill 
163968318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
164052322Smckusick 	if (error = namei(&nd))
164147540Skarels 		return (error);
164252322Smckusick 	vp = nd.ni_vp;
164367654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
164469409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
164569738Smckusick 	VATTR_NULL(&vattr);
164669738Smckusick 	vattr.va_uid = SCARG(uap, uid);
164769738Smckusick 	vattr.va_gid = SCARG(uap, gid);
164869738Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
164937741Smckusick 	vput(vp);
165047540Skarels 	return (error);
16517701Ssam }
16527439Sroot 
16539167Ssam /*
16549167Ssam  * Set ownership given a file descriptor.
16559167Ssam  */
165642441Smckusick /* ARGSUSED */
165768318Scgd int
fchown(p,uap,retval)165842441Smckusick fchown(p, uap, retval)
165945914Smckusick 	struct proc *p;
166068318Scgd 	register struct fchown_args /* {
166168318Scgd 		syscallarg(int) fd;
166268318Scgd 		syscallarg(int) uid;
166368318Scgd 		syscallarg(int) gid;
166468318Scgd 	} */ *uap;
166568318Scgd 	register_t *retval;
166642441Smckusick {
166737741Smckusick 	struct vattr vattr;
166837741Smckusick 	struct vnode *vp;
166937741Smckusick 	struct file *fp;
167037741Smckusick 	int error;
16717701Ssam 
167268318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
167347540Skarels 		return (error);
167437741Smckusick 	vp = (struct vnode *)fp->f_data;
167567654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
167669409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
167769738Smckusick 	VATTR_NULL(&vattr);
167869738Smckusick 	vattr.va_uid = SCARG(uap, uid);
167969738Smckusick 	vattr.va_gid = SCARG(uap, gid);
168069738Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
168169409Smckusick 	VOP_UNLOCK(vp, 0, p);
168247540Skarels 	return (error);
16837701Ssam }
16847701Ssam 
168542441Smckusick /*
168642441Smckusick  * Set the access and modification times of a file.
168742441Smckusick  */
168842441Smckusick /* ARGSUSED */
168968318Scgd int
utimes(p,uap,retval)169042441Smckusick utimes(p, uap, retval)
169145914Smckusick 	struct proc *p;
169268318Scgd 	register struct utimes_args /* {
169368318Scgd 		syscallarg(char *) path;
169468318Scgd 		syscallarg(struct timeval *) tptr;
169568318Scgd 	} */ *uap;
169668318Scgd 	register_t *retval;
169742441Smckusick {
169837741Smckusick 	register struct vnode *vp;
169911811Ssam 	struct timeval tv[2];
170037741Smckusick 	struct vattr vattr;
170158840Storek 	int error;
170247540Skarels 	struct nameidata nd;
170311811Ssam 
170458505Sbostic 	VATTR_NULL(&vattr);
170568318Scgd 	if (SCARG(uap, tptr) == NULL) {
170658505Sbostic 		microtime(&tv[0]);
170758505Sbostic 		tv[1] = tv[0];
170858548Sbostic 		vattr.va_vaflags |= VA_UTIMES_NULL;
170968318Scgd 	} else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv,
171068318Scgd 	    sizeof (tv)))
171158505Sbostic   		return (error);
171268318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
171352322Smckusick 	if (error = namei(&nd))
171447540Skarels 		return (error);
171552322Smckusick 	vp = nd.ni_vp;
171667654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
171769409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
171869738Smckusick 	vattr.va_atime.ts_sec = tv[0].tv_sec;
171969738Smckusick 	vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
172069738Smckusick 	vattr.va_mtime.ts_sec = tv[1].tv_sec;
172169738Smckusick 	vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
172269738Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
172337741Smckusick 	vput(vp);
172447540Skarels 	return (error);
172511811Ssam }
172611811Ssam 
172764410Sbostic /*
172864410Sbostic  * Truncate a file given its path name.
172964410Sbostic  */
173053468Smckusick /* ARGSUSED */
173168318Scgd int
truncate(p,uap,retval)173260414Smckusick truncate(p, uap, retval)
173353468Smckusick 	struct proc *p;
173468318Scgd 	register struct truncate_args /* {
173568318Scgd 		syscallarg(char *) path;
173668318Scgd 		syscallarg(int) pad;
173768318Scgd 		syscallarg(off_t) length;
173868318Scgd 	} */ *uap;
173968318Scgd 	register_t *retval;
174053468Smckusick {
174137741Smckusick 	register struct vnode *vp;
174237741Smckusick 	struct vattr vattr;
174337741Smckusick 	int error;
174447540Skarels 	struct nameidata nd;
17457701Ssam 
174668318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
174752322Smckusick 	if (error = namei(&nd))
174847540Skarels 		return (error);
174952322Smckusick 	vp = nd.ni_vp;
175067654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
175169409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
175264410Sbostic 	if (vp->v_type == VDIR)
175337741Smckusick 		error = EISDIR;
175464410Sbostic 	else if ((error = vn_writechk(vp)) == 0 &&
175564410Sbostic 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
175664410Sbostic 		VATTR_NULL(&vattr);
175768318Scgd 		vattr.va_size = SCARG(uap, length);
175864410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
17597701Ssam 	}
176037741Smckusick 	vput(vp);
176147540Skarels 	return (error);
17627701Ssam }
17637701Ssam 
176464410Sbostic /*
176564410Sbostic  * Truncate a file given a file descriptor.
176664410Sbostic  */
176742441Smckusick /* ARGSUSED */
176868318Scgd int
ftruncate(p,uap,retval)176960414Smckusick ftruncate(p, uap, retval)
177045914Smckusick 	struct proc *p;
177168318Scgd 	register struct ftruncate_args /* {
177268318Scgd 		syscallarg(int) fd;
177368318Scgd 		syscallarg(int) pad;
177468318Scgd 		syscallarg(off_t) length;
177568318Scgd 	} */ *uap;
177668318Scgd 	register_t *retval;
177742441Smckusick {
177837741Smckusick 	struct vattr vattr;
177937741Smckusick 	struct vnode *vp;
17807701Ssam 	struct file *fp;
178137741Smckusick 	int error;
17827701Ssam 
178368318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
178447540Skarels 		return (error);
178537741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
178647540Skarels 		return (EINVAL);
178737741Smckusick 	vp = (struct vnode *)fp->f_data;
178867654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
178969409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
179064410Sbostic 	if (vp->v_type == VDIR)
179137741Smckusick 		error = EISDIR;
179264410Sbostic 	else if ((error = vn_writechk(vp)) == 0) {
179364410Sbostic 		VATTR_NULL(&vattr);
179468318Scgd 		vattr.va_size = SCARG(uap, length);
179564410Sbostic 		error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
17967701Ssam 	}
179769409Smckusick 	VOP_UNLOCK(vp, 0, p);
179847540Skarels 	return (error);
17997701Ssam }
18007701Ssam 
180154863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
18029167Ssam /*
180354863Storek  * Truncate a file given its path name.
180454863Storek  */
180554863Storek /* ARGSUSED */
180668318Scgd int
compat_43_truncate(p,uap,retval)180768318Scgd compat_43_truncate(p, uap, retval)
180854863Storek 	struct proc *p;
180968318Scgd 	register struct compat_43_truncate_args /* {
181068318Scgd 		syscallarg(char *) path;
181168318Scgd 		syscallarg(long) length;
181268318Scgd 	} */ *uap;
181368318Scgd 	register_t *retval;
181454863Storek {
181568318Scgd 	struct truncate_args /* {
181668318Scgd 		syscallarg(char *) path;
181768318Scgd 		syscallarg(int) pad;
181868318Scgd 		syscallarg(off_t) length;
181968318Scgd 	} */ nuap;
182054863Storek 
182168318Scgd 	SCARG(&nuap, path) = SCARG(uap, path);
182268318Scgd 	SCARG(&nuap, length) = SCARG(uap, length);
182360428Smckusick 	return (truncate(p, &nuap, retval));
182454863Storek }
182554863Storek 
182654863Storek /*
182754863Storek  * Truncate a file given a file descriptor.
182854863Storek  */
182954863Storek /* ARGSUSED */
183068318Scgd int
compat_43_ftruncate(p,uap,retval)183168318Scgd compat_43_ftruncate(p, uap, retval)
183254863Storek 	struct proc *p;
183368318Scgd 	register struct compat_43_ftruncate_args /* {
183468318Scgd 		syscallarg(int) fd;
183568318Scgd 		syscallarg(long) length;
183668318Scgd 	} */ *uap;
183768318Scgd 	register_t *retval;
183854863Storek {
183968318Scgd 	struct ftruncate_args /* {
184068318Scgd 		syscallarg(int) fd;
184168318Scgd 		syscallarg(int) pad;
184268318Scgd 		syscallarg(off_t) length;
184368318Scgd 	} */ nuap;
184454863Storek 
184568318Scgd 	SCARG(&nuap, fd) = SCARG(uap, fd);
184668318Scgd 	SCARG(&nuap, length) = SCARG(uap, length);
184760428Smckusick 	return (ftruncate(p, &nuap, retval));
184854863Storek }
184954863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */
185054863Storek 
185154863Storek /*
185264410Sbostic  * Sync an open file.
18539167Ssam  */
185442441Smckusick /* ARGSUSED */
185568318Scgd int
fsync(p,uap,retval)185642441Smckusick fsync(p, uap, retval)
185745914Smckusick 	struct proc *p;
185868318Scgd 	struct fsync_args /* {
185968318Scgd 		syscallarg(int) fd;
186068318Scgd 	} */ *uap;
186168318Scgd 	register_t *retval;
18629167Ssam {
186339592Smckusick 	register struct vnode *vp;
18649167Ssam 	struct file *fp;
186537741Smckusick 	int error;
18669167Ssam 
186768318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
186847540Skarels 		return (error);
186939592Smckusick 	vp = (struct vnode *)fp->f_data;
187069409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
187154441Smckusick 	error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
187269409Smckusick 	VOP_UNLOCK(vp, 0, p);
187347540Skarels 	return (error);
18749167Ssam }
18759167Ssam 
18769167Ssam /*
187764410Sbostic  * Rename files.  Source and destination must either both be directories,
187864410Sbostic  * or both not be directories.  If target is a directory, it must be empty.
18799167Ssam  */
188042441Smckusick /* ARGSUSED */
188168318Scgd int
rename(p,uap,retval)188242441Smckusick rename(p, uap, retval)
188345914Smckusick 	struct proc *p;
188468318Scgd 	register struct rename_args /* {
188568318Scgd 		syscallarg(char *) from;
188668318Scgd 		syscallarg(char *) to;
188768318Scgd 	} */ *uap;
188868318Scgd 	register_t *retval;
188942441Smckusick {
189037741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
189149735Smckusick 	struct nameidata fromnd, tond;
189237741Smckusick 	int error;
18937701Ssam 
189452322Smckusick 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
189568318Scgd 	    SCARG(uap, from), p);
189652322Smckusick 	if (error = namei(&fromnd))
189747540Skarels 		return (error);
189849735Smckusick 	fvp = fromnd.ni_vp;
189952322Smckusick 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
190068318Scgd 	    UIO_USERSPACE, SCARG(uap, to), p);
190152322Smckusick 	if (error = namei(&tond)) {
190252230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
190349735Smckusick 		vrele(fromnd.ni_dvp);
190442465Smckusick 		vrele(fvp);
190542465Smckusick 		goto out1;
190642465Smckusick 	}
190737741Smckusick 	tdvp = tond.ni_dvp;
190837741Smckusick 	tvp = tond.ni_vp;
190937741Smckusick 	if (tvp != NULL) {
191037741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
191139242Sbostic 			error = ENOTDIR;
191237741Smckusick 			goto out;
191337741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
191439242Sbostic 			error = EISDIR;
191537741Smckusick 			goto out;
19169167Ssam 		}
19179167Ssam 	}
191839286Smckusick 	if (fvp == tdvp)
191937741Smckusick 		error = EINVAL;
192039286Smckusick 	/*
192149735Smckusick 	 * If source is the same as the destination (that is the
192249735Smckusick 	 * same inode number with the same name in the same directory),
192339286Smckusick 	 * then there is nothing to do.
192439286Smckusick 	 */
192549735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
192652322Smckusick 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
192752322Smckusick 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
192852322Smckusick 	      fromnd.ni_cnd.cn_namelen))
192939286Smckusick 		error = -1;
193037741Smckusick out:
193142465Smckusick 	if (!error) {
193267654Smckusick 		VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE);
193352192Smckusick 		if (fromnd.ni_dvp != tdvp)
193467654Smckusick 			VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
193552192Smckusick 		if (tvp)
193667654Smckusick 			VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE);
193752230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
193852230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
193942465Smckusick 	} else {
194052230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
194143344Smckusick 		if (tdvp == tvp)
194243344Smckusick 			vrele(tdvp);
194343344Smckusick 		else
194443344Smckusick 			vput(tdvp);
194542465Smckusick 		if (tvp)
194642465Smckusick 			vput(tvp);
194752230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
194849735Smckusick 		vrele(fromnd.ni_dvp);
194942465Smckusick 		vrele(fvp);
19509167Ssam 	}
195149735Smckusick 	vrele(tond.ni_startdir);
195252322Smckusick 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
195337741Smckusick out1:
195466801Smckusick 	if (fromnd.ni_startdir)
195566801Smckusick 		vrele(fromnd.ni_startdir);
195652322Smckusick 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
195739286Smckusick 	if (error == -1)
195847540Skarels 		return (0);
195947540Skarels 	return (error);
19607701Ssam }
19617701Ssam 
19627535Sroot /*
196364410Sbostic  * Make a directory file.
196412756Ssam  */
196542441Smckusick /* ARGSUSED */
196668318Scgd int
mkdir(p,uap,retval)196742441Smckusick mkdir(p, uap, retval)
196845914Smckusick 	struct proc *p;
196968318Scgd 	register struct mkdir_args /* {
197068318Scgd 		syscallarg(char *) path;
197168318Scgd 		syscallarg(int) mode;
197268318Scgd 	} */ *uap;
197368318Scgd 	register_t *retval;
197442441Smckusick {
197537741Smckusick 	register struct vnode *vp;
197637741Smckusick 	struct vattr vattr;
197737741Smckusick 	int error;
197847540Skarels 	struct nameidata nd;
197912756Ssam 
198068318Scgd 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
198152322Smckusick 	if (error = namei(&nd))
198247540Skarels 		return (error);
198352322Smckusick 	vp = nd.ni_vp;
198437741Smckusick 	if (vp != NULL) {
198552322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
198652322Smckusick 		if (nd.ni_dvp == vp)
198752322Smckusick 			vrele(nd.ni_dvp);
198843344Smckusick 		else
198952322Smckusick 			vput(nd.ni_dvp);
199042465Smckusick 		vrele(vp);
199147540Skarels 		return (EEXIST);
199212756Ssam 	}
199341362Smckusick 	VATTR_NULL(&vattr);
199437741Smckusick 	vattr.va_type = VDIR;
199568318Scgd 	vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask;
199667654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
199752322Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
199838145Smckusick 	if (!error)
199952322Smckusick 		vput(nd.ni_vp);
200047540Skarels 	return (error);
200112756Ssam }
200212756Ssam 
200312756Ssam /*
200464410Sbostic  * Remove a directory file.
200512756Ssam  */
200642441Smckusick /* ARGSUSED */
200768318Scgd int
rmdir(p,uap,retval)200842441Smckusick rmdir(p, uap, retval)
200945914Smckusick 	struct proc *p;
201068318Scgd 	struct rmdir_args /* {
201168318Scgd 		syscallarg(char *) path;
201268318Scgd 	} */ *uap;
201368318Scgd 	register_t *retval;
201412756Ssam {
201537741Smckusick 	register struct vnode *vp;
201637741Smckusick 	int error;
201747540Skarels 	struct nameidata nd;
201812756Ssam 
201968318Scgd 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
202068318Scgd 	    SCARG(uap, path), p);
202152322Smckusick 	if (error = namei(&nd))
202247540Skarels 		return (error);
202352322Smckusick 	vp = nd.ni_vp;
202437741Smckusick 	if (vp->v_type != VDIR) {
202537741Smckusick 		error = ENOTDIR;
202612756Ssam 		goto out;
202712756Ssam 	}
202812756Ssam 	/*
202937741Smckusick 	 * No rmdir "." please.
203012756Ssam 	 */
203152322Smckusick 	if (nd.ni_dvp == vp) {
203237741Smckusick 		error = EINVAL;
203312756Ssam 		goto out;
203412756Ssam 	}
203512756Ssam 	/*
203649365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
203712756Ssam 	 */
203837741Smckusick 	if (vp->v_flag & VROOT)
203937741Smckusick 		error = EBUSY;
204012756Ssam out:
204142465Smckusick 	if (!error) {
204267654Smckusick 		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
204367654Smckusick 		VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
204452322Smckusick 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
204542465Smckusick 	} else {
204652322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
204752322Smckusick 		if (nd.ni_dvp == vp)
204852322Smckusick 			vrele(nd.ni_dvp);
204943344Smckusick 		else
205052322Smckusick 			vput(nd.ni_dvp);
205142465Smckusick 		vput(vp);
205242465Smckusick 	}
205347540Skarels 	return (error);
205412756Ssam }
205512756Ssam 
205654620Smckusick #ifdef COMPAT_43
205737741Smckusick /*
205849365Smckusick  * Read a block of directory entries in a file system independent format.
205937741Smckusick  */
206068318Scgd int
compat_43_getdirentries(p,uap,retval)206168318Scgd compat_43_getdirentries(p, uap, retval)
206254620Smckusick 	struct proc *p;
206368318Scgd 	register struct compat_43_getdirentries_args /* {
206468318Scgd 		syscallarg(int) fd;
206568318Scgd 		syscallarg(char *) buf;
206668318Scgd 		syscallarg(u_int) count;
206768318Scgd 		syscallarg(long *) basep;
206868318Scgd 	} */ *uap;
206968318Scgd 	register_t *retval;
207054620Smckusick {
207154620Smckusick 	register struct vnode *vp;
207254620Smckusick 	struct file *fp;
207354620Smckusick 	struct uio auio, kuio;
207454620Smckusick 	struct iovec aiov, kiov;
207554620Smckusick 	struct dirent *dp, *edp;
207654620Smckusick 	caddr_t dirbuf;
207767362Smckusick 	int error, eofflag, readcnt;
207854969Smckusick 	long loff;
207954620Smckusick 
208068318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
208154620Smckusick 		return (error);
208254620Smckusick 	if ((fp->f_flag & FREAD) == 0)
208354620Smckusick 		return (EBADF);
208454620Smckusick 	vp = (struct vnode *)fp->f_data;
208567362Smckusick unionread:
208654620Smckusick 	if (vp->v_type != VDIR)
208754620Smckusick 		return (EINVAL);
208868318Scgd 	aiov.iov_base = SCARG(uap, buf);
208968318Scgd 	aiov.iov_len = SCARG(uap, count);
209054620Smckusick 	auio.uio_iov = &aiov;
209154620Smckusick 	auio.uio_iovcnt = 1;
209254620Smckusick 	auio.uio_rw = UIO_READ;
209354620Smckusick 	auio.uio_segflg = UIO_USERSPACE;
209454620Smckusick 	auio.uio_procp = p;
209568318Scgd 	auio.uio_resid = SCARG(uap, count);
209669409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
209754969Smckusick 	loff = auio.uio_offset = fp->f_offset;
209854620Smckusick #	if (BYTE_ORDER != LITTLE_ENDIAN)
209956339Smckusick 		if (vp->v_mount->mnt_maxsymlinklen <= 0) {
210067362Smckusick 			error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
210168663Smckusick 			    (int *)0, (u_long *)0);
210256339Smckusick 			fp->f_offset = auio.uio_offset;
210356339Smckusick 		} else
210454620Smckusick #	endif
210554620Smckusick 	{
210654620Smckusick 		kuio = auio;
210754620Smckusick 		kuio.uio_iov = &kiov;
210854620Smckusick 		kuio.uio_segflg = UIO_SYSSPACE;
210968318Scgd 		kiov.iov_len = SCARG(uap, count);
211068318Scgd 		MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK);
211154620Smckusick 		kiov.iov_base = dirbuf;
211267362Smckusick 		error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
211368663Smckusick 			    (int *)0, (u_long *)0);
211456339Smckusick 		fp->f_offset = kuio.uio_offset;
211554620Smckusick 		if (error == 0) {
211668318Scgd 			readcnt = SCARG(uap, count) - kuio.uio_resid;
211754620Smckusick 			edp = (struct dirent *)&dirbuf[readcnt];
211854620Smckusick 			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
211954620Smckusick #				if (BYTE_ORDER == LITTLE_ENDIAN)
212054969Smckusick 					/*
212155009Smckusick 					 * The expected low byte of
212255009Smckusick 					 * dp->d_namlen is our dp->d_type.
212355009Smckusick 					 * The high MBZ byte of dp->d_namlen
212455009Smckusick 					 * is our dp->d_namlen.
212554969Smckusick 					 */
212655009Smckusick 					dp->d_type = dp->d_namlen;
212755009Smckusick 					dp->d_namlen = 0;
212855009Smckusick #				else
212955009Smckusick 					/*
213055009Smckusick 					 * The dp->d_type is the high byte
213155009Smckusick 					 * of the expected dp->d_namlen,
213255009Smckusick 					 * so must be zero'ed.
213355009Smckusick 					 */
213455009Smckusick 					dp->d_type = 0;
213554620Smckusick #				endif
213654620Smckusick 				if (dp->d_reclen > 0) {
213754620Smckusick 					dp = (struct dirent *)
213854620Smckusick 					    ((char *)dp + dp->d_reclen);
213954620Smckusick 				} else {
214054620Smckusick 					error = EIO;
214154620Smckusick 					break;
214254620Smckusick 				}
214354620Smckusick 			}
214454620Smckusick 			if (dp >= edp)
214554620Smckusick 				error = uiomove(dirbuf, readcnt, &auio);
214654620Smckusick 		}
214754620Smckusick 		FREE(dirbuf, M_TEMP);
214854620Smckusick 	}
214969409Smckusick 	VOP_UNLOCK(vp, 0, p);
215054620Smckusick 	if (error)
215154620Smckusick 		return (error);
215267362Smckusick 
215367362Smckusick #ifdef UNION
215467362Smckusick {
215567362Smckusick 	extern int (**union_vnodeop_p)();
215669547Spendry 	extern struct vnode *union_dircache __P((struct vnode*, struct proc*));
215767362Smckusick 
215868318Scgd 	if ((SCARG(uap, count) == auio.uio_resid) &&
215967362Smckusick 	    (vp->v_op == union_vnodeop_p)) {
216067362Smckusick 		struct vnode *lvp;
216167362Smckusick 
216269547Spendry 		lvp = union_dircache(vp, p);
216367362Smckusick 		if (lvp != NULLVP) {
216467575Spendry 			struct vattr va;
216567575Spendry 
216667575Spendry 			/*
216767575Spendry 			 * If the directory is opaque,
216867575Spendry 			 * then don't show lower entries
216967575Spendry 			 */
217067575Spendry 			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
217167575Spendry 			if (va.va_flags & OPAQUE) {
217268079Spendry 				vput(lvp);
217367575Spendry 				lvp = NULL;
217467575Spendry 			}
217567575Spendry 		}
217667575Spendry 
217767575Spendry 		if (lvp != NULLVP) {
217867362Smckusick 			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
217967362Smckusick 			if (error) {
218069547Spendry 				vput(lvp);
218167362Smckusick 				return (error);
218267362Smckusick 			}
218369547Spendry 			VOP_UNLOCK(lvp, 0, p);
218467362Smckusick 			fp->f_data = (caddr_t) lvp;
218567362Smckusick 			fp->f_offset = 0;
218667362Smckusick 			error = vn_close(vp, FREAD, fp->f_cred, p);
218767362Smckusick 			if (error)
218867362Smckusick 				return (error);
218967362Smckusick 			vp = lvp;
219067362Smckusick 			goto unionread;
219167362Smckusick 		}
219267362Smckusick 	}
219367362Smckusick }
219467362Smckusick #endif /* UNION */
219567362Smckusick 
219668318Scgd 	if ((SCARG(uap, count) == auio.uio_resid) &&
219767362Smckusick 	    (vp->v_flag & VROOT) &&
219867362Smckusick 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
219967362Smckusick 		struct vnode *tvp = vp;
220067362Smckusick 		vp = vp->v_mount->mnt_vnodecovered;
220167362Smckusick 		VREF(vp);
220267362Smckusick 		fp->f_data = (caddr_t) vp;
220367362Smckusick 		fp->f_offset = 0;
220467362Smckusick 		vrele(tvp);
220567362Smckusick 		goto unionread;
220667362Smckusick 	}
220768318Scgd 	error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
220868318Scgd 	    sizeof(long));
220968318Scgd 	*retval = SCARG(uap, count) - auio.uio_resid;
221054620Smckusick 	return (error);
221154620Smckusick }
221267362Smckusick #endif /* COMPAT_43 */
221354620Smckusick 
221454620Smckusick /*
221554620Smckusick  * Read a block of directory entries in a file system independent format.
221654620Smckusick  */
221768318Scgd int
getdirentries(p,uap,retval)221842441Smckusick getdirentries(p, uap, retval)
221945914Smckusick 	struct proc *p;
222068318Scgd 	register struct getdirentries_args /* {
222168318Scgd 		syscallarg(int) fd;
222268318Scgd 		syscallarg(char *) buf;
222368318Scgd 		syscallarg(u_int) count;
222468318Scgd 		syscallarg(long *) basep;
222568318Scgd 	} */ *uap;
222668318Scgd 	register_t *retval;
222742441Smckusick {
222839592Smckusick 	register struct vnode *vp;
222916540Ssam 	struct file *fp;
223037741Smckusick 	struct uio auio;
223137741Smckusick 	struct iovec aiov;
223254969Smckusick 	long loff;
223367362Smckusick 	int error, eofflag;
223412756Ssam 
223568318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
223647540Skarels 		return (error);
223737741Smckusick 	if ((fp->f_flag & FREAD) == 0)
223847540Skarels 		return (EBADF);
223939592Smckusick 	vp = (struct vnode *)fp->f_data;
224055451Spendry unionread:
224139592Smckusick 	if (vp->v_type != VDIR)
224247540Skarels 		return (EINVAL);
224368318Scgd 	aiov.iov_base = SCARG(uap, buf);
224468318Scgd 	aiov.iov_len = SCARG(uap, count);
224537741Smckusick 	auio.uio_iov = &aiov;
224637741Smckusick 	auio.uio_iovcnt = 1;
224737741Smckusick 	auio.uio_rw = UIO_READ;
224837741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
224948026Smckusick 	auio.uio_procp = p;
225068318Scgd 	auio.uio_resid = SCARG(uap, count);
225169409Smckusick 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
225254969Smckusick 	loff = auio.uio_offset = fp->f_offset;
225368663Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
225468663Smckusick 			    (int *)0, (u_long *)0);
225539592Smckusick 	fp->f_offset = auio.uio_offset;
225669409Smckusick 	VOP_UNLOCK(vp, 0, p);
225739592Smckusick 	if (error)
225847540Skarels 		return (error);
225966095Spendry 
226066095Spendry #ifdef UNION
226166095Spendry {
226266095Spendry 	extern int (**union_vnodeop_p)();
226369547Spendry 	extern struct vnode *union_dircache __P((struct vnode*, struct proc*));
226466095Spendry 
226568318Scgd 	if ((SCARG(uap, count) == auio.uio_resid) &&
226666095Spendry 	    (vp->v_op == union_vnodeop_p)) {
226767122Spendry 		struct vnode *lvp;
226866095Spendry 
226969547Spendry 		lvp = union_dircache(vp, p);
227067122Spendry 		if (lvp != NULLVP) {
227167575Spendry 			struct vattr va;
227267575Spendry 
227367575Spendry 			/*
227467575Spendry 			 * If the directory is opaque,
227567575Spendry 			 * then don't show lower entries
227667575Spendry 			 */
227767575Spendry 			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
227867575Spendry 			if (va.va_flags & OPAQUE) {
227968079Spendry 				vput(lvp);
228067575Spendry 				lvp = NULL;
228167575Spendry 			}
228267575Spendry 		}
228369547Spendry 
228467575Spendry 		if (lvp != NULLVP) {
228567362Smckusick 			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
228666095Spendry 			if (error) {
228769547Spendry 				vput(lvp);
228866095Spendry 				return (error);
228966095Spendry 			}
229069547Spendry 			VOP_UNLOCK(lvp, 0, p);
229167122Spendry 			fp->f_data = (caddr_t) lvp;
229266095Spendry 			fp->f_offset = 0;
229367122Spendry 			error = vn_close(vp, FREAD, fp->f_cred, p);
229466095Spendry 			if (error)
229566095Spendry 				return (error);
229667122Spendry 			vp = lvp;
229766095Spendry 			goto unionread;
229866095Spendry 		}
229966095Spendry 	}
230066095Spendry }
230168318Scgd #endif /* UNION */
230266095Spendry 
230368318Scgd 	if ((SCARG(uap, count) == auio.uio_resid) &&
230455451Spendry 	    (vp->v_flag & VROOT) &&
230555451Spendry 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
230655451Spendry 		struct vnode *tvp = vp;
230755451Spendry 		vp = vp->v_mount->mnt_vnodecovered;
230855451Spendry 		VREF(vp);
230955451Spendry 		fp->f_data = (caddr_t) vp;
231055451Spendry 		fp->f_offset = 0;
231155451Spendry 		vrele(tvp);
231255451Spendry 		goto unionread;
231355451Spendry 	}
231468318Scgd 	error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
231568318Scgd 	    sizeof(long));
231668318Scgd 	*retval = SCARG(uap, count) - auio.uio_resid;
231747540Skarels 	return (error);
231812756Ssam }
231912756Ssam 
232012756Ssam /*
232149365Smckusick  * Set the mode mask for creation of filesystem nodes.
232212756Ssam  */
232368318Scgd int
umask(p,uap,retval)232442441Smckusick umask(p, uap, retval)
232545914Smckusick 	struct proc *p;
232668318Scgd 	struct umask_args /* {
232768318Scgd 		syscallarg(int) newmask;
232868318Scgd 	} */ *uap;
232968318Scgd 	register_t *retval;
233012756Ssam {
233164410Sbostic 	register struct filedesc *fdp;
233212756Ssam 
233364410Sbostic 	fdp = p->p_fd;
233445914Smckusick 	*retval = fdp->fd_cmask;
233568318Scgd 	fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS;
233647540Skarels 	return (0);
233712756Ssam }
233837741Smckusick 
233939566Smarc /*
234039566Smarc  * Void all references to file by ripping underlying filesystem
234139566Smarc  * away from vnode.
234239566Smarc  */
234342441Smckusick /* ARGSUSED */
234468318Scgd int
revoke(p,uap,retval)234542441Smckusick revoke(p, uap, retval)
234645914Smckusick 	struct proc *p;
234768318Scgd 	register struct revoke_args /* {
234868318Scgd 		syscallarg(char *) path;
234968318Scgd 	} */ *uap;
235068318Scgd 	register_t *retval;
235142441Smckusick {
235239566Smarc 	register struct vnode *vp;
235339566Smarc 	struct vattr vattr;
235439566Smarc 	int error;
235547540Skarels 	struct nameidata nd;
235639566Smarc 
235768318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
235852322Smckusick 	if (error = namei(&nd))
235947540Skarels 		return (error);
236052322Smckusick 	vp = nd.ni_vp;
236148026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
236239566Smarc 		goto out;
236347540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
236447540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
236539566Smarc 		goto out;
236639805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
236768423Smckusick 		VOP_REVOKE(vp, REVOKEALL);
236839566Smarc out:
236939566Smarc 	vrele(vp);
237047540Skarels 	return (error);
237139566Smarc }
237239566Smarc 
237349365Smckusick /*
237449365Smckusick  * Convert a user file descriptor to a kernel file entry.
237549365Smckusick  */
237668318Scgd int
getvnode(fdp,fd,fpp)237764410Sbostic getvnode(fdp, fd, fpp)
237845914Smckusick 	struct filedesc *fdp;
237937741Smckusick 	struct file **fpp;
238064410Sbostic 	int fd;
238137741Smckusick {
238237741Smckusick 	struct file *fp;
238337741Smckusick 
238464410Sbostic 	if ((u_int)fd >= fdp->fd_nfiles ||
238564410Sbostic 	    (fp = fdp->fd_ofiles[fd]) == NULL)
238637741Smckusick 		return (EBADF);
238737741Smckusick 	if (fp->f_type != DTYPE_VNODE)
238837741Smckusick 		return (EINVAL);
238937741Smckusick 	*fpp = fp;
239037741Smckusick 	return (0);
239137741Smckusick }
2392