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