xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 68079)
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*68079Spendry  *	@(#)vfs_syscalls.c	8.28 (Berkeley) 12/10/94
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 
2953468Smckusick #include <vm/vm.h>
3059875Smckusick #include <sys/sysctl.h>
3137Sbill 
3264410Sbostic static int change_dir __P((struct nameidata *ndp, struct proc *p));
3364410Sbostic 
3437741Smckusick /*
3537741Smckusick  * Virtual File System System Calls
3637741Smckusick  */
3712756Ssam 
389167Ssam /*
3964410Sbostic  * Mount a file system.
409167Ssam  */
4154916Storek struct mount_args {
4254916Storek 	int	type;
4364410Sbostic 	char	*path;
4454916Storek 	int	flags;
4554916Storek 	caddr_t	data;
4654916Storek };
4742441Smckusick /* ARGSUSED */
4842441Smckusick mount(p, uap, retval)
4945914Smckusick 	struct proc *p;
5054916Storek 	register struct mount_args *uap;
5142441Smckusick 	int *retval;
5242441Smckusick {
5339335Smckusick 	register struct vnode *vp;
5439335Smckusick 	register struct mount *mp;
5540111Smckusick 	int error, flag;
5667532Smckusick 	struct vattr va;
5747540Skarels 	struct nameidata nd;
586254Sroot 
5937741Smckusick 	/*
6037741Smckusick 	 * Get vnode to be covered
6137741Smckusick 	 */
6264410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
6352322Smckusick 	if (error = namei(&nd))
6447540Skarels 		return (error);
6552322Smckusick 	vp = nd.ni_vp;
6641400Smckusick 	if (uap->flags & MNT_UPDATE) {
6739335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
6839335Smckusick 			vput(vp);
6947540Skarels 			return (EINVAL);
7039335Smckusick 		}
7139335Smckusick 		mp = vp->v_mount;
7257047Smckusick 		flag = mp->mnt_flag;
7339335Smckusick 		/*
7457047Smckusick 		 * We only allow the filesystem to be reloaded if it
7557047Smckusick 		 * is currently mounted read-only.
7639335Smckusick 		 */
7757047Smckusick 		if ((uap->flags & MNT_RELOAD) &&
7857047Smckusick 		    ((mp->mnt_flag & MNT_RDONLY) == 0)) {
7939335Smckusick 			vput(vp);
8047540Skarels 			return (EOPNOTSUPP);	/* Needs translation */
8139335Smckusick 		}
8257047Smckusick 		mp->mnt_flag |=
8357047Smckusick 		    uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
8467532Smckusick 		/*
8567532Smckusick 		 * Only root, or the user that did the original mount is
8667532Smckusick 		 * permitted to update it.
8767532Smckusick 		 */
8867532Smckusick 		if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid &&
8967532Smckusick 		    (error = suser(p->p_ucred, &p->p_acflag))) {
9067532Smckusick 			vput(vp);
9167532Smckusick 			return (error);
9267532Smckusick 		}
9367532Smckusick 		/*
9467532Smckusick 		 * Do not allow NFS export by non-root users. Silently
9567532Smckusick 		 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
9667532Smckusick 		 */
9767532Smckusick 		if (p->p_ucred->cr_uid != 0) {
9867532Smckusick 			if (uap->flags & MNT_EXPORTED) {
9967532Smckusick 				vput(vp);
10067532Smckusick 				return (EPERM);
10167532Smckusick 			}
10267532Smckusick 			uap->flags |= MNT_NOSUID | MNT_NODEV;
10367532Smckusick 		}
10439335Smckusick 		VOP_UNLOCK(vp);
10539335Smckusick 		goto update;
10639335Smckusick 	}
10767532Smckusick 	/*
10867532Smckusick 	 * If the user is not root, ensure that they own the directory
10967532Smckusick 	 * onto which we are attempting to mount.
11067532Smckusick 	 */
11167532Smckusick 	if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) ||
11267532Smckusick 	    (va.va_uid != p->p_ucred->cr_uid &&
11367532Smckusick 	     (error = suser(p->p_ucred, &p->p_acflag)))) {
11467532Smckusick 		vput(vp);
11567532Smckusick 		return (error);
11667532Smckusick 	}
11767532Smckusick 	/*
11867532Smckusick 	 * Do not allow NFS export by non-root users. Silently
11967532Smckusick 	 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
12067532Smckusick 	 */
12167532Smckusick 	if (p->p_ucred->cr_uid != 0) {
12267532Smckusick 		if (uap->flags & MNT_EXPORTED) {
12367532Smckusick 			vput(vp);
12467532Smckusick 			return (EPERM);
12567532Smckusick 		}
12667532Smckusick 		uap->flags |= MNT_NOSUID | MNT_NODEV;
12767532Smckusick 	}
12857793Smckusick 	if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0))
12954441Smckusick 		return (error);
13037741Smckusick 	if (vp->v_type != VDIR) {
13137741Smckusick 		vput(vp);
13247540Skarels 		return (ENOTDIR);
13337741Smckusick 	}
13464410Sbostic 	if ((u_long)uap->type > MOUNT_MAXTYPE || vfssw[uap->type] == NULL) {
13537741Smckusick 		vput(vp);
13647540Skarels 		return (ENODEV);
13737741Smckusick 	}
13867969Spendry 	if (vp->v_mountedhere != NULL) {
13967961Smckusick 		vput(vp);
14067961Smckusick 		return (EBUSY);
14167961Smckusick 	}
14237741Smckusick 
14337741Smckusick 	/*
14439335Smckusick 	 * Allocate and initialize the file system.
14537741Smckusick 	 */
14637741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
14737741Smckusick 		M_MOUNT, M_WAITOK);
14854172Smckusick 	bzero((char *)mp, (u_long)sizeof(struct mount));
14941400Smckusick 	mp->mnt_op = vfssw[uap->type];
15039335Smckusick 	if (error = vfs_lock(mp)) {
15139335Smckusick 		free((caddr_t)mp, M_MOUNT);
15239335Smckusick 		vput(vp);
15347540Skarels 		return (error);
15439335Smckusick 	}
15539335Smckusick 	vp->v_mountedhere = mp;
15641400Smckusick 	mp->mnt_vnodecovered = vp;
15767532Smckusick 	mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
15839335Smckusick update:
15939335Smckusick 	/*
16039335Smckusick 	 * Set the mount level flags.
16139335Smckusick 	 */
16241400Smckusick 	if (uap->flags & MNT_RDONLY)
16341400Smckusick 		mp->mnt_flag |= MNT_RDONLY;
16457047Smckusick 	else if (mp->mnt_flag & MNT_RDONLY)
16557047Smckusick 		mp->mnt_flag |= MNT_WANTRDWR;
16665613Smckusick 	mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
16765613Smckusick 	    MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);
16865613Smckusick 	mp->mnt_flag |= uap->flags & (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
16965613Smckusick 	    MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);
17039335Smckusick 	/*
17139335Smckusick 	 * Mount the filesystem.
17239335Smckusick 	 */
17364410Sbostic 	error = VFS_MOUNT(mp, uap->path, uap->data, &nd, p);
17441400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
17539335Smckusick 		vrele(vp);
17657047Smckusick 		if (mp->mnt_flag & MNT_WANTRDWR)
17757047Smckusick 			mp->mnt_flag &= ~MNT_RDONLY;
17857047Smckusick 		mp->mnt_flag &=~
17957047Smckusick 		    (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
18040111Smckusick 		if (error)
18141400Smckusick 			mp->mnt_flag = flag;
18247540Skarels 		return (error);
18339335Smckusick 	}
18440110Smckusick 	/*
18540110Smckusick 	 * Put the new filesystem on the mount list after root.
18640110Smckusick 	 */
18737741Smckusick 	cache_purge(vp);
18837741Smckusick 	if (!error) {
18965259Smckusick 		TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
19067974Smckusick 		checkdirs(vp);
19139335Smckusick 		VOP_UNLOCK(vp);
19237741Smckusick 		vfs_unlock(mp);
19348026Smckusick 		error = VFS_START(mp, 0, p);
19437741Smckusick 	} else {
19565259Smckusick 		mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
19665259Smckusick 		vfs_unlock(mp);
19737741Smckusick 		free((caddr_t)mp, M_MOUNT);
19839335Smckusick 		vput(vp);
19937741Smckusick 	}
20047540Skarels 	return (error);
2016254Sroot }
2026254Sroot 
2039167Ssam /*
20467974Smckusick  * Scan all active processes to see if any of them have a current
20567974Smckusick  * or root directory onto which the new filesystem has just been
20667974Smckusick  * mounted. If so, replace them with the new mount point.
20767974Smckusick  */
20867974Smckusick checkdirs(olddp)
20967974Smckusick 	struct vnode *olddp;
21067974Smckusick {
21167974Smckusick 	struct filedesc *fdp;
21267974Smckusick 	struct vnode *newdp;
21367974Smckusick 	struct proc *p;
21467974Smckusick 
21567974Smckusick 	if (olddp->v_usecount == 1)
21667974Smckusick 		return;
21767974Smckusick 	if (VFS_ROOT(olddp->v_mountedhere, &newdp))
21867974Smckusick 		panic("mount: lost mount");
21967974Smckusick 	for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
22067974Smckusick 		fdp = p->p_fd;
22167974Smckusick 		if (fdp->fd_cdir == olddp) {
22267974Smckusick 			vrele(fdp->fd_cdir);
22367974Smckusick 			VREF(newdp);
22467974Smckusick 			fdp->fd_cdir = newdp;
22567974Smckusick 		}
22667974Smckusick 		if (fdp->fd_rdir == olddp) {
22767974Smckusick 			vrele(fdp->fd_rdir);
22867974Smckusick 			VREF(newdp);
22967974Smckusick 			fdp->fd_rdir = newdp;
23067974Smckusick 		}
23167974Smckusick 	}
23267974Smckusick 	if (rootvnode == olddp) {
23367974Smckusick 		vrele(rootvnode);
23467974Smckusick 		VREF(newdp);
23567974Smckusick 		rootvnode = newdp;
23667974Smckusick 	}
23767974Smckusick 	vput(newdp);
23867974Smckusick }
23967974Smckusick 
24067974Smckusick /*
24164410Sbostic  * Unmount a file system.
24237741Smckusick  *
24337741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
24437741Smckusick  * not special file (as before).
2459167Ssam  */
24654916Storek struct unmount_args {
24764410Sbostic 	char	*path;
24854916Storek 	int	flags;
24954916Storek };
25042441Smckusick /* ARGSUSED */
25142441Smckusick unmount(p, uap, retval)
25245914Smckusick 	struct proc *p;
25354916Storek 	register struct unmount_args *uap;
25442441Smckusick 	int *retval;
25542441Smckusick {
25637741Smckusick 	register struct vnode *vp;
25739356Smckusick 	struct mount *mp;
25837741Smckusick 	int error;
25947540Skarels 	struct nameidata nd;
2606254Sroot 
26164410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
26252322Smckusick 	if (error = namei(&nd))
26347540Skarels 		return (error);
26452322Smckusick 	vp = nd.ni_vp;
26567532Smckusick 	mp = vp->v_mount;
26666172Spendry 
26737741Smckusick 	/*
26867532Smckusick 	 * Only root, or the user that did the original mount is
26967532Smckusick 	 * permitted to unmount this filesystem.
27066172Spendry 	 */
27167532Smckusick 	if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) &&
27266172Spendry 	    (error = suser(p->p_ucred, &p->p_acflag))) {
27366172Spendry 		vput(vp);
27466172Spendry 		return (error);
27566172Spendry 	}
27666172Spendry 
27766172Spendry 	/*
27837741Smckusick 	 * Must be the root of the filesystem
27937741Smckusick 	 */
28037741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
28137741Smckusick 		vput(vp);
28247540Skarels 		return (EINVAL);
28337741Smckusick 	}
28437741Smckusick 	vput(vp);
28548026Smckusick 	return (dounmount(mp, uap->flags, p));
28639356Smckusick }
28739356Smckusick 
28839356Smckusick /*
28964410Sbostic  * Do the actual file system unmount.
29039356Smckusick  */
29148026Smckusick dounmount(mp, flags, p)
29239356Smckusick 	register struct mount *mp;
29339356Smckusick 	int flags;
29448026Smckusick 	struct proc *p;
29539356Smckusick {
29639356Smckusick 	struct vnode *coveredvp;
29739356Smckusick 	int error;
29839356Smckusick 
29941400Smckusick 	coveredvp = mp->mnt_vnodecovered;
30041298Smckusick 	if (vfs_busy(mp))
30141298Smckusick 		return (EBUSY);
30241400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
30337741Smckusick 	if (error = vfs_lock(mp))
30439356Smckusick 		return (error);
30537741Smckusick 
30665859Smckusick 	mp->mnt_flag &=~ MNT_ASYNC;
30745738Smckusick 	vnode_pager_umount(mp);	/* release cached vnodes */
30837741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
30954441Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 ||
31054441Smckusick 	    (flags & MNT_FORCE))
31148026Smckusick 		error = VFS_UNMOUNT(mp, flags, p);
31241400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
31341298Smckusick 	vfs_unbusy(mp);
31437741Smckusick 	if (error) {
31537741Smckusick 		vfs_unlock(mp);
31637741Smckusick 	} else {
31737741Smckusick 		vrele(coveredvp);
31865259Smckusick 		TAILQ_REMOVE(&mountlist, mp, mnt_list);
31965259Smckusick 		mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
32065259Smckusick 		vfs_unlock(mp);
32165259Smckusick 		if (mp->mnt_vnodelist.lh_first != NULL)
32252287Smckusick 			panic("unmount: dangling vnode");
32337741Smckusick 		free((caddr_t)mp, M_MOUNT);
32437741Smckusick 	}
32539356Smckusick 	return (error);
3266254Sroot }
3276254Sroot 
3289167Ssam /*
32937741Smckusick  * Sync each mounted filesystem.
3309167Ssam  */
33167403Smckusick #ifdef DEBUG
33256352Smckusick int syncprt = 0;
33359875Smckusick struct ctldebug debug0 = { "syncprt", &syncprt };
33456352Smckusick #endif
33556352Smckusick 
33654916Storek struct sync_args {
33754916Storek 	int	dummy;
33854916Storek };
33939491Smckusick /* ARGSUSED */
34042441Smckusick sync(p, uap, retval)
34145914Smckusick 	struct proc *p;
34254916Storek 	struct sync_args *uap;
34342441Smckusick 	int *retval;
3446254Sroot {
34565259Smckusick 	register struct mount *mp, *nmp;
34665859Smckusick 	int asyncflag;
34737741Smckusick 
34865259Smckusick 	for (mp = mountlist.tqh_first; mp != NULL; mp = nmp) {
34967678Smckusick 		/*
35067678Smckusick 		 * Get the next pointer in case we hang on vfs_busy
35167678Smckusick 		 * while we are being unmounted.
35267678Smckusick 		 */
35365259Smckusick 		nmp = mp->mnt_list.tqe_next;
35440343Smckusick 		/*
35540343Smckusick 		 * The lock check below is to avoid races with mount
35640343Smckusick 		 * and unmount.
35740343Smckusick 		 */
35841400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
35941298Smckusick 		    !vfs_busy(mp)) {
36065859Smckusick 			asyncflag = mp->mnt_flag & MNT_ASYNC;
36165859Smckusick 			mp->mnt_flag &= ~MNT_ASYNC;
36254441Smckusick 			VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
36365859Smckusick 			if (asyncflag)
36465859Smckusick 				mp->mnt_flag |= MNT_ASYNC;
36567678Smckusick 			/*
36667678Smckusick 			 * Get the next pointer again, as the next filesystem
36767678Smckusick 			 * might have been unmounted while we were sync'ing.
36867678Smckusick 			 */
36967678Smckusick 			nmp = mp->mnt_list.tqe_next;
37065259Smckusick 			vfs_unbusy(mp);
37165259Smckusick 		}
37265259Smckusick 	}
37356352Smckusick #ifdef DIAGNOSTIC
37456352Smckusick 	if (syncprt)
37556352Smckusick 		vfs_bufstats();
37656352Smckusick #endif /* DIAGNOSTIC */
37747688Skarels 	return (0);
37837741Smckusick }
37937741Smckusick 
38037741Smckusick /*
38164410Sbostic  * Change filesystem quotas.
38241298Smckusick  */
38354916Storek struct quotactl_args {
38454916Storek 	char *path;
38554916Storek 	int cmd;
38654916Storek 	int uid;
38754916Storek 	caddr_t arg;
38854916Storek };
38942441Smckusick /* ARGSUSED */
39042441Smckusick quotactl(p, uap, retval)
39145914Smckusick 	struct proc *p;
39254916Storek 	register struct quotactl_args *uap;
39342441Smckusick 	int *retval;
39442441Smckusick {
39541298Smckusick 	register struct mount *mp;
39641298Smckusick 	int error;
39747540Skarels 	struct nameidata nd;
39841298Smckusick 
39952322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
40052322Smckusick 	if (error = namei(&nd))
40147540Skarels 		return (error);
40252322Smckusick 	mp = nd.ni_vp->v_mount;
40352322Smckusick 	vrele(nd.ni_vp);
40448026Smckusick 	return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p));
40541298Smckusick }
40641298Smckusick 
40741298Smckusick /*
40849365Smckusick  * Get filesystem statistics.
40937741Smckusick  */
41054916Storek struct statfs_args {
41154916Storek 	char *path;
41254916Storek 	struct statfs *buf;
41354916Storek };
41442441Smckusick /* ARGSUSED */
41542441Smckusick statfs(p, uap, retval)
41645914Smckusick 	struct proc *p;
41754916Storek 	register struct statfs_args *uap;
41842441Smckusick 	int *retval;
41942441Smckusick {
42039464Smckusick 	register struct mount *mp;
42140343Smckusick 	register struct statfs *sp;
42237741Smckusick 	int error;
42347540Skarels 	struct nameidata nd;
42437741Smckusick 
42552322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
42652322Smckusick 	if (error = namei(&nd))
42747540Skarels 		return (error);
42852322Smckusick 	mp = nd.ni_vp->v_mount;
42941400Smckusick 	sp = &mp->mnt_stat;
43052322Smckusick 	vrele(nd.ni_vp);
43148026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
43247540Skarels 		return (error);
43341400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
43447540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
43537741Smckusick }
43637741Smckusick 
43742441Smckusick /*
43849365Smckusick  * Get filesystem statistics.
43942441Smckusick  */
44054916Storek struct fstatfs_args {
44154916Storek 	int fd;
44254916Storek 	struct statfs *buf;
44354916Storek };
44442441Smckusick /* ARGSUSED */
44542441Smckusick fstatfs(p, uap, retval)
44645914Smckusick 	struct proc *p;
44754916Storek 	register struct fstatfs_args *uap;
44842441Smckusick 	int *retval;
44942441Smckusick {
45037741Smckusick 	struct file *fp;
45139464Smckusick 	struct mount *mp;
45240343Smckusick 	register struct statfs *sp;
45337741Smckusick 	int error;
45437741Smckusick 
45545914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
45647540Skarels 		return (error);
45739464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
45841400Smckusick 	sp = &mp->mnt_stat;
45948026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
46047540Skarels 		return (error);
46141400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
46247540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
46337741Smckusick }
46437741Smckusick 
46537741Smckusick /*
46649365Smckusick  * Get statistics on all filesystems.
46738270Smckusick  */
46854916Storek struct getfsstat_args {
46954916Storek 	struct statfs *buf;
47054916Storek 	long bufsize;
47154916Storek 	int flags;
47254916Storek };
47342441Smckusick getfsstat(p, uap, retval)
47445914Smckusick 	struct proc *p;
47554916Storek 	register struct getfsstat_args *uap;
47642441Smckusick 	int *retval;
47742441Smckusick {
47865259Smckusick 	register struct mount *mp, *nmp;
47940343Smckusick 	register struct statfs *sp;
48039606Smckusick 	caddr_t sfsp;
48138270Smckusick 	long count, maxcount, error;
48238270Smckusick 
48338270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
48439606Smckusick 	sfsp = (caddr_t)uap->buf;
48565259Smckusick 	for (count = 0, mp = mountlist.tqh_first; mp != NULL; mp = nmp) {
48665259Smckusick 		nmp = mp->mnt_list.tqe_next;
48741400Smckusick 		if (sfsp && count < maxcount &&
48841400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
48941400Smckusick 			sp = &mp->mnt_stat;
49040343Smckusick 			/*
49140343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
49240343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
49340343Smckusick 			 */
49440343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
49540343Smckusick 			    (uap->flags & MNT_WAIT)) &&
49665259Smckusick 			    (error = VFS_STATFS(mp, sp, p)))
49739607Smckusick 				continue;
49841400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
49940343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
50047540Skarels 				return (error);
50140343Smckusick 			sfsp += sizeof(*sp);
50238270Smckusick 		}
50339606Smckusick 		count++;
50465259Smckusick 	}
50538270Smckusick 	if (sfsp && count > maxcount)
50642441Smckusick 		*retval = maxcount;
50738270Smckusick 	else
50842441Smckusick 		*retval = count;
50947540Skarels 	return (0);
51038270Smckusick }
51138270Smckusick 
51238270Smckusick /*
51338259Smckusick  * Change current working directory to a given file descriptor.
51438259Smckusick  */
51554916Storek struct fchdir_args {
51654916Storek 	int	fd;
51754916Storek };
51842441Smckusick /* ARGSUSED */
51942441Smckusick fchdir(p, uap, retval)
52045914Smckusick 	struct proc *p;
52154916Storek 	struct fchdir_args *uap;
52242441Smckusick 	int *retval;
52338259Smckusick {
52445914Smckusick 	register struct filedesc *fdp = p->p_fd;
52567974Smckusick 	struct vnode *vp, *tdp;
52667974Smckusick 	struct mount *mp;
52738259Smckusick 	struct file *fp;
52838259Smckusick 	int error;
52938259Smckusick 
53045914Smckusick 	if (error = getvnode(fdp, uap->fd, &fp))
53147540Skarels 		return (error);
53238259Smckusick 	vp = (struct vnode *)fp->f_data;
53367974Smckusick 	VREF(vp);
53438259Smckusick 	VOP_LOCK(vp);
53538259Smckusick 	if (vp->v_type != VDIR)
53638259Smckusick 		error = ENOTDIR;
53738259Smckusick 	else
53848026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
53967974Smckusick 	while (!error && (mp = vp->v_mountedhere) != NULL) {
54067974Smckusick 		if (mp->mnt_flag & MNT_MLOCK) {
54167974Smckusick 			mp->mnt_flag |= MNT_MWAIT;
54267974Smckusick 			sleep((caddr_t)mp, PVFS);
54367974Smckusick 			continue;
54467974Smckusick 		}
54567974Smckusick 		if (error = VFS_ROOT(mp, &tdp))
54667974Smckusick 			break;
54767974Smckusick 		vput(vp);
54867974Smckusick 		vp = tdp;
54967974Smckusick 	}
55038259Smckusick 	VOP_UNLOCK(vp);
55167974Smckusick 	if (error) {
55267974Smckusick 		vrele(vp);
55347540Skarels 		return (error);
55467974Smckusick 	}
55545914Smckusick 	vrele(fdp->fd_cdir);
55645914Smckusick 	fdp->fd_cdir = vp;
55747540Skarels 	return (0);
55838259Smckusick }
55938259Smckusick 
56038259Smckusick /*
56137741Smckusick  * Change current working directory (``.'').
56237741Smckusick  */
56354916Storek struct chdir_args {
56464410Sbostic 	char	*path;
56554916Storek };
56642441Smckusick /* ARGSUSED */
56742441Smckusick chdir(p, uap, retval)
56845914Smckusick 	struct proc *p;
56954916Storek 	struct chdir_args *uap;
57042441Smckusick 	int *retval;
57137741Smckusick {
57245914Smckusick 	register struct filedesc *fdp = p->p_fd;
57337741Smckusick 	int error;
57447540Skarels 	struct nameidata nd;
5756254Sroot 
57664410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
57764410Sbostic 	if (error = change_dir(&nd, p))
57847540Skarels 		return (error);
57945914Smckusick 	vrele(fdp->fd_cdir);
58052322Smckusick 	fdp->fd_cdir = nd.ni_vp;
58147540Skarels 	return (0);
58237741Smckusick }
5836254Sroot 
58437741Smckusick /*
58537741Smckusick  * Change notion of root (``/'') directory.
58637741Smckusick  */
58754916Storek struct chroot_args {
58864410Sbostic 	char	*path;
58954916Storek };
59042441Smckusick /* ARGSUSED */
59142441Smckusick chroot(p, uap, retval)
59245914Smckusick 	struct proc *p;
59354916Storek 	struct chroot_args *uap;
59442441Smckusick 	int *retval;
59537741Smckusick {
59645914Smckusick 	register struct filedesc *fdp = p->p_fd;
59737741Smckusick 	int error;
59847540Skarels 	struct nameidata nd;
59937741Smckusick 
60047540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
60147540Skarels 		return (error);
60264410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
60364410Sbostic 	if (error = change_dir(&nd, p))
60447540Skarels 		return (error);
60545914Smckusick 	if (fdp->fd_rdir != NULL)
60645914Smckusick 		vrele(fdp->fd_rdir);
60752322Smckusick 	fdp->fd_rdir = nd.ni_vp;
60847540Skarels 	return (0);
6096254Sroot }
6106254Sroot 
61137Sbill /*
61237741Smckusick  * Common routine for chroot and chdir.
61337741Smckusick  */
61464410Sbostic static int
61564410Sbostic change_dir(ndp, p)
61652322Smckusick 	register struct nameidata *ndp;
61747540Skarels 	struct proc *p;
61837741Smckusick {
61937741Smckusick 	struct vnode *vp;
62037741Smckusick 	int error;
62137741Smckusick 
62252322Smckusick 	if (error = namei(ndp))
62337741Smckusick 		return (error);
62437741Smckusick 	vp = ndp->ni_vp;
62537741Smckusick 	if (vp->v_type != VDIR)
62637741Smckusick 		error = ENOTDIR;
62737741Smckusick 	else
62848026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
62937741Smckusick 	VOP_UNLOCK(vp);
63037741Smckusick 	if (error)
63137741Smckusick 		vrele(vp);
63237741Smckusick 	return (error);
63337741Smckusick }
63437741Smckusick 
63537741Smckusick /*
63642441Smckusick  * Check permissions, allocate an open file structure,
63742441Smckusick  * and call the device open routine if any.
6386254Sroot  */
63954916Storek struct open_args {
64064410Sbostic 	char	*path;
64164410Sbostic 	int	flags;
64254916Storek 	int	mode;
64354916Storek };
64442441Smckusick open(p, uap, retval)
64545914Smckusick 	struct proc *p;
64654916Storek 	register struct open_args *uap;
64742441Smckusick 	int *retval;
6486254Sroot {
64945914Smckusick 	register struct filedesc *fdp = p->p_fd;
65042441Smckusick 	register struct file *fp;
65150111Smckusick 	register struct vnode *vp;
65264410Sbostic 	int flags, cmode;
65337741Smckusick 	struct file *nfp;
65449945Smckusick 	int type, indx, error;
65549945Smckusick 	struct flock lf;
65647540Skarels 	struct nameidata nd;
65737741Smckusick 	extern struct fileops vnops;
6586254Sroot 
65945914Smckusick 	if (error = falloc(p, &nfp, &indx))
66047540Skarels 		return (error);
66137741Smckusick 	fp = nfp;
66264410Sbostic 	flags = FFLAGS(uap->flags);
66364410Sbostic 	cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
66464410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
66545202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
66664410Sbostic 	if (error = vn_open(&nd, flags, cmode)) {
66749980Smckusick 		ffree(fp);
66854723Smckusick 		if ((error == ENODEV || error == ENXIO) &&
66954723Smckusick 		    p->p_dupfd >= 0 && 			/* XXX from fdopen */
67064410Sbostic 		    (error =
67164410Sbostic 		        dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
67242441Smckusick 			*retval = indx;
67347540Skarels 			return (0);
67442441Smckusick 		}
67540884Smckusick 		if (error == ERESTART)
67640884Smckusick 			error = EINTR;
67747688Skarels 		fdp->fd_ofiles[indx] = NULL;
67847540Skarels 		return (error);
67912756Ssam 	}
68053828Spendry 	p->p_dupfd = 0;
68152322Smckusick 	vp = nd.ni_vp;
68264410Sbostic 	fp->f_flag = flags & FMASK;
68354348Smckusick 	fp->f_type = DTYPE_VNODE;
68454348Smckusick 	fp->f_ops = &vnops;
68554348Smckusick 	fp->f_data = (caddr_t)vp;
68664410Sbostic 	if (flags & (O_EXLOCK | O_SHLOCK)) {
68749945Smckusick 		lf.l_whence = SEEK_SET;
68849945Smckusick 		lf.l_start = 0;
68949945Smckusick 		lf.l_len = 0;
69064410Sbostic 		if (flags & O_EXLOCK)
69149945Smckusick 			lf.l_type = F_WRLCK;
69249945Smckusick 		else
69349945Smckusick 			lf.l_type = F_RDLCK;
69449945Smckusick 		type = F_FLOCK;
69564410Sbostic 		if ((flags & FNONBLOCK) == 0)
69649945Smckusick 			type |= F_WAIT;
69765757Smckusick 		VOP_UNLOCK(vp);
69850111Smckusick 		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
69950111Smckusick 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
70049980Smckusick 			ffree(fp);
70149945Smckusick 			fdp->fd_ofiles[indx] = NULL;
70249945Smckusick 			return (error);
70349945Smckusick 		}
70465757Smckusick 		VOP_LOCK(vp);
70549949Smckusick 		fp->f_flag |= FHASLOCK;
70649945Smckusick 	}
70750111Smckusick 	VOP_UNLOCK(vp);
70842441Smckusick 	*retval = indx;
70947540Skarels 	return (0);
7106254Sroot }
7116254Sroot 
71242955Smckusick #ifdef COMPAT_43
7136254Sroot /*
71464410Sbostic  * Create a file.
7156254Sroot  */
71654916Storek struct ocreat_args {
71764410Sbostic 	char	*path;
71864410Sbostic 	int	mode;
71954916Storek };
72042955Smckusick ocreat(p, uap, retval)
72142441Smckusick 	struct proc *p;
72254916Storek 	register struct ocreat_args *uap;
72342441Smckusick 	int *retval;
7246254Sroot {
72554916Storek 	struct open_args openuap;
72642441Smckusick 
72764410Sbostic 	openuap.path = uap->path;
72864410Sbostic 	openuap.mode = uap->mode;
72964410Sbostic 	openuap.flags = O_WRONLY | O_CREAT | O_TRUNC;
73047540Skarels 	return (open(p, &openuap, retval));
73142441Smckusick }
73242955Smckusick #endif /* COMPAT_43 */
73342441Smckusick 
73442441Smckusick /*
73564410Sbostic  * Create a special file.
73642441Smckusick  */
73754916Storek struct mknod_args {
73864410Sbostic 	char	*path;
73964410Sbostic 	int	mode;
74054916Storek 	int	dev;
74154916Storek };
74242441Smckusick /* ARGSUSED */
74342441Smckusick mknod(p, uap, retval)
74445914Smckusick 	struct proc *p;
74554916Storek 	register struct mknod_args *uap;
74642441Smckusick 	int *retval;
74742441Smckusick {
74837741Smckusick 	register struct vnode *vp;
74937741Smckusick 	struct vattr vattr;
75037741Smckusick 	int error;
75167575Spendry 	int whiteout;
75247540Skarels 	struct nameidata nd;
7536254Sroot 
75447540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
75547540Skarels 		return (error);
75664410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
75752322Smckusick 	if (error = namei(&nd))
75847540Skarels 		return (error);
75952322Smckusick 	vp = nd.ni_vp;
76064585Sbostic 	if (vp != NULL)
76137741Smckusick 		error = EEXIST;
76264585Sbostic 	else {
76364585Sbostic 		VATTR_NULL(&vattr);
76464585Sbostic 		vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
76564585Sbostic 		vattr.va_rdev = uap->dev;
76667575Spendry 		whiteout = 0;
76764585Sbostic 
76864585Sbostic 		switch (uap->mode & S_IFMT) {
76964585Sbostic 		case S_IFMT:	/* used by badsect to flag bad sectors */
77064585Sbostic 			vattr.va_type = VBAD;
77164585Sbostic 			break;
77264585Sbostic 		case S_IFCHR:
77364585Sbostic 			vattr.va_type = VCHR;
77464585Sbostic 			break;
77564585Sbostic 		case S_IFBLK:
77664585Sbostic 			vattr.va_type = VBLK;
77764585Sbostic 			break;
77867575Spendry 		case S_IFWHT:
77967575Spendry 			whiteout = 1;
78067575Spendry 			break;
78164585Sbostic 		default:
78264585Sbostic 			error = EINVAL;
78364585Sbostic 			break;
78464585Sbostic 		}
7856254Sroot 	}
78667747Spendry 	if (!error) {
78767654Smckusick 		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
78867747Spendry 		if (whiteout) {
78967747Spendry 			error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
79067747Spendry 			if (error)
79167747Spendry 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
79267747Spendry 			vput(nd.ni_dvp);
79367747Spendry 		} else {
79467747Spendry 			error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
79567747Spendry 						&nd.ni_cnd, &vattr);
79667747Spendry 		}
79742465Smckusick 	} else {
79852322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
79952322Smckusick 		if (nd.ni_dvp == vp)
80052322Smckusick 			vrele(nd.ni_dvp);
80143344Smckusick 		else
80252322Smckusick 			vput(nd.ni_dvp);
80342465Smckusick 		if (vp)
80442465Smckusick 			vrele(vp);
80542465Smckusick 	}
80647540Skarels 	return (error);
8076254Sroot }
8086254Sroot 
8096254Sroot /*
81064410Sbostic  * Create named pipe.
81140285Smckusick  */
81254916Storek struct mkfifo_args {
81364410Sbostic 	char	*path;
81464410Sbostic 	int	mode;
81554916Storek };
81642441Smckusick /* ARGSUSED */
81742441Smckusick mkfifo(p, uap, retval)
81845914Smckusick 	struct proc *p;
81954916Storek 	register struct mkfifo_args *uap;
82042441Smckusick 	int *retval;
82142441Smckusick {
82240285Smckusick 	struct vattr vattr;
82340285Smckusick 	int error;
82447540Skarels 	struct nameidata nd;
82540285Smckusick 
82640285Smckusick #ifndef FIFO
82747540Skarels 	return (EOPNOTSUPP);
82840285Smckusick #else
82964410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
83052322Smckusick 	if (error = namei(&nd))
83147540Skarels 		return (error);
83252322Smckusick 	if (nd.ni_vp != NULL) {
83352322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
83452322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
83552322Smckusick 			vrele(nd.ni_dvp);
83643344Smckusick 		else
83752322Smckusick 			vput(nd.ni_dvp);
83852322Smckusick 		vrele(nd.ni_vp);
83947540Skarels 		return (EEXIST);
84040285Smckusick 	}
84145785Sbostic 	VATTR_NULL(&vattr);
84245785Sbostic 	vattr.va_type = VFIFO;
84364410Sbostic 	vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
84467654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
84552322Smckusick 	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
84640285Smckusick #endif /* FIFO */
84740285Smckusick }
84840285Smckusick 
84940285Smckusick /*
85064410Sbostic  * Make a hard file link.
8516254Sroot  */
85254916Storek struct link_args {
85364410Sbostic 	char	*path;
85464410Sbostic 	char	*link;
85554916Storek };
85642441Smckusick /* ARGSUSED */
85742441Smckusick link(p, uap, retval)
85845914Smckusick 	struct proc *p;
85954916Storek 	register struct link_args *uap;
86042441Smckusick 	int *retval;
86142441Smckusick {
86264410Sbostic 	register struct vnode *vp;
86364410Sbostic 	struct nameidata nd;
86437741Smckusick 	int error;
8656254Sroot 
86664410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
86752322Smckusick 	if (error = namei(&nd))
86847540Skarels 		return (error);
86952322Smckusick 	vp = nd.ni_vp;
87064585Sbostic 	if (vp->v_type != VDIR ||
87164585Sbostic 	    (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
87264585Sbostic 		nd.ni_cnd.cn_nameiop = CREATE;
87364585Sbostic 		nd.ni_cnd.cn_flags = LOCKPARENT;
87464585Sbostic 		nd.ni_dirp = uap->link;
87564585Sbostic 		if ((error = namei(&nd)) == 0) {
87664585Sbostic 			if (nd.ni_vp != NULL)
87764585Sbostic 				error = EEXIST;
87864585Sbostic 			if (!error) {
87967654Smckusick 				VOP_LEASE(nd.ni_dvp, p, p->p_ucred,
88067654Smckusick 				    LEASE_WRITE);
88167654Smckusick 				VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
88264585Sbostic 				error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
88364585Sbostic 			} else {
88464585Sbostic 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
88564585Sbostic 				if (nd.ni_dvp == nd.ni_vp)
88664585Sbostic 					vrele(nd.ni_dvp);
88764585Sbostic 				else
88864585Sbostic 					vput(nd.ni_dvp);
88964585Sbostic 				if (nd.ni_vp)
89064585Sbostic 					vrele(nd.ni_vp);
89164585Sbostic 			}
89264585Sbostic 		}
89342465Smckusick 	}
89464585Sbostic 	vrele(vp);
89547540Skarels 	return (error);
8966254Sroot }
8976254Sroot 
8986254Sroot /*
89949365Smckusick  * Make a symbolic link.
9006254Sroot  */
90154916Storek struct symlink_args {
90264410Sbostic 	char	*path;
90364410Sbostic 	char	*link;
90454916Storek };
90542441Smckusick /* ARGSUSED */
90642441Smckusick symlink(p, uap, retval)
90745914Smckusick 	struct proc *p;
90854916Storek 	register struct symlink_args *uap;
90942441Smckusick 	int *retval;
91042441Smckusick {
91137741Smckusick 	struct vattr vattr;
91264410Sbostic 	char *path;
91337741Smckusick 	int error;
91447540Skarels 	struct nameidata nd;
9156254Sroot 
91664410Sbostic 	MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
91764410Sbostic 	if (error = copyinstr(uap->path, path, MAXPATHLEN, NULL))
91842465Smckusick 		goto out;
91964410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p);
92052322Smckusick 	if (error = namei(&nd))
92142465Smckusick 		goto out;
92252322Smckusick 	if (nd.ni_vp) {
92352322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
92452322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
92552322Smckusick 			vrele(nd.ni_dvp);
92643344Smckusick 		else
92752322Smckusick 			vput(nd.ni_dvp);
92852322Smckusick 		vrele(nd.ni_vp);
92937741Smckusick 		error = EEXIST;
93037741Smckusick 		goto out;
9316254Sroot 	}
93241362Smckusick 	VATTR_NULL(&vattr);
93364410Sbostic 	vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
93467654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
93564410Sbostic 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
93637741Smckusick out:
93764410Sbostic 	FREE(path, M_NAMEI);
93847540Skarels 	return (error);
9396254Sroot }
9406254Sroot 
9416254Sroot /*
94267518Spendry  * Delete a whiteout from the filesystem.
94367518Spendry  */
94467845Smckusick struct undelete_args {
94567518Spendry 	char	*path;
94667518Spendry };
94767518Spendry /* ARGSUSED */
94867845Smckusick undelete(p, uap, retval)
94967518Spendry 	struct proc *p;
95067845Smckusick 	struct undelete_args *uap;
95167518Spendry 	int *retval;
95267518Spendry {
95367518Spendry 	int error;
95467518Spendry 	struct nameidata nd;
95567518Spendry 
95667575Spendry 	NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, uap->path, p);
95767575Spendry 	error = namei(&nd);
95867575Spendry 	if (error)
95967518Spendry 		return (error);
96067575Spendry 
96167575Spendry 	if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
96267518Spendry 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
96367518Spendry 		if (nd.ni_dvp == nd.ni_vp)
96467518Spendry 			vrele(nd.ni_dvp);
96567518Spendry 		else
96667518Spendry 			vput(nd.ni_dvp);
96767518Spendry 		if (nd.ni_vp)
96867518Spendry 			vrele(nd.ni_vp);
96967518Spendry 		return (EEXIST);
97067518Spendry 	}
97167575Spendry 
97267654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
97367747Spendry 	if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE))
97467575Spendry 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
97567518Spendry 	vput(nd.ni_dvp);
97667518Spendry 	return (error);
97767518Spendry }
97867518Spendry 
97967518Spendry /*
98049365Smckusick  * Delete a name from the filesystem.
9816254Sroot  */
98254916Storek struct unlink_args {
98364410Sbostic 	char	*path;
98454916Storek };
98542441Smckusick /* ARGSUSED */
98642441Smckusick unlink(p, uap, retval)
98745914Smckusick 	struct proc *p;
98854916Storek 	struct unlink_args *uap;
98942441Smckusick 	int *retval;
9906254Sroot {
99137741Smckusick 	register struct vnode *vp;
99237741Smckusick 	int error;
99347540Skarels 	struct nameidata nd;
9946254Sroot 
99564410Sbostic 	NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
99652322Smckusick 	if (error = namei(&nd))
99747540Skarels 		return (error);
99852322Smckusick 	vp = nd.ni_vp;
99967654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
100059382Smckusick 	VOP_LOCK(vp);
100164410Sbostic 
100264585Sbostic 	if (vp->v_type != VDIR ||
100364585Sbostic 	    (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
100464585Sbostic 		/*
100564585Sbostic 		 * The root of a mounted filesystem cannot be deleted.
100664585Sbostic 		 */
100764585Sbostic 		if (vp->v_flag & VROOT)
100864585Sbostic 			error = EBUSY;
100964585Sbostic 		else
101064585Sbostic 			(void)vnode_pager_uncache(vp);
101164585Sbostic 	}
101264585Sbostic 
101364585Sbostic 	if (!error) {
101467654Smckusick 		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
101552322Smckusick 		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
101642465Smckusick 	} else {
101752322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
101852322Smckusick 		if (nd.ni_dvp == vp)
101952322Smckusick 			vrele(nd.ni_dvp);
102043344Smckusick 		else
102152322Smckusick 			vput(nd.ni_dvp);
102267575Spendry 		if (vp != NULLVP)
102367575Spendry 			vput(vp);
102442465Smckusick 	}
102547540Skarels 	return (error);
10266254Sroot }
10276254Sroot 
102864410Sbostic /*
102964410Sbostic  * Reposition read/write file offset.
103064410Sbostic  */
103160428Smckusick struct lseek_args {
103264410Sbostic 	int	fd;
103354863Storek 	int	pad;
103464410Sbostic 	off_t	offset;
103564410Sbostic 	int	whence;
103654863Storek };
103760414Smckusick lseek(p, uap, retval)
103853468Smckusick 	struct proc *p;
103960428Smckusick 	register struct lseek_args *uap;
104054916Storek 	int *retval;
104142441Smckusick {
104247540Skarels 	struct ucred *cred = p->p_ucred;
104345914Smckusick 	register struct filedesc *fdp = p->p_fd;
104442441Smckusick 	register struct file *fp;
104537741Smckusick 	struct vattr vattr;
104637741Smckusick 	int error;
10476254Sroot 
104864410Sbostic 	if ((u_int)uap->fd >= fdp->fd_nfiles ||
104964410Sbostic 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
105047540Skarels 		return (EBADF);
105137741Smckusick 	if (fp->f_type != DTYPE_VNODE)
105247540Skarels 		return (ESPIPE);
105364410Sbostic 	switch (uap->whence) {
105413878Ssam 	case L_INCR:
105564410Sbostic 		fp->f_offset += uap->offset;
105613878Ssam 		break;
105713878Ssam 	case L_XTND:
105864410Sbostic 		if (error =
105964410Sbostic 		    VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p))
106047540Skarels 			return (error);
106164410Sbostic 		fp->f_offset = uap->offset + vattr.va_size;
106213878Ssam 		break;
106313878Ssam 	case L_SET:
106464410Sbostic 		fp->f_offset = uap->offset;
106513878Ssam 		break;
106613878Ssam 	default:
106747540Skarels 		return (EINVAL);
106813878Ssam 	}
106954916Storek 	*(off_t *)retval = fp->f_offset;
107047540Skarels 	return (0);
10716254Sroot }
10726254Sroot 
107360414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
10746254Sroot /*
107564410Sbostic  * Reposition read/write file offset.
107660036Smckusick  */
107760428Smckusick struct olseek_args {
107864410Sbostic 	int	fd;
107964410Sbostic 	long	offset;
108064410Sbostic 	int	whence;
108160036Smckusick };
108260414Smckusick olseek(p, uap, retval)
108360036Smckusick 	struct proc *p;
108460428Smckusick 	register struct olseek_args *uap;
108560036Smckusick 	int *retval;
108660036Smckusick {
108760428Smckusick 	struct lseek_args nuap;
108860036Smckusick 	off_t qret;
108960036Smckusick 	int error;
109060036Smckusick 
109164410Sbostic 	nuap.fd = uap->fd;
109264410Sbostic 	nuap.offset = uap->offset;
109364410Sbostic 	nuap.whence = uap->whence;
109460428Smckusick 	error = lseek(p, &nuap, &qret);
109560036Smckusick 	*(long *)retval = qret;
109660036Smckusick 	return (error);
109760036Smckusick }
109860414Smckusick #endif /* COMPAT_43 */
109960036Smckusick 
110060036Smckusick /*
110149365Smckusick  * Check access permissions.
11026254Sroot  */
110363427Sbostic struct access_args {
110464410Sbostic 	char	*path;
110564410Sbostic 	int	flags;
110654916Storek };
110763427Sbostic access(p, uap, retval)
110845914Smckusick 	struct proc *p;
110963427Sbostic 	register struct access_args *uap;
111042441Smckusick 	int *retval;
111142441Smckusick {
111247540Skarels 	register struct ucred *cred = p->p_ucred;
111337741Smckusick 	register struct vnode *vp;
111464585Sbostic 	int error, flags, t_gid, t_uid;
111547540Skarels 	struct nameidata nd;
11166254Sroot 
111764585Sbostic 	t_uid = cred->cr_uid;
111864585Sbostic 	t_gid = cred->cr_groups[0];
111947540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
112047540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
112164410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
112252322Smckusick 	if (error = namei(&nd))
112337741Smckusick 		goto out1;
112452322Smckusick 	vp = nd.ni_vp;
112564410Sbostic 
112664410Sbostic 	/* Flags == 0 means only check for existence. */
112764410Sbostic 	if (uap->flags) {
112864410Sbostic 		flags = 0;
112964410Sbostic 		if (uap->flags & R_OK)
113064410Sbostic 			flags |= VREAD;
113164410Sbostic 		if (uap->flags & W_OK)
113264410Sbostic 			flags |= VWRITE;
113364410Sbostic 		if (uap->flags & X_OK)
113464410Sbostic 			flags |= VEXEC;
113564410Sbostic 		if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
113664410Sbostic 			error = VOP_ACCESS(vp, flags, cred, p);
11376254Sroot 	}
113837741Smckusick 	vput(vp);
113937741Smckusick out1:
114064585Sbostic 	cred->cr_uid = t_uid;
114164585Sbostic 	cred->cr_groups[0] = t_gid;
114247540Skarels 	return (error);
11436254Sroot }
11446254Sroot 
114554348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
11466254Sroot /*
114764410Sbostic  * Get file status; this version follows links.
114837Sbill  */
114954916Storek struct ostat_args {
115064410Sbostic 	char	*path;
115154916Storek 	struct ostat *ub;
115254916Storek };
115342441Smckusick /* ARGSUSED */
115453759Smckusick ostat(p, uap, retval)
115545914Smckusick 	struct proc *p;
115654916Storek 	register struct ostat_args *uap;
115753468Smckusick 	int *retval;
115853468Smckusick {
115953468Smckusick 	struct stat sb;
116053468Smckusick 	struct ostat osb;
116153468Smckusick 	int error;
116253468Smckusick 	struct nameidata nd;
116353468Smckusick 
116464410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
116553468Smckusick 	if (error = namei(&nd))
116653468Smckusick 		return (error);
116753468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
116853468Smckusick 	vput(nd.ni_vp);
116953468Smckusick 	if (error)
117053468Smckusick 		return (error);
117153468Smckusick 	cvtstat(&sb, &osb);
117253468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
117353468Smckusick 	return (error);
117453468Smckusick }
117553468Smckusick 
117653468Smckusick /*
117764410Sbostic  * Get file status; this version does not follow links.
117853468Smckusick  */
117954916Storek struct olstat_args {
118064410Sbostic 	char	*path;
118154916Storek 	struct ostat *ub;
118254916Storek };
118353468Smckusick /* ARGSUSED */
118453759Smckusick olstat(p, uap, retval)
118553468Smckusick 	struct proc *p;
118654916Storek 	register struct olstat_args *uap;
118753468Smckusick 	int *retval;
118853468Smckusick {
118967748Smckusick 	struct vnode *vp, *dvp;
119067748Smckusick 	struct stat sb, sb1;
119153468Smckusick 	struct ostat osb;
119253468Smckusick 	int error;
119353468Smckusick 	struct nameidata nd;
119453468Smckusick 
119567748Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
119667748Smckusick 	    uap->path, p);
119753468Smckusick 	if (error = namei(&nd))
119853468Smckusick 		return (error);
119967748Smckusick 	/*
120067748Smckusick 	 * For symbolic links, always return the attributes of its
120167748Smckusick 	 * containing directory, except for mode, size, and links.
120267748Smckusick 	 */
120367748Smckusick 	vp = nd.ni_vp;
120467748Smckusick 	dvp = nd.ni_dvp;
120567748Smckusick 	if (vp->v_type != VLNK) {
120667748Smckusick 		if (dvp == vp)
120767748Smckusick 			vrele(dvp);
120867748Smckusick 		else
120967748Smckusick 			vput(dvp);
121067748Smckusick 		error = vn_stat(vp, &sb, p);
121167748Smckusick 		vput(vp);
121267748Smckusick 		if (error)
121367748Smckusick 			return (error);
121467748Smckusick 	} else {
121567748Smckusick 		error = vn_stat(dvp, &sb, p);
121667748Smckusick 		vput(dvp);
121767748Smckusick 		if (error) {
121867748Smckusick 			vput(vp);
121967748Smckusick 			return (error);
122067748Smckusick 		}
122167748Smckusick 		error = vn_stat(vp, &sb1, p);
122267748Smckusick 		vput(vp);
122367748Smckusick 		if (error)
122467748Smckusick 			return (error);
122567748Smckusick 		sb.st_mode &= ~S_IFDIR;
122667748Smckusick 		sb.st_mode |= S_IFLNK;
122767748Smckusick 		sb.st_nlink = sb1.st_nlink;
122867748Smckusick 		sb.st_size = sb1.st_size;
122967748Smckusick 		sb.st_blocks = sb1.st_blocks;
123067748Smckusick 	}
123153468Smckusick 	cvtstat(&sb, &osb);
123253468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
123353468Smckusick 	return (error);
123453468Smckusick }
123553468Smckusick 
123653468Smckusick /*
123764410Sbostic  * Convert from an old to a new stat structure.
123853468Smckusick  */
123953468Smckusick cvtstat(st, ost)
124053468Smckusick 	struct stat *st;
124153468Smckusick 	struct ostat *ost;
124253468Smckusick {
124353468Smckusick 
124453468Smckusick 	ost->st_dev = st->st_dev;
124553468Smckusick 	ost->st_ino = st->st_ino;
124653468Smckusick 	ost->st_mode = st->st_mode;
124753468Smckusick 	ost->st_nlink = st->st_nlink;
124853468Smckusick 	ost->st_uid = st->st_uid;
124953468Smckusick 	ost->st_gid = st->st_gid;
125053468Smckusick 	ost->st_rdev = st->st_rdev;
125153468Smckusick 	if (st->st_size < (quad_t)1 << 32)
125253468Smckusick 		ost->st_size = st->st_size;
125353468Smckusick 	else
125453468Smckusick 		ost->st_size = -2;
125553468Smckusick 	ost->st_atime = st->st_atime;
125653468Smckusick 	ost->st_mtime = st->st_mtime;
125753468Smckusick 	ost->st_ctime = st->st_ctime;
125853468Smckusick 	ost->st_blksize = st->st_blksize;
125953468Smckusick 	ost->st_blocks = st->st_blocks;
126053468Smckusick 	ost->st_flags = st->st_flags;
126153468Smckusick 	ost->st_gen = st->st_gen;
126253468Smckusick }
126354348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
126453468Smckusick 
126553468Smckusick /*
126664410Sbostic  * Get file status; this version follows links.
126753468Smckusick  */
126854916Storek struct stat_args {
126964410Sbostic 	char	*path;
127054916Storek 	struct stat *ub;
127154916Storek };
127253468Smckusick /* ARGSUSED */
127353759Smckusick stat(p, uap, retval)
127453468Smckusick 	struct proc *p;
127554916Storek 	register struct stat_args *uap;
127642441Smckusick 	int *retval;
127737Sbill {
127842441Smckusick 	struct stat sb;
127942441Smckusick 	int error;
128047540Skarels 	struct nameidata nd;
128137Sbill 
128264410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
128352322Smckusick 	if (error = namei(&nd))
128447540Skarels 		return (error);
128552322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
128652322Smckusick 	vput(nd.ni_vp);
128742441Smckusick 	if (error)
128847540Skarels 		return (error);
128942441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
129047540Skarels 	return (error);
129137Sbill }
129237Sbill 
129337Sbill /*
129464410Sbostic  * Get file status; this version does not follow links.
12955992Swnj  */
129654916Storek struct lstat_args {
129764410Sbostic 	char	*path;
129854916Storek 	struct stat *ub;
129954916Storek };
130042441Smckusick /* ARGSUSED */
130153759Smckusick lstat(p, uap, retval)
130245914Smckusick 	struct proc *p;
130354916Storek 	register struct lstat_args *uap;
130442441Smckusick 	int *retval;
130542441Smckusick {
130637741Smckusick 	int error;
130759373Smckusick 	struct vnode *vp, *dvp;
130859373Smckusick 	struct stat sb, sb1;
130947540Skarels 	struct nameidata nd;
13105992Swnj 
131159373Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
131264410Sbostic 	    uap->path, p);
131352322Smckusick 	if (error = namei(&nd))
131447540Skarels 		return (error);
131559373Smckusick 	/*
131659373Smckusick 	 * For symbolic links, always return the attributes of its
131759373Smckusick 	 * containing directory, except for mode, size, and links.
131859373Smckusick 	 */
131959373Smckusick 	vp = nd.ni_vp;
132059373Smckusick 	dvp = nd.ni_dvp;
132159373Smckusick 	if (vp->v_type != VLNK) {
132259373Smckusick 		if (dvp == vp)
132359373Smckusick 			vrele(dvp);
132459373Smckusick 		else
132559373Smckusick 			vput(dvp);
132659373Smckusick 		error = vn_stat(vp, &sb, p);
132759373Smckusick 		vput(vp);
132859373Smckusick 		if (error)
132959373Smckusick 			return (error);
133059373Smckusick 	} else {
133159373Smckusick 		error = vn_stat(dvp, &sb, p);
133259373Smckusick 		vput(dvp);
133359373Smckusick 		if (error) {
133459373Smckusick 			vput(vp);
133559373Smckusick 			return (error);
133659373Smckusick 		}
133759373Smckusick 		error = vn_stat(vp, &sb1, p);
133859373Smckusick 		vput(vp);
133959373Smckusick 		if (error)
134059373Smckusick 			return (error);
134159373Smckusick 		sb.st_mode &= ~S_IFDIR;
134259373Smckusick 		sb.st_mode |= S_IFLNK;
134359373Smckusick 		sb.st_nlink = sb1.st_nlink;
134459373Smckusick 		sb.st_size = sb1.st_size;
134559373Smckusick 		sb.st_blocks = sb1.st_blocks;
134659373Smckusick 	}
134737741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
134847540Skarels 	return (error);
13495992Swnj }
13505992Swnj 
13515992Swnj /*
135264410Sbostic  * Get configurable pathname variables.
135360414Smckusick  */
135460414Smckusick struct pathconf_args {
135564410Sbostic 	char	*path;
135660414Smckusick 	int	name;
135760414Smckusick };
135860414Smckusick /* ARGSUSED */
135960414Smckusick pathconf(p, uap, retval)
136060414Smckusick 	struct proc *p;
136160414Smckusick 	register struct pathconf_args *uap;
136260414Smckusick 	int *retval;
136360414Smckusick {
136460414Smckusick 	int error;
136560414Smckusick 	struct nameidata nd;
136660414Smckusick 
136764410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
136860414Smckusick 	if (error = namei(&nd))
136960414Smckusick 		return (error);
137060414Smckusick 	error = VOP_PATHCONF(nd.ni_vp, uap->name, retval);
137160414Smckusick 	vput(nd.ni_vp);
137260414Smckusick 	return (error);
137360414Smckusick }
137460414Smckusick 
137560414Smckusick /*
137649365Smckusick  * Return target name of a symbolic link.
137737Sbill  */
137854916Storek struct readlink_args {
137964410Sbostic 	char	*path;
138054916Storek 	char	*buf;
138154916Storek 	int	count;
138254916Storek };
138342441Smckusick /* ARGSUSED */
138442441Smckusick readlink(p, uap, retval)
138545914Smckusick 	struct proc *p;
138654916Storek 	register struct readlink_args *uap;
138742441Smckusick 	int *retval;
138842441Smckusick {
138937741Smckusick 	register struct vnode *vp;
139037741Smckusick 	struct iovec aiov;
139137741Smckusick 	struct uio auio;
139237741Smckusick 	int error;
139347540Skarels 	struct nameidata nd;
13945992Swnj 
139564410Sbostic 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
139652322Smckusick 	if (error = namei(&nd))
139747540Skarels 		return (error);
139852322Smckusick 	vp = nd.ni_vp;
139964410Sbostic 	if (vp->v_type != VLNK)
140037741Smckusick 		error = EINVAL;
140164410Sbostic 	else {
140264410Sbostic 		aiov.iov_base = uap->buf;
140364410Sbostic 		aiov.iov_len = uap->count;
140464410Sbostic 		auio.uio_iov = &aiov;
140564410Sbostic 		auio.uio_iovcnt = 1;
140664410Sbostic 		auio.uio_offset = 0;
140764410Sbostic 		auio.uio_rw = UIO_READ;
140864410Sbostic 		auio.uio_segflg = UIO_USERSPACE;
140964410Sbostic 		auio.uio_procp = p;
141064410Sbostic 		auio.uio_resid = uap->count;
141164410Sbostic 		error = VOP_READLINK(vp, &auio, p->p_ucred);
14125992Swnj 	}
141337741Smckusick 	vput(vp);
141442441Smckusick 	*retval = uap->count - auio.uio_resid;
141547540Skarels 	return (error);
14165992Swnj }
14175992Swnj 
14189167Ssam /*
141964410Sbostic  * Change flags of a file given a path name.
142038259Smckusick  */
142154916Storek struct chflags_args {
142264410Sbostic 	char	*path;
142354916Storek 	int	flags;
142454916Storek };
142542441Smckusick /* ARGSUSED */
142642441Smckusick chflags(p, uap, retval)
142745914Smckusick 	struct proc *p;
142854916Storek 	register struct chflags_args *uap;
142942441Smckusick 	int *retval;
143042441Smckusick {
143138259Smckusick 	register struct vnode *vp;
143238259Smckusick 	struct vattr vattr;
143338259Smckusick 	int error;
143447540Skarels 	struct nameidata nd;
143538259Smckusick 
143664410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
143752322Smckusick 	if (error = namei(&nd))
143847540Skarels 		return (error);
143952322Smckusick 	vp = nd.ni_vp;
144067654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
144159382Smckusick 	VOP_LOCK(vp);
144264410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
144338259Smckusick 		error = EROFS;
144464410Sbostic 	else {
144564410Sbostic 		VATTR_NULL(&vattr);
144664410Sbostic 		vattr.va_flags = uap->flags;
144764410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
144838259Smckusick 	}
144938259Smckusick 	vput(vp);
145047540Skarels 	return (error);
145138259Smckusick }
145238259Smckusick 
145338259Smckusick /*
145438259Smckusick  * Change flags of a file given a file descriptor.
145538259Smckusick  */
145654916Storek struct fchflags_args {
145754916Storek 	int	fd;
145854916Storek 	int	flags;
145954916Storek };
146042441Smckusick /* ARGSUSED */
146142441Smckusick fchflags(p, uap, retval)
146245914Smckusick 	struct proc *p;
146354916Storek 	register struct fchflags_args *uap;
146442441Smckusick 	int *retval;
146542441Smckusick {
146638259Smckusick 	struct vattr vattr;
146738259Smckusick 	struct vnode *vp;
146838259Smckusick 	struct file *fp;
146938259Smckusick 	int error;
147038259Smckusick 
147145914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
147247540Skarels 		return (error);
147338259Smckusick 	vp = (struct vnode *)fp->f_data;
147467654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
147538259Smckusick 	VOP_LOCK(vp);
147664410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
147738259Smckusick 		error = EROFS;
147864410Sbostic 	else {
147964410Sbostic 		VATTR_NULL(&vattr);
148064410Sbostic 		vattr.va_flags = uap->flags;
148164410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
148238259Smckusick 	}
148338259Smckusick 	VOP_UNLOCK(vp);
148447540Skarels 	return (error);
148538259Smckusick }
148638259Smckusick 
148738259Smckusick /*
14889167Ssam  * Change mode of a file given path name.
14899167Ssam  */
149054916Storek struct chmod_args {
149164410Sbostic 	char	*path;
149264410Sbostic 	int	mode;
149354916Storek };
149442441Smckusick /* ARGSUSED */
149542441Smckusick chmod(p, uap, retval)
149645914Smckusick 	struct proc *p;
149754916Storek 	register struct chmod_args *uap;
149842441Smckusick 	int *retval;
149942441Smckusick {
150037741Smckusick 	register struct vnode *vp;
150137741Smckusick 	struct vattr vattr;
150237741Smckusick 	int error;
150347540Skarels 	struct nameidata nd;
15045992Swnj 
150564410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
150652322Smckusick 	if (error = namei(&nd))
150747540Skarels 		return (error);
150852322Smckusick 	vp = nd.ni_vp;
150967654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
151059382Smckusick 	VOP_LOCK(vp);
151164410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
151237741Smckusick 		error = EROFS;
151364410Sbostic 	else {
151464410Sbostic 		VATTR_NULL(&vattr);
151564410Sbostic 		vattr.va_mode = uap->mode & ALLPERMS;
151664410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
151737741Smckusick 	}
151837741Smckusick 	vput(vp);
151947540Skarels 	return (error);
15207701Ssam }
15217439Sroot 
15229167Ssam /*
15239167Ssam  * Change mode of a file given a file descriptor.
15249167Ssam  */
152554916Storek struct fchmod_args {
152654916Storek 	int	fd;
152764410Sbostic 	int	mode;
152854916Storek };
152942441Smckusick /* ARGSUSED */
153042441Smckusick fchmod(p, uap, retval)
153145914Smckusick 	struct proc *p;
153254916Storek 	register struct fchmod_args *uap;
153342441Smckusick 	int *retval;
153442441Smckusick {
153537741Smckusick 	struct vattr vattr;
153637741Smckusick 	struct vnode *vp;
153737741Smckusick 	struct file *fp;
153837741Smckusick 	int error;
15397701Ssam 
154045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
154147540Skarels 		return (error);
154237741Smckusick 	vp = (struct vnode *)fp->f_data;
154367654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
154437741Smckusick 	VOP_LOCK(vp);
154564410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
154637741Smckusick 		error = EROFS;
154764410Sbostic 	else {
154864410Sbostic 		VATTR_NULL(&vattr);
154964410Sbostic 		vattr.va_mode = uap->mode & ALLPERMS;
155064410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
15517439Sroot 	}
155237741Smckusick 	VOP_UNLOCK(vp);
155347540Skarels 	return (error);
15545992Swnj }
15555992Swnj 
15569167Ssam /*
15579167Ssam  * Set ownership given a path name.
15589167Ssam  */
155954916Storek struct chown_args {
156064410Sbostic 	char	*path;
156154916Storek 	int	uid;
156254916Storek 	int	gid;
156354916Storek };
156442441Smckusick /* ARGSUSED */
156542441Smckusick chown(p, uap, retval)
156645914Smckusick 	struct proc *p;
156754916Storek 	register struct chown_args *uap;
156842441Smckusick 	int *retval;
156942441Smckusick {
157037741Smckusick 	register struct vnode *vp;
157137741Smckusick 	struct vattr vattr;
157237741Smckusick 	int error;
157347540Skarels 	struct nameidata nd;
157437Sbill 
157566510Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
157652322Smckusick 	if (error = namei(&nd))
157747540Skarels 		return (error);
157852322Smckusick 	vp = nd.ni_vp;
157967654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
158059382Smckusick 	VOP_LOCK(vp);
158164410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
158237741Smckusick 		error = EROFS;
158364410Sbostic 	else {
158464410Sbostic 		VATTR_NULL(&vattr);
158564410Sbostic 		vattr.va_uid = uap->uid;
158664410Sbostic 		vattr.va_gid = uap->gid;
158764410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
158837741Smckusick 	}
158937741Smckusick 	vput(vp);
159047540Skarels 	return (error);
15917701Ssam }
15927439Sroot 
15939167Ssam /*
15949167Ssam  * Set ownership given a file descriptor.
15959167Ssam  */
159654916Storek struct fchown_args {
159754916Storek 	int	fd;
159854916Storek 	int	uid;
159954916Storek 	int	gid;
160054916Storek };
160142441Smckusick /* ARGSUSED */
160242441Smckusick fchown(p, uap, retval)
160345914Smckusick 	struct proc *p;
160454916Storek 	register struct fchown_args *uap;
160542441Smckusick 	int *retval;
160642441Smckusick {
160737741Smckusick 	struct vattr vattr;
160837741Smckusick 	struct vnode *vp;
160937741Smckusick 	struct file *fp;
161037741Smckusick 	int error;
16117701Ssam 
161245914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
161347540Skarels 		return (error);
161437741Smckusick 	vp = (struct vnode *)fp->f_data;
161567654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
161637741Smckusick 	VOP_LOCK(vp);
161764410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
161837741Smckusick 		error = EROFS;
161964410Sbostic 	else {
162064410Sbostic 		VATTR_NULL(&vattr);
162164410Sbostic 		vattr.va_uid = uap->uid;
162264410Sbostic 		vattr.va_gid = uap->gid;
162364410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
162437741Smckusick 	}
162537741Smckusick 	VOP_UNLOCK(vp);
162647540Skarels 	return (error);
16277701Ssam }
16287701Ssam 
162942441Smckusick /*
163042441Smckusick  * Set the access and modification times of a file.
163142441Smckusick  */
163254916Storek struct utimes_args {
163364410Sbostic 	char	*path;
163454916Storek 	struct	timeval *tptr;
163554916Storek };
163642441Smckusick /* ARGSUSED */
163742441Smckusick utimes(p, uap, retval)
163845914Smckusick 	struct proc *p;
163954916Storek 	register struct utimes_args *uap;
164042441Smckusick 	int *retval;
164142441Smckusick {
164237741Smckusick 	register struct vnode *vp;
164311811Ssam 	struct timeval tv[2];
164437741Smckusick 	struct vattr vattr;
164558840Storek 	int error;
164647540Skarels 	struct nameidata nd;
164711811Ssam 
164858505Sbostic 	VATTR_NULL(&vattr);
164958505Sbostic 	if (uap->tptr == NULL) {
165058505Sbostic 		microtime(&tv[0]);
165158505Sbostic 		tv[1] = tv[0];
165258548Sbostic 		vattr.va_vaflags |= VA_UTIMES_NULL;
165358505Sbostic 	} else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
165458505Sbostic   		return (error);
165564410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
165652322Smckusick 	if (error = namei(&nd))
165747540Skarels 		return (error);
165852322Smckusick 	vp = nd.ni_vp;
165967654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
166059382Smckusick 	VOP_LOCK(vp);
166164410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
166237741Smckusick 		error = EROFS;
166364410Sbostic 	else {
166464410Sbostic 		vattr.va_atime.ts_sec = tv[0].tv_sec;
166564410Sbostic 		vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
166664410Sbostic 		vattr.va_mtime.ts_sec = tv[1].tv_sec;
166764410Sbostic 		vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
166864410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
166921015Smckusick 	}
167037741Smckusick 	vput(vp);
167147540Skarels 	return (error);
167211811Ssam }
167311811Ssam 
167464410Sbostic /*
167564410Sbostic  * Truncate a file given its path name.
167664410Sbostic  */
167760428Smckusick struct truncate_args {
167864410Sbostic 	char	*path;
167954863Storek 	int	pad;
168054863Storek 	off_t	length;
168154863Storek };
168253468Smckusick /* ARGSUSED */
168360414Smckusick truncate(p, uap, retval)
168453468Smckusick 	struct proc *p;
168560428Smckusick 	register struct truncate_args *uap;
168653468Smckusick 	int *retval;
168753468Smckusick {
168837741Smckusick 	register struct vnode *vp;
168937741Smckusick 	struct vattr vattr;
169037741Smckusick 	int error;
169147540Skarels 	struct nameidata nd;
16927701Ssam 
169364410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
169452322Smckusick 	if (error = namei(&nd))
169547540Skarels 		return (error);
169652322Smckusick 	vp = nd.ni_vp;
169767654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
169859382Smckusick 	VOP_LOCK(vp);
169964410Sbostic 	if (vp->v_type == VDIR)
170037741Smckusick 		error = EISDIR;
170164410Sbostic 	else if ((error = vn_writechk(vp)) == 0 &&
170264410Sbostic 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
170364410Sbostic 		VATTR_NULL(&vattr);
170464410Sbostic 		vattr.va_size = uap->length;
170564410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
17067701Ssam 	}
170737741Smckusick 	vput(vp);
170847540Skarels 	return (error);
17097701Ssam }
17107701Ssam 
171164410Sbostic /*
171264410Sbostic  * Truncate a file given a file descriptor.
171364410Sbostic  */
171460428Smckusick struct ftruncate_args {
171554863Storek 	int	fd;
171654863Storek 	int	pad;
171754863Storek 	off_t	length;
171854863Storek };
171942441Smckusick /* ARGSUSED */
172060414Smckusick ftruncate(p, uap, retval)
172145914Smckusick 	struct proc *p;
172260428Smckusick 	register struct ftruncate_args *uap;
172342441Smckusick 	int *retval;
172442441Smckusick {
172537741Smckusick 	struct vattr vattr;
172637741Smckusick 	struct vnode *vp;
17277701Ssam 	struct file *fp;
172837741Smckusick 	int error;
17297701Ssam 
173045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
173147540Skarels 		return (error);
173237741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
173347540Skarels 		return (EINVAL);
173437741Smckusick 	vp = (struct vnode *)fp->f_data;
173567654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
173637741Smckusick 	VOP_LOCK(vp);
173764410Sbostic 	if (vp->v_type == VDIR)
173837741Smckusick 		error = EISDIR;
173964410Sbostic 	else if ((error = vn_writechk(vp)) == 0) {
174064410Sbostic 		VATTR_NULL(&vattr);
174164410Sbostic 		vattr.va_size = uap->length;
174264410Sbostic 		error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
17437701Ssam 	}
174437741Smckusick 	VOP_UNLOCK(vp);
174547540Skarels 	return (error);
17467701Ssam }
17477701Ssam 
174854863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
17499167Ssam /*
175054863Storek  * Truncate a file given its path name.
175154863Storek  */
175260428Smckusick struct otruncate_args {
175364410Sbostic 	char	*path;
175454916Storek 	long	length;
175554916Storek };
175654863Storek /* ARGSUSED */
175760105Smckusick otruncate(p, uap, retval)
175854863Storek 	struct proc *p;
175960428Smckusick 	register struct otruncate_args *uap;
176054863Storek 	int *retval;
176154863Storek {
176260428Smckusick 	struct truncate_args nuap;
176354863Storek 
176464410Sbostic 	nuap.path = uap->path;
176554863Storek 	nuap.length = uap->length;
176660428Smckusick 	return (truncate(p, &nuap, retval));
176754863Storek }
176854863Storek 
176954863Storek /*
177054863Storek  * Truncate a file given a file descriptor.
177154863Storek  */
177260428Smckusick struct oftruncate_args {
177354916Storek 	int	fd;
177454916Storek 	long	length;
177554916Storek };
177654863Storek /* ARGSUSED */
177760105Smckusick oftruncate(p, uap, retval)
177854863Storek 	struct proc *p;
177960428Smckusick 	register struct oftruncate_args *uap;
178054863Storek 	int *retval;
178154863Storek {
178260428Smckusick 	struct ftruncate_args nuap;
178354863Storek 
178454863Storek 	nuap.fd = uap->fd;
178554863Storek 	nuap.length = uap->length;
178660428Smckusick 	return (ftruncate(p, &nuap, retval));
178754863Storek }
178854863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */
178954863Storek 
179054863Storek /*
179164410Sbostic  * Sync an open file.
17929167Ssam  */
179354916Storek struct fsync_args {
179454916Storek 	int	fd;
179554916Storek };
179642441Smckusick /* ARGSUSED */
179742441Smckusick fsync(p, uap, retval)
179845914Smckusick 	struct proc *p;
179954916Storek 	struct fsync_args *uap;
180042441Smckusick 	int *retval;
18019167Ssam {
180239592Smckusick 	register struct vnode *vp;
18039167Ssam 	struct file *fp;
180437741Smckusick 	int error;
18059167Ssam 
180645914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
180747540Skarels 		return (error);
180839592Smckusick 	vp = (struct vnode *)fp->f_data;
180939592Smckusick 	VOP_LOCK(vp);
181054441Smckusick 	error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
181139592Smckusick 	VOP_UNLOCK(vp);
181247540Skarels 	return (error);
18139167Ssam }
18149167Ssam 
18159167Ssam /*
181664410Sbostic  * Rename files.  Source and destination must either both be directories,
181764410Sbostic  * or both not be directories.  If target is a directory, it must be empty.
18189167Ssam  */
181954916Storek struct rename_args {
182054916Storek 	char	*from;
182154916Storek 	char	*to;
182254916Storek };
182342441Smckusick /* ARGSUSED */
182442441Smckusick rename(p, uap, retval)
182545914Smckusick 	struct proc *p;
182654916Storek 	register struct rename_args *uap;
182742441Smckusick 	int *retval;
182842441Smckusick {
182937741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
183049735Smckusick 	struct nameidata fromnd, tond;
183137741Smckusick 	int error;
18327701Ssam 
183352322Smckusick 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
183452322Smckusick 		uap->from, p);
183552322Smckusick 	if (error = namei(&fromnd))
183647540Skarels 		return (error);
183749735Smckusick 	fvp = fromnd.ni_vp;
183852322Smckusick 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
183952322Smckusick 		UIO_USERSPACE, uap->to, p);
184052322Smckusick 	if (error = namei(&tond)) {
184152230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
184249735Smckusick 		vrele(fromnd.ni_dvp);
184342465Smckusick 		vrele(fvp);
184442465Smckusick 		goto out1;
184542465Smckusick 	}
184637741Smckusick 	tdvp = tond.ni_dvp;
184737741Smckusick 	tvp = tond.ni_vp;
184837741Smckusick 	if (tvp != NULL) {
184937741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
185039242Sbostic 			error = ENOTDIR;
185137741Smckusick 			goto out;
185237741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
185339242Sbostic 			error = EISDIR;
185437741Smckusick 			goto out;
18559167Ssam 		}
18569167Ssam 	}
185739286Smckusick 	if (fvp == tdvp)
185837741Smckusick 		error = EINVAL;
185939286Smckusick 	/*
186049735Smckusick 	 * If source is the same as the destination (that is the
186149735Smckusick 	 * same inode number with the same name in the same directory),
186239286Smckusick 	 * then there is nothing to do.
186339286Smckusick 	 */
186449735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
186552322Smckusick 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
186652322Smckusick 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
186752322Smckusick 	      fromnd.ni_cnd.cn_namelen))
186839286Smckusick 		error = -1;
186937741Smckusick out:
187042465Smckusick 	if (!error) {
187167654Smckusick 		VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE);
187252192Smckusick 		if (fromnd.ni_dvp != tdvp)
187367654Smckusick 			VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
187452192Smckusick 		if (tvp)
187567654Smckusick 			VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE);
187652230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
187752230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
187842465Smckusick 	} else {
187952230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
188043344Smckusick 		if (tdvp == tvp)
188143344Smckusick 			vrele(tdvp);
188243344Smckusick 		else
188343344Smckusick 			vput(tdvp);
188442465Smckusick 		if (tvp)
188542465Smckusick 			vput(tvp);
188652230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
188749735Smckusick 		vrele(fromnd.ni_dvp);
188842465Smckusick 		vrele(fvp);
18899167Ssam 	}
189049735Smckusick 	vrele(tond.ni_startdir);
189152322Smckusick 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
189237741Smckusick out1:
189366801Smckusick 	if (fromnd.ni_startdir)
189466801Smckusick 		vrele(fromnd.ni_startdir);
189552322Smckusick 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
189639286Smckusick 	if (error == -1)
189747540Skarels 		return (0);
189847540Skarels 	return (error);
18997701Ssam }
19007701Ssam 
19017535Sroot /*
190264410Sbostic  * Make a directory file.
190312756Ssam  */
190454916Storek struct mkdir_args {
190564410Sbostic 	char	*path;
190664410Sbostic 	int	mode;
190754916Storek };
190842441Smckusick /* ARGSUSED */
190942441Smckusick mkdir(p, uap, retval)
191045914Smckusick 	struct proc *p;
191154916Storek 	register struct mkdir_args *uap;
191242441Smckusick 	int *retval;
191342441Smckusick {
191437741Smckusick 	register struct vnode *vp;
191537741Smckusick 	struct vattr vattr;
191637741Smckusick 	int error;
191747540Skarels 	struct nameidata nd;
191812756Ssam 
191964410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
192052322Smckusick 	if (error = namei(&nd))
192147540Skarels 		return (error);
192252322Smckusick 	vp = nd.ni_vp;
192337741Smckusick 	if (vp != NULL) {
192452322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
192552322Smckusick 		if (nd.ni_dvp == vp)
192652322Smckusick 			vrele(nd.ni_dvp);
192743344Smckusick 		else
192852322Smckusick 			vput(nd.ni_dvp);
192942465Smckusick 		vrele(vp);
193047540Skarels 		return (EEXIST);
193112756Ssam 	}
193241362Smckusick 	VATTR_NULL(&vattr);
193337741Smckusick 	vattr.va_type = VDIR;
193464410Sbostic 	vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask;
193567654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
193652322Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
193738145Smckusick 	if (!error)
193852322Smckusick 		vput(nd.ni_vp);
193947540Skarels 	return (error);
194012756Ssam }
194112756Ssam 
194212756Ssam /*
194364410Sbostic  * Remove a directory file.
194412756Ssam  */
194554916Storek struct rmdir_args {
194664410Sbostic 	char	*path;
194754916Storek };
194842441Smckusick /* ARGSUSED */
194942441Smckusick rmdir(p, uap, retval)
195045914Smckusick 	struct proc *p;
195154916Storek 	struct rmdir_args *uap;
195242441Smckusick 	int *retval;
195312756Ssam {
195437741Smckusick 	register struct vnode *vp;
195537741Smckusick 	int error;
195647540Skarels 	struct nameidata nd;
195712756Ssam 
195864410Sbostic 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p);
195952322Smckusick 	if (error = namei(&nd))
196047540Skarels 		return (error);
196152322Smckusick 	vp = nd.ni_vp;
196237741Smckusick 	if (vp->v_type != VDIR) {
196337741Smckusick 		error = ENOTDIR;
196412756Ssam 		goto out;
196512756Ssam 	}
196612756Ssam 	/*
196737741Smckusick 	 * No rmdir "." please.
196812756Ssam 	 */
196952322Smckusick 	if (nd.ni_dvp == vp) {
197037741Smckusick 		error = EINVAL;
197112756Ssam 		goto out;
197212756Ssam 	}
197312756Ssam 	/*
197449365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
197512756Ssam 	 */
197637741Smckusick 	if (vp->v_flag & VROOT)
197737741Smckusick 		error = EBUSY;
197812756Ssam out:
197942465Smckusick 	if (!error) {
198067654Smckusick 		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
198167654Smckusick 		VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
198252322Smckusick 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
198342465Smckusick 	} else {
198452322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
198552322Smckusick 		if (nd.ni_dvp == vp)
198652322Smckusick 			vrele(nd.ni_dvp);
198743344Smckusick 		else
198852322Smckusick 			vput(nd.ni_dvp);
198942465Smckusick 		vput(vp);
199042465Smckusick 	}
199147540Skarels 	return (error);
199212756Ssam }
199312756Ssam 
199454620Smckusick #ifdef COMPAT_43
199537741Smckusick /*
199649365Smckusick  * Read a block of directory entries in a file system independent format.
199737741Smckusick  */
199854916Storek struct ogetdirentries_args {
199954916Storek 	int	fd;
200054916Storek 	char	*buf;
200164410Sbostic 	u_int	count;
200254916Storek 	long	*basep;
200354916Storek };
200454620Smckusick ogetdirentries(p, uap, retval)
200554620Smckusick 	struct proc *p;
200654916Storek 	register struct ogetdirentries_args *uap;
200754620Smckusick 	int *retval;
200854620Smckusick {
200954620Smckusick 	register struct vnode *vp;
201054620Smckusick 	struct file *fp;
201154620Smckusick 	struct uio auio, kuio;
201254620Smckusick 	struct iovec aiov, kiov;
201354620Smckusick 	struct dirent *dp, *edp;
201454620Smckusick 	caddr_t dirbuf;
201567362Smckusick 	int error, eofflag, readcnt;
201654969Smckusick 	long loff;
201754620Smckusick 
201854620Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
201954620Smckusick 		return (error);
202054620Smckusick 	if ((fp->f_flag & FREAD) == 0)
202154620Smckusick 		return (EBADF);
202254620Smckusick 	vp = (struct vnode *)fp->f_data;
202367362Smckusick unionread:
202454620Smckusick 	if (vp->v_type != VDIR)
202554620Smckusick 		return (EINVAL);
202654620Smckusick 	aiov.iov_base = uap->buf;
202754620Smckusick 	aiov.iov_len = uap->count;
202854620Smckusick 	auio.uio_iov = &aiov;
202954620Smckusick 	auio.uio_iovcnt = 1;
203054620Smckusick 	auio.uio_rw = UIO_READ;
203154620Smckusick 	auio.uio_segflg = UIO_USERSPACE;
203254620Smckusick 	auio.uio_procp = p;
203354620Smckusick 	auio.uio_resid = uap->count;
203454620Smckusick 	VOP_LOCK(vp);
203554969Smckusick 	loff = auio.uio_offset = fp->f_offset;
203654620Smckusick #	if (BYTE_ORDER != LITTLE_ENDIAN)
203756339Smckusick 		if (vp->v_mount->mnt_maxsymlinklen <= 0) {
203867362Smckusick 			error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
203967362Smckusick 			    (u_long *)0, 0);
204056339Smckusick 			fp->f_offset = auio.uio_offset;
204156339Smckusick 		} else
204254620Smckusick #	endif
204354620Smckusick 	{
204454620Smckusick 		kuio = auio;
204554620Smckusick 		kuio.uio_iov = &kiov;
204654620Smckusick 		kuio.uio_segflg = UIO_SYSSPACE;
204754620Smckusick 		kiov.iov_len = uap->count;
204854620Smckusick 		MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK);
204954620Smckusick 		kiov.iov_base = dirbuf;
205067362Smckusick 		error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
205167362Smckusick 			    (u_long *)0, 0);
205256339Smckusick 		fp->f_offset = kuio.uio_offset;
205354620Smckusick 		if (error == 0) {
205454620Smckusick 			readcnt = uap->count - kuio.uio_resid;
205554620Smckusick 			edp = (struct dirent *)&dirbuf[readcnt];
205654620Smckusick 			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
205754620Smckusick #				if (BYTE_ORDER == LITTLE_ENDIAN)
205854969Smckusick 					/*
205955009Smckusick 					 * The expected low byte of
206055009Smckusick 					 * dp->d_namlen is our dp->d_type.
206155009Smckusick 					 * The high MBZ byte of dp->d_namlen
206255009Smckusick 					 * is our dp->d_namlen.
206354969Smckusick 					 */
206455009Smckusick 					dp->d_type = dp->d_namlen;
206555009Smckusick 					dp->d_namlen = 0;
206655009Smckusick #				else
206755009Smckusick 					/*
206855009Smckusick 					 * The dp->d_type is the high byte
206955009Smckusick 					 * of the expected dp->d_namlen,
207055009Smckusick 					 * so must be zero'ed.
207155009Smckusick 					 */
207255009Smckusick 					dp->d_type = 0;
207354620Smckusick #				endif
207454620Smckusick 				if (dp->d_reclen > 0) {
207554620Smckusick 					dp = (struct dirent *)
207654620Smckusick 					    ((char *)dp + dp->d_reclen);
207754620Smckusick 				} else {
207854620Smckusick 					error = EIO;
207954620Smckusick 					break;
208054620Smckusick 				}
208154620Smckusick 			}
208254620Smckusick 			if (dp >= edp)
208354620Smckusick 				error = uiomove(dirbuf, readcnt, &auio);
208454620Smckusick 		}
208554620Smckusick 		FREE(dirbuf, M_TEMP);
208654620Smckusick 	}
208754620Smckusick 	VOP_UNLOCK(vp);
208854620Smckusick 	if (error)
208954620Smckusick 		return (error);
209067362Smckusick 
209167362Smckusick #ifdef UNION
209267362Smckusick {
209367362Smckusick 	extern int (**union_vnodeop_p)();
2094*68079Spendry 	extern struct vnode *union_dircache __P((struct vnode *));
209567362Smckusick 
209667362Smckusick 	if ((uap->count == auio.uio_resid) &&
209767362Smckusick 	    (vp->v_op == union_vnodeop_p)) {
209867362Smckusick 		struct vnode *lvp;
209967362Smckusick 
2100*68079Spendry 		lvp = union_dircache(vp);
210167362Smckusick 		if (lvp != NULLVP) {
210267575Spendry 			struct vattr va;
210367575Spendry 
210467575Spendry 			/*
210567575Spendry 			 * If the directory is opaque,
210667575Spendry 			 * then don't show lower entries
210767575Spendry 			 */
210867575Spendry 			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
210967575Spendry 			if (va.va_flags & OPAQUE) {
2110*68079Spendry 				vput(lvp);
211167575Spendry 				lvp = NULL;
211267575Spendry 			}
211367575Spendry 		}
211467575Spendry 
211567575Spendry 		if (lvp != NULLVP) {
211667362Smckusick 			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
211767362Smckusick 			VOP_UNLOCK(lvp);
211867362Smckusick 
211967362Smckusick 			if (error) {
212067362Smckusick 				vrele(lvp);
212167362Smckusick 				return (error);
212267362Smckusick 			}
212367362Smckusick 			fp->f_data = (caddr_t) lvp;
212467362Smckusick 			fp->f_offset = 0;
212567362Smckusick 			error = vn_close(vp, FREAD, fp->f_cred, p);
212667362Smckusick 			if (error)
212767362Smckusick 				return (error);
212867362Smckusick 			vp = lvp;
212967362Smckusick 			goto unionread;
213067362Smckusick 		}
213167362Smckusick 	}
213267362Smckusick }
213367362Smckusick #endif /* UNION */
213467362Smckusick 
213567362Smckusick 	if ((uap->count == auio.uio_resid) &&
213667362Smckusick 	    (vp->v_flag & VROOT) &&
213767362Smckusick 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
213867362Smckusick 		struct vnode *tvp = vp;
213967362Smckusick 		vp = vp->v_mount->mnt_vnodecovered;
214067362Smckusick 		VREF(vp);
214167362Smckusick 		fp->f_data = (caddr_t) vp;
214267362Smckusick 		fp->f_offset = 0;
214367362Smckusick 		vrele(tvp);
214467362Smckusick 		goto unionread;
214567362Smckusick 	}
214654969Smckusick 	error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
214754620Smckusick 	*retval = uap->count - auio.uio_resid;
214854620Smckusick 	return (error);
214954620Smckusick }
215067362Smckusick #endif /* COMPAT_43 */
215154620Smckusick 
215254620Smckusick /*
215354620Smckusick  * Read a block of directory entries in a file system independent format.
215454620Smckusick  */
215554916Storek struct getdirentries_args {
215654916Storek 	int	fd;
215754916Storek 	char	*buf;
215864410Sbostic 	u_int	count;
215954916Storek 	long	*basep;
216054916Storek };
216142441Smckusick getdirentries(p, uap, retval)
216245914Smckusick 	struct proc *p;
216354916Storek 	register struct getdirentries_args *uap;
216442441Smckusick 	int *retval;
216542441Smckusick {
216639592Smckusick 	register struct vnode *vp;
216716540Ssam 	struct file *fp;
216837741Smckusick 	struct uio auio;
216937741Smckusick 	struct iovec aiov;
217054969Smckusick 	long loff;
217167362Smckusick 	int error, eofflag;
217212756Ssam 
217345914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
217447540Skarels 		return (error);
217537741Smckusick 	if ((fp->f_flag & FREAD) == 0)
217647540Skarels 		return (EBADF);
217739592Smckusick 	vp = (struct vnode *)fp->f_data;
217855451Spendry unionread:
217939592Smckusick 	if (vp->v_type != VDIR)
218047540Skarels 		return (EINVAL);
218137741Smckusick 	aiov.iov_base = uap->buf;
218237741Smckusick 	aiov.iov_len = uap->count;
218337741Smckusick 	auio.uio_iov = &aiov;
218437741Smckusick 	auio.uio_iovcnt = 1;
218537741Smckusick 	auio.uio_rw = UIO_READ;
218637741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
218748026Smckusick 	auio.uio_procp = p;
218837741Smckusick 	auio.uio_resid = uap->count;
218939592Smckusick 	VOP_LOCK(vp);
219054969Smckusick 	loff = auio.uio_offset = fp->f_offset;
219167362Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *)0, 0);
219239592Smckusick 	fp->f_offset = auio.uio_offset;
219339592Smckusick 	VOP_UNLOCK(vp);
219439592Smckusick 	if (error)
219547540Skarels 		return (error);
219666095Spendry 
219766095Spendry #ifdef UNION
219866095Spendry {
219966095Spendry 	extern int (**union_vnodeop_p)();
2200*68079Spendry 	extern struct vnode *union_dircache __P((struct vnode *));
220166095Spendry 
220255451Spendry 	if ((uap->count == auio.uio_resid) &&
220366095Spendry 	    (vp->v_op == union_vnodeop_p)) {
220467122Spendry 		struct vnode *lvp;
220566095Spendry 
2206*68079Spendry 		lvp = union_dircache(vp);
220767122Spendry 		if (lvp != NULLVP) {
220867575Spendry 			struct vattr va;
220967575Spendry 
221067575Spendry 			/*
221167575Spendry 			 * If the directory is opaque,
221267575Spendry 			 * then don't show lower entries
221367575Spendry 			 */
221467575Spendry 			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
221567575Spendry 			if (va.va_flags & OPAQUE) {
2216*68079Spendry 				vput(lvp);
221767575Spendry 				lvp = NULL;
221867575Spendry 			}
221967575Spendry 		}
222067575Spendry 
222167575Spendry 		if (lvp != NULLVP) {
222267362Smckusick 			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
222367122Spendry 			VOP_UNLOCK(lvp);
222466095Spendry 
222566095Spendry 			if (error) {
222667122Spendry 				vrele(lvp);
222766095Spendry 				return (error);
222866095Spendry 			}
222967122Spendry 			fp->f_data = (caddr_t) lvp;
223066095Spendry 			fp->f_offset = 0;
223167122Spendry 			error = vn_close(vp, FREAD, fp->f_cred, p);
223266095Spendry 			if (error)
223366095Spendry 				return (error);
223467122Spendry 			vp = lvp;
223566095Spendry 			goto unionread;
223666095Spendry 		}
223766095Spendry 	}
223866095Spendry }
223966095Spendry #endif
224066095Spendry 
224166095Spendry 	if ((uap->count == auio.uio_resid) &&
224255451Spendry 	    (vp->v_flag & VROOT) &&
224355451Spendry 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
224455451Spendry 		struct vnode *tvp = vp;
224555451Spendry 		vp = vp->v_mount->mnt_vnodecovered;
224655451Spendry 		VREF(vp);
224755451Spendry 		fp->f_data = (caddr_t) vp;
224855451Spendry 		fp->f_offset = 0;
224955451Spendry 		vrele(tvp);
225055451Spendry 		goto unionread;
225155451Spendry 	}
225254969Smckusick 	error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
225342441Smckusick 	*retval = uap->count - auio.uio_resid;
225447540Skarels 	return (error);
225512756Ssam }
225612756Ssam 
225712756Ssam /*
225849365Smckusick  * Set the mode mask for creation of filesystem nodes.
225912756Ssam  */
226054916Storek struct umask_args {
226164410Sbostic 	int	newmask;
226254916Storek };
226354916Storek mode_t				/* XXX */
226442441Smckusick umask(p, uap, retval)
226545914Smckusick 	struct proc *p;
226654916Storek 	struct umask_args *uap;
226742441Smckusick 	int *retval;
226812756Ssam {
226964410Sbostic 	register struct filedesc *fdp;
227012756Ssam 
227164410Sbostic 	fdp = p->p_fd;
227245914Smckusick 	*retval = fdp->fd_cmask;
227364410Sbostic 	fdp->fd_cmask = uap->newmask & ALLPERMS;
227447540Skarels 	return (0);
227512756Ssam }
227637741Smckusick 
227739566Smarc /*
227839566Smarc  * Void all references to file by ripping underlying filesystem
227939566Smarc  * away from vnode.
228039566Smarc  */
228154916Storek struct revoke_args {
228264410Sbostic 	char	*path;
228354916Storek };
228442441Smckusick /* ARGSUSED */
228542441Smckusick revoke(p, uap, retval)
228645914Smckusick 	struct proc *p;
228754916Storek 	register struct revoke_args *uap;
228842441Smckusick 	int *retval;
228942441Smckusick {
229039566Smarc 	register struct vnode *vp;
229139566Smarc 	struct vattr vattr;
229239566Smarc 	int error;
229347540Skarels 	struct nameidata nd;
229439566Smarc 
229564410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
229652322Smckusick 	if (error = namei(&nd))
229747540Skarels 		return (error);
229852322Smckusick 	vp = nd.ni_vp;
229939566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
230039566Smarc 		error = EINVAL;
230139566Smarc 		goto out;
230239566Smarc 	}
230348026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
230439566Smarc 		goto out;
230547540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
230647540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
230739566Smarc 		goto out;
230839805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
230939632Smckusick 		vgoneall(vp);
231039566Smarc out:
231139566Smarc 	vrele(vp);
231247540Skarels 	return (error);
231339566Smarc }
231439566Smarc 
231549365Smckusick /*
231649365Smckusick  * Convert a user file descriptor to a kernel file entry.
231749365Smckusick  */
231864410Sbostic getvnode(fdp, fd, fpp)
231945914Smckusick 	struct filedesc *fdp;
232037741Smckusick 	struct file **fpp;
232164410Sbostic 	int fd;
232237741Smckusick {
232337741Smckusick 	struct file *fp;
232437741Smckusick 
232564410Sbostic 	if ((u_int)fd >= fdp->fd_nfiles ||
232664410Sbostic 	    (fp = fdp->fd_ofiles[fd]) == NULL)
232737741Smckusick 		return (EBADF);
232837741Smckusick 	if (fp->f_type != DTYPE_VNODE)
232937741Smckusick 		return (EINVAL);
233037741Smckusick 	*fpp = fp;
233137741Smckusick 	return (0);
233237741Smckusick }
2333