xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 67532)
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*67532Smckusick  *	@(#)vfs_syscalls.c	8.18 (Berkeley) 07/14/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;
56*67532Smckusick 	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);
84*67532Smckusick 		/*
85*67532Smckusick 		 * Only root, or the user that did the original mount is
86*67532Smckusick 		 * permitted to update it.
87*67532Smckusick 		 */
88*67532Smckusick 		if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid &&
89*67532Smckusick 		    (error = suser(p->p_ucred, &p->p_acflag))) {
90*67532Smckusick 			vput(vp);
91*67532Smckusick 			return (error);
92*67532Smckusick 		}
93*67532Smckusick 		/*
94*67532Smckusick 		 * Do not allow NFS export by non-root users. Silently
95*67532Smckusick 		 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
96*67532Smckusick 		 */
97*67532Smckusick 		if (p->p_ucred->cr_uid != 0) {
98*67532Smckusick 			if (uap->flags & MNT_EXPORTED) {
99*67532Smckusick 				vput(vp);
100*67532Smckusick 				return (EPERM);
101*67532Smckusick 			}
102*67532Smckusick 			uap->flags |= MNT_NOSUID | MNT_NODEV;
103*67532Smckusick 		}
10439335Smckusick 		VOP_UNLOCK(vp);
10539335Smckusick 		goto update;
10639335Smckusick 	}
107*67532Smckusick 	/*
108*67532Smckusick 	 * If the user is not root, ensure that they own the directory
109*67532Smckusick 	 * onto which we are attempting to mount.
110*67532Smckusick 	 */
111*67532Smckusick 	if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) ||
112*67532Smckusick 	    (va.va_uid != p->p_ucred->cr_uid &&
113*67532Smckusick 	     (error = suser(p->p_ucred, &p->p_acflag)))) {
114*67532Smckusick 		vput(vp);
115*67532Smckusick 		return (error);
116*67532Smckusick 	}
117*67532Smckusick 	/*
118*67532Smckusick 	 * Do not allow NFS export by non-root users. Silently
119*67532Smckusick 	 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
120*67532Smckusick 	 */
121*67532Smckusick 	if (p->p_ucred->cr_uid != 0) {
122*67532Smckusick 		if (uap->flags & MNT_EXPORTED) {
123*67532Smckusick 			vput(vp);
124*67532Smckusick 			return (EPERM);
125*67532Smckusick 		}
126*67532Smckusick 		uap->flags |= MNT_NOSUID | MNT_NODEV;
127*67532Smckusick 	}
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 	}
13837741Smckusick 
13937741Smckusick 	/*
14039335Smckusick 	 * Allocate and initialize the file system.
14137741Smckusick 	 */
14237741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
14337741Smckusick 		M_MOUNT, M_WAITOK);
14454172Smckusick 	bzero((char *)mp, (u_long)sizeof(struct mount));
14541400Smckusick 	mp->mnt_op = vfssw[uap->type];
14639335Smckusick 	if (error = vfs_lock(mp)) {
14739335Smckusick 		free((caddr_t)mp, M_MOUNT);
14839335Smckusick 		vput(vp);
14947540Skarels 		return (error);
15039335Smckusick 	}
15164410Sbostic 	if (vp->v_mountedhere != NULL) {
15239335Smckusick 		vfs_unlock(mp);
15339335Smckusick 		free((caddr_t)mp, M_MOUNT);
15439335Smckusick 		vput(vp);
15547540Skarels 		return (EBUSY);
15639335Smckusick 	}
15739335Smckusick 	vp->v_mountedhere = mp;
15841400Smckusick 	mp->mnt_vnodecovered = vp;
159*67532Smckusick 	mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
16039335Smckusick update:
16139335Smckusick 	/*
16239335Smckusick 	 * Set the mount level flags.
16339335Smckusick 	 */
16441400Smckusick 	if (uap->flags & MNT_RDONLY)
16541400Smckusick 		mp->mnt_flag |= MNT_RDONLY;
16657047Smckusick 	else if (mp->mnt_flag & MNT_RDONLY)
16757047Smckusick 		mp->mnt_flag |= MNT_WANTRDWR;
16865613Smckusick 	mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
16965613Smckusick 	    MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);
17065613Smckusick 	mp->mnt_flag |= uap->flags & (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
17165613Smckusick 	    MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);
17239335Smckusick 	/*
17339335Smckusick 	 * Mount the filesystem.
17439335Smckusick 	 */
17564410Sbostic 	error = VFS_MOUNT(mp, uap->path, uap->data, &nd, p);
17641400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
17739335Smckusick 		vrele(vp);
17857047Smckusick 		if (mp->mnt_flag & MNT_WANTRDWR)
17957047Smckusick 			mp->mnt_flag &= ~MNT_RDONLY;
18057047Smckusick 		mp->mnt_flag &=~
18157047Smckusick 		    (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
18240111Smckusick 		if (error)
18341400Smckusick 			mp->mnt_flag = flag;
18447540Skarels 		return (error);
18539335Smckusick 	}
18640110Smckusick 	/*
18740110Smckusick 	 * Put the new filesystem on the mount list after root.
18840110Smckusick 	 */
18937741Smckusick 	cache_purge(vp);
19037741Smckusick 	if (!error) {
19165259Smckusick 		TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
19239335Smckusick 		VOP_UNLOCK(vp);
19337741Smckusick 		vfs_unlock(mp);
19448026Smckusick 		error = VFS_START(mp, 0, p);
19537741Smckusick 	} else {
19665259Smckusick 		mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
19765259Smckusick 		vfs_unlock(mp);
19837741Smckusick 		free((caddr_t)mp, M_MOUNT);
19939335Smckusick 		vput(vp);
20037741Smckusick 	}
20147540Skarels 	return (error);
2026254Sroot }
2036254Sroot 
2049167Ssam /*
20564410Sbostic  * Unmount a file system.
20637741Smckusick  *
20737741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
20837741Smckusick  * not special file (as before).
2099167Ssam  */
21054916Storek struct unmount_args {
21164410Sbostic 	char	*path;
21254916Storek 	int	flags;
21354916Storek };
21442441Smckusick /* ARGSUSED */
21542441Smckusick unmount(p, uap, retval)
21645914Smckusick 	struct proc *p;
21754916Storek 	register struct unmount_args *uap;
21842441Smckusick 	int *retval;
21942441Smckusick {
22037741Smckusick 	register struct vnode *vp;
22139356Smckusick 	struct mount *mp;
22237741Smckusick 	int error;
22347540Skarels 	struct nameidata nd;
2246254Sroot 
22564410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
22652322Smckusick 	if (error = namei(&nd))
22747540Skarels 		return (error);
22852322Smckusick 	vp = nd.ni_vp;
229*67532Smckusick 	mp = vp->v_mount;
23066172Spendry 
23137741Smckusick 	/*
232*67532Smckusick 	 * Only root, or the user that did the original mount is
233*67532Smckusick 	 * permitted to unmount this filesystem.
23466172Spendry 	 */
235*67532Smckusick 	if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) &&
23666172Spendry 	    (error = suser(p->p_ucred, &p->p_acflag))) {
23766172Spendry 		vput(vp);
23866172Spendry 		return (error);
23966172Spendry 	}
24066172Spendry 
24166172Spendry 	/*
24237741Smckusick 	 * Must be the root of the filesystem
24337741Smckusick 	 */
24437741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
24537741Smckusick 		vput(vp);
24647540Skarels 		return (EINVAL);
24737741Smckusick 	}
24837741Smckusick 	vput(vp);
24948026Smckusick 	return (dounmount(mp, uap->flags, p));
25039356Smckusick }
25139356Smckusick 
25239356Smckusick /*
25364410Sbostic  * Do the actual file system unmount.
25439356Smckusick  */
25548026Smckusick dounmount(mp, flags, p)
25639356Smckusick 	register struct mount *mp;
25739356Smckusick 	int flags;
25848026Smckusick 	struct proc *p;
25939356Smckusick {
26039356Smckusick 	struct vnode *coveredvp;
26139356Smckusick 	int error;
26239356Smckusick 
26341400Smckusick 	coveredvp = mp->mnt_vnodecovered;
26441298Smckusick 	if (vfs_busy(mp))
26541298Smckusick 		return (EBUSY);
26641400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
26737741Smckusick 	if (error = vfs_lock(mp))
26839356Smckusick 		return (error);
26937741Smckusick 
27065859Smckusick 	mp->mnt_flag &=~ MNT_ASYNC;
27145738Smckusick 	vnode_pager_umount(mp);	/* release cached vnodes */
27237741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
27354441Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 ||
27454441Smckusick 	    (flags & MNT_FORCE))
27548026Smckusick 		error = VFS_UNMOUNT(mp, flags, p);
27641400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
27741298Smckusick 	vfs_unbusy(mp);
27837741Smckusick 	if (error) {
27937741Smckusick 		vfs_unlock(mp);
28037741Smckusick 	} else {
28137741Smckusick 		vrele(coveredvp);
28265259Smckusick 		TAILQ_REMOVE(&mountlist, mp, mnt_list);
28365259Smckusick 		mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
28465259Smckusick 		vfs_unlock(mp);
28565259Smckusick 		if (mp->mnt_vnodelist.lh_first != NULL)
28652287Smckusick 			panic("unmount: dangling vnode");
28737741Smckusick 		free((caddr_t)mp, M_MOUNT);
28837741Smckusick 	}
28939356Smckusick 	return (error);
2906254Sroot }
2916254Sroot 
2929167Ssam /*
29337741Smckusick  * Sync each mounted filesystem.
2949167Ssam  */
29567403Smckusick #ifdef DEBUG
29656352Smckusick int syncprt = 0;
29759875Smckusick struct ctldebug debug0 = { "syncprt", &syncprt };
29856352Smckusick #endif
29956352Smckusick 
30054916Storek struct sync_args {
30154916Storek 	int	dummy;
30254916Storek };
30339491Smckusick /* ARGSUSED */
30442441Smckusick sync(p, uap, retval)
30545914Smckusick 	struct proc *p;
30654916Storek 	struct sync_args *uap;
30742441Smckusick 	int *retval;
3086254Sroot {
30965259Smckusick 	register struct mount *mp, *nmp;
31065859Smckusick 	int asyncflag;
31137741Smckusick 
31265259Smckusick 	for (mp = mountlist.tqh_first; mp != NULL; mp = nmp) {
31365259Smckusick 		nmp = mp->mnt_list.tqe_next;
31440343Smckusick 		/*
31540343Smckusick 		 * The lock check below is to avoid races with mount
31640343Smckusick 		 * and unmount.
31740343Smckusick 		 */
31841400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
31941298Smckusick 		    !vfs_busy(mp)) {
32065859Smckusick 			asyncflag = mp->mnt_flag & MNT_ASYNC;
32165859Smckusick 			mp->mnt_flag &= ~MNT_ASYNC;
32254441Smckusick 			VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
32365859Smckusick 			if (asyncflag)
32465859Smckusick 				mp->mnt_flag |= MNT_ASYNC;
32565259Smckusick 			vfs_unbusy(mp);
32665259Smckusick 		}
32765259Smckusick 	}
32856352Smckusick #ifdef DIAGNOSTIC
32956352Smckusick 	if (syncprt)
33056352Smckusick 		vfs_bufstats();
33156352Smckusick #endif /* DIAGNOSTIC */
33247688Skarels 	return (0);
33337741Smckusick }
33437741Smckusick 
33537741Smckusick /*
33664410Sbostic  * Change filesystem quotas.
33741298Smckusick  */
33854916Storek struct quotactl_args {
33954916Storek 	char *path;
34054916Storek 	int cmd;
34154916Storek 	int uid;
34254916Storek 	caddr_t arg;
34354916Storek };
34442441Smckusick /* ARGSUSED */
34542441Smckusick quotactl(p, uap, retval)
34645914Smckusick 	struct proc *p;
34754916Storek 	register struct quotactl_args *uap;
34842441Smckusick 	int *retval;
34942441Smckusick {
35041298Smckusick 	register struct mount *mp;
35141298Smckusick 	int error;
35247540Skarels 	struct nameidata nd;
35341298Smckusick 
35452322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
35552322Smckusick 	if (error = namei(&nd))
35647540Skarels 		return (error);
35752322Smckusick 	mp = nd.ni_vp->v_mount;
35852322Smckusick 	vrele(nd.ni_vp);
35948026Smckusick 	return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p));
36041298Smckusick }
36141298Smckusick 
36241298Smckusick /*
36349365Smckusick  * Get filesystem statistics.
36437741Smckusick  */
36554916Storek struct statfs_args {
36654916Storek 	char *path;
36754916Storek 	struct statfs *buf;
36854916Storek };
36942441Smckusick /* ARGSUSED */
37042441Smckusick statfs(p, uap, retval)
37145914Smckusick 	struct proc *p;
37254916Storek 	register struct statfs_args *uap;
37342441Smckusick 	int *retval;
37442441Smckusick {
37539464Smckusick 	register struct mount *mp;
37640343Smckusick 	register struct statfs *sp;
37737741Smckusick 	int error;
37847540Skarels 	struct nameidata nd;
37937741Smckusick 
38052322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
38152322Smckusick 	if (error = namei(&nd))
38247540Skarels 		return (error);
38352322Smckusick 	mp = nd.ni_vp->v_mount;
38441400Smckusick 	sp = &mp->mnt_stat;
38552322Smckusick 	vrele(nd.ni_vp);
38648026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
38747540Skarels 		return (error);
38841400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
38947540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
39037741Smckusick }
39137741Smckusick 
39242441Smckusick /*
39349365Smckusick  * Get filesystem statistics.
39442441Smckusick  */
39554916Storek struct fstatfs_args {
39654916Storek 	int fd;
39754916Storek 	struct statfs *buf;
39854916Storek };
39942441Smckusick /* ARGSUSED */
40042441Smckusick fstatfs(p, uap, retval)
40145914Smckusick 	struct proc *p;
40254916Storek 	register struct fstatfs_args *uap;
40342441Smckusick 	int *retval;
40442441Smckusick {
40537741Smckusick 	struct file *fp;
40639464Smckusick 	struct mount *mp;
40740343Smckusick 	register struct statfs *sp;
40837741Smckusick 	int error;
40937741Smckusick 
41045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
41147540Skarels 		return (error);
41239464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
41341400Smckusick 	sp = &mp->mnt_stat;
41448026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
41547540Skarels 		return (error);
41641400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
41747540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
41837741Smckusick }
41937741Smckusick 
42037741Smckusick /*
42149365Smckusick  * Get statistics on all filesystems.
42238270Smckusick  */
42354916Storek struct getfsstat_args {
42454916Storek 	struct statfs *buf;
42554916Storek 	long bufsize;
42654916Storek 	int flags;
42754916Storek };
42842441Smckusick getfsstat(p, uap, retval)
42945914Smckusick 	struct proc *p;
43054916Storek 	register struct getfsstat_args *uap;
43142441Smckusick 	int *retval;
43242441Smckusick {
43365259Smckusick 	register struct mount *mp, *nmp;
43440343Smckusick 	register struct statfs *sp;
43539606Smckusick 	caddr_t sfsp;
43638270Smckusick 	long count, maxcount, error;
43738270Smckusick 
43838270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
43939606Smckusick 	sfsp = (caddr_t)uap->buf;
44065259Smckusick 	for (count = 0, mp = mountlist.tqh_first; mp != NULL; mp = nmp) {
44165259Smckusick 		nmp = mp->mnt_list.tqe_next;
44241400Smckusick 		if (sfsp && count < maxcount &&
44341400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
44441400Smckusick 			sp = &mp->mnt_stat;
44540343Smckusick 			/*
44640343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
44740343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
44840343Smckusick 			 */
44940343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
45040343Smckusick 			    (uap->flags & MNT_WAIT)) &&
45165259Smckusick 			    (error = VFS_STATFS(mp, sp, p)))
45239607Smckusick 				continue;
45341400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
45440343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
45547540Skarels 				return (error);
45640343Smckusick 			sfsp += sizeof(*sp);
45738270Smckusick 		}
45839606Smckusick 		count++;
45965259Smckusick 	}
46038270Smckusick 	if (sfsp && count > maxcount)
46142441Smckusick 		*retval = maxcount;
46238270Smckusick 	else
46342441Smckusick 		*retval = count;
46447540Skarels 	return (0);
46538270Smckusick }
46638270Smckusick 
46738270Smckusick /*
46838259Smckusick  * Change current working directory to a given file descriptor.
46938259Smckusick  */
47054916Storek struct fchdir_args {
47154916Storek 	int	fd;
47254916Storek };
47342441Smckusick /* ARGSUSED */
47442441Smckusick fchdir(p, uap, retval)
47545914Smckusick 	struct proc *p;
47654916Storek 	struct fchdir_args *uap;
47742441Smckusick 	int *retval;
47838259Smckusick {
47945914Smckusick 	register struct filedesc *fdp = p->p_fd;
48038259Smckusick 	register struct vnode *vp;
48138259Smckusick 	struct file *fp;
48238259Smckusick 	int error;
48338259Smckusick 
48445914Smckusick 	if (error = getvnode(fdp, uap->fd, &fp))
48547540Skarels 		return (error);
48638259Smckusick 	vp = (struct vnode *)fp->f_data;
48738259Smckusick 	VOP_LOCK(vp);
48838259Smckusick 	if (vp->v_type != VDIR)
48938259Smckusick 		error = ENOTDIR;
49038259Smckusick 	else
49148026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
49238259Smckusick 	VOP_UNLOCK(vp);
49339860Smckusick 	if (error)
49447540Skarels 		return (error);
49539860Smckusick 	VREF(vp);
49645914Smckusick 	vrele(fdp->fd_cdir);
49745914Smckusick 	fdp->fd_cdir = vp;
49847540Skarels 	return (0);
49938259Smckusick }
50038259Smckusick 
50138259Smckusick /*
50237741Smckusick  * Change current working directory (``.'').
50337741Smckusick  */
50454916Storek struct chdir_args {
50564410Sbostic 	char	*path;
50654916Storek };
50742441Smckusick /* ARGSUSED */
50842441Smckusick chdir(p, uap, retval)
50945914Smckusick 	struct proc *p;
51054916Storek 	struct chdir_args *uap;
51142441Smckusick 	int *retval;
51237741Smckusick {
51345914Smckusick 	register struct filedesc *fdp = p->p_fd;
51437741Smckusick 	int error;
51547540Skarels 	struct nameidata nd;
5166254Sroot 
51764410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
51864410Sbostic 	if (error = change_dir(&nd, p))
51947540Skarels 		return (error);
52045914Smckusick 	vrele(fdp->fd_cdir);
52152322Smckusick 	fdp->fd_cdir = nd.ni_vp;
52247540Skarels 	return (0);
52337741Smckusick }
5246254Sroot 
52537741Smckusick /*
52637741Smckusick  * Change notion of root (``/'') directory.
52737741Smckusick  */
52854916Storek struct chroot_args {
52964410Sbostic 	char	*path;
53054916Storek };
53142441Smckusick /* ARGSUSED */
53242441Smckusick chroot(p, uap, retval)
53345914Smckusick 	struct proc *p;
53454916Storek 	struct chroot_args *uap;
53542441Smckusick 	int *retval;
53637741Smckusick {
53745914Smckusick 	register struct filedesc *fdp = p->p_fd;
53837741Smckusick 	int error;
53947540Skarels 	struct nameidata nd;
54037741Smckusick 
54147540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
54247540Skarels 		return (error);
54364410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
54464410Sbostic 	if (error = change_dir(&nd, p))
54547540Skarels 		return (error);
54645914Smckusick 	if (fdp->fd_rdir != NULL)
54745914Smckusick 		vrele(fdp->fd_rdir);
54852322Smckusick 	fdp->fd_rdir = nd.ni_vp;
54947540Skarels 	return (0);
5506254Sroot }
5516254Sroot 
55237Sbill /*
55337741Smckusick  * Common routine for chroot and chdir.
55437741Smckusick  */
55564410Sbostic static int
55664410Sbostic change_dir(ndp, p)
55752322Smckusick 	register struct nameidata *ndp;
55847540Skarels 	struct proc *p;
55937741Smckusick {
56037741Smckusick 	struct vnode *vp;
56137741Smckusick 	int error;
56237741Smckusick 
56352322Smckusick 	if (error = namei(ndp))
56437741Smckusick 		return (error);
56537741Smckusick 	vp = ndp->ni_vp;
56637741Smckusick 	if (vp->v_type != VDIR)
56737741Smckusick 		error = ENOTDIR;
56837741Smckusick 	else
56948026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
57037741Smckusick 	VOP_UNLOCK(vp);
57137741Smckusick 	if (error)
57237741Smckusick 		vrele(vp);
57337741Smckusick 	return (error);
57437741Smckusick }
57537741Smckusick 
57637741Smckusick /*
57742441Smckusick  * Check permissions, allocate an open file structure,
57842441Smckusick  * and call the device open routine if any.
5796254Sroot  */
58054916Storek struct open_args {
58164410Sbostic 	char	*path;
58264410Sbostic 	int	flags;
58354916Storek 	int	mode;
58454916Storek };
58542441Smckusick open(p, uap, retval)
58645914Smckusick 	struct proc *p;
58754916Storek 	register struct open_args *uap;
58842441Smckusick 	int *retval;
5896254Sroot {
59045914Smckusick 	register struct filedesc *fdp = p->p_fd;
59142441Smckusick 	register struct file *fp;
59250111Smckusick 	register struct vnode *vp;
59364410Sbostic 	int flags, cmode;
59437741Smckusick 	struct file *nfp;
59549945Smckusick 	int type, indx, error;
59649945Smckusick 	struct flock lf;
59747540Skarels 	struct nameidata nd;
59837741Smckusick 	extern struct fileops vnops;
5996254Sroot 
60045914Smckusick 	if (error = falloc(p, &nfp, &indx))
60147540Skarels 		return (error);
60237741Smckusick 	fp = nfp;
60364410Sbostic 	flags = FFLAGS(uap->flags);
60464410Sbostic 	cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
60564410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
60645202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
60764410Sbostic 	if (error = vn_open(&nd, flags, cmode)) {
60849980Smckusick 		ffree(fp);
60954723Smckusick 		if ((error == ENODEV || error == ENXIO) &&
61054723Smckusick 		    p->p_dupfd >= 0 && 			/* XXX from fdopen */
61164410Sbostic 		    (error =
61264410Sbostic 		        dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
61342441Smckusick 			*retval = indx;
61447540Skarels 			return (0);
61542441Smckusick 		}
61640884Smckusick 		if (error == ERESTART)
61740884Smckusick 			error = EINTR;
61847688Skarels 		fdp->fd_ofiles[indx] = NULL;
61947540Skarels 		return (error);
62012756Ssam 	}
62153828Spendry 	p->p_dupfd = 0;
62252322Smckusick 	vp = nd.ni_vp;
62364410Sbostic 	fp->f_flag = flags & FMASK;
62454348Smckusick 	fp->f_type = DTYPE_VNODE;
62554348Smckusick 	fp->f_ops = &vnops;
62654348Smckusick 	fp->f_data = (caddr_t)vp;
62764410Sbostic 	if (flags & (O_EXLOCK | O_SHLOCK)) {
62849945Smckusick 		lf.l_whence = SEEK_SET;
62949945Smckusick 		lf.l_start = 0;
63049945Smckusick 		lf.l_len = 0;
63164410Sbostic 		if (flags & O_EXLOCK)
63249945Smckusick 			lf.l_type = F_WRLCK;
63349945Smckusick 		else
63449945Smckusick 			lf.l_type = F_RDLCK;
63549945Smckusick 		type = F_FLOCK;
63664410Sbostic 		if ((flags & FNONBLOCK) == 0)
63749945Smckusick 			type |= F_WAIT;
63865757Smckusick 		VOP_UNLOCK(vp);
63950111Smckusick 		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
64050111Smckusick 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
64149980Smckusick 			ffree(fp);
64249945Smckusick 			fdp->fd_ofiles[indx] = NULL;
64349945Smckusick 			return (error);
64449945Smckusick 		}
64565757Smckusick 		VOP_LOCK(vp);
64649949Smckusick 		fp->f_flag |= FHASLOCK;
64749945Smckusick 	}
64850111Smckusick 	VOP_UNLOCK(vp);
64942441Smckusick 	*retval = indx;
65047540Skarels 	return (0);
6516254Sroot }
6526254Sroot 
65342955Smckusick #ifdef COMPAT_43
6546254Sroot /*
65564410Sbostic  * Create a file.
6566254Sroot  */
65754916Storek struct ocreat_args {
65864410Sbostic 	char	*path;
65964410Sbostic 	int	mode;
66054916Storek };
66142955Smckusick ocreat(p, uap, retval)
66242441Smckusick 	struct proc *p;
66354916Storek 	register struct ocreat_args *uap;
66442441Smckusick 	int *retval;
6656254Sroot {
66654916Storek 	struct open_args openuap;
66742441Smckusick 
66864410Sbostic 	openuap.path = uap->path;
66964410Sbostic 	openuap.mode = uap->mode;
67064410Sbostic 	openuap.flags = O_WRONLY | O_CREAT | O_TRUNC;
67147540Skarels 	return (open(p, &openuap, retval));
67242441Smckusick }
67342955Smckusick #endif /* COMPAT_43 */
67442441Smckusick 
67542441Smckusick /*
67664410Sbostic  * Create a special file.
67742441Smckusick  */
67854916Storek struct mknod_args {
67964410Sbostic 	char	*path;
68064410Sbostic 	int	mode;
68154916Storek 	int	dev;
68254916Storek };
68342441Smckusick /* ARGSUSED */
68442441Smckusick mknod(p, uap, retval)
68545914Smckusick 	struct proc *p;
68654916Storek 	register struct mknod_args *uap;
68742441Smckusick 	int *retval;
68842441Smckusick {
68937741Smckusick 	register struct vnode *vp;
69037741Smckusick 	struct vattr vattr;
69137741Smckusick 	int error;
69247540Skarels 	struct nameidata nd;
6936254Sroot 
69447540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
69547540Skarels 		return (error);
69664410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
69752322Smckusick 	if (error = namei(&nd))
69847540Skarels 		return (error);
69952322Smckusick 	vp = nd.ni_vp;
70064585Sbostic 	if (vp != NULL)
70137741Smckusick 		error = EEXIST;
70264585Sbostic 	else {
70364585Sbostic 		VATTR_NULL(&vattr);
70464585Sbostic 		vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
70564585Sbostic 		vattr.va_rdev = uap->dev;
70664585Sbostic 
70764585Sbostic 		switch (uap->mode & S_IFMT) {
70864585Sbostic 		case S_IFMT:	/* used by badsect to flag bad sectors */
70964585Sbostic 			vattr.va_type = VBAD;
71064585Sbostic 			break;
71164585Sbostic 		case S_IFCHR:
71264585Sbostic 			vattr.va_type = VCHR;
71364585Sbostic 			break;
71464585Sbostic 		case S_IFBLK:
71564585Sbostic 			vattr.va_type = VBLK;
71664585Sbostic 			break;
71764585Sbostic 		default:
71864585Sbostic 			error = EINVAL;
71964585Sbostic 			break;
72064585Sbostic 		}
7216254Sroot 	}
72242465Smckusick 	if (!error) {
72352322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
72452322Smckusick 		error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
72542465Smckusick 	} else {
72652322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
72752322Smckusick 		if (nd.ni_dvp == vp)
72852322Smckusick 			vrele(nd.ni_dvp);
72943344Smckusick 		else
73052322Smckusick 			vput(nd.ni_dvp);
73142465Smckusick 		if (vp)
73242465Smckusick 			vrele(vp);
73342465Smckusick 	}
73447540Skarels 	return (error);
7356254Sroot }
7366254Sroot 
7376254Sroot /*
73864410Sbostic  * Create named pipe.
73940285Smckusick  */
74054916Storek struct mkfifo_args {
74164410Sbostic 	char	*path;
74264410Sbostic 	int	mode;
74354916Storek };
74442441Smckusick /* ARGSUSED */
74542441Smckusick mkfifo(p, uap, retval)
74645914Smckusick 	struct proc *p;
74754916Storek 	register struct mkfifo_args *uap;
74842441Smckusick 	int *retval;
74942441Smckusick {
75040285Smckusick 	struct vattr vattr;
75140285Smckusick 	int error;
75247540Skarels 	struct nameidata nd;
75340285Smckusick 
75440285Smckusick #ifndef FIFO
75547540Skarels 	return (EOPNOTSUPP);
75640285Smckusick #else
75764410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
75852322Smckusick 	if (error = namei(&nd))
75947540Skarels 		return (error);
76052322Smckusick 	if (nd.ni_vp != NULL) {
76152322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
76252322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
76352322Smckusick 			vrele(nd.ni_dvp);
76443344Smckusick 		else
76552322Smckusick 			vput(nd.ni_dvp);
76652322Smckusick 		vrele(nd.ni_vp);
76747540Skarels 		return (EEXIST);
76840285Smckusick 	}
76945785Sbostic 	VATTR_NULL(&vattr);
77045785Sbostic 	vattr.va_type = VFIFO;
77164410Sbostic 	vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
77252322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
77352322Smckusick 	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
77440285Smckusick #endif /* FIFO */
77540285Smckusick }
77640285Smckusick 
77740285Smckusick /*
77864410Sbostic  * Make a hard file link.
7796254Sroot  */
78054916Storek struct link_args {
78164410Sbostic 	char	*path;
78264410Sbostic 	char	*link;
78354916Storek };
78442441Smckusick /* ARGSUSED */
78542441Smckusick link(p, uap, retval)
78645914Smckusick 	struct proc *p;
78754916Storek 	register struct link_args *uap;
78842441Smckusick 	int *retval;
78942441Smckusick {
79064410Sbostic 	register struct vnode *vp;
79164410Sbostic 	struct nameidata nd;
79237741Smckusick 	int error;
7936254Sroot 
79464410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
79552322Smckusick 	if (error = namei(&nd))
79647540Skarels 		return (error);
79752322Smckusick 	vp = nd.ni_vp;
79864585Sbostic 	if (vp->v_type != VDIR ||
79964585Sbostic 	    (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
80064585Sbostic 		nd.ni_cnd.cn_nameiop = CREATE;
80164585Sbostic 		nd.ni_cnd.cn_flags = LOCKPARENT;
80264585Sbostic 		nd.ni_dirp = uap->link;
80364585Sbostic 		if ((error = namei(&nd)) == 0) {
80464585Sbostic 			if (nd.ni_vp != NULL)
80564585Sbostic 				error = EEXIST;
80664585Sbostic 			if (!error) {
80764585Sbostic 				LEASE_CHECK(nd.ni_dvp,
80864585Sbostic 				    p, p->p_ucred, LEASE_WRITE);
80964585Sbostic 				LEASE_CHECK(vp,
81064585Sbostic 				    p, p->p_ucred, LEASE_WRITE);
81164585Sbostic 				error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
81264585Sbostic 			} else {
81364585Sbostic 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
81464585Sbostic 				if (nd.ni_dvp == nd.ni_vp)
81564585Sbostic 					vrele(nd.ni_dvp);
81664585Sbostic 				else
81764585Sbostic 					vput(nd.ni_dvp);
81864585Sbostic 				if (nd.ni_vp)
81964585Sbostic 					vrele(nd.ni_vp);
82064585Sbostic 			}
82164585Sbostic 		}
82242465Smckusick 	}
82364585Sbostic 	vrele(vp);
82447540Skarels 	return (error);
8256254Sroot }
8266254Sroot 
8276254Sroot /*
82849365Smckusick  * Make a symbolic link.
8296254Sroot  */
83054916Storek struct symlink_args {
83164410Sbostic 	char	*path;
83264410Sbostic 	char	*link;
83354916Storek };
83442441Smckusick /* ARGSUSED */
83542441Smckusick symlink(p, uap, retval)
83645914Smckusick 	struct proc *p;
83754916Storek 	register struct symlink_args *uap;
83842441Smckusick 	int *retval;
83942441Smckusick {
84037741Smckusick 	struct vattr vattr;
84164410Sbostic 	char *path;
84237741Smckusick 	int error;
84347540Skarels 	struct nameidata nd;
8446254Sroot 
84564410Sbostic 	MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
84664410Sbostic 	if (error = copyinstr(uap->path, path, MAXPATHLEN, NULL))
84742465Smckusick 		goto out;
84864410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p);
84952322Smckusick 	if (error = namei(&nd))
85042465Smckusick 		goto out;
85152322Smckusick 	if (nd.ni_vp) {
85252322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
85352322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
85452322Smckusick 			vrele(nd.ni_dvp);
85543344Smckusick 		else
85652322Smckusick 			vput(nd.ni_dvp);
85752322Smckusick 		vrele(nd.ni_vp);
85837741Smckusick 		error = EEXIST;
85937741Smckusick 		goto out;
8606254Sroot 	}
86141362Smckusick 	VATTR_NULL(&vattr);
86264410Sbostic 	vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
86352322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
86464410Sbostic 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
86537741Smckusick out:
86664410Sbostic 	FREE(path, M_NAMEI);
86747540Skarels 	return (error);
8686254Sroot }
8696254Sroot 
8706254Sroot /*
87167518Spendry  * Delete a whiteout from the filesystem.
87267518Spendry  */
87367518Spendry struct unwhiteout_args {
87467518Spendry 	char	*path;
87567518Spendry };
87667518Spendry /* ARGSUSED */
87767518Spendry unwhiteout(p, uap, retval)
87867518Spendry 	struct proc *p;
87967518Spendry 	struct unwhiteout_args *uap;
88067518Spendry 	int *retval;
88167518Spendry {
88267518Spendry 	int error;
88367518Spendry 	struct nameidata nd;
88467518Spendry 
88567518Spendry 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
88667518Spendry 	if (error = namei(&nd))
88767518Spendry 		return (error);
88867518Spendry 	if (nd.ni_vp || !(nd.ni_cnd.cn_flags & WHITEOUT)) {
88967518Spendry 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
89067518Spendry 		if (nd.ni_dvp == nd.ni_vp)
89167518Spendry 			vrele(nd.ni_dvp);
89267518Spendry 		else
89367518Spendry 			vput(nd.ni_dvp);
89467518Spendry 		if (nd.ni_vp)
89567518Spendry 			vrele(nd.ni_vp);
89667518Spendry 		return (EEXIST);
89767518Spendry 	}
89867518Spendry 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
89967518Spendry 	error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE);
90067518Spendry 	vput(nd.ni_dvp);
90167518Spendry 	return (error);
90267518Spendry }
90367518Spendry 
90467518Spendry /*
90549365Smckusick  * Delete a name from the filesystem.
9066254Sroot  */
90754916Storek struct unlink_args {
90864410Sbostic 	char	*path;
90954916Storek };
91042441Smckusick /* ARGSUSED */
91142441Smckusick unlink(p, uap, retval)
91245914Smckusick 	struct proc *p;
91354916Storek 	struct unlink_args *uap;
91442441Smckusick 	int *retval;
9156254Sroot {
91637741Smckusick 	register struct vnode *vp;
91737741Smckusick 	int error;
91847540Skarels 	struct nameidata nd;
9196254Sroot 
92064410Sbostic 	NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
92152322Smckusick 	if (error = namei(&nd))
92247540Skarels 		return (error);
92352322Smckusick 	vp = nd.ni_vp;
92459382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
92559382Smckusick 	VOP_LOCK(vp);
92664410Sbostic 
92764585Sbostic 	if (vp->v_type != VDIR ||
92864585Sbostic 	    (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
92964585Sbostic 		/*
93064585Sbostic 		 * The root of a mounted filesystem cannot be deleted.
93164585Sbostic 		 */
93264585Sbostic 		if (vp->v_flag & VROOT)
93364585Sbostic 			error = EBUSY;
93464585Sbostic 		else
93564585Sbostic 			(void)vnode_pager_uncache(vp);
93664585Sbostic 	}
93764585Sbostic 
93864585Sbostic 	if (!error) {
93952322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
94052322Smckusick 		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
94142465Smckusick 	} else {
94252322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
94352322Smckusick 		if (nd.ni_dvp == vp)
94452322Smckusick 			vrele(nd.ni_dvp);
94543344Smckusick 		else
94652322Smckusick 			vput(nd.ni_dvp);
94742465Smckusick 		vput(vp);
94842465Smckusick 	}
94947540Skarels 	return (error);
9506254Sroot }
9516254Sroot 
95264410Sbostic /*
95364410Sbostic  * Reposition read/write file offset.
95464410Sbostic  */
95560428Smckusick struct lseek_args {
95664410Sbostic 	int	fd;
95754863Storek 	int	pad;
95864410Sbostic 	off_t	offset;
95964410Sbostic 	int	whence;
96054863Storek };
96160414Smckusick lseek(p, uap, retval)
96253468Smckusick 	struct proc *p;
96360428Smckusick 	register struct lseek_args *uap;
96454916Storek 	int *retval;
96542441Smckusick {
96647540Skarels 	struct ucred *cred = p->p_ucred;
96745914Smckusick 	register struct filedesc *fdp = p->p_fd;
96842441Smckusick 	register struct file *fp;
96937741Smckusick 	struct vattr vattr;
97037741Smckusick 	int error;
9716254Sroot 
97264410Sbostic 	if ((u_int)uap->fd >= fdp->fd_nfiles ||
97364410Sbostic 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
97447540Skarels 		return (EBADF);
97537741Smckusick 	if (fp->f_type != DTYPE_VNODE)
97647540Skarels 		return (ESPIPE);
97764410Sbostic 	switch (uap->whence) {
97813878Ssam 	case L_INCR:
97964410Sbostic 		fp->f_offset += uap->offset;
98013878Ssam 		break;
98113878Ssam 	case L_XTND:
98264410Sbostic 		if (error =
98364410Sbostic 		    VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p))
98447540Skarels 			return (error);
98564410Sbostic 		fp->f_offset = uap->offset + vattr.va_size;
98613878Ssam 		break;
98713878Ssam 	case L_SET:
98864410Sbostic 		fp->f_offset = uap->offset;
98913878Ssam 		break;
99013878Ssam 	default:
99147540Skarels 		return (EINVAL);
99213878Ssam 	}
99354916Storek 	*(off_t *)retval = fp->f_offset;
99447540Skarels 	return (0);
9956254Sroot }
9966254Sroot 
99760414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
9986254Sroot /*
99964410Sbostic  * Reposition read/write file offset.
100060036Smckusick  */
100160428Smckusick struct olseek_args {
100264410Sbostic 	int	fd;
100364410Sbostic 	long	offset;
100464410Sbostic 	int	whence;
100560036Smckusick };
100660414Smckusick olseek(p, uap, retval)
100760036Smckusick 	struct proc *p;
100860428Smckusick 	register struct olseek_args *uap;
100960036Smckusick 	int *retval;
101060036Smckusick {
101160428Smckusick 	struct lseek_args nuap;
101260036Smckusick 	off_t qret;
101360036Smckusick 	int error;
101460036Smckusick 
101564410Sbostic 	nuap.fd = uap->fd;
101664410Sbostic 	nuap.offset = uap->offset;
101764410Sbostic 	nuap.whence = uap->whence;
101860428Smckusick 	error = lseek(p, &nuap, &qret);
101960036Smckusick 	*(long *)retval = qret;
102060036Smckusick 	return (error);
102160036Smckusick }
102260414Smckusick #endif /* COMPAT_43 */
102360036Smckusick 
102460036Smckusick /*
102549365Smckusick  * Check access permissions.
10266254Sroot  */
102763427Sbostic struct access_args {
102864410Sbostic 	char	*path;
102964410Sbostic 	int	flags;
103054916Storek };
103163427Sbostic access(p, uap, retval)
103245914Smckusick 	struct proc *p;
103363427Sbostic 	register struct access_args *uap;
103442441Smckusick 	int *retval;
103542441Smckusick {
103647540Skarels 	register struct ucred *cred = p->p_ucred;
103737741Smckusick 	register struct vnode *vp;
103864585Sbostic 	int error, flags, t_gid, t_uid;
103947540Skarels 	struct nameidata nd;
10406254Sroot 
104164585Sbostic 	t_uid = cred->cr_uid;
104264585Sbostic 	t_gid = cred->cr_groups[0];
104347540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
104447540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
104564410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
104652322Smckusick 	if (error = namei(&nd))
104737741Smckusick 		goto out1;
104852322Smckusick 	vp = nd.ni_vp;
104964410Sbostic 
105064410Sbostic 	/* Flags == 0 means only check for existence. */
105164410Sbostic 	if (uap->flags) {
105264410Sbostic 		flags = 0;
105364410Sbostic 		if (uap->flags & R_OK)
105464410Sbostic 			flags |= VREAD;
105564410Sbostic 		if (uap->flags & W_OK)
105664410Sbostic 			flags |= VWRITE;
105764410Sbostic 		if (uap->flags & X_OK)
105864410Sbostic 			flags |= VEXEC;
105964410Sbostic 		if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
106064410Sbostic 			error = VOP_ACCESS(vp, flags, cred, p);
10616254Sroot 	}
106237741Smckusick 	vput(vp);
106337741Smckusick out1:
106464585Sbostic 	cred->cr_uid = t_uid;
106564585Sbostic 	cred->cr_groups[0] = t_gid;
106647540Skarels 	return (error);
10676254Sroot }
10686254Sroot 
106954348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
10706254Sroot /*
107164410Sbostic  * Get file status; this version follows links.
107237Sbill  */
107354916Storek struct ostat_args {
107464410Sbostic 	char	*path;
107554916Storek 	struct ostat *ub;
107654916Storek };
107742441Smckusick /* ARGSUSED */
107853759Smckusick ostat(p, uap, retval)
107945914Smckusick 	struct proc *p;
108054916Storek 	register struct ostat_args *uap;
108153468Smckusick 	int *retval;
108253468Smckusick {
108353468Smckusick 	struct stat sb;
108453468Smckusick 	struct ostat osb;
108553468Smckusick 	int error;
108653468Smckusick 	struct nameidata nd;
108753468Smckusick 
108864410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
108953468Smckusick 	if (error = namei(&nd))
109053468Smckusick 		return (error);
109153468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
109253468Smckusick 	vput(nd.ni_vp);
109353468Smckusick 	if (error)
109453468Smckusick 		return (error);
109553468Smckusick 	cvtstat(&sb, &osb);
109653468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
109753468Smckusick 	return (error);
109853468Smckusick }
109953468Smckusick 
110053468Smckusick /*
110164410Sbostic  * Get file status; this version does not follow links.
110253468Smckusick  */
110354916Storek struct olstat_args {
110464410Sbostic 	char	*path;
110554916Storek 	struct ostat *ub;
110654916Storek };
110753468Smckusick /* ARGSUSED */
110853759Smckusick olstat(p, uap, retval)
110953468Smckusick 	struct proc *p;
111054916Storek 	register struct olstat_args *uap;
111153468Smckusick 	int *retval;
111253468Smckusick {
111353468Smckusick 	struct stat sb;
111453468Smckusick 	struct ostat osb;
111553468Smckusick 	int error;
111653468Smckusick 	struct nameidata nd;
111753468Smckusick 
111864410Sbostic 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
111953468Smckusick 	if (error = namei(&nd))
112053468Smckusick 		return (error);
112153468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
112253468Smckusick 	vput(nd.ni_vp);
112353468Smckusick 	if (error)
112453468Smckusick 		return (error);
112553468Smckusick 	cvtstat(&sb, &osb);
112653468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
112753468Smckusick 	return (error);
112853468Smckusick }
112953468Smckusick 
113053468Smckusick /*
113164410Sbostic  * Convert from an old to a new stat structure.
113253468Smckusick  */
113353468Smckusick cvtstat(st, ost)
113453468Smckusick 	struct stat *st;
113553468Smckusick 	struct ostat *ost;
113653468Smckusick {
113753468Smckusick 
113853468Smckusick 	ost->st_dev = st->st_dev;
113953468Smckusick 	ost->st_ino = st->st_ino;
114053468Smckusick 	ost->st_mode = st->st_mode;
114153468Smckusick 	ost->st_nlink = st->st_nlink;
114253468Smckusick 	ost->st_uid = st->st_uid;
114353468Smckusick 	ost->st_gid = st->st_gid;
114453468Smckusick 	ost->st_rdev = st->st_rdev;
114553468Smckusick 	if (st->st_size < (quad_t)1 << 32)
114653468Smckusick 		ost->st_size = st->st_size;
114753468Smckusick 	else
114853468Smckusick 		ost->st_size = -2;
114953468Smckusick 	ost->st_atime = st->st_atime;
115053468Smckusick 	ost->st_mtime = st->st_mtime;
115153468Smckusick 	ost->st_ctime = st->st_ctime;
115253468Smckusick 	ost->st_blksize = st->st_blksize;
115353468Smckusick 	ost->st_blocks = st->st_blocks;
115453468Smckusick 	ost->st_flags = st->st_flags;
115553468Smckusick 	ost->st_gen = st->st_gen;
115653468Smckusick }
115754348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
115853468Smckusick 
115953468Smckusick /*
116064410Sbostic  * Get file status; this version follows links.
116153468Smckusick  */
116254916Storek struct stat_args {
116364410Sbostic 	char	*path;
116454916Storek 	struct stat *ub;
116554916Storek };
116653468Smckusick /* ARGSUSED */
116753759Smckusick stat(p, uap, retval)
116853468Smckusick 	struct proc *p;
116954916Storek 	register struct stat_args *uap;
117042441Smckusick 	int *retval;
117137Sbill {
117242441Smckusick 	struct stat sb;
117342441Smckusick 	int error;
117447540Skarels 	struct nameidata nd;
117537Sbill 
117664410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
117752322Smckusick 	if (error = namei(&nd))
117847540Skarels 		return (error);
117952322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
118052322Smckusick 	vput(nd.ni_vp);
118142441Smckusick 	if (error)
118247540Skarels 		return (error);
118342441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
118447540Skarels 	return (error);
118537Sbill }
118637Sbill 
118737Sbill /*
118864410Sbostic  * Get file status; this version does not follow links.
11895992Swnj  */
119054916Storek struct lstat_args {
119164410Sbostic 	char	*path;
119254916Storek 	struct stat *ub;
119354916Storek };
119442441Smckusick /* ARGSUSED */
119553759Smckusick lstat(p, uap, retval)
119645914Smckusick 	struct proc *p;
119754916Storek 	register struct lstat_args *uap;
119842441Smckusick 	int *retval;
119942441Smckusick {
120037741Smckusick 	int error;
120159373Smckusick 	struct vnode *vp, *dvp;
120259373Smckusick 	struct stat sb, sb1;
120347540Skarels 	struct nameidata nd;
12045992Swnj 
120559373Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
120664410Sbostic 	    uap->path, p);
120752322Smckusick 	if (error = namei(&nd))
120847540Skarels 		return (error);
120959373Smckusick 	/*
121059373Smckusick 	 * For symbolic links, always return the attributes of its
121159373Smckusick 	 * containing directory, except for mode, size, and links.
121259373Smckusick 	 */
121359373Smckusick 	vp = nd.ni_vp;
121459373Smckusick 	dvp = nd.ni_dvp;
121559373Smckusick 	if (vp->v_type != VLNK) {
121659373Smckusick 		if (dvp == vp)
121759373Smckusick 			vrele(dvp);
121859373Smckusick 		else
121959373Smckusick 			vput(dvp);
122059373Smckusick 		error = vn_stat(vp, &sb, p);
122159373Smckusick 		vput(vp);
122259373Smckusick 		if (error)
122359373Smckusick 			return (error);
122459373Smckusick 	} else {
122559373Smckusick 		error = vn_stat(dvp, &sb, p);
122659373Smckusick 		vput(dvp);
122759373Smckusick 		if (error) {
122859373Smckusick 			vput(vp);
122959373Smckusick 			return (error);
123059373Smckusick 		}
123159373Smckusick 		error = vn_stat(vp, &sb1, p);
123259373Smckusick 		vput(vp);
123359373Smckusick 		if (error)
123459373Smckusick 			return (error);
123559373Smckusick 		sb.st_mode &= ~S_IFDIR;
123659373Smckusick 		sb.st_mode |= S_IFLNK;
123759373Smckusick 		sb.st_nlink = sb1.st_nlink;
123859373Smckusick 		sb.st_size = sb1.st_size;
123959373Smckusick 		sb.st_blocks = sb1.st_blocks;
124059373Smckusick 	}
124137741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
124247540Skarels 	return (error);
12435992Swnj }
12445992Swnj 
12455992Swnj /*
124664410Sbostic  * Get configurable pathname variables.
124760414Smckusick  */
124860414Smckusick struct pathconf_args {
124964410Sbostic 	char	*path;
125060414Smckusick 	int	name;
125160414Smckusick };
125260414Smckusick /* ARGSUSED */
125360414Smckusick pathconf(p, uap, retval)
125460414Smckusick 	struct proc *p;
125560414Smckusick 	register struct pathconf_args *uap;
125660414Smckusick 	int *retval;
125760414Smckusick {
125860414Smckusick 	int error;
125960414Smckusick 	struct nameidata nd;
126060414Smckusick 
126164410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
126260414Smckusick 	if (error = namei(&nd))
126360414Smckusick 		return (error);
126460414Smckusick 	error = VOP_PATHCONF(nd.ni_vp, uap->name, retval);
126560414Smckusick 	vput(nd.ni_vp);
126660414Smckusick 	return (error);
126760414Smckusick }
126860414Smckusick 
126960414Smckusick /*
127049365Smckusick  * Return target name of a symbolic link.
127137Sbill  */
127254916Storek struct readlink_args {
127364410Sbostic 	char	*path;
127454916Storek 	char	*buf;
127554916Storek 	int	count;
127654916Storek };
127742441Smckusick /* ARGSUSED */
127842441Smckusick readlink(p, uap, retval)
127945914Smckusick 	struct proc *p;
128054916Storek 	register struct readlink_args *uap;
128142441Smckusick 	int *retval;
128242441Smckusick {
128337741Smckusick 	register struct vnode *vp;
128437741Smckusick 	struct iovec aiov;
128537741Smckusick 	struct uio auio;
128637741Smckusick 	int error;
128747540Skarels 	struct nameidata nd;
12885992Swnj 
128964410Sbostic 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
129052322Smckusick 	if (error = namei(&nd))
129147540Skarels 		return (error);
129252322Smckusick 	vp = nd.ni_vp;
129364410Sbostic 	if (vp->v_type != VLNK)
129437741Smckusick 		error = EINVAL;
129564410Sbostic 	else {
129664410Sbostic 		aiov.iov_base = uap->buf;
129764410Sbostic 		aiov.iov_len = uap->count;
129864410Sbostic 		auio.uio_iov = &aiov;
129964410Sbostic 		auio.uio_iovcnt = 1;
130064410Sbostic 		auio.uio_offset = 0;
130164410Sbostic 		auio.uio_rw = UIO_READ;
130264410Sbostic 		auio.uio_segflg = UIO_USERSPACE;
130364410Sbostic 		auio.uio_procp = p;
130464410Sbostic 		auio.uio_resid = uap->count;
130564410Sbostic 		error = VOP_READLINK(vp, &auio, p->p_ucred);
13065992Swnj 	}
130737741Smckusick 	vput(vp);
130842441Smckusick 	*retval = uap->count - auio.uio_resid;
130947540Skarels 	return (error);
13105992Swnj }
13115992Swnj 
13129167Ssam /*
131364410Sbostic  * Change flags of a file given a path name.
131438259Smckusick  */
131554916Storek struct chflags_args {
131664410Sbostic 	char	*path;
131754916Storek 	int	flags;
131854916Storek };
131942441Smckusick /* ARGSUSED */
132042441Smckusick chflags(p, uap, retval)
132145914Smckusick 	struct proc *p;
132254916Storek 	register struct chflags_args *uap;
132342441Smckusick 	int *retval;
132442441Smckusick {
132538259Smckusick 	register struct vnode *vp;
132638259Smckusick 	struct vattr vattr;
132738259Smckusick 	int error;
132847540Skarels 	struct nameidata nd;
132938259Smckusick 
133064410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
133152322Smckusick 	if (error = namei(&nd))
133247540Skarels 		return (error);
133352322Smckusick 	vp = nd.ni_vp;
133459382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
133559382Smckusick 	VOP_LOCK(vp);
133664410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
133738259Smckusick 		error = EROFS;
133864410Sbostic 	else {
133964410Sbostic 		VATTR_NULL(&vattr);
134064410Sbostic 		vattr.va_flags = uap->flags;
134164410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
134238259Smckusick 	}
134338259Smckusick 	vput(vp);
134447540Skarels 	return (error);
134538259Smckusick }
134638259Smckusick 
134738259Smckusick /*
134838259Smckusick  * Change flags of a file given a file descriptor.
134938259Smckusick  */
135054916Storek struct fchflags_args {
135154916Storek 	int	fd;
135254916Storek 	int	flags;
135354916Storek };
135442441Smckusick /* ARGSUSED */
135542441Smckusick fchflags(p, uap, retval)
135645914Smckusick 	struct proc *p;
135754916Storek 	register struct fchflags_args *uap;
135842441Smckusick 	int *retval;
135942441Smckusick {
136038259Smckusick 	struct vattr vattr;
136138259Smckusick 	struct vnode *vp;
136238259Smckusick 	struct file *fp;
136338259Smckusick 	int error;
136438259Smckusick 
136545914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
136647540Skarels 		return (error);
136738259Smckusick 	vp = (struct vnode *)fp->f_data;
136859382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
136938259Smckusick 	VOP_LOCK(vp);
137064410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
137138259Smckusick 		error = EROFS;
137264410Sbostic 	else {
137364410Sbostic 		VATTR_NULL(&vattr);
137464410Sbostic 		vattr.va_flags = uap->flags;
137564410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
137638259Smckusick 	}
137738259Smckusick 	VOP_UNLOCK(vp);
137847540Skarels 	return (error);
137938259Smckusick }
138038259Smckusick 
138138259Smckusick /*
13829167Ssam  * Change mode of a file given path name.
13839167Ssam  */
138454916Storek struct chmod_args {
138564410Sbostic 	char	*path;
138664410Sbostic 	int	mode;
138754916Storek };
138842441Smckusick /* ARGSUSED */
138942441Smckusick chmod(p, uap, retval)
139045914Smckusick 	struct proc *p;
139154916Storek 	register struct chmod_args *uap;
139242441Smckusick 	int *retval;
139342441Smckusick {
139437741Smckusick 	register struct vnode *vp;
139537741Smckusick 	struct vattr vattr;
139637741Smckusick 	int error;
139747540Skarels 	struct nameidata nd;
13985992Swnj 
139964410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
140052322Smckusick 	if (error = namei(&nd))
140147540Skarels 		return (error);
140252322Smckusick 	vp = nd.ni_vp;
140359382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
140459382Smckusick 	VOP_LOCK(vp);
140564410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
140637741Smckusick 		error = EROFS;
140764410Sbostic 	else {
140864410Sbostic 		VATTR_NULL(&vattr);
140964410Sbostic 		vattr.va_mode = uap->mode & ALLPERMS;
141064410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
141137741Smckusick 	}
141237741Smckusick 	vput(vp);
141347540Skarels 	return (error);
14147701Ssam }
14157439Sroot 
14169167Ssam /*
14179167Ssam  * Change mode of a file given a file descriptor.
14189167Ssam  */
141954916Storek struct fchmod_args {
142054916Storek 	int	fd;
142164410Sbostic 	int	mode;
142254916Storek };
142342441Smckusick /* ARGSUSED */
142442441Smckusick fchmod(p, uap, retval)
142545914Smckusick 	struct proc *p;
142654916Storek 	register struct fchmod_args *uap;
142742441Smckusick 	int *retval;
142842441Smckusick {
142937741Smckusick 	struct vattr vattr;
143037741Smckusick 	struct vnode *vp;
143137741Smckusick 	struct file *fp;
143237741Smckusick 	int error;
14337701Ssam 
143445914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
143547540Skarels 		return (error);
143637741Smckusick 	vp = (struct vnode *)fp->f_data;
143759382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
143837741Smckusick 	VOP_LOCK(vp);
143964410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
144037741Smckusick 		error = EROFS;
144164410Sbostic 	else {
144264410Sbostic 		VATTR_NULL(&vattr);
144364410Sbostic 		vattr.va_mode = uap->mode & ALLPERMS;
144464410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
14457439Sroot 	}
144637741Smckusick 	VOP_UNLOCK(vp);
144747540Skarels 	return (error);
14485992Swnj }
14495992Swnj 
14509167Ssam /*
14519167Ssam  * Set ownership given a path name.
14529167Ssam  */
145354916Storek struct chown_args {
145464410Sbostic 	char	*path;
145554916Storek 	int	uid;
145654916Storek 	int	gid;
145754916Storek };
145842441Smckusick /* ARGSUSED */
145942441Smckusick chown(p, uap, retval)
146045914Smckusick 	struct proc *p;
146154916Storek 	register struct chown_args *uap;
146242441Smckusick 	int *retval;
146342441Smckusick {
146437741Smckusick 	register struct vnode *vp;
146537741Smckusick 	struct vattr vattr;
146637741Smckusick 	int error;
146747540Skarels 	struct nameidata nd;
146837Sbill 
146966510Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
147052322Smckusick 	if (error = namei(&nd))
147147540Skarels 		return (error);
147252322Smckusick 	vp = nd.ni_vp;
147359382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
147459382Smckusick 	VOP_LOCK(vp);
147564410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
147637741Smckusick 		error = EROFS;
147764410Sbostic 	else {
147864410Sbostic 		VATTR_NULL(&vattr);
147964410Sbostic 		vattr.va_uid = uap->uid;
148064410Sbostic 		vattr.va_gid = uap->gid;
148164410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
148237741Smckusick 	}
148337741Smckusick 	vput(vp);
148447540Skarels 	return (error);
14857701Ssam }
14867439Sroot 
14879167Ssam /*
14889167Ssam  * Set ownership given a file descriptor.
14899167Ssam  */
149054916Storek struct fchown_args {
149154916Storek 	int	fd;
149254916Storek 	int	uid;
149354916Storek 	int	gid;
149454916Storek };
149542441Smckusick /* ARGSUSED */
149642441Smckusick fchown(p, uap, retval)
149745914Smckusick 	struct proc *p;
149854916Storek 	register struct fchown_args *uap;
149942441Smckusick 	int *retval;
150042441Smckusick {
150137741Smckusick 	struct vattr vattr;
150237741Smckusick 	struct vnode *vp;
150337741Smckusick 	struct file *fp;
150437741Smckusick 	int error;
15057701Ssam 
150645914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
150747540Skarels 		return (error);
150837741Smckusick 	vp = (struct vnode *)fp->f_data;
150959382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
151037741Smckusick 	VOP_LOCK(vp);
151164410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
151237741Smckusick 		error = EROFS;
151364410Sbostic 	else {
151464410Sbostic 		VATTR_NULL(&vattr);
151564410Sbostic 		vattr.va_uid = uap->uid;
151664410Sbostic 		vattr.va_gid = uap->gid;
151764410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
151837741Smckusick 	}
151937741Smckusick 	VOP_UNLOCK(vp);
152047540Skarels 	return (error);
15217701Ssam }
15227701Ssam 
152342441Smckusick /*
152442441Smckusick  * Set the access and modification times of a file.
152542441Smckusick  */
152654916Storek struct utimes_args {
152764410Sbostic 	char	*path;
152854916Storek 	struct	timeval *tptr;
152954916Storek };
153042441Smckusick /* ARGSUSED */
153142441Smckusick utimes(p, uap, retval)
153245914Smckusick 	struct proc *p;
153354916Storek 	register struct utimes_args *uap;
153442441Smckusick 	int *retval;
153542441Smckusick {
153637741Smckusick 	register struct vnode *vp;
153711811Ssam 	struct timeval tv[2];
153837741Smckusick 	struct vattr vattr;
153958840Storek 	int error;
154047540Skarels 	struct nameidata nd;
154111811Ssam 
154258505Sbostic 	VATTR_NULL(&vattr);
154358505Sbostic 	if (uap->tptr == NULL) {
154458505Sbostic 		microtime(&tv[0]);
154558505Sbostic 		tv[1] = tv[0];
154658548Sbostic 		vattr.va_vaflags |= VA_UTIMES_NULL;
154758505Sbostic 	} else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
154858505Sbostic   		return (error);
154964410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
155052322Smckusick 	if (error = namei(&nd))
155147540Skarels 		return (error);
155252322Smckusick 	vp = nd.ni_vp;
155359382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
155459382Smckusick 	VOP_LOCK(vp);
155564410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
155637741Smckusick 		error = EROFS;
155764410Sbostic 	else {
155864410Sbostic 		vattr.va_atime.ts_sec = tv[0].tv_sec;
155964410Sbostic 		vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
156064410Sbostic 		vattr.va_mtime.ts_sec = tv[1].tv_sec;
156164410Sbostic 		vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
156264410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
156321015Smckusick 	}
156437741Smckusick 	vput(vp);
156547540Skarels 	return (error);
156611811Ssam }
156711811Ssam 
156864410Sbostic /*
156964410Sbostic  * Truncate a file given its path name.
157064410Sbostic  */
157160428Smckusick struct truncate_args {
157264410Sbostic 	char	*path;
157354863Storek 	int	pad;
157454863Storek 	off_t	length;
157554863Storek };
157653468Smckusick /* ARGSUSED */
157760414Smckusick truncate(p, uap, retval)
157853468Smckusick 	struct proc *p;
157960428Smckusick 	register struct truncate_args *uap;
158053468Smckusick 	int *retval;
158153468Smckusick {
158237741Smckusick 	register struct vnode *vp;
158337741Smckusick 	struct vattr vattr;
158437741Smckusick 	int error;
158547540Skarels 	struct nameidata nd;
15867701Ssam 
158764410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
158852322Smckusick 	if (error = namei(&nd))
158947540Skarels 		return (error);
159052322Smckusick 	vp = nd.ni_vp;
159159382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
159259382Smckusick 	VOP_LOCK(vp);
159364410Sbostic 	if (vp->v_type == VDIR)
159437741Smckusick 		error = EISDIR;
159564410Sbostic 	else if ((error = vn_writechk(vp)) == 0 &&
159664410Sbostic 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
159764410Sbostic 		VATTR_NULL(&vattr);
159864410Sbostic 		vattr.va_size = uap->length;
159964410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
16007701Ssam 	}
160137741Smckusick 	vput(vp);
160247540Skarels 	return (error);
16037701Ssam }
16047701Ssam 
160564410Sbostic /*
160664410Sbostic  * Truncate a file given a file descriptor.
160764410Sbostic  */
160860428Smckusick struct ftruncate_args {
160954863Storek 	int	fd;
161054863Storek 	int	pad;
161154863Storek 	off_t	length;
161254863Storek };
161342441Smckusick /* ARGSUSED */
161460414Smckusick ftruncate(p, uap, retval)
161545914Smckusick 	struct proc *p;
161660428Smckusick 	register struct ftruncate_args *uap;
161742441Smckusick 	int *retval;
161842441Smckusick {
161937741Smckusick 	struct vattr vattr;
162037741Smckusick 	struct vnode *vp;
16217701Ssam 	struct file *fp;
162237741Smckusick 	int error;
16237701Ssam 
162445914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
162547540Skarels 		return (error);
162637741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
162747540Skarels 		return (EINVAL);
162837741Smckusick 	vp = (struct vnode *)fp->f_data;
162959382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
163037741Smckusick 	VOP_LOCK(vp);
163164410Sbostic 	if (vp->v_type == VDIR)
163237741Smckusick 		error = EISDIR;
163364410Sbostic 	else if ((error = vn_writechk(vp)) == 0) {
163464410Sbostic 		VATTR_NULL(&vattr);
163564410Sbostic 		vattr.va_size = uap->length;
163664410Sbostic 		error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
16377701Ssam 	}
163837741Smckusick 	VOP_UNLOCK(vp);
163947540Skarels 	return (error);
16407701Ssam }
16417701Ssam 
164254863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
16439167Ssam /*
164454863Storek  * Truncate a file given its path name.
164554863Storek  */
164660428Smckusick struct otruncate_args {
164764410Sbostic 	char	*path;
164854916Storek 	long	length;
164954916Storek };
165054863Storek /* ARGSUSED */
165160105Smckusick otruncate(p, uap, retval)
165254863Storek 	struct proc *p;
165360428Smckusick 	register struct otruncate_args *uap;
165454863Storek 	int *retval;
165554863Storek {
165660428Smckusick 	struct truncate_args nuap;
165754863Storek 
165864410Sbostic 	nuap.path = uap->path;
165954863Storek 	nuap.length = uap->length;
166060428Smckusick 	return (truncate(p, &nuap, retval));
166154863Storek }
166254863Storek 
166354863Storek /*
166454863Storek  * Truncate a file given a file descriptor.
166554863Storek  */
166660428Smckusick struct oftruncate_args {
166754916Storek 	int	fd;
166854916Storek 	long	length;
166954916Storek };
167054863Storek /* ARGSUSED */
167160105Smckusick oftruncate(p, uap, retval)
167254863Storek 	struct proc *p;
167360428Smckusick 	register struct oftruncate_args *uap;
167454863Storek 	int *retval;
167554863Storek {
167660428Smckusick 	struct ftruncate_args nuap;
167754863Storek 
167854863Storek 	nuap.fd = uap->fd;
167954863Storek 	nuap.length = uap->length;
168060428Smckusick 	return (ftruncate(p, &nuap, retval));
168154863Storek }
168254863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */
168354863Storek 
168454863Storek /*
168564410Sbostic  * Sync an open file.
16869167Ssam  */
168754916Storek struct fsync_args {
168854916Storek 	int	fd;
168954916Storek };
169042441Smckusick /* ARGSUSED */
169142441Smckusick fsync(p, uap, retval)
169245914Smckusick 	struct proc *p;
169354916Storek 	struct fsync_args *uap;
169442441Smckusick 	int *retval;
16959167Ssam {
169639592Smckusick 	register struct vnode *vp;
16979167Ssam 	struct file *fp;
169837741Smckusick 	int error;
16999167Ssam 
170045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
170147540Skarels 		return (error);
170239592Smckusick 	vp = (struct vnode *)fp->f_data;
170339592Smckusick 	VOP_LOCK(vp);
170454441Smckusick 	error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
170539592Smckusick 	VOP_UNLOCK(vp);
170647540Skarels 	return (error);
17079167Ssam }
17089167Ssam 
17099167Ssam /*
171064410Sbostic  * Rename files.  Source and destination must either both be directories,
171164410Sbostic  * or both not be directories.  If target is a directory, it must be empty.
17129167Ssam  */
171354916Storek struct rename_args {
171454916Storek 	char	*from;
171554916Storek 	char	*to;
171654916Storek };
171742441Smckusick /* ARGSUSED */
171842441Smckusick rename(p, uap, retval)
171945914Smckusick 	struct proc *p;
172054916Storek 	register struct rename_args *uap;
172142441Smckusick 	int *retval;
172242441Smckusick {
172337741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
172449735Smckusick 	struct nameidata fromnd, tond;
172537741Smckusick 	int error;
17267701Ssam 
172752322Smckusick 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
172852322Smckusick 		uap->from, p);
172952322Smckusick 	if (error = namei(&fromnd))
173047540Skarels 		return (error);
173149735Smckusick 	fvp = fromnd.ni_vp;
173252322Smckusick 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
173352322Smckusick 		UIO_USERSPACE, uap->to, p);
173452322Smckusick 	if (error = namei(&tond)) {
173552230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
173649735Smckusick 		vrele(fromnd.ni_dvp);
173742465Smckusick 		vrele(fvp);
173842465Smckusick 		goto out1;
173942465Smckusick 	}
174037741Smckusick 	tdvp = tond.ni_dvp;
174137741Smckusick 	tvp = tond.ni_vp;
174237741Smckusick 	if (tvp != NULL) {
174337741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
174439242Sbostic 			error = ENOTDIR;
174537741Smckusick 			goto out;
174637741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
174739242Sbostic 			error = EISDIR;
174837741Smckusick 			goto out;
17499167Ssam 		}
17509167Ssam 	}
175139286Smckusick 	if (fvp == tdvp)
175237741Smckusick 		error = EINVAL;
175339286Smckusick 	/*
175449735Smckusick 	 * If source is the same as the destination (that is the
175549735Smckusick 	 * same inode number with the same name in the same directory),
175639286Smckusick 	 * then there is nothing to do.
175739286Smckusick 	 */
175849735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
175952322Smckusick 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
176052322Smckusick 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
176152322Smckusick 	      fromnd.ni_cnd.cn_namelen))
176239286Smckusick 		error = -1;
176337741Smckusick out:
176442465Smckusick 	if (!error) {
176552192Smckusick 		LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE);
176652192Smckusick 		if (fromnd.ni_dvp != tdvp)
176752192Smckusick 			LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
176852192Smckusick 		if (tvp)
176952192Smckusick 			LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE);
177052230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
177152230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
177242465Smckusick 	} else {
177352230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
177443344Smckusick 		if (tdvp == tvp)
177543344Smckusick 			vrele(tdvp);
177643344Smckusick 		else
177743344Smckusick 			vput(tdvp);
177842465Smckusick 		if (tvp)
177942465Smckusick 			vput(tvp);
178052230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
178149735Smckusick 		vrele(fromnd.ni_dvp);
178242465Smckusick 		vrele(fvp);
17839167Ssam 	}
178449735Smckusick 	vrele(tond.ni_startdir);
178552322Smckusick 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
178637741Smckusick out1:
178766801Smckusick 	if (fromnd.ni_startdir)
178866801Smckusick 		vrele(fromnd.ni_startdir);
178952322Smckusick 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
179039286Smckusick 	if (error == -1)
179147540Skarels 		return (0);
179247540Skarels 	return (error);
17937701Ssam }
17947701Ssam 
17957535Sroot /*
179664410Sbostic  * Make a directory file.
179712756Ssam  */
179854916Storek struct mkdir_args {
179964410Sbostic 	char	*path;
180064410Sbostic 	int	mode;
180154916Storek };
180242441Smckusick /* ARGSUSED */
180342441Smckusick mkdir(p, uap, retval)
180445914Smckusick 	struct proc *p;
180554916Storek 	register struct mkdir_args *uap;
180642441Smckusick 	int *retval;
180742441Smckusick {
180837741Smckusick 	register struct vnode *vp;
180937741Smckusick 	struct vattr vattr;
181037741Smckusick 	int error;
181147540Skarels 	struct nameidata nd;
181212756Ssam 
181364410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
181452322Smckusick 	if (error = namei(&nd))
181547540Skarels 		return (error);
181652322Smckusick 	vp = nd.ni_vp;
181737741Smckusick 	if (vp != NULL) {
181852322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
181952322Smckusick 		if (nd.ni_dvp == vp)
182052322Smckusick 			vrele(nd.ni_dvp);
182143344Smckusick 		else
182252322Smckusick 			vput(nd.ni_dvp);
182342465Smckusick 		vrele(vp);
182447540Skarels 		return (EEXIST);
182512756Ssam 	}
182641362Smckusick 	VATTR_NULL(&vattr);
182737741Smckusick 	vattr.va_type = VDIR;
182864410Sbostic 	vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask;
182952322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
183052322Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
183138145Smckusick 	if (!error)
183252322Smckusick 		vput(nd.ni_vp);
183347540Skarels 	return (error);
183412756Ssam }
183512756Ssam 
183612756Ssam /*
183764410Sbostic  * Remove a directory file.
183812756Ssam  */
183954916Storek struct rmdir_args {
184064410Sbostic 	char	*path;
184154916Storek };
184242441Smckusick /* ARGSUSED */
184342441Smckusick rmdir(p, uap, retval)
184445914Smckusick 	struct proc *p;
184554916Storek 	struct rmdir_args *uap;
184642441Smckusick 	int *retval;
184712756Ssam {
184837741Smckusick 	register struct vnode *vp;
184937741Smckusick 	int error;
185047540Skarels 	struct nameidata nd;
185112756Ssam 
185264410Sbostic 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p);
185352322Smckusick 	if (error = namei(&nd))
185447540Skarels 		return (error);
185552322Smckusick 	vp = nd.ni_vp;
185637741Smckusick 	if (vp->v_type != VDIR) {
185737741Smckusick 		error = ENOTDIR;
185812756Ssam 		goto out;
185912756Ssam 	}
186012756Ssam 	/*
186137741Smckusick 	 * No rmdir "." please.
186212756Ssam 	 */
186352322Smckusick 	if (nd.ni_dvp == vp) {
186437741Smckusick 		error = EINVAL;
186512756Ssam 		goto out;
186612756Ssam 	}
186712756Ssam 	/*
186849365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
186912756Ssam 	 */
187037741Smckusick 	if (vp->v_flag & VROOT)
187137741Smckusick 		error = EBUSY;
187212756Ssam out:
187342465Smckusick 	if (!error) {
187452322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
187552192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
187652322Smckusick 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
187742465Smckusick 	} else {
187852322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
187952322Smckusick 		if (nd.ni_dvp == vp)
188052322Smckusick 			vrele(nd.ni_dvp);
188143344Smckusick 		else
188252322Smckusick 			vput(nd.ni_dvp);
188342465Smckusick 		vput(vp);
188442465Smckusick 	}
188547540Skarels 	return (error);
188612756Ssam }
188712756Ssam 
188854620Smckusick #ifdef COMPAT_43
188937741Smckusick /*
189049365Smckusick  * Read a block of directory entries in a file system independent format.
189137741Smckusick  */
189254916Storek struct ogetdirentries_args {
189354916Storek 	int	fd;
189454916Storek 	char	*buf;
189564410Sbostic 	u_int	count;
189654916Storek 	long	*basep;
189754916Storek };
189854620Smckusick ogetdirentries(p, uap, retval)
189954620Smckusick 	struct proc *p;
190054916Storek 	register struct ogetdirentries_args *uap;
190154620Smckusick 	int *retval;
190254620Smckusick {
190354620Smckusick 	register struct vnode *vp;
190454620Smckusick 	struct file *fp;
190554620Smckusick 	struct uio auio, kuio;
190654620Smckusick 	struct iovec aiov, kiov;
190754620Smckusick 	struct dirent *dp, *edp;
190854620Smckusick 	caddr_t dirbuf;
190967362Smckusick 	int error, eofflag, readcnt;
191054969Smckusick 	long loff;
191154620Smckusick 
191254620Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
191354620Smckusick 		return (error);
191454620Smckusick 	if ((fp->f_flag & FREAD) == 0)
191554620Smckusick 		return (EBADF);
191654620Smckusick 	vp = (struct vnode *)fp->f_data;
191767362Smckusick unionread:
191854620Smckusick 	if (vp->v_type != VDIR)
191954620Smckusick 		return (EINVAL);
192054620Smckusick 	aiov.iov_base = uap->buf;
192154620Smckusick 	aiov.iov_len = uap->count;
192254620Smckusick 	auio.uio_iov = &aiov;
192354620Smckusick 	auio.uio_iovcnt = 1;
192454620Smckusick 	auio.uio_rw = UIO_READ;
192554620Smckusick 	auio.uio_segflg = UIO_USERSPACE;
192654620Smckusick 	auio.uio_procp = p;
192754620Smckusick 	auio.uio_resid = uap->count;
192854620Smckusick 	VOP_LOCK(vp);
192954969Smckusick 	loff = auio.uio_offset = fp->f_offset;
193054620Smckusick #	if (BYTE_ORDER != LITTLE_ENDIAN)
193156339Smckusick 		if (vp->v_mount->mnt_maxsymlinklen <= 0) {
193267362Smckusick 			error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
193367362Smckusick 			    (u_long *)0, 0);
193456339Smckusick 			fp->f_offset = auio.uio_offset;
193556339Smckusick 		} else
193654620Smckusick #	endif
193754620Smckusick 	{
193854620Smckusick 		kuio = auio;
193954620Smckusick 		kuio.uio_iov = &kiov;
194054620Smckusick 		kuio.uio_segflg = UIO_SYSSPACE;
194154620Smckusick 		kiov.iov_len = uap->count;
194254620Smckusick 		MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK);
194354620Smckusick 		kiov.iov_base = dirbuf;
194467362Smckusick 		error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
194567362Smckusick 			    (u_long *)0, 0);
194656339Smckusick 		fp->f_offset = kuio.uio_offset;
194754620Smckusick 		if (error == 0) {
194854620Smckusick 			readcnt = uap->count - kuio.uio_resid;
194954620Smckusick 			edp = (struct dirent *)&dirbuf[readcnt];
195054620Smckusick 			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
195154620Smckusick #				if (BYTE_ORDER == LITTLE_ENDIAN)
195254969Smckusick 					/*
195355009Smckusick 					 * The expected low byte of
195455009Smckusick 					 * dp->d_namlen is our dp->d_type.
195555009Smckusick 					 * The high MBZ byte of dp->d_namlen
195655009Smckusick 					 * is our dp->d_namlen.
195754969Smckusick 					 */
195855009Smckusick 					dp->d_type = dp->d_namlen;
195955009Smckusick 					dp->d_namlen = 0;
196055009Smckusick #				else
196155009Smckusick 					/*
196255009Smckusick 					 * The dp->d_type is the high byte
196355009Smckusick 					 * of the expected dp->d_namlen,
196455009Smckusick 					 * so must be zero'ed.
196555009Smckusick 					 */
196655009Smckusick 					dp->d_type = 0;
196754620Smckusick #				endif
196854620Smckusick 				if (dp->d_reclen > 0) {
196954620Smckusick 					dp = (struct dirent *)
197054620Smckusick 					    ((char *)dp + dp->d_reclen);
197154620Smckusick 				} else {
197254620Smckusick 					error = EIO;
197354620Smckusick 					break;
197454620Smckusick 				}
197554620Smckusick 			}
197654620Smckusick 			if (dp >= edp)
197754620Smckusick 				error = uiomove(dirbuf, readcnt, &auio);
197854620Smckusick 		}
197954620Smckusick 		FREE(dirbuf, M_TEMP);
198054620Smckusick 	}
198154620Smckusick 	VOP_UNLOCK(vp);
198254620Smckusick 	if (error)
198354620Smckusick 		return (error);
198467362Smckusick 
198567362Smckusick #ifdef UNION
198667362Smckusick {
198767362Smckusick 	extern int (**union_vnodeop_p)();
198867362Smckusick 	extern struct vnode *union_lowervp __P((struct vnode *));
198967362Smckusick 
199067362Smckusick 	if ((uap->count == auio.uio_resid) &&
199167362Smckusick 	    (vp->v_op == union_vnodeop_p)) {
199267362Smckusick 		struct vnode *lvp;
199367362Smckusick 
199467362Smckusick 		lvp = union_lowervp(vp);
199567362Smckusick 		if (lvp != NULLVP) {
199667362Smckusick 			VOP_LOCK(lvp);
199767362Smckusick 			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
199867362Smckusick 			VOP_UNLOCK(lvp);
199967362Smckusick 
200067362Smckusick 			if (error) {
200167362Smckusick 				vrele(lvp);
200267362Smckusick 				return (error);
200367362Smckusick 			}
200467362Smckusick 			fp->f_data = (caddr_t) lvp;
200567362Smckusick 			fp->f_offset = 0;
200667362Smckusick 			error = vn_close(vp, FREAD, fp->f_cred, p);
200767362Smckusick 			if (error)
200867362Smckusick 				return (error);
200967362Smckusick 			vp = lvp;
201067362Smckusick 			goto unionread;
201167362Smckusick 		}
201267362Smckusick 	}
201367362Smckusick }
201467362Smckusick #endif /* UNION */
201567362Smckusick 
201667362Smckusick 	if ((uap->count == auio.uio_resid) &&
201767362Smckusick 	    (vp->v_flag & VROOT) &&
201867362Smckusick 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
201967362Smckusick 		struct vnode *tvp = vp;
202067362Smckusick 		vp = vp->v_mount->mnt_vnodecovered;
202167362Smckusick 		VREF(vp);
202267362Smckusick 		fp->f_data = (caddr_t) vp;
202367362Smckusick 		fp->f_offset = 0;
202467362Smckusick 		vrele(tvp);
202567362Smckusick 		goto unionread;
202667362Smckusick 	}
202754969Smckusick 	error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
202854620Smckusick 	*retval = uap->count - auio.uio_resid;
202954620Smckusick 	return (error);
203054620Smckusick }
203167362Smckusick #endif /* COMPAT_43 */
203254620Smckusick 
203354620Smckusick /*
203454620Smckusick  * Read a block of directory entries in a file system independent format.
203554620Smckusick  */
203654916Storek struct getdirentries_args {
203754916Storek 	int	fd;
203854916Storek 	char	*buf;
203964410Sbostic 	u_int	count;
204054916Storek 	long	*basep;
204154916Storek };
204242441Smckusick getdirentries(p, uap, retval)
204345914Smckusick 	struct proc *p;
204454916Storek 	register struct getdirentries_args *uap;
204542441Smckusick 	int *retval;
204642441Smckusick {
204739592Smckusick 	register struct vnode *vp;
204816540Ssam 	struct file *fp;
204937741Smckusick 	struct uio auio;
205037741Smckusick 	struct iovec aiov;
205154969Smckusick 	long loff;
205267362Smckusick 	int error, eofflag;
205312756Ssam 
205445914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
205547540Skarels 		return (error);
205637741Smckusick 	if ((fp->f_flag & FREAD) == 0)
205747540Skarels 		return (EBADF);
205839592Smckusick 	vp = (struct vnode *)fp->f_data;
205955451Spendry unionread:
206039592Smckusick 	if (vp->v_type != VDIR)
206147540Skarels 		return (EINVAL);
206237741Smckusick 	aiov.iov_base = uap->buf;
206337741Smckusick 	aiov.iov_len = uap->count;
206437741Smckusick 	auio.uio_iov = &aiov;
206537741Smckusick 	auio.uio_iovcnt = 1;
206637741Smckusick 	auio.uio_rw = UIO_READ;
206737741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
206848026Smckusick 	auio.uio_procp = p;
206937741Smckusick 	auio.uio_resid = uap->count;
207039592Smckusick 	VOP_LOCK(vp);
207154969Smckusick 	loff = auio.uio_offset = fp->f_offset;
207267362Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *)0, 0);
207339592Smckusick 	fp->f_offset = auio.uio_offset;
207439592Smckusick 	VOP_UNLOCK(vp);
207539592Smckusick 	if (error)
207647540Skarels 		return (error);
207766095Spendry 
207866095Spendry #ifdef UNION
207966095Spendry {
208066095Spendry 	extern int (**union_vnodeop_p)();
208166095Spendry 	extern struct vnode *union_lowervp __P((struct vnode *));
208266095Spendry 
208355451Spendry 	if ((uap->count == auio.uio_resid) &&
208466095Spendry 	    (vp->v_op == union_vnodeop_p)) {
208567122Spendry 		struct vnode *lvp;
208666095Spendry 
208767122Spendry 		lvp = union_lowervp(vp);
208867122Spendry 		if (lvp != NULLVP) {
208967122Spendry 			VOP_LOCK(lvp);
209067362Smckusick 			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
209167122Spendry 			VOP_UNLOCK(lvp);
209266095Spendry 
209366095Spendry 			if (error) {
209467122Spendry 				vrele(lvp);
209566095Spendry 				return (error);
209666095Spendry 			}
209767122Spendry 			fp->f_data = (caddr_t) lvp;
209866095Spendry 			fp->f_offset = 0;
209967122Spendry 			error = vn_close(vp, FREAD, fp->f_cred, p);
210066095Spendry 			if (error)
210166095Spendry 				return (error);
210267122Spendry 			vp = lvp;
210366095Spendry 			goto unionread;
210466095Spendry 		}
210566095Spendry 	}
210666095Spendry }
210766095Spendry #endif
210866095Spendry 
210966095Spendry 	if ((uap->count == auio.uio_resid) &&
211055451Spendry 	    (vp->v_flag & VROOT) &&
211155451Spendry 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
211255451Spendry 		struct vnode *tvp = vp;
211355451Spendry 		vp = vp->v_mount->mnt_vnodecovered;
211455451Spendry 		VREF(vp);
211555451Spendry 		fp->f_data = (caddr_t) vp;
211655451Spendry 		fp->f_offset = 0;
211755451Spendry 		vrele(tvp);
211855451Spendry 		goto unionread;
211955451Spendry 	}
212054969Smckusick 	error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
212142441Smckusick 	*retval = uap->count - auio.uio_resid;
212247540Skarels 	return (error);
212312756Ssam }
212412756Ssam 
212512756Ssam /*
212649365Smckusick  * Set the mode mask for creation of filesystem nodes.
212712756Ssam  */
212854916Storek struct umask_args {
212964410Sbostic 	int	newmask;
213054916Storek };
213154916Storek mode_t				/* XXX */
213242441Smckusick umask(p, uap, retval)
213345914Smckusick 	struct proc *p;
213454916Storek 	struct umask_args *uap;
213542441Smckusick 	int *retval;
213612756Ssam {
213764410Sbostic 	register struct filedesc *fdp;
213812756Ssam 
213964410Sbostic 	fdp = p->p_fd;
214045914Smckusick 	*retval = fdp->fd_cmask;
214164410Sbostic 	fdp->fd_cmask = uap->newmask & ALLPERMS;
214247540Skarels 	return (0);
214312756Ssam }
214437741Smckusick 
214539566Smarc /*
214639566Smarc  * Void all references to file by ripping underlying filesystem
214739566Smarc  * away from vnode.
214839566Smarc  */
214954916Storek struct revoke_args {
215064410Sbostic 	char	*path;
215154916Storek };
215242441Smckusick /* ARGSUSED */
215342441Smckusick revoke(p, uap, retval)
215445914Smckusick 	struct proc *p;
215554916Storek 	register struct revoke_args *uap;
215642441Smckusick 	int *retval;
215742441Smckusick {
215839566Smarc 	register struct vnode *vp;
215939566Smarc 	struct vattr vattr;
216039566Smarc 	int error;
216147540Skarels 	struct nameidata nd;
216239566Smarc 
216364410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
216452322Smckusick 	if (error = namei(&nd))
216547540Skarels 		return (error);
216652322Smckusick 	vp = nd.ni_vp;
216739566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
216839566Smarc 		error = EINVAL;
216939566Smarc 		goto out;
217039566Smarc 	}
217148026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
217239566Smarc 		goto out;
217347540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
217447540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
217539566Smarc 		goto out;
217639805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
217739632Smckusick 		vgoneall(vp);
217839566Smarc out:
217939566Smarc 	vrele(vp);
218047540Skarels 	return (error);
218139566Smarc }
218239566Smarc 
218349365Smckusick /*
218449365Smckusick  * Convert a user file descriptor to a kernel file entry.
218549365Smckusick  */
218664410Sbostic getvnode(fdp, fd, fpp)
218745914Smckusick 	struct filedesc *fdp;
218837741Smckusick 	struct file **fpp;
218964410Sbostic 	int fd;
219037741Smckusick {
219137741Smckusick 	struct file *fp;
219237741Smckusick 
219364410Sbostic 	if ((u_int)fd >= fdp->fd_nfiles ||
219464410Sbostic 	    (fp = fdp->fd_ofiles[fd]) == NULL)
219537741Smckusick 		return (EBADF);
219637741Smckusick 	if (fp->f_type != DTYPE_VNODE)
219737741Smckusick 		return (EINVAL);
219837741Smckusick 	*fpp = fp;
219937741Smckusick 	return (0);
220037741Smckusick }
2201