xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 67575)
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*67575Spendry  *	@(#)vfs_syscalls.c	8.19 (Berkeley) 07/28/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 	}
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;
15967532Smckusick 	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;
22967532Smckusick 	mp = vp->v_mount;
23066172Spendry 
23137741Smckusick 	/*
23267532Smckusick 	 * Only root, or the user that did the original mount is
23367532Smckusick 	 * permitted to unmount this filesystem.
23466172Spendry 	 */
23567532Smckusick 	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;
692*67575Spendry 	int whiteout;
69347540Skarels 	struct nameidata nd;
6946254Sroot 
69547540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
69647540Skarels 		return (error);
69764410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
69852322Smckusick 	if (error = namei(&nd))
69947540Skarels 		return (error);
70052322Smckusick 	vp = nd.ni_vp;
70164585Sbostic 	if (vp != NULL)
70237741Smckusick 		error = EEXIST;
70364585Sbostic 	else {
70464585Sbostic 		VATTR_NULL(&vattr);
70564585Sbostic 		vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
70664585Sbostic 		vattr.va_rdev = uap->dev;
707*67575Spendry 		whiteout = 0;
70864585Sbostic 
70964585Sbostic 		switch (uap->mode & S_IFMT) {
71064585Sbostic 		case S_IFMT:	/* used by badsect to flag bad sectors */
71164585Sbostic 			vattr.va_type = VBAD;
71264585Sbostic 			break;
71364585Sbostic 		case S_IFCHR:
71464585Sbostic 			vattr.va_type = VCHR;
71564585Sbostic 			break;
71664585Sbostic 		case S_IFBLK:
71764585Sbostic 			vattr.va_type = VBLK;
71864585Sbostic 			break;
719*67575Spendry 		case S_IFWHT:
720*67575Spendry 			whiteout = 1;
721*67575Spendry 			break;
72264585Sbostic 		default:
72364585Sbostic 			error = EINVAL;
72464585Sbostic 			break;
72564585Sbostic 		}
7266254Sroot 	}
727*67575Spendry 	if (whiteout) {
728*67575Spendry 		error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
729*67575Spendry 		vput(nd.ni_dvp);
730*67575Spendry 	} else if (!error) {
73152322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
73252322Smckusick 		error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
73342465Smckusick 	} else {
73452322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
73552322Smckusick 		if (nd.ni_dvp == vp)
73652322Smckusick 			vrele(nd.ni_dvp);
73743344Smckusick 		else
73852322Smckusick 			vput(nd.ni_dvp);
73942465Smckusick 		if (vp)
74042465Smckusick 			vrele(vp);
74142465Smckusick 	}
74247540Skarels 	return (error);
7436254Sroot }
7446254Sroot 
7456254Sroot /*
74664410Sbostic  * Create named pipe.
74740285Smckusick  */
74854916Storek struct mkfifo_args {
74964410Sbostic 	char	*path;
75064410Sbostic 	int	mode;
75154916Storek };
75242441Smckusick /* ARGSUSED */
75342441Smckusick mkfifo(p, uap, retval)
75445914Smckusick 	struct proc *p;
75554916Storek 	register struct mkfifo_args *uap;
75642441Smckusick 	int *retval;
75742441Smckusick {
75840285Smckusick 	struct vattr vattr;
75940285Smckusick 	int error;
76047540Skarels 	struct nameidata nd;
76140285Smckusick 
76240285Smckusick #ifndef FIFO
76347540Skarels 	return (EOPNOTSUPP);
76440285Smckusick #else
76564410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
76652322Smckusick 	if (error = namei(&nd))
76747540Skarels 		return (error);
76852322Smckusick 	if (nd.ni_vp != NULL) {
76952322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
77052322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
77152322Smckusick 			vrele(nd.ni_dvp);
77243344Smckusick 		else
77352322Smckusick 			vput(nd.ni_dvp);
77452322Smckusick 		vrele(nd.ni_vp);
77547540Skarels 		return (EEXIST);
77640285Smckusick 	}
77745785Sbostic 	VATTR_NULL(&vattr);
77845785Sbostic 	vattr.va_type = VFIFO;
77964410Sbostic 	vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
78052322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
78152322Smckusick 	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
78240285Smckusick #endif /* FIFO */
78340285Smckusick }
78440285Smckusick 
78540285Smckusick /*
78664410Sbostic  * Make a hard file link.
7876254Sroot  */
78854916Storek struct link_args {
78964410Sbostic 	char	*path;
79064410Sbostic 	char	*link;
79154916Storek };
79242441Smckusick /* ARGSUSED */
79342441Smckusick link(p, uap, retval)
79445914Smckusick 	struct proc *p;
79554916Storek 	register struct link_args *uap;
79642441Smckusick 	int *retval;
79742441Smckusick {
79864410Sbostic 	register struct vnode *vp;
79964410Sbostic 	struct nameidata nd;
80037741Smckusick 	int error;
8016254Sroot 
80264410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
80352322Smckusick 	if (error = namei(&nd))
80447540Skarels 		return (error);
80552322Smckusick 	vp = nd.ni_vp;
80664585Sbostic 	if (vp->v_type != VDIR ||
80764585Sbostic 	    (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
80864585Sbostic 		nd.ni_cnd.cn_nameiop = CREATE;
80964585Sbostic 		nd.ni_cnd.cn_flags = LOCKPARENT;
81064585Sbostic 		nd.ni_dirp = uap->link;
81164585Sbostic 		if ((error = namei(&nd)) == 0) {
81264585Sbostic 			if (nd.ni_vp != NULL)
81364585Sbostic 				error = EEXIST;
81464585Sbostic 			if (!error) {
81564585Sbostic 				LEASE_CHECK(nd.ni_dvp,
81664585Sbostic 				    p, p->p_ucred, LEASE_WRITE);
81764585Sbostic 				LEASE_CHECK(vp,
81864585Sbostic 				    p, p->p_ucred, LEASE_WRITE);
81964585Sbostic 				error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
82064585Sbostic 			} else {
82164585Sbostic 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
82264585Sbostic 				if (nd.ni_dvp == nd.ni_vp)
82364585Sbostic 					vrele(nd.ni_dvp);
82464585Sbostic 				else
82564585Sbostic 					vput(nd.ni_dvp);
82664585Sbostic 				if (nd.ni_vp)
82764585Sbostic 					vrele(nd.ni_vp);
82864585Sbostic 			}
82964585Sbostic 		}
83042465Smckusick 	}
83164585Sbostic 	vrele(vp);
83247540Skarels 	return (error);
8336254Sroot }
8346254Sroot 
8356254Sroot /*
83649365Smckusick  * Make a symbolic link.
8376254Sroot  */
83854916Storek struct symlink_args {
83964410Sbostic 	char	*path;
84064410Sbostic 	char	*link;
84154916Storek };
84242441Smckusick /* ARGSUSED */
84342441Smckusick symlink(p, uap, retval)
84445914Smckusick 	struct proc *p;
84554916Storek 	register struct symlink_args *uap;
84642441Smckusick 	int *retval;
84742441Smckusick {
84837741Smckusick 	struct vattr vattr;
84964410Sbostic 	char *path;
85037741Smckusick 	int error;
85147540Skarels 	struct nameidata nd;
8526254Sroot 
85364410Sbostic 	MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
85464410Sbostic 	if (error = copyinstr(uap->path, path, MAXPATHLEN, NULL))
85542465Smckusick 		goto out;
85664410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p);
85752322Smckusick 	if (error = namei(&nd))
85842465Smckusick 		goto out;
85952322Smckusick 	if (nd.ni_vp) {
86052322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
86152322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
86252322Smckusick 			vrele(nd.ni_dvp);
86343344Smckusick 		else
86452322Smckusick 			vput(nd.ni_dvp);
86552322Smckusick 		vrele(nd.ni_vp);
86637741Smckusick 		error = EEXIST;
86737741Smckusick 		goto out;
8686254Sroot 	}
86941362Smckusick 	VATTR_NULL(&vattr);
87064410Sbostic 	vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
87152322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
87264410Sbostic 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
87337741Smckusick out:
87464410Sbostic 	FREE(path, M_NAMEI);
87547540Skarels 	return (error);
8766254Sroot }
8776254Sroot 
8786254Sroot /*
87967518Spendry  * Delete a whiteout from the filesystem.
88067518Spendry  */
88167518Spendry struct unwhiteout_args {
88267518Spendry 	char	*path;
88367518Spendry };
88467518Spendry /* ARGSUSED */
88567518Spendry unwhiteout(p, uap, retval)
88667518Spendry 	struct proc *p;
88767518Spendry 	struct unwhiteout_args *uap;
88867518Spendry 	int *retval;
88967518Spendry {
89067518Spendry 	int error;
89167518Spendry 	struct nameidata nd;
89267518Spendry 
893*67575Spendry 	NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, uap->path, p);
894*67575Spendry 	error = namei(&nd);
895*67575Spendry 	if (error)
89667518Spendry 		return (error);
897*67575Spendry 
898*67575Spendry 	if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
89967518Spendry 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
90067518Spendry 		if (nd.ni_dvp == nd.ni_vp)
90167518Spendry 			vrele(nd.ni_dvp);
90267518Spendry 		else
90367518Spendry 			vput(nd.ni_dvp);
90467518Spendry 		if (nd.ni_vp)
90567518Spendry 			vrele(nd.ni_vp);
90667518Spendry 		return (EEXIST);
90767518Spendry 	}
908*67575Spendry 
90967518Spendry 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
91067518Spendry 	error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE);
911*67575Spendry 	if (error != 0)
912*67575Spendry 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
91367518Spendry 	vput(nd.ni_dvp);
91467518Spendry 	return (error);
91567518Spendry }
91667518Spendry 
91767518Spendry /*
91849365Smckusick  * Delete a name from the filesystem.
9196254Sroot  */
92054916Storek struct unlink_args {
92164410Sbostic 	char	*path;
92254916Storek };
92342441Smckusick /* ARGSUSED */
92442441Smckusick unlink(p, uap, retval)
92545914Smckusick 	struct proc *p;
92654916Storek 	struct unlink_args *uap;
92742441Smckusick 	int *retval;
9286254Sroot {
92937741Smckusick 	register struct vnode *vp;
93037741Smckusick 	int error;
93147540Skarels 	struct nameidata nd;
9326254Sroot 
93364410Sbostic 	NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
93452322Smckusick 	if (error = namei(&nd))
93547540Skarels 		return (error);
93652322Smckusick 	vp = nd.ni_vp;
93759382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
93859382Smckusick 	VOP_LOCK(vp);
93964410Sbostic 
94064585Sbostic 	if (vp->v_type != VDIR ||
94164585Sbostic 	    (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
94264585Sbostic 		/*
94364585Sbostic 		 * The root of a mounted filesystem cannot be deleted.
94464585Sbostic 		 */
94564585Sbostic 		if (vp->v_flag & VROOT)
94664585Sbostic 			error = EBUSY;
94764585Sbostic 		else
94864585Sbostic 			(void)vnode_pager_uncache(vp);
94964585Sbostic 	}
95064585Sbostic 
95164585Sbostic 	if (!error) {
95252322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
95352322Smckusick 		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
95442465Smckusick 	} else {
95552322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
95652322Smckusick 		if (nd.ni_dvp == vp)
95752322Smckusick 			vrele(nd.ni_dvp);
95843344Smckusick 		else
95952322Smckusick 			vput(nd.ni_dvp);
960*67575Spendry 		if (vp != NULLVP)
961*67575Spendry 			vput(vp);
96242465Smckusick 	}
96347540Skarels 	return (error);
9646254Sroot }
9656254Sroot 
96664410Sbostic /*
96764410Sbostic  * Reposition read/write file offset.
96864410Sbostic  */
96960428Smckusick struct lseek_args {
97064410Sbostic 	int	fd;
97154863Storek 	int	pad;
97264410Sbostic 	off_t	offset;
97364410Sbostic 	int	whence;
97454863Storek };
97560414Smckusick lseek(p, uap, retval)
97653468Smckusick 	struct proc *p;
97760428Smckusick 	register struct lseek_args *uap;
97854916Storek 	int *retval;
97942441Smckusick {
98047540Skarels 	struct ucred *cred = p->p_ucred;
98145914Smckusick 	register struct filedesc *fdp = p->p_fd;
98242441Smckusick 	register struct file *fp;
98337741Smckusick 	struct vattr vattr;
98437741Smckusick 	int error;
9856254Sroot 
98664410Sbostic 	if ((u_int)uap->fd >= fdp->fd_nfiles ||
98764410Sbostic 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
98847540Skarels 		return (EBADF);
98937741Smckusick 	if (fp->f_type != DTYPE_VNODE)
99047540Skarels 		return (ESPIPE);
99164410Sbostic 	switch (uap->whence) {
99213878Ssam 	case L_INCR:
99364410Sbostic 		fp->f_offset += uap->offset;
99413878Ssam 		break;
99513878Ssam 	case L_XTND:
99664410Sbostic 		if (error =
99764410Sbostic 		    VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p))
99847540Skarels 			return (error);
99964410Sbostic 		fp->f_offset = uap->offset + vattr.va_size;
100013878Ssam 		break;
100113878Ssam 	case L_SET:
100264410Sbostic 		fp->f_offset = uap->offset;
100313878Ssam 		break;
100413878Ssam 	default:
100547540Skarels 		return (EINVAL);
100613878Ssam 	}
100754916Storek 	*(off_t *)retval = fp->f_offset;
100847540Skarels 	return (0);
10096254Sroot }
10106254Sroot 
101160414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
10126254Sroot /*
101364410Sbostic  * Reposition read/write file offset.
101460036Smckusick  */
101560428Smckusick struct olseek_args {
101664410Sbostic 	int	fd;
101764410Sbostic 	long	offset;
101864410Sbostic 	int	whence;
101960036Smckusick };
102060414Smckusick olseek(p, uap, retval)
102160036Smckusick 	struct proc *p;
102260428Smckusick 	register struct olseek_args *uap;
102360036Smckusick 	int *retval;
102460036Smckusick {
102560428Smckusick 	struct lseek_args nuap;
102660036Smckusick 	off_t qret;
102760036Smckusick 	int error;
102860036Smckusick 
102964410Sbostic 	nuap.fd = uap->fd;
103064410Sbostic 	nuap.offset = uap->offset;
103164410Sbostic 	nuap.whence = uap->whence;
103260428Smckusick 	error = lseek(p, &nuap, &qret);
103360036Smckusick 	*(long *)retval = qret;
103460036Smckusick 	return (error);
103560036Smckusick }
103660414Smckusick #endif /* COMPAT_43 */
103760036Smckusick 
103860036Smckusick /*
103949365Smckusick  * Check access permissions.
10406254Sroot  */
104163427Sbostic struct access_args {
104264410Sbostic 	char	*path;
104364410Sbostic 	int	flags;
104454916Storek };
104563427Sbostic access(p, uap, retval)
104645914Smckusick 	struct proc *p;
104763427Sbostic 	register struct access_args *uap;
104842441Smckusick 	int *retval;
104942441Smckusick {
105047540Skarels 	register struct ucred *cred = p->p_ucred;
105137741Smckusick 	register struct vnode *vp;
105264585Sbostic 	int error, flags, t_gid, t_uid;
105347540Skarels 	struct nameidata nd;
10546254Sroot 
105564585Sbostic 	t_uid = cred->cr_uid;
105664585Sbostic 	t_gid = cred->cr_groups[0];
105747540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
105847540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
105964410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
106052322Smckusick 	if (error = namei(&nd))
106137741Smckusick 		goto out1;
106252322Smckusick 	vp = nd.ni_vp;
106364410Sbostic 
106464410Sbostic 	/* Flags == 0 means only check for existence. */
106564410Sbostic 	if (uap->flags) {
106664410Sbostic 		flags = 0;
106764410Sbostic 		if (uap->flags & R_OK)
106864410Sbostic 			flags |= VREAD;
106964410Sbostic 		if (uap->flags & W_OK)
107064410Sbostic 			flags |= VWRITE;
107164410Sbostic 		if (uap->flags & X_OK)
107264410Sbostic 			flags |= VEXEC;
107364410Sbostic 		if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
107464410Sbostic 			error = VOP_ACCESS(vp, flags, cred, p);
10756254Sroot 	}
107637741Smckusick 	vput(vp);
107737741Smckusick out1:
107864585Sbostic 	cred->cr_uid = t_uid;
107964585Sbostic 	cred->cr_groups[0] = t_gid;
108047540Skarels 	return (error);
10816254Sroot }
10826254Sroot 
108354348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
10846254Sroot /*
108564410Sbostic  * Get file status; this version follows links.
108637Sbill  */
108754916Storek struct ostat_args {
108864410Sbostic 	char	*path;
108954916Storek 	struct ostat *ub;
109054916Storek };
109142441Smckusick /* ARGSUSED */
109253759Smckusick ostat(p, uap, retval)
109345914Smckusick 	struct proc *p;
109454916Storek 	register struct ostat_args *uap;
109553468Smckusick 	int *retval;
109653468Smckusick {
109753468Smckusick 	struct stat sb;
109853468Smckusick 	struct ostat osb;
109953468Smckusick 	int error;
110053468Smckusick 	struct nameidata nd;
110153468Smckusick 
110264410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
110353468Smckusick 	if (error = namei(&nd))
110453468Smckusick 		return (error);
110553468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
110653468Smckusick 	vput(nd.ni_vp);
110753468Smckusick 	if (error)
110853468Smckusick 		return (error);
110953468Smckusick 	cvtstat(&sb, &osb);
111053468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
111153468Smckusick 	return (error);
111253468Smckusick }
111353468Smckusick 
111453468Smckusick /*
111564410Sbostic  * Get file status; this version does not follow links.
111653468Smckusick  */
111754916Storek struct olstat_args {
111864410Sbostic 	char	*path;
111954916Storek 	struct ostat *ub;
112054916Storek };
112153468Smckusick /* ARGSUSED */
112253759Smckusick olstat(p, uap, retval)
112353468Smckusick 	struct proc *p;
112454916Storek 	register struct olstat_args *uap;
112553468Smckusick 	int *retval;
112653468Smckusick {
112753468Smckusick 	struct stat sb;
112853468Smckusick 	struct ostat osb;
112953468Smckusick 	int error;
113053468Smckusick 	struct nameidata nd;
113153468Smckusick 
113264410Sbostic 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
113353468Smckusick 	if (error = namei(&nd))
113453468Smckusick 		return (error);
113553468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
113653468Smckusick 	vput(nd.ni_vp);
113753468Smckusick 	if (error)
113853468Smckusick 		return (error);
113953468Smckusick 	cvtstat(&sb, &osb);
114053468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
114153468Smckusick 	return (error);
114253468Smckusick }
114353468Smckusick 
114453468Smckusick /*
114564410Sbostic  * Convert from an old to a new stat structure.
114653468Smckusick  */
114753468Smckusick cvtstat(st, ost)
114853468Smckusick 	struct stat *st;
114953468Smckusick 	struct ostat *ost;
115053468Smckusick {
115153468Smckusick 
115253468Smckusick 	ost->st_dev = st->st_dev;
115353468Smckusick 	ost->st_ino = st->st_ino;
115453468Smckusick 	ost->st_mode = st->st_mode;
115553468Smckusick 	ost->st_nlink = st->st_nlink;
115653468Smckusick 	ost->st_uid = st->st_uid;
115753468Smckusick 	ost->st_gid = st->st_gid;
115853468Smckusick 	ost->st_rdev = st->st_rdev;
115953468Smckusick 	if (st->st_size < (quad_t)1 << 32)
116053468Smckusick 		ost->st_size = st->st_size;
116153468Smckusick 	else
116253468Smckusick 		ost->st_size = -2;
116353468Smckusick 	ost->st_atime = st->st_atime;
116453468Smckusick 	ost->st_mtime = st->st_mtime;
116553468Smckusick 	ost->st_ctime = st->st_ctime;
116653468Smckusick 	ost->st_blksize = st->st_blksize;
116753468Smckusick 	ost->st_blocks = st->st_blocks;
116853468Smckusick 	ost->st_flags = st->st_flags;
116953468Smckusick 	ost->st_gen = st->st_gen;
117053468Smckusick }
117154348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
117253468Smckusick 
117353468Smckusick /*
117464410Sbostic  * Get file status; this version follows links.
117553468Smckusick  */
117654916Storek struct stat_args {
117764410Sbostic 	char	*path;
117854916Storek 	struct stat *ub;
117954916Storek };
118053468Smckusick /* ARGSUSED */
118153759Smckusick stat(p, uap, retval)
118253468Smckusick 	struct proc *p;
118354916Storek 	register struct stat_args *uap;
118442441Smckusick 	int *retval;
118537Sbill {
118642441Smckusick 	struct stat sb;
118742441Smckusick 	int error;
118847540Skarels 	struct nameidata nd;
118937Sbill 
119064410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
119152322Smckusick 	if (error = namei(&nd))
119247540Skarels 		return (error);
119352322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
119452322Smckusick 	vput(nd.ni_vp);
119542441Smckusick 	if (error)
119647540Skarels 		return (error);
119742441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
119847540Skarels 	return (error);
119937Sbill }
120037Sbill 
120137Sbill /*
120264410Sbostic  * Get file status; this version does not follow links.
12035992Swnj  */
120454916Storek struct lstat_args {
120564410Sbostic 	char	*path;
120654916Storek 	struct stat *ub;
120754916Storek };
120842441Smckusick /* ARGSUSED */
120953759Smckusick lstat(p, uap, retval)
121045914Smckusick 	struct proc *p;
121154916Storek 	register struct lstat_args *uap;
121242441Smckusick 	int *retval;
121342441Smckusick {
121437741Smckusick 	int error;
121559373Smckusick 	struct vnode *vp, *dvp;
121659373Smckusick 	struct stat sb, sb1;
121747540Skarels 	struct nameidata nd;
12185992Swnj 
121959373Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
122064410Sbostic 	    uap->path, p);
122152322Smckusick 	if (error = namei(&nd))
122247540Skarels 		return (error);
122359373Smckusick 	/*
122459373Smckusick 	 * For symbolic links, always return the attributes of its
122559373Smckusick 	 * containing directory, except for mode, size, and links.
122659373Smckusick 	 */
122759373Smckusick 	vp = nd.ni_vp;
122859373Smckusick 	dvp = nd.ni_dvp;
122959373Smckusick 	if (vp->v_type != VLNK) {
123059373Smckusick 		if (dvp == vp)
123159373Smckusick 			vrele(dvp);
123259373Smckusick 		else
123359373Smckusick 			vput(dvp);
123459373Smckusick 		error = vn_stat(vp, &sb, p);
123559373Smckusick 		vput(vp);
123659373Smckusick 		if (error)
123759373Smckusick 			return (error);
123859373Smckusick 	} else {
123959373Smckusick 		error = vn_stat(dvp, &sb, p);
124059373Smckusick 		vput(dvp);
124159373Smckusick 		if (error) {
124259373Smckusick 			vput(vp);
124359373Smckusick 			return (error);
124459373Smckusick 		}
124559373Smckusick 		error = vn_stat(vp, &sb1, p);
124659373Smckusick 		vput(vp);
124759373Smckusick 		if (error)
124859373Smckusick 			return (error);
124959373Smckusick 		sb.st_mode &= ~S_IFDIR;
125059373Smckusick 		sb.st_mode |= S_IFLNK;
125159373Smckusick 		sb.st_nlink = sb1.st_nlink;
125259373Smckusick 		sb.st_size = sb1.st_size;
125359373Smckusick 		sb.st_blocks = sb1.st_blocks;
125459373Smckusick 	}
125537741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
125647540Skarels 	return (error);
12575992Swnj }
12585992Swnj 
12595992Swnj /*
126064410Sbostic  * Get configurable pathname variables.
126160414Smckusick  */
126260414Smckusick struct pathconf_args {
126364410Sbostic 	char	*path;
126460414Smckusick 	int	name;
126560414Smckusick };
126660414Smckusick /* ARGSUSED */
126760414Smckusick pathconf(p, uap, retval)
126860414Smckusick 	struct proc *p;
126960414Smckusick 	register struct pathconf_args *uap;
127060414Smckusick 	int *retval;
127160414Smckusick {
127260414Smckusick 	int error;
127360414Smckusick 	struct nameidata nd;
127460414Smckusick 
127564410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
127660414Smckusick 	if (error = namei(&nd))
127760414Smckusick 		return (error);
127860414Smckusick 	error = VOP_PATHCONF(nd.ni_vp, uap->name, retval);
127960414Smckusick 	vput(nd.ni_vp);
128060414Smckusick 	return (error);
128160414Smckusick }
128260414Smckusick 
128360414Smckusick /*
128449365Smckusick  * Return target name of a symbolic link.
128537Sbill  */
128654916Storek struct readlink_args {
128764410Sbostic 	char	*path;
128854916Storek 	char	*buf;
128954916Storek 	int	count;
129054916Storek };
129142441Smckusick /* ARGSUSED */
129242441Smckusick readlink(p, uap, retval)
129345914Smckusick 	struct proc *p;
129454916Storek 	register struct readlink_args *uap;
129542441Smckusick 	int *retval;
129642441Smckusick {
129737741Smckusick 	register struct vnode *vp;
129837741Smckusick 	struct iovec aiov;
129937741Smckusick 	struct uio auio;
130037741Smckusick 	int error;
130147540Skarels 	struct nameidata nd;
13025992Swnj 
130364410Sbostic 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
130452322Smckusick 	if (error = namei(&nd))
130547540Skarels 		return (error);
130652322Smckusick 	vp = nd.ni_vp;
130764410Sbostic 	if (vp->v_type != VLNK)
130837741Smckusick 		error = EINVAL;
130964410Sbostic 	else {
131064410Sbostic 		aiov.iov_base = uap->buf;
131164410Sbostic 		aiov.iov_len = uap->count;
131264410Sbostic 		auio.uio_iov = &aiov;
131364410Sbostic 		auio.uio_iovcnt = 1;
131464410Sbostic 		auio.uio_offset = 0;
131564410Sbostic 		auio.uio_rw = UIO_READ;
131664410Sbostic 		auio.uio_segflg = UIO_USERSPACE;
131764410Sbostic 		auio.uio_procp = p;
131864410Sbostic 		auio.uio_resid = uap->count;
131964410Sbostic 		error = VOP_READLINK(vp, &auio, p->p_ucred);
13205992Swnj 	}
132137741Smckusick 	vput(vp);
132242441Smckusick 	*retval = uap->count - auio.uio_resid;
132347540Skarels 	return (error);
13245992Swnj }
13255992Swnj 
13269167Ssam /*
132764410Sbostic  * Change flags of a file given a path name.
132838259Smckusick  */
132954916Storek struct chflags_args {
133064410Sbostic 	char	*path;
133154916Storek 	int	flags;
133254916Storek };
133342441Smckusick /* ARGSUSED */
133442441Smckusick chflags(p, uap, retval)
133545914Smckusick 	struct proc *p;
133654916Storek 	register struct chflags_args *uap;
133742441Smckusick 	int *retval;
133842441Smckusick {
133938259Smckusick 	register struct vnode *vp;
134038259Smckusick 	struct vattr vattr;
134138259Smckusick 	int error;
134247540Skarels 	struct nameidata nd;
134338259Smckusick 
134464410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
134552322Smckusick 	if (error = namei(&nd))
134647540Skarels 		return (error);
134752322Smckusick 	vp = nd.ni_vp;
134859382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
134959382Smckusick 	VOP_LOCK(vp);
135064410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
135138259Smckusick 		error = EROFS;
135264410Sbostic 	else {
135364410Sbostic 		VATTR_NULL(&vattr);
135464410Sbostic 		vattr.va_flags = uap->flags;
135564410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
135638259Smckusick 	}
135738259Smckusick 	vput(vp);
135847540Skarels 	return (error);
135938259Smckusick }
136038259Smckusick 
136138259Smckusick /*
136238259Smckusick  * Change flags of a file given a file descriptor.
136338259Smckusick  */
136454916Storek struct fchflags_args {
136554916Storek 	int	fd;
136654916Storek 	int	flags;
136754916Storek };
136842441Smckusick /* ARGSUSED */
136942441Smckusick fchflags(p, uap, retval)
137045914Smckusick 	struct proc *p;
137154916Storek 	register struct fchflags_args *uap;
137242441Smckusick 	int *retval;
137342441Smckusick {
137438259Smckusick 	struct vattr vattr;
137538259Smckusick 	struct vnode *vp;
137638259Smckusick 	struct file *fp;
137738259Smckusick 	int error;
137838259Smckusick 
137945914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
138047540Skarels 		return (error);
138138259Smckusick 	vp = (struct vnode *)fp->f_data;
138259382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
138338259Smckusick 	VOP_LOCK(vp);
138464410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
138538259Smckusick 		error = EROFS;
138664410Sbostic 	else {
138764410Sbostic 		VATTR_NULL(&vattr);
138864410Sbostic 		vattr.va_flags = uap->flags;
138964410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
139038259Smckusick 	}
139138259Smckusick 	VOP_UNLOCK(vp);
139247540Skarels 	return (error);
139338259Smckusick }
139438259Smckusick 
139538259Smckusick /*
13969167Ssam  * Change mode of a file given path name.
13979167Ssam  */
139854916Storek struct chmod_args {
139964410Sbostic 	char	*path;
140064410Sbostic 	int	mode;
140154916Storek };
140242441Smckusick /* ARGSUSED */
140342441Smckusick chmod(p, uap, retval)
140445914Smckusick 	struct proc *p;
140554916Storek 	register struct chmod_args *uap;
140642441Smckusick 	int *retval;
140742441Smckusick {
140837741Smckusick 	register struct vnode *vp;
140937741Smckusick 	struct vattr vattr;
141037741Smckusick 	int error;
141147540Skarels 	struct nameidata nd;
14125992Swnj 
141364410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
141452322Smckusick 	if (error = namei(&nd))
141547540Skarels 		return (error);
141652322Smckusick 	vp = nd.ni_vp;
141759382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
141859382Smckusick 	VOP_LOCK(vp);
141964410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
142037741Smckusick 		error = EROFS;
142164410Sbostic 	else {
142264410Sbostic 		VATTR_NULL(&vattr);
142364410Sbostic 		vattr.va_mode = uap->mode & ALLPERMS;
142464410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
142537741Smckusick 	}
142637741Smckusick 	vput(vp);
142747540Skarels 	return (error);
14287701Ssam }
14297439Sroot 
14309167Ssam /*
14319167Ssam  * Change mode of a file given a file descriptor.
14329167Ssam  */
143354916Storek struct fchmod_args {
143454916Storek 	int	fd;
143564410Sbostic 	int	mode;
143654916Storek };
143742441Smckusick /* ARGSUSED */
143842441Smckusick fchmod(p, uap, retval)
143945914Smckusick 	struct proc *p;
144054916Storek 	register struct fchmod_args *uap;
144142441Smckusick 	int *retval;
144242441Smckusick {
144337741Smckusick 	struct vattr vattr;
144437741Smckusick 	struct vnode *vp;
144537741Smckusick 	struct file *fp;
144637741Smckusick 	int error;
14477701Ssam 
144845914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
144947540Skarels 		return (error);
145037741Smckusick 	vp = (struct vnode *)fp->f_data;
145159382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
145237741Smckusick 	VOP_LOCK(vp);
145364410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
145437741Smckusick 		error = EROFS;
145564410Sbostic 	else {
145664410Sbostic 		VATTR_NULL(&vattr);
145764410Sbostic 		vattr.va_mode = uap->mode & ALLPERMS;
145864410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
14597439Sroot 	}
146037741Smckusick 	VOP_UNLOCK(vp);
146147540Skarels 	return (error);
14625992Swnj }
14635992Swnj 
14649167Ssam /*
14659167Ssam  * Set ownership given a path name.
14669167Ssam  */
146754916Storek struct chown_args {
146864410Sbostic 	char	*path;
146954916Storek 	int	uid;
147054916Storek 	int	gid;
147154916Storek };
147242441Smckusick /* ARGSUSED */
147342441Smckusick chown(p, uap, retval)
147445914Smckusick 	struct proc *p;
147554916Storek 	register struct chown_args *uap;
147642441Smckusick 	int *retval;
147742441Smckusick {
147837741Smckusick 	register struct vnode *vp;
147937741Smckusick 	struct vattr vattr;
148037741Smckusick 	int error;
148147540Skarels 	struct nameidata nd;
148237Sbill 
148366510Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
148452322Smckusick 	if (error = namei(&nd))
148547540Skarels 		return (error);
148652322Smckusick 	vp = nd.ni_vp;
148759382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
148859382Smckusick 	VOP_LOCK(vp);
148964410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
149037741Smckusick 		error = EROFS;
149164410Sbostic 	else {
149264410Sbostic 		VATTR_NULL(&vattr);
149364410Sbostic 		vattr.va_uid = uap->uid;
149464410Sbostic 		vattr.va_gid = uap->gid;
149564410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
149637741Smckusick 	}
149737741Smckusick 	vput(vp);
149847540Skarels 	return (error);
14997701Ssam }
15007439Sroot 
15019167Ssam /*
15029167Ssam  * Set ownership given a file descriptor.
15039167Ssam  */
150454916Storek struct fchown_args {
150554916Storek 	int	fd;
150654916Storek 	int	uid;
150754916Storek 	int	gid;
150854916Storek };
150942441Smckusick /* ARGSUSED */
151042441Smckusick fchown(p, uap, retval)
151145914Smckusick 	struct proc *p;
151254916Storek 	register struct fchown_args *uap;
151342441Smckusick 	int *retval;
151442441Smckusick {
151537741Smckusick 	struct vattr vattr;
151637741Smckusick 	struct vnode *vp;
151737741Smckusick 	struct file *fp;
151837741Smckusick 	int error;
15197701Ssam 
152045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
152147540Skarels 		return (error);
152237741Smckusick 	vp = (struct vnode *)fp->f_data;
152359382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
152437741Smckusick 	VOP_LOCK(vp);
152564410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
152637741Smckusick 		error = EROFS;
152764410Sbostic 	else {
152864410Sbostic 		VATTR_NULL(&vattr);
152964410Sbostic 		vattr.va_uid = uap->uid;
153064410Sbostic 		vattr.va_gid = uap->gid;
153164410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
153237741Smckusick 	}
153337741Smckusick 	VOP_UNLOCK(vp);
153447540Skarels 	return (error);
15357701Ssam }
15367701Ssam 
153742441Smckusick /*
153842441Smckusick  * Set the access and modification times of a file.
153942441Smckusick  */
154054916Storek struct utimes_args {
154164410Sbostic 	char	*path;
154254916Storek 	struct	timeval *tptr;
154354916Storek };
154442441Smckusick /* ARGSUSED */
154542441Smckusick utimes(p, uap, retval)
154645914Smckusick 	struct proc *p;
154754916Storek 	register struct utimes_args *uap;
154842441Smckusick 	int *retval;
154942441Smckusick {
155037741Smckusick 	register struct vnode *vp;
155111811Ssam 	struct timeval tv[2];
155237741Smckusick 	struct vattr vattr;
155358840Storek 	int error;
155447540Skarels 	struct nameidata nd;
155511811Ssam 
155658505Sbostic 	VATTR_NULL(&vattr);
155758505Sbostic 	if (uap->tptr == NULL) {
155858505Sbostic 		microtime(&tv[0]);
155958505Sbostic 		tv[1] = tv[0];
156058548Sbostic 		vattr.va_vaflags |= VA_UTIMES_NULL;
156158505Sbostic 	} else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
156258505Sbostic   		return (error);
156364410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
156452322Smckusick 	if (error = namei(&nd))
156547540Skarels 		return (error);
156652322Smckusick 	vp = nd.ni_vp;
156759382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
156859382Smckusick 	VOP_LOCK(vp);
156964410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
157037741Smckusick 		error = EROFS;
157164410Sbostic 	else {
157264410Sbostic 		vattr.va_atime.ts_sec = tv[0].tv_sec;
157364410Sbostic 		vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
157464410Sbostic 		vattr.va_mtime.ts_sec = tv[1].tv_sec;
157564410Sbostic 		vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
157664410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
157721015Smckusick 	}
157837741Smckusick 	vput(vp);
157947540Skarels 	return (error);
158011811Ssam }
158111811Ssam 
158264410Sbostic /*
158364410Sbostic  * Truncate a file given its path name.
158464410Sbostic  */
158560428Smckusick struct truncate_args {
158664410Sbostic 	char	*path;
158754863Storek 	int	pad;
158854863Storek 	off_t	length;
158954863Storek };
159053468Smckusick /* ARGSUSED */
159160414Smckusick truncate(p, uap, retval)
159253468Smckusick 	struct proc *p;
159360428Smckusick 	register struct truncate_args *uap;
159453468Smckusick 	int *retval;
159553468Smckusick {
159637741Smckusick 	register struct vnode *vp;
159737741Smckusick 	struct vattr vattr;
159837741Smckusick 	int error;
159947540Skarels 	struct nameidata nd;
16007701Ssam 
160164410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
160252322Smckusick 	if (error = namei(&nd))
160347540Skarels 		return (error);
160452322Smckusick 	vp = nd.ni_vp;
160559382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
160659382Smckusick 	VOP_LOCK(vp);
160764410Sbostic 	if (vp->v_type == VDIR)
160837741Smckusick 		error = EISDIR;
160964410Sbostic 	else if ((error = vn_writechk(vp)) == 0 &&
161064410Sbostic 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
161164410Sbostic 		VATTR_NULL(&vattr);
161264410Sbostic 		vattr.va_size = uap->length;
161364410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
16147701Ssam 	}
161537741Smckusick 	vput(vp);
161647540Skarels 	return (error);
16177701Ssam }
16187701Ssam 
161964410Sbostic /*
162064410Sbostic  * Truncate a file given a file descriptor.
162164410Sbostic  */
162260428Smckusick struct ftruncate_args {
162354863Storek 	int	fd;
162454863Storek 	int	pad;
162554863Storek 	off_t	length;
162654863Storek };
162742441Smckusick /* ARGSUSED */
162860414Smckusick ftruncate(p, uap, retval)
162945914Smckusick 	struct proc *p;
163060428Smckusick 	register struct ftruncate_args *uap;
163142441Smckusick 	int *retval;
163242441Smckusick {
163337741Smckusick 	struct vattr vattr;
163437741Smckusick 	struct vnode *vp;
16357701Ssam 	struct file *fp;
163637741Smckusick 	int error;
16377701Ssam 
163845914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
163947540Skarels 		return (error);
164037741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
164147540Skarels 		return (EINVAL);
164237741Smckusick 	vp = (struct vnode *)fp->f_data;
164359382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
164437741Smckusick 	VOP_LOCK(vp);
164564410Sbostic 	if (vp->v_type == VDIR)
164637741Smckusick 		error = EISDIR;
164764410Sbostic 	else if ((error = vn_writechk(vp)) == 0) {
164864410Sbostic 		VATTR_NULL(&vattr);
164964410Sbostic 		vattr.va_size = uap->length;
165064410Sbostic 		error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
16517701Ssam 	}
165237741Smckusick 	VOP_UNLOCK(vp);
165347540Skarels 	return (error);
16547701Ssam }
16557701Ssam 
165654863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
16579167Ssam /*
165854863Storek  * Truncate a file given its path name.
165954863Storek  */
166060428Smckusick struct otruncate_args {
166164410Sbostic 	char	*path;
166254916Storek 	long	length;
166354916Storek };
166454863Storek /* ARGSUSED */
166560105Smckusick otruncate(p, uap, retval)
166654863Storek 	struct proc *p;
166760428Smckusick 	register struct otruncate_args *uap;
166854863Storek 	int *retval;
166954863Storek {
167060428Smckusick 	struct truncate_args nuap;
167154863Storek 
167264410Sbostic 	nuap.path = uap->path;
167354863Storek 	nuap.length = uap->length;
167460428Smckusick 	return (truncate(p, &nuap, retval));
167554863Storek }
167654863Storek 
167754863Storek /*
167854863Storek  * Truncate a file given a file descriptor.
167954863Storek  */
168060428Smckusick struct oftruncate_args {
168154916Storek 	int	fd;
168254916Storek 	long	length;
168354916Storek };
168454863Storek /* ARGSUSED */
168560105Smckusick oftruncate(p, uap, retval)
168654863Storek 	struct proc *p;
168760428Smckusick 	register struct oftruncate_args *uap;
168854863Storek 	int *retval;
168954863Storek {
169060428Smckusick 	struct ftruncate_args nuap;
169154863Storek 
169254863Storek 	nuap.fd = uap->fd;
169354863Storek 	nuap.length = uap->length;
169460428Smckusick 	return (ftruncate(p, &nuap, retval));
169554863Storek }
169654863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */
169754863Storek 
169854863Storek /*
169964410Sbostic  * Sync an open file.
17009167Ssam  */
170154916Storek struct fsync_args {
170254916Storek 	int	fd;
170354916Storek };
170442441Smckusick /* ARGSUSED */
170542441Smckusick fsync(p, uap, retval)
170645914Smckusick 	struct proc *p;
170754916Storek 	struct fsync_args *uap;
170842441Smckusick 	int *retval;
17099167Ssam {
171039592Smckusick 	register struct vnode *vp;
17119167Ssam 	struct file *fp;
171237741Smckusick 	int error;
17139167Ssam 
171445914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
171547540Skarels 		return (error);
171639592Smckusick 	vp = (struct vnode *)fp->f_data;
171739592Smckusick 	VOP_LOCK(vp);
171854441Smckusick 	error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
171939592Smckusick 	VOP_UNLOCK(vp);
172047540Skarels 	return (error);
17219167Ssam }
17229167Ssam 
17239167Ssam /*
172464410Sbostic  * Rename files.  Source and destination must either both be directories,
172564410Sbostic  * or both not be directories.  If target is a directory, it must be empty.
17269167Ssam  */
172754916Storek struct rename_args {
172854916Storek 	char	*from;
172954916Storek 	char	*to;
173054916Storek };
173142441Smckusick /* ARGSUSED */
173242441Smckusick rename(p, uap, retval)
173345914Smckusick 	struct proc *p;
173454916Storek 	register struct rename_args *uap;
173542441Smckusick 	int *retval;
173642441Smckusick {
173737741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
173849735Smckusick 	struct nameidata fromnd, tond;
173937741Smckusick 	int error;
17407701Ssam 
174152322Smckusick 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
174252322Smckusick 		uap->from, p);
174352322Smckusick 	if (error = namei(&fromnd))
174447540Skarels 		return (error);
174549735Smckusick 	fvp = fromnd.ni_vp;
174652322Smckusick 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
174752322Smckusick 		UIO_USERSPACE, uap->to, p);
174852322Smckusick 	if (error = namei(&tond)) {
174952230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
175049735Smckusick 		vrele(fromnd.ni_dvp);
175142465Smckusick 		vrele(fvp);
175242465Smckusick 		goto out1;
175342465Smckusick 	}
175437741Smckusick 	tdvp = tond.ni_dvp;
175537741Smckusick 	tvp = tond.ni_vp;
175637741Smckusick 	if (tvp != NULL) {
175737741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
175839242Sbostic 			error = ENOTDIR;
175937741Smckusick 			goto out;
176037741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
176139242Sbostic 			error = EISDIR;
176237741Smckusick 			goto out;
17639167Ssam 		}
17649167Ssam 	}
176539286Smckusick 	if (fvp == tdvp)
176637741Smckusick 		error = EINVAL;
176739286Smckusick 	/*
176849735Smckusick 	 * If source is the same as the destination (that is the
176949735Smckusick 	 * same inode number with the same name in the same directory),
177039286Smckusick 	 * then there is nothing to do.
177139286Smckusick 	 */
177249735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
177352322Smckusick 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
177452322Smckusick 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
177552322Smckusick 	      fromnd.ni_cnd.cn_namelen))
177639286Smckusick 		error = -1;
177737741Smckusick out:
177842465Smckusick 	if (!error) {
177952192Smckusick 		LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE);
178052192Smckusick 		if (fromnd.ni_dvp != tdvp)
178152192Smckusick 			LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
178252192Smckusick 		if (tvp)
178352192Smckusick 			LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE);
178452230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
178552230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
178642465Smckusick 	} else {
178752230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
178843344Smckusick 		if (tdvp == tvp)
178943344Smckusick 			vrele(tdvp);
179043344Smckusick 		else
179143344Smckusick 			vput(tdvp);
179242465Smckusick 		if (tvp)
179342465Smckusick 			vput(tvp);
179452230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
179549735Smckusick 		vrele(fromnd.ni_dvp);
179642465Smckusick 		vrele(fvp);
17979167Ssam 	}
179849735Smckusick 	vrele(tond.ni_startdir);
179952322Smckusick 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
180037741Smckusick out1:
180166801Smckusick 	if (fromnd.ni_startdir)
180266801Smckusick 		vrele(fromnd.ni_startdir);
180352322Smckusick 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
180439286Smckusick 	if (error == -1)
180547540Skarels 		return (0);
180647540Skarels 	return (error);
18077701Ssam }
18087701Ssam 
18097535Sroot /*
181064410Sbostic  * Make a directory file.
181112756Ssam  */
181254916Storek struct mkdir_args {
181364410Sbostic 	char	*path;
181464410Sbostic 	int	mode;
181554916Storek };
181642441Smckusick /* ARGSUSED */
181742441Smckusick mkdir(p, uap, retval)
181845914Smckusick 	struct proc *p;
181954916Storek 	register struct mkdir_args *uap;
182042441Smckusick 	int *retval;
182142441Smckusick {
182237741Smckusick 	register struct vnode *vp;
182337741Smckusick 	struct vattr vattr;
182437741Smckusick 	int error;
182547540Skarels 	struct nameidata nd;
182612756Ssam 
182764410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
182852322Smckusick 	if (error = namei(&nd))
182947540Skarels 		return (error);
183052322Smckusick 	vp = nd.ni_vp;
183137741Smckusick 	if (vp != NULL) {
183252322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
183352322Smckusick 		if (nd.ni_dvp == vp)
183452322Smckusick 			vrele(nd.ni_dvp);
183543344Smckusick 		else
183652322Smckusick 			vput(nd.ni_dvp);
183742465Smckusick 		vrele(vp);
183847540Skarels 		return (EEXIST);
183912756Ssam 	}
184041362Smckusick 	VATTR_NULL(&vattr);
184137741Smckusick 	vattr.va_type = VDIR;
184264410Sbostic 	vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask;
184352322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
184452322Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
184538145Smckusick 	if (!error)
184652322Smckusick 		vput(nd.ni_vp);
184747540Skarels 	return (error);
184812756Ssam }
184912756Ssam 
185012756Ssam /*
185164410Sbostic  * Remove a directory file.
185212756Ssam  */
185354916Storek struct rmdir_args {
185464410Sbostic 	char	*path;
185554916Storek };
185642441Smckusick /* ARGSUSED */
185742441Smckusick rmdir(p, uap, retval)
185845914Smckusick 	struct proc *p;
185954916Storek 	struct rmdir_args *uap;
186042441Smckusick 	int *retval;
186112756Ssam {
186237741Smckusick 	register struct vnode *vp;
186337741Smckusick 	int error;
186447540Skarels 	struct nameidata nd;
186512756Ssam 
186664410Sbostic 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p);
186752322Smckusick 	if (error = namei(&nd))
186847540Skarels 		return (error);
186952322Smckusick 	vp = nd.ni_vp;
187037741Smckusick 	if (vp->v_type != VDIR) {
187137741Smckusick 		error = ENOTDIR;
187212756Ssam 		goto out;
187312756Ssam 	}
187412756Ssam 	/*
187537741Smckusick 	 * No rmdir "." please.
187612756Ssam 	 */
187752322Smckusick 	if (nd.ni_dvp == vp) {
187837741Smckusick 		error = EINVAL;
187912756Ssam 		goto out;
188012756Ssam 	}
188112756Ssam 	/*
188249365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
188312756Ssam 	 */
188437741Smckusick 	if (vp->v_flag & VROOT)
188537741Smckusick 		error = EBUSY;
188612756Ssam out:
188742465Smckusick 	if (!error) {
188852322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
188952192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
189052322Smckusick 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
189142465Smckusick 	} else {
189252322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
189352322Smckusick 		if (nd.ni_dvp == vp)
189452322Smckusick 			vrele(nd.ni_dvp);
189543344Smckusick 		else
189652322Smckusick 			vput(nd.ni_dvp);
189742465Smckusick 		vput(vp);
189842465Smckusick 	}
189947540Skarels 	return (error);
190012756Ssam }
190112756Ssam 
190254620Smckusick #ifdef COMPAT_43
190337741Smckusick /*
190449365Smckusick  * Read a block of directory entries in a file system independent format.
190537741Smckusick  */
190654916Storek struct ogetdirentries_args {
190754916Storek 	int	fd;
190854916Storek 	char	*buf;
190964410Sbostic 	u_int	count;
191054916Storek 	long	*basep;
191154916Storek };
191254620Smckusick ogetdirentries(p, uap, retval)
191354620Smckusick 	struct proc *p;
191454916Storek 	register struct ogetdirentries_args *uap;
191554620Smckusick 	int *retval;
191654620Smckusick {
191754620Smckusick 	register struct vnode *vp;
191854620Smckusick 	struct file *fp;
191954620Smckusick 	struct uio auio, kuio;
192054620Smckusick 	struct iovec aiov, kiov;
192154620Smckusick 	struct dirent *dp, *edp;
192254620Smckusick 	caddr_t dirbuf;
192367362Smckusick 	int error, eofflag, readcnt;
192454969Smckusick 	long loff;
192554620Smckusick 
192654620Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
192754620Smckusick 		return (error);
192854620Smckusick 	if ((fp->f_flag & FREAD) == 0)
192954620Smckusick 		return (EBADF);
193054620Smckusick 	vp = (struct vnode *)fp->f_data;
193167362Smckusick unionread:
193254620Smckusick 	if (vp->v_type != VDIR)
193354620Smckusick 		return (EINVAL);
193454620Smckusick 	aiov.iov_base = uap->buf;
193554620Smckusick 	aiov.iov_len = uap->count;
193654620Smckusick 	auio.uio_iov = &aiov;
193754620Smckusick 	auio.uio_iovcnt = 1;
193854620Smckusick 	auio.uio_rw = UIO_READ;
193954620Smckusick 	auio.uio_segflg = UIO_USERSPACE;
194054620Smckusick 	auio.uio_procp = p;
194154620Smckusick 	auio.uio_resid = uap->count;
194254620Smckusick 	VOP_LOCK(vp);
194354969Smckusick 	loff = auio.uio_offset = fp->f_offset;
194454620Smckusick #	if (BYTE_ORDER != LITTLE_ENDIAN)
194556339Smckusick 		if (vp->v_mount->mnt_maxsymlinklen <= 0) {
194667362Smckusick 			error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
194767362Smckusick 			    (u_long *)0, 0);
194856339Smckusick 			fp->f_offset = auio.uio_offset;
194956339Smckusick 		} else
195054620Smckusick #	endif
195154620Smckusick 	{
195254620Smckusick 		kuio = auio;
195354620Smckusick 		kuio.uio_iov = &kiov;
195454620Smckusick 		kuio.uio_segflg = UIO_SYSSPACE;
195554620Smckusick 		kiov.iov_len = uap->count;
195654620Smckusick 		MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK);
195754620Smckusick 		kiov.iov_base = dirbuf;
195867362Smckusick 		error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
195967362Smckusick 			    (u_long *)0, 0);
196056339Smckusick 		fp->f_offset = kuio.uio_offset;
196154620Smckusick 		if (error == 0) {
196254620Smckusick 			readcnt = uap->count - kuio.uio_resid;
196354620Smckusick 			edp = (struct dirent *)&dirbuf[readcnt];
196454620Smckusick 			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
196554620Smckusick #				if (BYTE_ORDER == LITTLE_ENDIAN)
196654969Smckusick 					/*
196755009Smckusick 					 * The expected low byte of
196855009Smckusick 					 * dp->d_namlen is our dp->d_type.
196955009Smckusick 					 * The high MBZ byte of dp->d_namlen
197055009Smckusick 					 * is our dp->d_namlen.
197154969Smckusick 					 */
197255009Smckusick 					dp->d_type = dp->d_namlen;
197355009Smckusick 					dp->d_namlen = 0;
197455009Smckusick #				else
197555009Smckusick 					/*
197655009Smckusick 					 * The dp->d_type is the high byte
197755009Smckusick 					 * of the expected dp->d_namlen,
197855009Smckusick 					 * so must be zero'ed.
197955009Smckusick 					 */
198055009Smckusick 					dp->d_type = 0;
198154620Smckusick #				endif
198254620Smckusick 				if (dp->d_reclen > 0) {
198354620Smckusick 					dp = (struct dirent *)
198454620Smckusick 					    ((char *)dp + dp->d_reclen);
198554620Smckusick 				} else {
198654620Smckusick 					error = EIO;
198754620Smckusick 					break;
198854620Smckusick 				}
198954620Smckusick 			}
199054620Smckusick 			if (dp >= edp)
199154620Smckusick 				error = uiomove(dirbuf, readcnt, &auio);
199254620Smckusick 		}
199354620Smckusick 		FREE(dirbuf, M_TEMP);
199454620Smckusick 	}
199554620Smckusick 	VOP_UNLOCK(vp);
199654620Smckusick 	if (error)
199754620Smckusick 		return (error);
199867362Smckusick 
199967362Smckusick #ifdef UNION
200067362Smckusick {
200167362Smckusick 	extern int (**union_vnodeop_p)();
200267362Smckusick 	extern struct vnode *union_lowervp __P((struct vnode *));
200367362Smckusick 
200467362Smckusick 	if ((uap->count == auio.uio_resid) &&
200567362Smckusick 	    (vp->v_op == union_vnodeop_p)) {
200667362Smckusick 		struct vnode *lvp;
200767362Smckusick 
200867362Smckusick 		lvp = union_lowervp(vp);
200967362Smckusick 		if (lvp != NULLVP) {
2010*67575Spendry 			struct vattr va;
2011*67575Spendry 
2012*67575Spendry 			/*
2013*67575Spendry 			 * If the directory is opaque,
2014*67575Spendry 			 * then don't show lower entries
2015*67575Spendry 			 */
2016*67575Spendry 			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
2017*67575Spendry 			if (va.va_flags & OPAQUE) {
2018*67575Spendry 				vrele(lvp);
2019*67575Spendry 				lvp = NULL;
2020*67575Spendry 			}
2021*67575Spendry 		}
2022*67575Spendry 
2023*67575Spendry 		if (lvp != NULLVP) {
202467362Smckusick 			VOP_LOCK(lvp);
202567362Smckusick 			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
202667362Smckusick 			VOP_UNLOCK(lvp);
202767362Smckusick 
202867362Smckusick 			if (error) {
202967362Smckusick 				vrele(lvp);
203067362Smckusick 				return (error);
203167362Smckusick 			}
203267362Smckusick 			fp->f_data = (caddr_t) lvp;
203367362Smckusick 			fp->f_offset = 0;
203467362Smckusick 			error = vn_close(vp, FREAD, fp->f_cred, p);
203567362Smckusick 			if (error)
203667362Smckusick 				return (error);
203767362Smckusick 			vp = lvp;
203867362Smckusick 			goto unionread;
203967362Smckusick 		}
204067362Smckusick 	}
204167362Smckusick }
204267362Smckusick #endif /* UNION */
204367362Smckusick 
204467362Smckusick 	if ((uap->count == auio.uio_resid) &&
204567362Smckusick 	    (vp->v_flag & VROOT) &&
204667362Smckusick 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
204767362Smckusick 		struct vnode *tvp = vp;
204867362Smckusick 		vp = vp->v_mount->mnt_vnodecovered;
204967362Smckusick 		VREF(vp);
205067362Smckusick 		fp->f_data = (caddr_t) vp;
205167362Smckusick 		fp->f_offset = 0;
205267362Smckusick 		vrele(tvp);
205367362Smckusick 		goto unionread;
205467362Smckusick 	}
205554969Smckusick 	error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
205654620Smckusick 	*retval = uap->count - auio.uio_resid;
205754620Smckusick 	return (error);
205854620Smckusick }
205967362Smckusick #endif /* COMPAT_43 */
206054620Smckusick 
206154620Smckusick /*
206254620Smckusick  * Read a block of directory entries in a file system independent format.
206354620Smckusick  */
206454916Storek struct getdirentries_args {
206554916Storek 	int	fd;
206654916Storek 	char	*buf;
206764410Sbostic 	u_int	count;
206854916Storek 	long	*basep;
206954916Storek };
207042441Smckusick getdirentries(p, uap, retval)
207145914Smckusick 	struct proc *p;
207254916Storek 	register struct getdirentries_args *uap;
207342441Smckusick 	int *retval;
207442441Smckusick {
207539592Smckusick 	register struct vnode *vp;
207616540Ssam 	struct file *fp;
207737741Smckusick 	struct uio auio;
207837741Smckusick 	struct iovec aiov;
207954969Smckusick 	long loff;
208067362Smckusick 	int error, eofflag;
208112756Ssam 
208245914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
208347540Skarels 		return (error);
208437741Smckusick 	if ((fp->f_flag & FREAD) == 0)
208547540Skarels 		return (EBADF);
208639592Smckusick 	vp = (struct vnode *)fp->f_data;
208755451Spendry unionread:
208839592Smckusick 	if (vp->v_type != VDIR)
208947540Skarels 		return (EINVAL);
209037741Smckusick 	aiov.iov_base = uap->buf;
209137741Smckusick 	aiov.iov_len = uap->count;
209237741Smckusick 	auio.uio_iov = &aiov;
209337741Smckusick 	auio.uio_iovcnt = 1;
209437741Smckusick 	auio.uio_rw = UIO_READ;
209537741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
209648026Smckusick 	auio.uio_procp = p;
209737741Smckusick 	auio.uio_resid = uap->count;
209839592Smckusick 	VOP_LOCK(vp);
209954969Smckusick 	loff = auio.uio_offset = fp->f_offset;
210067362Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *)0, 0);
210139592Smckusick 	fp->f_offset = auio.uio_offset;
210239592Smckusick 	VOP_UNLOCK(vp);
210339592Smckusick 	if (error)
210447540Skarels 		return (error);
210566095Spendry 
210666095Spendry #ifdef UNION
210766095Spendry {
210866095Spendry 	extern int (**union_vnodeop_p)();
210966095Spendry 	extern struct vnode *union_lowervp __P((struct vnode *));
211066095Spendry 
211155451Spendry 	if ((uap->count == auio.uio_resid) &&
211266095Spendry 	    (vp->v_op == union_vnodeop_p)) {
211367122Spendry 		struct vnode *lvp;
211466095Spendry 
211567122Spendry 		lvp = union_lowervp(vp);
211667122Spendry 		if (lvp != NULLVP) {
2117*67575Spendry 			struct vattr va;
2118*67575Spendry 
2119*67575Spendry 			/*
2120*67575Spendry 			 * If the directory is opaque,
2121*67575Spendry 			 * then don't show lower entries
2122*67575Spendry 			 */
2123*67575Spendry 			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
2124*67575Spendry 			if (va.va_flags & OPAQUE) {
2125*67575Spendry 				vrele(lvp);
2126*67575Spendry 				lvp = NULL;
2127*67575Spendry 			}
2128*67575Spendry 		}
2129*67575Spendry 
2130*67575Spendry 		if (lvp != NULLVP) {
213167122Spendry 			VOP_LOCK(lvp);
213267362Smckusick 			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
213367122Spendry 			VOP_UNLOCK(lvp);
213466095Spendry 
213566095Spendry 			if (error) {
213667122Spendry 				vrele(lvp);
213766095Spendry 				return (error);
213866095Spendry 			}
213967122Spendry 			fp->f_data = (caddr_t) lvp;
214066095Spendry 			fp->f_offset = 0;
214167122Spendry 			error = vn_close(vp, FREAD, fp->f_cred, p);
214266095Spendry 			if (error)
214366095Spendry 				return (error);
214467122Spendry 			vp = lvp;
214566095Spendry 			goto unionread;
214666095Spendry 		}
214766095Spendry 	}
214866095Spendry }
214966095Spendry #endif
215066095Spendry 
215166095Spendry 	if ((uap->count == auio.uio_resid) &&
215255451Spendry 	    (vp->v_flag & VROOT) &&
215355451Spendry 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
215455451Spendry 		struct vnode *tvp = vp;
215555451Spendry 		vp = vp->v_mount->mnt_vnodecovered;
215655451Spendry 		VREF(vp);
215755451Spendry 		fp->f_data = (caddr_t) vp;
215855451Spendry 		fp->f_offset = 0;
215955451Spendry 		vrele(tvp);
216055451Spendry 		goto unionread;
216155451Spendry 	}
216254969Smckusick 	error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
216342441Smckusick 	*retval = uap->count - auio.uio_resid;
216447540Skarels 	return (error);
216512756Ssam }
216612756Ssam 
216712756Ssam /*
216849365Smckusick  * Set the mode mask for creation of filesystem nodes.
216912756Ssam  */
217054916Storek struct umask_args {
217164410Sbostic 	int	newmask;
217254916Storek };
217354916Storek mode_t				/* XXX */
217442441Smckusick umask(p, uap, retval)
217545914Smckusick 	struct proc *p;
217654916Storek 	struct umask_args *uap;
217742441Smckusick 	int *retval;
217812756Ssam {
217964410Sbostic 	register struct filedesc *fdp;
218012756Ssam 
218164410Sbostic 	fdp = p->p_fd;
218245914Smckusick 	*retval = fdp->fd_cmask;
218364410Sbostic 	fdp->fd_cmask = uap->newmask & ALLPERMS;
218447540Skarels 	return (0);
218512756Ssam }
218637741Smckusick 
218739566Smarc /*
218839566Smarc  * Void all references to file by ripping underlying filesystem
218939566Smarc  * away from vnode.
219039566Smarc  */
219154916Storek struct revoke_args {
219264410Sbostic 	char	*path;
219354916Storek };
219442441Smckusick /* ARGSUSED */
219542441Smckusick revoke(p, uap, retval)
219645914Smckusick 	struct proc *p;
219754916Storek 	register struct revoke_args *uap;
219842441Smckusick 	int *retval;
219942441Smckusick {
220039566Smarc 	register struct vnode *vp;
220139566Smarc 	struct vattr vattr;
220239566Smarc 	int error;
220347540Skarels 	struct nameidata nd;
220439566Smarc 
220564410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
220652322Smckusick 	if (error = namei(&nd))
220747540Skarels 		return (error);
220852322Smckusick 	vp = nd.ni_vp;
220939566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
221039566Smarc 		error = EINVAL;
221139566Smarc 		goto out;
221239566Smarc 	}
221348026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
221439566Smarc 		goto out;
221547540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
221647540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
221739566Smarc 		goto out;
221839805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
221939632Smckusick 		vgoneall(vp);
222039566Smarc out:
222139566Smarc 	vrele(vp);
222247540Skarels 	return (error);
222339566Smarc }
222439566Smarc 
222549365Smckusick /*
222649365Smckusick  * Convert a user file descriptor to a kernel file entry.
222749365Smckusick  */
222864410Sbostic getvnode(fdp, fd, fpp)
222945914Smckusick 	struct filedesc *fdp;
223037741Smckusick 	struct file **fpp;
223164410Sbostic 	int fd;
223237741Smckusick {
223337741Smckusick 	struct file *fp;
223437741Smckusick 
223564410Sbostic 	if ((u_int)fd >= fdp->fd_nfiles ||
223664410Sbostic 	    (fp = fdp->fd_ofiles[fd]) == NULL)
223737741Smckusick 		return (EBADF);
223837741Smckusick 	if (fp->f_type != DTYPE_VNODE)
223937741Smckusick 		return (EINVAL);
224037741Smckusick 	*fpp = fp;
224137741Smckusick 	return (0);
224237741Smckusick }
2243