xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 67748)
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*67748Smckusick  *	@(#)vfs_syscalls.c	8.23 (Berkeley) 08/30/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) {
31367678Smckusick 		/*
31467678Smckusick 		 * Get the next pointer in case we hang on vfs_busy
31567678Smckusick 		 * while we are being unmounted.
31667678Smckusick 		 */
31765259Smckusick 		nmp = mp->mnt_list.tqe_next;
31840343Smckusick 		/*
31940343Smckusick 		 * The lock check below is to avoid races with mount
32040343Smckusick 		 * and unmount.
32140343Smckusick 		 */
32241400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
32341298Smckusick 		    !vfs_busy(mp)) {
32465859Smckusick 			asyncflag = mp->mnt_flag & MNT_ASYNC;
32565859Smckusick 			mp->mnt_flag &= ~MNT_ASYNC;
32654441Smckusick 			VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
32765859Smckusick 			if (asyncflag)
32865859Smckusick 				mp->mnt_flag |= MNT_ASYNC;
32967678Smckusick 			/*
33067678Smckusick 			 * Get the next pointer again, as the next filesystem
33167678Smckusick 			 * might have been unmounted while we were sync'ing.
33267678Smckusick 			 */
33367678Smckusick 			nmp = mp->mnt_list.tqe_next;
33465259Smckusick 			vfs_unbusy(mp);
33565259Smckusick 		}
33665259Smckusick 	}
33756352Smckusick #ifdef DIAGNOSTIC
33856352Smckusick 	if (syncprt)
33956352Smckusick 		vfs_bufstats();
34056352Smckusick #endif /* DIAGNOSTIC */
34147688Skarels 	return (0);
34237741Smckusick }
34337741Smckusick 
34437741Smckusick /*
34564410Sbostic  * Change filesystem quotas.
34641298Smckusick  */
34754916Storek struct quotactl_args {
34854916Storek 	char *path;
34954916Storek 	int cmd;
35054916Storek 	int uid;
35154916Storek 	caddr_t arg;
35254916Storek };
35342441Smckusick /* ARGSUSED */
35442441Smckusick quotactl(p, uap, retval)
35545914Smckusick 	struct proc *p;
35654916Storek 	register struct quotactl_args *uap;
35742441Smckusick 	int *retval;
35842441Smckusick {
35941298Smckusick 	register struct mount *mp;
36041298Smckusick 	int error;
36147540Skarels 	struct nameidata nd;
36241298Smckusick 
36352322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
36452322Smckusick 	if (error = namei(&nd))
36547540Skarels 		return (error);
36652322Smckusick 	mp = nd.ni_vp->v_mount;
36752322Smckusick 	vrele(nd.ni_vp);
36848026Smckusick 	return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p));
36941298Smckusick }
37041298Smckusick 
37141298Smckusick /*
37249365Smckusick  * Get filesystem statistics.
37337741Smckusick  */
37454916Storek struct statfs_args {
37554916Storek 	char *path;
37654916Storek 	struct statfs *buf;
37754916Storek };
37842441Smckusick /* ARGSUSED */
37942441Smckusick statfs(p, uap, retval)
38045914Smckusick 	struct proc *p;
38154916Storek 	register struct statfs_args *uap;
38242441Smckusick 	int *retval;
38342441Smckusick {
38439464Smckusick 	register struct mount *mp;
38540343Smckusick 	register struct statfs *sp;
38637741Smckusick 	int error;
38747540Skarels 	struct nameidata nd;
38837741Smckusick 
38952322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
39052322Smckusick 	if (error = namei(&nd))
39147540Skarels 		return (error);
39252322Smckusick 	mp = nd.ni_vp->v_mount;
39341400Smckusick 	sp = &mp->mnt_stat;
39452322Smckusick 	vrele(nd.ni_vp);
39548026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
39647540Skarels 		return (error);
39741400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
39847540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
39937741Smckusick }
40037741Smckusick 
40142441Smckusick /*
40249365Smckusick  * Get filesystem statistics.
40342441Smckusick  */
40454916Storek struct fstatfs_args {
40554916Storek 	int fd;
40654916Storek 	struct statfs *buf;
40754916Storek };
40842441Smckusick /* ARGSUSED */
40942441Smckusick fstatfs(p, uap, retval)
41045914Smckusick 	struct proc *p;
41154916Storek 	register struct fstatfs_args *uap;
41242441Smckusick 	int *retval;
41342441Smckusick {
41437741Smckusick 	struct file *fp;
41539464Smckusick 	struct mount *mp;
41640343Smckusick 	register struct statfs *sp;
41737741Smckusick 	int error;
41837741Smckusick 
41945914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
42047540Skarels 		return (error);
42139464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
42241400Smckusick 	sp = &mp->mnt_stat;
42348026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
42447540Skarels 		return (error);
42541400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
42647540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
42737741Smckusick }
42837741Smckusick 
42937741Smckusick /*
43049365Smckusick  * Get statistics on all filesystems.
43138270Smckusick  */
43254916Storek struct getfsstat_args {
43354916Storek 	struct statfs *buf;
43454916Storek 	long bufsize;
43554916Storek 	int flags;
43654916Storek };
43742441Smckusick getfsstat(p, uap, retval)
43845914Smckusick 	struct proc *p;
43954916Storek 	register struct getfsstat_args *uap;
44042441Smckusick 	int *retval;
44142441Smckusick {
44265259Smckusick 	register struct mount *mp, *nmp;
44340343Smckusick 	register struct statfs *sp;
44439606Smckusick 	caddr_t sfsp;
44538270Smckusick 	long count, maxcount, error;
44638270Smckusick 
44738270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
44839606Smckusick 	sfsp = (caddr_t)uap->buf;
44965259Smckusick 	for (count = 0, mp = mountlist.tqh_first; mp != NULL; mp = nmp) {
45065259Smckusick 		nmp = mp->mnt_list.tqe_next;
45141400Smckusick 		if (sfsp && count < maxcount &&
45241400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
45341400Smckusick 			sp = &mp->mnt_stat;
45440343Smckusick 			/*
45540343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
45640343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
45740343Smckusick 			 */
45840343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
45940343Smckusick 			    (uap->flags & MNT_WAIT)) &&
46065259Smckusick 			    (error = VFS_STATFS(mp, sp, p)))
46139607Smckusick 				continue;
46241400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
46340343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
46447540Skarels 				return (error);
46540343Smckusick 			sfsp += sizeof(*sp);
46638270Smckusick 		}
46739606Smckusick 		count++;
46865259Smckusick 	}
46938270Smckusick 	if (sfsp && count > maxcount)
47042441Smckusick 		*retval = maxcount;
47138270Smckusick 	else
47242441Smckusick 		*retval = count;
47347540Skarels 	return (0);
47438270Smckusick }
47538270Smckusick 
47638270Smckusick /*
47738259Smckusick  * Change current working directory to a given file descriptor.
47838259Smckusick  */
47954916Storek struct fchdir_args {
48054916Storek 	int	fd;
48154916Storek };
48242441Smckusick /* ARGSUSED */
48342441Smckusick fchdir(p, uap, retval)
48445914Smckusick 	struct proc *p;
48554916Storek 	struct fchdir_args *uap;
48642441Smckusick 	int *retval;
48738259Smckusick {
48845914Smckusick 	register struct filedesc *fdp = p->p_fd;
48938259Smckusick 	register struct vnode *vp;
49038259Smckusick 	struct file *fp;
49138259Smckusick 	int error;
49238259Smckusick 
49345914Smckusick 	if (error = getvnode(fdp, uap->fd, &fp))
49447540Skarels 		return (error);
49538259Smckusick 	vp = (struct vnode *)fp->f_data;
49638259Smckusick 	VOP_LOCK(vp);
49738259Smckusick 	if (vp->v_type != VDIR)
49838259Smckusick 		error = ENOTDIR;
49938259Smckusick 	else
50048026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
50138259Smckusick 	VOP_UNLOCK(vp);
50239860Smckusick 	if (error)
50347540Skarels 		return (error);
50439860Smckusick 	VREF(vp);
50545914Smckusick 	vrele(fdp->fd_cdir);
50645914Smckusick 	fdp->fd_cdir = vp;
50747540Skarels 	return (0);
50838259Smckusick }
50938259Smckusick 
51038259Smckusick /*
51137741Smckusick  * Change current working directory (``.'').
51237741Smckusick  */
51354916Storek struct chdir_args {
51464410Sbostic 	char	*path;
51554916Storek };
51642441Smckusick /* ARGSUSED */
51742441Smckusick chdir(p, uap, retval)
51845914Smckusick 	struct proc *p;
51954916Storek 	struct chdir_args *uap;
52042441Smckusick 	int *retval;
52137741Smckusick {
52245914Smckusick 	register struct filedesc *fdp = p->p_fd;
52337741Smckusick 	int error;
52447540Skarels 	struct nameidata nd;
5256254Sroot 
52664410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
52764410Sbostic 	if (error = change_dir(&nd, p))
52847540Skarels 		return (error);
52945914Smckusick 	vrele(fdp->fd_cdir);
53052322Smckusick 	fdp->fd_cdir = nd.ni_vp;
53147540Skarels 	return (0);
53237741Smckusick }
5336254Sroot 
53437741Smckusick /*
53537741Smckusick  * Change notion of root (``/'') directory.
53637741Smckusick  */
53754916Storek struct chroot_args {
53864410Sbostic 	char	*path;
53954916Storek };
54042441Smckusick /* ARGSUSED */
54142441Smckusick chroot(p, uap, retval)
54245914Smckusick 	struct proc *p;
54354916Storek 	struct chroot_args *uap;
54442441Smckusick 	int *retval;
54537741Smckusick {
54645914Smckusick 	register struct filedesc *fdp = p->p_fd;
54737741Smckusick 	int error;
54847540Skarels 	struct nameidata nd;
54937741Smckusick 
55047540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
55147540Skarels 		return (error);
55264410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
55364410Sbostic 	if (error = change_dir(&nd, p))
55447540Skarels 		return (error);
55545914Smckusick 	if (fdp->fd_rdir != NULL)
55645914Smckusick 		vrele(fdp->fd_rdir);
55752322Smckusick 	fdp->fd_rdir = nd.ni_vp;
55847540Skarels 	return (0);
5596254Sroot }
5606254Sroot 
56137Sbill /*
56237741Smckusick  * Common routine for chroot and chdir.
56337741Smckusick  */
56464410Sbostic static int
56564410Sbostic change_dir(ndp, p)
56652322Smckusick 	register struct nameidata *ndp;
56747540Skarels 	struct proc *p;
56837741Smckusick {
56937741Smckusick 	struct vnode *vp;
57037741Smckusick 	int error;
57137741Smckusick 
57252322Smckusick 	if (error = namei(ndp))
57337741Smckusick 		return (error);
57437741Smckusick 	vp = ndp->ni_vp;
57537741Smckusick 	if (vp->v_type != VDIR)
57637741Smckusick 		error = ENOTDIR;
57737741Smckusick 	else
57848026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
57937741Smckusick 	VOP_UNLOCK(vp);
58037741Smckusick 	if (error)
58137741Smckusick 		vrele(vp);
58237741Smckusick 	return (error);
58337741Smckusick }
58437741Smckusick 
58537741Smckusick /*
58642441Smckusick  * Check permissions, allocate an open file structure,
58742441Smckusick  * and call the device open routine if any.
5886254Sroot  */
58954916Storek struct open_args {
59064410Sbostic 	char	*path;
59164410Sbostic 	int	flags;
59254916Storek 	int	mode;
59354916Storek };
59442441Smckusick open(p, uap, retval)
59545914Smckusick 	struct proc *p;
59654916Storek 	register struct open_args *uap;
59742441Smckusick 	int *retval;
5986254Sroot {
59945914Smckusick 	register struct filedesc *fdp = p->p_fd;
60042441Smckusick 	register struct file *fp;
60150111Smckusick 	register struct vnode *vp;
60264410Sbostic 	int flags, cmode;
60337741Smckusick 	struct file *nfp;
60449945Smckusick 	int type, indx, error;
60549945Smckusick 	struct flock lf;
60647540Skarels 	struct nameidata nd;
60737741Smckusick 	extern struct fileops vnops;
6086254Sroot 
60945914Smckusick 	if (error = falloc(p, &nfp, &indx))
61047540Skarels 		return (error);
61137741Smckusick 	fp = nfp;
61264410Sbostic 	flags = FFLAGS(uap->flags);
61364410Sbostic 	cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
61464410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
61545202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
61664410Sbostic 	if (error = vn_open(&nd, flags, cmode)) {
61749980Smckusick 		ffree(fp);
61854723Smckusick 		if ((error == ENODEV || error == ENXIO) &&
61954723Smckusick 		    p->p_dupfd >= 0 && 			/* XXX from fdopen */
62064410Sbostic 		    (error =
62164410Sbostic 		        dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
62242441Smckusick 			*retval = indx;
62347540Skarels 			return (0);
62442441Smckusick 		}
62540884Smckusick 		if (error == ERESTART)
62640884Smckusick 			error = EINTR;
62747688Skarels 		fdp->fd_ofiles[indx] = NULL;
62847540Skarels 		return (error);
62912756Ssam 	}
63053828Spendry 	p->p_dupfd = 0;
63152322Smckusick 	vp = nd.ni_vp;
63264410Sbostic 	fp->f_flag = flags & FMASK;
63354348Smckusick 	fp->f_type = DTYPE_VNODE;
63454348Smckusick 	fp->f_ops = &vnops;
63554348Smckusick 	fp->f_data = (caddr_t)vp;
63664410Sbostic 	if (flags & (O_EXLOCK | O_SHLOCK)) {
63749945Smckusick 		lf.l_whence = SEEK_SET;
63849945Smckusick 		lf.l_start = 0;
63949945Smckusick 		lf.l_len = 0;
64064410Sbostic 		if (flags & O_EXLOCK)
64149945Smckusick 			lf.l_type = F_WRLCK;
64249945Smckusick 		else
64349945Smckusick 			lf.l_type = F_RDLCK;
64449945Smckusick 		type = F_FLOCK;
64564410Sbostic 		if ((flags & FNONBLOCK) == 0)
64649945Smckusick 			type |= F_WAIT;
64765757Smckusick 		VOP_UNLOCK(vp);
64850111Smckusick 		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
64950111Smckusick 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
65049980Smckusick 			ffree(fp);
65149945Smckusick 			fdp->fd_ofiles[indx] = NULL;
65249945Smckusick 			return (error);
65349945Smckusick 		}
65465757Smckusick 		VOP_LOCK(vp);
65549949Smckusick 		fp->f_flag |= FHASLOCK;
65649945Smckusick 	}
65750111Smckusick 	VOP_UNLOCK(vp);
65842441Smckusick 	*retval = indx;
65947540Skarels 	return (0);
6606254Sroot }
6616254Sroot 
66242955Smckusick #ifdef COMPAT_43
6636254Sroot /*
66464410Sbostic  * Create a file.
6656254Sroot  */
66654916Storek struct ocreat_args {
66764410Sbostic 	char	*path;
66864410Sbostic 	int	mode;
66954916Storek };
67042955Smckusick ocreat(p, uap, retval)
67142441Smckusick 	struct proc *p;
67254916Storek 	register struct ocreat_args *uap;
67342441Smckusick 	int *retval;
6746254Sroot {
67554916Storek 	struct open_args openuap;
67642441Smckusick 
67764410Sbostic 	openuap.path = uap->path;
67864410Sbostic 	openuap.mode = uap->mode;
67964410Sbostic 	openuap.flags = O_WRONLY | O_CREAT | O_TRUNC;
68047540Skarels 	return (open(p, &openuap, retval));
68142441Smckusick }
68242955Smckusick #endif /* COMPAT_43 */
68342441Smckusick 
68442441Smckusick /*
68564410Sbostic  * Create a special file.
68642441Smckusick  */
68754916Storek struct mknod_args {
68864410Sbostic 	char	*path;
68964410Sbostic 	int	mode;
69054916Storek 	int	dev;
69154916Storek };
69242441Smckusick /* ARGSUSED */
69342441Smckusick mknod(p, uap, retval)
69445914Smckusick 	struct proc *p;
69554916Storek 	register struct mknod_args *uap;
69642441Smckusick 	int *retval;
69742441Smckusick {
69837741Smckusick 	register struct vnode *vp;
69937741Smckusick 	struct vattr vattr;
70037741Smckusick 	int error;
70167575Spendry 	int whiteout;
70247540Skarels 	struct nameidata nd;
7036254Sroot 
70447540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
70547540Skarels 		return (error);
70664410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
70752322Smckusick 	if (error = namei(&nd))
70847540Skarels 		return (error);
70952322Smckusick 	vp = nd.ni_vp;
71064585Sbostic 	if (vp != NULL)
71137741Smckusick 		error = EEXIST;
71264585Sbostic 	else {
71364585Sbostic 		VATTR_NULL(&vattr);
71464585Sbostic 		vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
71564585Sbostic 		vattr.va_rdev = uap->dev;
71667575Spendry 		whiteout = 0;
71764585Sbostic 
71864585Sbostic 		switch (uap->mode & S_IFMT) {
71964585Sbostic 		case S_IFMT:	/* used by badsect to flag bad sectors */
72064585Sbostic 			vattr.va_type = VBAD;
72164585Sbostic 			break;
72264585Sbostic 		case S_IFCHR:
72364585Sbostic 			vattr.va_type = VCHR;
72464585Sbostic 			break;
72564585Sbostic 		case S_IFBLK:
72664585Sbostic 			vattr.va_type = VBLK;
72764585Sbostic 			break;
72867575Spendry 		case S_IFWHT:
72967575Spendry 			whiteout = 1;
73067575Spendry 			break;
73164585Sbostic 		default:
73264585Sbostic 			error = EINVAL;
73364585Sbostic 			break;
73464585Sbostic 		}
7356254Sroot 	}
73667747Spendry 	if (!error) {
73767654Smckusick 		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
73867747Spendry 		if (whiteout) {
73967747Spendry 			error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
74067747Spendry 			if (error)
74167747Spendry 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
74267747Spendry 			vput(nd.ni_dvp);
74367747Spendry 		} else {
74467747Spendry 			error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
74567747Spendry 						&nd.ni_cnd, &vattr);
74667747Spendry 		}
74742465Smckusick 	} else {
74852322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
74952322Smckusick 		if (nd.ni_dvp == vp)
75052322Smckusick 			vrele(nd.ni_dvp);
75143344Smckusick 		else
75252322Smckusick 			vput(nd.ni_dvp);
75342465Smckusick 		if (vp)
75442465Smckusick 			vrele(vp);
75542465Smckusick 	}
75647540Skarels 	return (error);
7576254Sroot }
7586254Sroot 
7596254Sroot /*
76064410Sbostic  * Create named pipe.
76140285Smckusick  */
76254916Storek struct mkfifo_args {
76364410Sbostic 	char	*path;
76464410Sbostic 	int	mode;
76554916Storek };
76642441Smckusick /* ARGSUSED */
76742441Smckusick mkfifo(p, uap, retval)
76845914Smckusick 	struct proc *p;
76954916Storek 	register struct mkfifo_args *uap;
77042441Smckusick 	int *retval;
77142441Smckusick {
77240285Smckusick 	struct vattr vattr;
77340285Smckusick 	int error;
77447540Skarels 	struct nameidata nd;
77540285Smckusick 
77640285Smckusick #ifndef FIFO
77747540Skarels 	return (EOPNOTSUPP);
77840285Smckusick #else
77964410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
78052322Smckusick 	if (error = namei(&nd))
78147540Skarels 		return (error);
78252322Smckusick 	if (nd.ni_vp != NULL) {
78352322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
78452322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
78552322Smckusick 			vrele(nd.ni_dvp);
78643344Smckusick 		else
78752322Smckusick 			vput(nd.ni_dvp);
78852322Smckusick 		vrele(nd.ni_vp);
78947540Skarels 		return (EEXIST);
79040285Smckusick 	}
79145785Sbostic 	VATTR_NULL(&vattr);
79245785Sbostic 	vattr.va_type = VFIFO;
79364410Sbostic 	vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
79467654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
79552322Smckusick 	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
79640285Smckusick #endif /* FIFO */
79740285Smckusick }
79840285Smckusick 
79940285Smckusick /*
80064410Sbostic  * Make a hard file link.
8016254Sroot  */
80254916Storek struct link_args {
80364410Sbostic 	char	*path;
80464410Sbostic 	char	*link;
80554916Storek };
80642441Smckusick /* ARGSUSED */
80742441Smckusick link(p, uap, retval)
80845914Smckusick 	struct proc *p;
80954916Storek 	register struct link_args *uap;
81042441Smckusick 	int *retval;
81142441Smckusick {
81264410Sbostic 	register struct vnode *vp;
81364410Sbostic 	struct nameidata nd;
81437741Smckusick 	int error;
8156254Sroot 
81664410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
81752322Smckusick 	if (error = namei(&nd))
81847540Skarels 		return (error);
81952322Smckusick 	vp = nd.ni_vp;
82064585Sbostic 	if (vp->v_type != VDIR ||
82164585Sbostic 	    (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
82264585Sbostic 		nd.ni_cnd.cn_nameiop = CREATE;
82364585Sbostic 		nd.ni_cnd.cn_flags = LOCKPARENT;
82464585Sbostic 		nd.ni_dirp = uap->link;
82564585Sbostic 		if ((error = namei(&nd)) == 0) {
82664585Sbostic 			if (nd.ni_vp != NULL)
82764585Sbostic 				error = EEXIST;
82864585Sbostic 			if (!error) {
82967654Smckusick 				VOP_LEASE(nd.ni_dvp, p, p->p_ucred,
83067654Smckusick 				    LEASE_WRITE);
83167654Smckusick 				VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
83264585Sbostic 				error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
83364585Sbostic 			} else {
83464585Sbostic 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
83564585Sbostic 				if (nd.ni_dvp == nd.ni_vp)
83664585Sbostic 					vrele(nd.ni_dvp);
83764585Sbostic 				else
83864585Sbostic 					vput(nd.ni_dvp);
83964585Sbostic 				if (nd.ni_vp)
84064585Sbostic 					vrele(nd.ni_vp);
84164585Sbostic 			}
84264585Sbostic 		}
84342465Smckusick 	}
84464585Sbostic 	vrele(vp);
84547540Skarels 	return (error);
8466254Sroot }
8476254Sroot 
8486254Sroot /*
84949365Smckusick  * Make a symbolic link.
8506254Sroot  */
85154916Storek struct symlink_args {
85264410Sbostic 	char	*path;
85364410Sbostic 	char	*link;
85454916Storek };
85542441Smckusick /* ARGSUSED */
85642441Smckusick symlink(p, uap, retval)
85745914Smckusick 	struct proc *p;
85854916Storek 	register struct symlink_args *uap;
85942441Smckusick 	int *retval;
86042441Smckusick {
86137741Smckusick 	struct vattr vattr;
86264410Sbostic 	char *path;
86337741Smckusick 	int error;
86447540Skarels 	struct nameidata nd;
8656254Sroot 
86664410Sbostic 	MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
86764410Sbostic 	if (error = copyinstr(uap->path, path, MAXPATHLEN, NULL))
86842465Smckusick 		goto out;
86964410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p);
87052322Smckusick 	if (error = namei(&nd))
87142465Smckusick 		goto out;
87252322Smckusick 	if (nd.ni_vp) {
87352322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
87452322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
87552322Smckusick 			vrele(nd.ni_dvp);
87643344Smckusick 		else
87752322Smckusick 			vput(nd.ni_dvp);
87852322Smckusick 		vrele(nd.ni_vp);
87937741Smckusick 		error = EEXIST;
88037741Smckusick 		goto out;
8816254Sroot 	}
88241362Smckusick 	VATTR_NULL(&vattr);
88364410Sbostic 	vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
88467654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
88564410Sbostic 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
88637741Smckusick out:
88764410Sbostic 	FREE(path, M_NAMEI);
88847540Skarels 	return (error);
8896254Sroot }
8906254Sroot 
8916254Sroot /*
89267518Spendry  * Delete a whiteout from the filesystem.
89367518Spendry  */
89467518Spendry struct unwhiteout_args {
89567518Spendry 	char	*path;
89667518Spendry };
89767518Spendry /* ARGSUSED */
89867518Spendry unwhiteout(p, uap, retval)
89967518Spendry 	struct proc *p;
90067518Spendry 	struct unwhiteout_args *uap;
90167518Spendry 	int *retval;
90267518Spendry {
90367518Spendry 	int error;
90467518Spendry 	struct nameidata nd;
90567518Spendry 
90667575Spendry 	NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE, uap->path, p);
90767575Spendry 	error = namei(&nd);
90867575Spendry 	if (error)
90967518Spendry 		return (error);
91067575Spendry 
91167575Spendry 	if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
91267518Spendry 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
91367518Spendry 		if (nd.ni_dvp == nd.ni_vp)
91467518Spendry 			vrele(nd.ni_dvp);
91567518Spendry 		else
91667518Spendry 			vput(nd.ni_dvp);
91767518Spendry 		if (nd.ni_vp)
91867518Spendry 			vrele(nd.ni_vp);
91967518Spendry 		return (EEXIST);
92067518Spendry 	}
92167575Spendry 
92267654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
92367747Spendry 	if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE))
92467575Spendry 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
92567518Spendry 	vput(nd.ni_dvp);
92667518Spendry 	return (error);
92767518Spendry }
92867518Spendry 
92967518Spendry /*
93049365Smckusick  * Delete a name from the filesystem.
9316254Sroot  */
93254916Storek struct unlink_args {
93364410Sbostic 	char	*path;
93454916Storek };
93542441Smckusick /* ARGSUSED */
93642441Smckusick unlink(p, uap, retval)
93745914Smckusick 	struct proc *p;
93854916Storek 	struct unlink_args *uap;
93942441Smckusick 	int *retval;
9406254Sroot {
94137741Smckusick 	register struct vnode *vp;
94237741Smckusick 	int error;
94347540Skarels 	struct nameidata nd;
9446254Sroot 
94564410Sbostic 	NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
94652322Smckusick 	if (error = namei(&nd))
94747540Skarels 		return (error);
94852322Smckusick 	vp = nd.ni_vp;
94967654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
95059382Smckusick 	VOP_LOCK(vp);
95164410Sbostic 
95264585Sbostic 	if (vp->v_type != VDIR ||
95364585Sbostic 	    (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
95464585Sbostic 		/*
95564585Sbostic 		 * The root of a mounted filesystem cannot be deleted.
95664585Sbostic 		 */
95764585Sbostic 		if (vp->v_flag & VROOT)
95864585Sbostic 			error = EBUSY;
95964585Sbostic 		else
96064585Sbostic 			(void)vnode_pager_uncache(vp);
96164585Sbostic 	}
96264585Sbostic 
96364585Sbostic 	if (!error) {
96467654Smckusick 		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
96552322Smckusick 		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
96642465Smckusick 	} else {
96752322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
96852322Smckusick 		if (nd.ni_dvp == vp)
96952322Smckusick 			vrele(nd.ni_dvp);
97043344Smckusick 		else
97152322Smckusick 			vput(nd.ni_dvp);
97267575Spendry 		if (vp != NULLVP)
97367575Spendry 			vput(vp);
97442465Smckusick 	}
97547540Skarels 	return (error);
9766254Sroot }
9776254Sroot 
97864410Sbostic /*
97964410Sbostic  * Reposition read/write file offset.
98064410Sbostic  */
98160428Smckusick struct lseek_args {
98264410Sbostic 	int	fd;
98354863Storek 	int	pad;
98464410Sbostic 	off_t	offset;
98564410Sbostic 	int	whence;
98654863Storek };
98760414Smckusick lseek(p, uap, retval)
98853468Smckusick 	struct proc *p;
98960428Smckusick 	register struct lseek_args *uap;
99054916Storek 	int *retval;
99142441Smckusick {
99247540Skarels 	struct ucred *cred = p->p_ucred;
99345914Smckusick 	register struct filedesc *fdp = p->p_fd;
99442441Smckusick 	register struct file *fp;
99537741Smckusick 	struct vattr vattr;
99637741Smckusick 	int error;
9976254Sroot 
99864410Sbostic 	if ((u_int)uap->fd >= fdp->fd_nfiles ||
99964410Sbostic 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
100047540Skarels 		return (EBADF);
100137741Smckusick 	if (fp->f_type != DTYPE_VNODE)
100247540Skarels 		return (ESPIPE);
100364410Sbostic 	switch (uap->whence) {
100413878Ssam 	case L_INCR:
100564410Sbostic 		fp->f_offset += uap->offset;
100613878Ssam 		break;
100713878Ssam 	case L_XTND:
100864410Sbostic 		if (error =
100964410Sbostic 		    VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p))
101047540Skarels 			return (error);
101164410Sbostic 		fp->f_offset = uap->offset + vattr.va_size;
101213878Ssam 		break;
101313878Ssam 	case L_SET:
101464410Sbostic 		fp->f_offset = uap->offset;
101513878Ssam 		break;
101613878Ssam 	default:
101747540Skarels 		return (EINVAL);
101813878Ssam 	}
101954916Storek 	*(off_t *)retval = fp->f_offset;
102047540Skarels 	return (0);
10216254Sroot }
10226254Sroot 
102360414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
10246254Sroot /*
102564410Sbostic  * Reposition read/write file offset.
102660036Smckusick  */
102760428Smckusick struct olseek_args {
102864410Sbostic 	int	fd;
102964410Sbostic 	long	offset;
103064410Sbostic 	int	whence;
103160036Smckusick };
103260414Smckusick olseek(p, uap, retval)
103360036Smckusick 	struct proc *p;
103460428Smckusick 	register struct olseek_args *uap;
103560036Smckusick 	int *retval;
103660036Smckusick {
103760428Smckusick 	struct lseek_args nuap;
103860036Smckusick 	off_t qret;
103960036Smckusick 	int error;
104060036Smckusick 
104164410Sbostic 	nuap.fd = uap->fd;
104264410Sbostic 	nuap.offset = uap->offset;
104364410Sbostic 	nuap.whence = uap->whence;
104460428Smckusick 	error = lseek(p, &nuap, &qret);
104560036Smckusick 	*(long *)retval = qret;
104660036Smckusick 	return (error);
104760036Smckusick }
104860414Smckusick #endif /* COMPAT_43 */
104960036Smckusick 
105060036Smckusick /*
105149365Smckusick  * Check access permissions.
10526254Sroot  */
105363427Sbostic struct access_args {
105464410Sbostic 	char	*path;
105564410Sbostic 	int	flags;
105654916Storek };
105763427Sbostic access(p, uap, retval)
105845914Smckusick 	struct proc *p;
105963427Sbostic 	register struct access_args *uap;
106042441Smckusick 	int *retval;
106142441Smckusick {
106247540Skarels 	register struct ucred *cred = p->p_ucred;
106337741Smckusick 	register struct vnode *vp;
106464585Sbostic 	int error, flags, t_gid, t_uid;
106547540Skarels 	struct nameidata nd;
10666254Sroot 
106764585Sbostic 	t_uid = cred->cr_uid;
106864585Sbostic 	t_gid = cred->cr_groups[0];
106947540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
107047540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
107164410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
107252322Smckusick 	if (error = namei(&nd))
107337741Smckusick 		goto out1;
107452322Smckusick 	vp = nd.ni_vp;
107564410Sbostic 
107664410Sbostic 	/* Flags == 0 means only check for existence. */
107764410Sbostic 	if (uap->flags) {
107864410Sbostic 		flags = 0;
107964410Sbostic 		if (uap->flags & R_OK)
108064410Sbostic 			flags |= VREAD;
108164410Sbostic 		if (uap->flags & W_OK)
108264410Sbostic 			flags |= VWRITE;
108364410Sbostic 		if (uap->flags & X_OK)
108464410Sbostic 			flags |= VEXEC;
108564410Sbostic 		if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
108664410Sbostic 			error = VOP_ACCESS(vp, flags, cred, p);
10876254Sroot 	}
108837741Smckusick 	vput(vp);
108937741Smckusick out1:
109064585Sbostic 	cred->cr_uid = t_uid;
109164585Sbostic 	cred->cr_groups[0] = t_gid;
109247540Skarels 	return (error);
10936254Sroot }
10946254Sroot 
109554348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
10966254Sroot /*
109764410Sbostic  * Get file status; this version follows links.
109837Sbill  */
109954916Storek struct ostat_args {
110064410Sbostic 	char	*path;
110154916Storek 	struct ostat *ub;
110254916Storek };
110342441Smckusick /* ARGSUSED */
110453759Smckusick ostat(p, uap, retval)
110545914Smckusick 	struct proc *p;
110654916Storek 	register struct ostat_args *uap;
110753468Smckusick 	int *retval;
110853468Smckusick {
110953468Smckusick 	struct stat sb;
111053468Smckusick 	struct ostat osb;
111153468Smckusick 	int error;
111253468Smckusick 	struct nameidata nd;
111353468Smckusick 
111464410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
111553468Smckusick 	if (error = namei(&nd))
111653468Smckusick 		return (error);
111753468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
111853468Smckusick 	vput(nd.ni_vp);
111953468Smckusick 	if (error)
112053468Smckusick 		return (error);
112153468Smckusick 	cvtstat(&sb, &osb);
112253468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
112353468Smckusick 	return (error);
112453468Smckusick }
112553468Smckusick 
112653468Smckusick /*
112764410Sbostic  * Get file status; this version does not follow links.
112853468Smckusick  */
112954916Storek struct olstat_args {
113064410Sbostic 	char	*path;
113154916Storek 	struct ostat *ub;
113254916Storek };
113353468Smckusick /* ARGSUSED */
113453759Smckusick olstat(p, uap, retval)
113553468Smckusick 	struct proc *p;
113654916Storek 	register struct olstat_args *uap;
113753468Smckusick 	int *retval;
113853468Smckusick {
1139*67748Smckusick 	struct vnode *vp, *dvp;
1140*67748Smckusick 	struct stat sb, sb1;
114153468Smckusick 	struct ostat osb;
114253468Smckusick 	int error;
114353468Smckusick 	struct nameidata nd;
114453468Smckusick 
1145*67748Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
1146*67748Smckusick 	    uap->path, p);
114753468Smckusick 	if (error = namei(&nd))
114853468Smckusick 		return (error);
1149*67748Smckusick 	/*
1150*67748Smckusick 	 * For symbolic links, always return the attributes of its
1151*67748Smckusick 	 * containing directory, except for mode, size, and links.
1152*67748Smckusick 	 */
1153*67748Smckusick 	vp = nd.ni_vp;
1154*67748Smckusick 	dvp = nd.ni_dvp;
1155*67748Smckusick 	if (vp->v_type != VLNK) {
1156*67748Smckusick 		if (dvp == vp)
1157*67748Smckusick 			vrele(dvp);
1158*67748Smckusick 		else
1159*67748Smckusick 			vput(dvp);
1160*67748Smckusick 		error = vn_stat(vp, &sb, p);
1161*67748Smckusick 		vput(vp);
1162*67748Smckusick 		if (error)
1163*67748Smckusick 			return (error);
1164*67748Smckusick 	} else {
1165*67748Smckusick 		error = vn_stat(dvp, &sb, p);
1166*67748Smckusick 		vput(dvp);
1167*67748Smckusick 		if (error) {
1168*67748Smckusick 			vput(vp);
1169*67748Smckusick 			return (error);
1170*67748Smckusick 		}
1171*67748Smckusick 		error = vn_stat(vp, &sb1, p);
1172*67748Smckusick 		vput(vp);
1173*67748Smckusick 		if (error)
1174*67748Smckusick 			return (error);
1175*67748Smckusick 		sb.st_mode &= ~S_IFDIR;
1176*67748Smckusick 		sb.st_mode |= S_IFLNK;
1177*67748Smckusick 		sb.st_nlink = sb1.st_nlink;
1178*67748Smckusick 		sb.st_size = sb1.st_size;
1179*67748Smckusick 		sb.st_blocks = sb1.st_blocks;
1180*67748Smckusick 	}
118153468Smckusick 	cvtstat(&sb, &osb);
118253468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
118353468Smckusick 	return (error);
118453468Smckusick }
118553468Smckusick 
118653468Smckusick /*
118764410Sbostic  * Convert from an old to a new stat structure.
118853468Smckusick  */
118953468Smckusick cvtstat(st, ost)
119053468Smckusick 	struct stat *st;
119153468Smckusick 	struct ostat *ost;
119253468Smckusick {
119353468Smckusick 
119453468Smckusick 	ost->st_dev = st->st_dev;
119553468Smckusick 	ost->st_ino = st->st_ino;
119653468Smckusick 	ost->st_mode = st->st_mode;
119753468Smckusick 	ost->st_nlink = st->st_nlink;
119853468Smckusick 	ost->st_uid = st->st_uid;
119953468Smckusick 	ost->st_gid = st->st_gid;
120053468Smckusick 	ost->st_rdev = st->st_rdev;
120153468Smckusick 	if (st->st_size < (quad_t)1 << 32)
120253468Smckusick 		ost->st_size = st->st_size;
120353468Smckusick 	else
120453468Smckusick 		ost->st_size = -2;
120553468Smckusick 	ost->st_atime = st->st_atime;
120653468Smckusick 	ost->st_mtime = st->st_mtime;
120753468Smckusick 	ost->st_ctime = st->st_ctime;
120853468Smckusick 	ost->st_blksize = st->st_blksize;
120953468Smckusick 	ost->st_blocks = st->st_blocks;
121053468Smckusick 	ost->st_flags = st->st_flags;
121153468Smckusick 	ost->st_gen = st->st_gen;
121253468Smckusick }
121354348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
121453468Smckusick 
121553468Smckusick /*
121664410Sbostic  * Get file status; this version follows links.
121753468Smckusick  */
121854916Storek struct stat_args {
121964410Sbostic 	char	*path;
122054916Storek 	struct stat *ub;
122154916Storek };
122253468Smckusick /* ARGSUSED */
122353759Smckusick stat(p, uap, retval)
122453468Smckusick 	struct proc *p;
122554916Storek 	register struct stat_args *uap;
122642441Smckusick 	int *retval;
122737Sbill {
122842441Smckusick 	struct stat sb;
122942441Smckusick 	int error;
123047540Skarels 	struct nameidata nd;
123137Sbill 
123264410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
123352322Smckusick 	if (error = namei(&nd))
123447540Skarels 		return (error);
123552322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
123652322Smckusick 	vput(nd.ni_vp);
123742441Smckusick 	if (error)
123847540Skarels 		return (error);
123942441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
124047540Skarels 	return (error);
124137Sbill }
124237Sbill 
124337Sbill /*
124464410Sbostic  * Get file status; this version does not follow links.
12455992Swnj  */
124654916Storek struct lstat_args {
124764410Sbostic 	char	*path;
124854916Storek 	struct stat *ub;
124954916Storek };
125042441Smckusick /* ARGSUSED */
125153759Smckusick lstat(p, uap, retval)
125245914Smckusick 	struct proc *p;
125354916Storek 	register struct lstat_args *uap;
125442441Smckusick 	int *retval;
125542441Smckusick {
125637741Smckusick 	int error;
125759373Smckusick 	struct vnode *vp, *dvp;
125859373Smckusick 	struct stat sb, sb1;
125947540Skarels 	struct nameidata nd;
12605992Swnj 
126159373Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
126264410Sbostic 	    uap->path, p);
126352322Smckusick 	if (error = namei(&nd))
126447540Skarels 		return (error);
126559373Smckusick 	/*
126659373Smckusick 	 * For symbolic links, always return the attributes of its
126759373Smckusick 	 * containing directory, except for mode, size, and links.
126859373Smckusick 	 */
126959373Smckusick 	vp = nd.ni_vp;
127059373Smckusick 	dvp = nd.ni_dvp;
127159373Smckusick 	if (vp->v_type != VLNK) {
127259373Smckusick 		if (dvp == vp)
127359373Smckusick 			vrele(dvp);
127459373Smckusick 		else
127559373Smckusick 			vput(dvp);
127659373Smckusick 		error = vn_stat(vp, &sb, p);
127759373Smckusick 		vput(vp);
127859373Smckusick 		if (error)
127959373Smckusick 			return (error);
128059373Smckusick 	} else {
128159373Smckusick 		error = vn_stat(dvp, &sb, p);
128259373Smckusick 		vput(dvp);
128359373Smckusick 		if (error) {
128459373Smckusick 			vput(vp);
128559373Smckusick 			return (error);
128659373Smckusick 		}
128759373Smckusick 		error = vn_stat(vp, &sb1, p);
128859373Smckusick 		vput(vp);
128959373Smckusick 		if (error)
129059373Smckusick 			return (error);
129159373Smckusick 		sb.st_mode &= ~S_IFDIR;
129259373Smckusick 		sb.st_mode |= S_IFLNK;
129359373Smckusick 		sb.st_nlink = sb1.st_nlink;
129459373Smckusick 		sb.st_size = sb1.st_size;
129559373Smckusick 		sb.st_blocks = sb1.st_blocks;
129659373Smckusick 	}
129737741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
129847540Skarels 	return (error);
12995992Swnj }
13005992Swnj 
13015992Swnj /*
130264410Sbostic  * Get configurable pathname variables.
130360414Smckusick  */
130460414Smckusick struct pathconf_args {
130564410Sbostic 	char	*path;
130660414Smckusick 	int	name;
130760414Smckusick };
130860414Smckusick /* ARGSUSED */
130960414Smckusick pathconf(p, uap, retval)
131060414Smckusick 	struct proc *p;
131160414Smckusick 	register struct pathconf_args *uap;
131260414Smckusick 	int *retval;
131360414Smckusick {
131460414Smckusick 	int error;
131560414Smckusick 	struct nameidata nd;
131660414Smckusick 
131764410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
131860414Smckusick 	if (error = namei(&nd))
131960414Smckusick 		return (error);
132060414Smckusick 	error = VOP_PATHCONF(nd.ni_vp, uap->name, retval);
132160414Smckusick 	vput(nd.ni_vp);
132260414Smckusick 	return (error);
132360414Smckusick }
132460414Smckusick 
132560414Smckusick /*
132649365Smckusick  * Return target name of a symbolic link.
132737Sbill  */
132854916Storek struct readlink_args {
132964410Sbostic 	char	*path;
133054916Storek 	char	*buf;
133154916Storek 	int	count;
133254916Storek };
133342441Smckusick /* ARGSUSED */
133442441Smckusick readlink(p, uap, retval)
133545914Smckusick 	struct proc *p;
133654916Storek 	register struct readlink_args *uap;
133742441Smckusick 	int *retval;
133842441Smckusick {
133937741Smckusick 	register struct vnode *vp;
134037741Smckusick 	struct iovec aiov;
134137741Smckusick 	struct uio auio;
134237741Smckusick 	int error;
134347540Skarels 	struct nameidata nd;
13445992Swnj 
134564410Sbostic 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
134652322Smckusick 	if (error = namei(&nd))
134747540Skarels 		return (error);
134852322Smckusick 	vp = nd.ni_vp;
134964410Sbostic 	if (vp->v_type != VLNK)
135037741Smckusick 		error = EINVAL;
135164410Sbostic 	else {
135264410Sbostic 		aiov.iov_base = uap->buf;
135364410Sbostic 		aiov.iov_len = uap->count;
135464410Sbostic 		auio.uio_iov = &aiov;
135564410Sbostic 		auio.uio_iovcnt = 1;
135664410Sbostic 		auio.uio_offset = 0;
135764410Sbostic 		auio.uio_rw = UIO_READ;
135864410Sbostic 		auio.uio_segflg = UIO_USERSPACE;
135964410Sbostic 		auio.uio_procp = p;
136064410Sbostic 		auio.uio_resid = uap->count;
136164410Sbostic 		error = VOP_READLINK(vp, &auio, p->p_ucred);
13625992Swnj 	}
136337741Smckusick 	vput(vp);
136442441Smckusick 	*retval = uap->count - auio.uio_resid;
136547540Skarels 	return (error);
13665992Swnj }
13675992Swnj 
13689167Ssam /*
136964410Sbostic  * Change flags of a file given a path name.
137038259Smckusick  */
137154916Storek struct chflags_args {
137264410Sbostic 	char	*path;
137354916Storek 	int	flags;
137454916Storek };
137542441Smckusick /* ARGSUSED */
137642441Smckusick chflags(p, uap, retval)
137745914Smckusick 	struct proc *p;
137854916Storek 	register struct chflags_args *uap;
137942441Smckusick 	int *retval;
138042441Smckusick {
138138259Smckusick 	register struct vnode *vp;
138238259Smckusick 	struct vattr vattr;
138338259Smckusick 	int error;
138447540Skarels 	struct nameidata nd;
138538259Smckusick 
138664410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
138752322Smckusick 	if (error = namei(&nd))
138847540Skarels 		return (error);
138952322Smckusick 	vp = nd.ni_vp;
139067654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
139159382Smckusick 	VOP_LOCK(vp);
139264410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
139338259Smckusick 		error = EROFS;
139464410Sbostic 	else {
139564410Sbostic 		VATTR_NULL(&vattr);
139664410Sbostic 		vattr.va_flags = uap->flags;
139764410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
139838259Smckusick 	}
139938259Smckusick 	vput(vp);
140047540Skarels 	return (error);
140138259Smckusick }
140238259Smckusick 
140338259Smckusick /*
140438259Smckusick  * Change flags of a file given a file descriptor.
140538259Smckusick  */
140654916Storek struct fchflags_args {
140754916Storek 	int	fd;
140854916Storek 	int	flags;
140954916Storek };
141042441Smckusick /* ARGSUSED */
141142441Smckusick fchflags(p, uap, retval)
141245914Smckusick 	struct proc *p;
141354916Storek 	register struct fchflags_args *uap;
141442441Smckusick 	int *retval;
141542441Smckusick {
141638259Smckusick 	struct vattr vattr;
141738259Smckusick 	struct vnode *vp;
141838259Smckusick 	struct file *fp;
141938259Smckusick 	int error;
142038259Smckusick 
142145914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
142247540Skarels 		return (error);
142338259Smckusick 	vp = (struct vnode *)fp->f_data;
142467654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
142538259Smckusick 	VOP_LOCK(vp);
142664410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
142738259Smckusick 		error = EROFS;
142864410Sbostic 	else {
142964410Sbostic 		VATTR_NULL(&vattr);
143064410Sbostic 		vattr.va_flags = uap->flags;
143164410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
143238259Smckusick 	}
143338259Smckusick 	VOP_UNLOCK(vp);
143447540Skarels 	return (error);
143538259Smckusick }
143638259Smckusick 
143738259Smckusick /*
14389167Ssam  * Change mode of a file given path name.
14399167Ssam  */
144054916Storek struct chmod_args {
144164410Sbostic 	char	*path;
144264410Sbostic 	int	mode;
144354916Storek };
144442441Smckusick /* ARGSUSED */
144542441Smckusick chmod(p, uap, retval)
144645914Smckusick 	struct proc *p;
144754916Storek 	register struct chmod_args *uap;
144842441Smckusick 	int *retval;
144942441Smckusick {
145037741Smckusick 	register struct vnode *vp;
145137741Smckusick 	struct vattr vattr;
145237741Smckusick 	int error;
145347540Skarels 	struct nameidata nd;
14545992Swnj 
145564410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
145652322Smckusick 	if (error = namei(&nd))
145747540Skarels 		return (error);
145852322Smckusick 	vp = nd.ni_vp;
145967654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
146059382Smckusick 	VOP_LOCK(vp);
146164410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
146237741Smckusick 		error = EROFS;
146364410Sbostic 	else {
146464410Sbostic 		VATTR_NULL(&vattr);
146564410Sbostic 		vattr.va_mode = uap->mode & ALLPERMS;
146664410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
146737741Smckusick 	}
146837741Smckusick 	vput(vp);
146947540Skarels 	return (error);
14707701Ssam }
14717439Sroot 
14729167Ssam /*
14739167Ssam  * Change mode of a file given a file descriptor.
14749167Ssam  */
147554916Storek struct fchmod_args {
147654916Storek 	int	fd;
147764410Sbostic 	int	mode;
147854916Storek };
147942441Smckusick /* ARGSUSED */
148042441Smckusick fchmod(p, uap, retval)
148145914Smckusick 	struct proc *p;
148254916Storek 	register struct fchmod_args *uap;
148342441Smckusick 	int *retval;
148442441Smckusick {
148537741Smckusick 	struct vattr vattr;
148637741Smckusick 	struct vnode *vp;
148737741Smckusick 	struct file *fp;
148837741Smckusick 	int error;
14897701Ssam 
149045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
149147540Skarels 		return (error);
149237741Smckusick 	vp = (struct vnode *)fp->f_data;
149367654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
149437741Smckusick 	VOP_LOCK(vp);
149564410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
149637741Smckusick 		error = EROFS;
149764410Sbostic 	else {
149864410Sbostic 		VATTR_NULL(&vattr);
149964410Sbostic 		vattr.va_mode = uap->mode & ALLPERMS;
150064410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
15017439Sroot 	}
150237741Smckusick 	VOP_UNLOCK(vp);
150347540Skarels 	return (error);
15045992Swnj }
15055992Swnj 
15069167Ssam /*
15079167Ssam  * Set ownership given a path name.
15089167Ssam  */
150954916Storek struct chown_args {
151064410Sbostic 	char	*path;
151154916Storek 	int	uid;
151254916Storek 	int	gid;
151354916Storek };
151442441Smckusick /* ARGSUSED */
151542441Smckusick chown(p, uap, retval)
151645914Smckusick 	struct proc *p;
151754916Storek 	register struct chown_args *uap;
151842441Smckusick 	int *retval;
151942441Smckusick {
152037741Smckusick 	register struct vnode *vp;
152137741Smckusick 	struct vattr vattr;
152237741Smckusick 	int error;
152347540Skarels 	struct nameidata nd;
152437Sbill 
152566510Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
152652322Smckusick 	if (error = namei(&nd))
152747540Skarels 		return (error);
152852322Smckusick 	vp = nd.ni_vp;
152967654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
153059382Smckusick 	VOP_LOCK(vp);
153164410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
153237741Smckusick 		error = EROFS;
153364410Sbostic 	else {
153464410Sbostic 		VATTR_NULL(&vattr);
153564410Sbostic 		vattr.va_uid = uap->uid;
153664410Sbostic 		vattr.va_gid = uap->gid;
153764410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
153837741Smckusick 	}
153937741Smckusick 	vput(vp);
154047540Skarels 	return (error);
15417701Ssam }
15427439Sroot 
15439167Ssam /*
15449167Ssam  * Set ownership given a file descriptor.
15459167Ssam  */
154654916Storek struct fchown_args {
154754916Storek 	int	fd;
154854916Storek 	int	uid;
154954916Storek 	int	gid;
155054916Storek };
155142441Smckusick /* ARGSUSED */
155242441Smckusick fchown(p, uap, retval)
155345914Smckusick 	struct proc *p;
155454916Storek 	register struct fchown_args *uap;
155542441Smckusick 	int *retval;
155642441Smckusick {
155737741Smckusick 	struct vattr vattr;
155837741Smckusick 	struct vnode *vp;
155937741Smckusick 	struct file *fp;
156037741Smckusick 	int error;
15617701Ssam 
156245914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
156347540Skarels 		return (error);
156437741Smckusick 	vp = (struct vnode *)fp->f_data;
156567654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
156637741Smckusick 	VOP_LOCK(vp);
156764410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
156837741Smckusick 		error = EROFS;
156964410Sbostic 	else {
157064410Sbostic 		VATTR_NULL(&vattr);
157164410Sbostic 		vattr.va_uid = uap->uid;
157264410Sbostic 		vattr.va_gid = uap->gid;
157364410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
157437741Smckusick 	}
157537741Smckusick 	VOP_UNLOCK(vp);
157647540Skarels 	return (error);
15777701Ssam }
15787701Ssam 
157942441Smckusick /*
158042441Smckusick  * Set the access and modification times of a file.
158142441Smckusick  */
158254916Storek struct utimes_args {
158364410Sbostic 	char	*path;
158454916Storek 	struct	timeval *tptr;
158554916Storek };
158642441Smckusick /* ARGSUSED */
158742441Smckusick utimes(p, uap, retval)
158845914Smckusick 	struct proc *p;
158954916Storek 	register struct utimes_args *uap;
159042441Smckusick 	int *retval;
159142441Smckusick {
159237741Smckusick 	register struct vnode *vp;
159311811Ssam 	struct timeval tv[2];
159437741Smckusick 	struct vattr vattr;
159558840Storek 	int error;
159647540Skarels 	struct nameidata nd;
159711811Ssam 
159858505Sbostic 	VATTR_NULL(&vattr);
159958505Sbostic 	if (uap->tptr == NULL) {
160058505Sbostic 		microtime(&tv[0]);
160158505Sbostic 		tv[1] = tv[0];
160258548Sbostic 		vattr.va_vaflags |= VA_UTIMES_NULL;
160358505Sbostic 	} else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
160458505Sbostic   		return (error);
160564410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
160652322Smckusick 	if (error = namei(&nd))
160747540Skarels 		return (error);
160852322Smckusick 	vp = nd.ni_vp;
160967654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
161059382Smckusick 	VOP_LOCK(vp);
161164410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
161237741Smckusick 		error = EROFS;
161364410Sbostic 	else {
161464410Sbostic 		vattr.va_atime.ts_sec = tv[0].tv_sec;
161564410Sbostic 		vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
161664410Sbostic 		vattr.va_mtime.ts_sec = tv[1].tv_sec;
161764410Sbostic 		vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
161864410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
161921015Smckusick 	}
162037741Smckusick 	vput(vp);
162147540Skarels 	return (error);
162211811Ssam }
162311811Ssam 
162464410Sbostic /*
162564410Sbostic  * Truncate a file given its path name.
162664410Sbostic  */
162760428Smckusick struct truncate_args {
162864410Sbostic 	char	*path;
162954863Storek 	int	pad;
163054863Storek 	off_t	length;
163154863Storek };
163253468Smckusick /* ARGSUSED */
163360414Smckusick truncate(p, uap, retval)
163453468Smckusick 	struct proc *p;
163560428Smckusick 	register struct truncate_args *uap;
163653468Smckusick 	int *retval;
163753468Smckusick {
163837741Smckusick 	register struct vnode *vp;
163937741Smckusick 	struct vattr vattr;
164037741Smckusick 	int error;
164147540Skarels 	struct nameidata nd;
16427701Ssam 
164364410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
164452322Smckusick 	if (error = namei(&nd))
164547540Skarels 		return (error);
164652322Smckusick 	vp = nd.ni_vp;
164767654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
164859382Smckusick 	VOP_LOCK(vp);
164964410Sbostic 	if (vp->v_type == VDIR)
165037741Smckusick 		error = EISDIR;
165164410Sbostic 	else if ((error = vn_writechk(vp)) == 0 &&
165264410Sbostic 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
165364410Sbostic 		VATTR_NULL(&vattr);
165464410Sbostic 		vattr.va_size = uap->length;
165564410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
16567701Ssam 	}
165737741Smckusick 	vput(vp);
165847540Skarels 	return (error);
16597701Ssam }
16607701Ssam 
166164410Sbostic /*
166264410Sbostic  * Truncate a file given a file descriptor.
166364410Sbostic  */
166460428Smckusick struct ftruncate_args {
166554863Storek 	int	fd;
166654863Storek 	int	pad;
166754863Storek 	off_t	length;
166854863Storek };
166942441Smckusick /* ARGSUSED */
167060414Smckusick ftruncate(p, uap, retval)
167145914Smckusick 	struct proc *p;
167260428Smckusick 	register struct ftruncate_args *uap;
167342441Smckusick 	int *retval;
167442441Smckusick {
167537741Smckusick 	struct vattr vattr;
167637741Smckusick 	struct vnode *vp;
16777701Ssam 	struct file *fp;
167837741Smckusick 	int error;
16797701Ssam 
168045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
168147540Skarels 		return (error);
168237741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
168347540Skarels 		return (EINVAL);
168437741Smckusick 	vp = (struct vnode *)fp->f_data;
168567654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
168637741Smckusick 	VOP_LOCK(vp);
168764410Sbostic 	if (vp->v_type == VDIR)
168837741Smckusick 		error = EISDIR;
168964410Sbostic 	else if ((error = vn_writechk(vp)) == 0) {
169064410Sbostic 		VATTR_NULL(&vattr);
169164410Sbostic 		vattr.va_size = uap->length;
169264410Sbostic 		error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
16937701Ssam 	}
169437741Smckusick 	VOP_UNLOCK(vp);
169547540Skarels 	return (error);
16967701Ssam }
16977701Ssam 
169854863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
16999167Ssam /*
170054863Storek  * Truncate a file given its path name.
170154863Storek  */
170260428Smckusick struct otruncate_args {
170364410Sbostic 	char	*path;
170454916Storek 	long	length;
170554916Storek };
170654863Storek /* ARGSUSED */
170760105Smckusick otruncate(p, uap, retval)
170854863Storek 	struct proc *p;
170960428Smckusick 	register struct otruncate_args *uap;
171054863Storek 	int *retval;
171154863Storek {
171260428Smckusick 	struct truncate_args nuap;
171354863Storek 
171464410Sbostic 	nuap.path = uap->path;
171554863Storek 	nuap.length = uap->length;
171660428Smckusick 	return (truncate(p, &nuap, retval));
171754863Storek }
171854863Storek 
171954863Storek /*
172054863Storek  * Truncate a file given a file descriptor.
172154863Storek  */
172260428Smckusick struct oftruncate_args {
172354916Storek 	int	fd;
172454916Storek 	long	length;
172554916Storek };
172654863Storek /* ARGSUSED */
172760105Smckusick oftruncate(p, uap, retval)
172854863Storek 	struct proc *p;
172960428Smckusick 	register struct oftruncate_args *uap;
173054863Storek 	int *retval;
173154863Storek {
173260428Smckusick 	struct ftruncate_args nuap;
173354863Storek 
173454863Storek 	nuap.fd = uap->fd;
173554863Storek 	nuap.length = uap->length;
173660428Smckusick 	return (ftruncate(p, &nuap, retval));
173754863Storek }
173854863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */
173954863Storek 
174054863Storek /*
174164410Sbostic  * Sync an open file.
17429167Ssam  */
174354916Storek struct fsync_args {
174454916Storek 	int	fd;
174554916Storek };
174642441Smckusick /* ARGSUSED */
174742441Smckusick fsync(p, uap, retval)
174845914Smckusick 	struct proc *p;
174954916Storek 	struct fsync_args *uap;
175042441Smckusick 	int *retval;
17519167Ssam {
175239592Smckusick 	register struct vnode *vp;
17539167Ssam 	struct file *fp;
175437741Smckusick 	int error;
17559167Ssam 
175645914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
175747540Skarels 		return (error);
175839592Smckusick 	vp = (struct vnode *)fp->f_data;
175939592Smckusick 	VOP_LOCK(vp);
176054441Smckusick 	error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
176139592Smckusick 	VOP_UNLOCK(vp);
176247540Skarels 	return (error);
17639167Ssam }
17649167Ssam 
17659167Ssam /*
176664410Sbostic  * Rename files.  Source and destination must either both be directories,
176764410Sbostic  * or both not be directories.  If target is a directory, it must be empty.
17689167Ssam  */
176954916Storek struct rename_args {
177054916Storek 	char	*from;
177154916Storek 	char	*to;
177254916Storek };
177342441Smckusick /* ARGSUSED */
177442441Smckusick rename(p, uap, retval)
177545914Smckusick 	struct proc *p;
177654916Storek 	register struct rename_args *uap;
177742441Smckusick 	int *retval;
177842441Smckusick {
177937741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
178049735Smckusick 	struct nameidata fromnd, tond;
178137741Smckusick 	int error;
17827701Ssam 
178352322Smckusick 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
178452322Smckusick 		uap->from, p);
178552322Smckusick 	if (error = namei(&fromnd))
178647540Skarels 		return (error);
178749735Smckusick 	fvp = fromnd.ni_vp;
178852322Smckusick 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
178952322Smckusick 		UIO_USERSPACE, uap->to, p);
179052322Smckusick 	if (error = namei(&tond)) {
179152230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
179249735Smckusick 		vrele(fromnd.ni_dvp);
179342465Smckusick 		vrele(fvp);
179442465Smckusick 		goto out1;
179542465Smckusick 	}
179637741Smckusick 	tdvp = tond.ni_dvp;
179737741Smckusick 	tvp = tond.ni_vp;
179837741Smckusick 	if (tvp != NULL) {
179937741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
180039242Sbostic 			error = ENOTDIR;
180137741Smckusick 			goto out;
180237741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
180339242Sbostic 			error = EISDIR;
180437741Smckusick 			goto out;
18059167Ssam 		}
18069167Ssam 	}
180739286Smckusick 	if (fvp == tdvp)
180837741Smckusick 		error = EINVAL;
180939286Smckusick 	/*
181049735Smckusick 	 * If source is the same as the destination (that is the
181149735Smckusick 	 * same inode number with the same name in the same directory),
181239286Smckusick 	 * then there is nothing to do.
181339286Smckusick 	 */
181449735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
181552322Smckusick 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
181652322Smckusick 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
181752322Smckusick 	      fromnd.ni_cnd.cn_namelen))
181839286Smckusick 		error = -1;
181937741Smckusick out:
182042465Smckusick 	if (!error) {
182167654Smckusick 		VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE);
182252192Smckusick 		if (fromnd.ni_dvp != tdvp)
182367654Smckusick 			VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
182452192Smckusick 		if (tvp)
182567654Smckusick 			VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE);
182652230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
182752230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
182842465Smckusick 	} else {
182952230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
183043344Smckusick 		if (tdvp == tvp)
183143344Smckusick 			vrele(tdvp);
183243344Smckusick 		else
183343344Smckusick 			vput(tdvp);
183442465Smckusick 		if (tvp)
183542465Smckusick 			vput(tvp);
183652230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
183749735Smckusick 		vrele(fromnd.ni_dvp);
183842465Smckusick 		vrele(fvp);
18399167Ssam 	}
184049735Smckusick 	vrele(tond.ni_startdir);
184152322Smckusick 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
184237741Smckusick out1:
184366801Smckusick 	if (fromnd.ni_startdir)
184466801Smckusick 		vrele(fromnd.ni_startdir);
184552322Smckusick 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
184639286Smckusick 	if (error == -1)
184747540Skarels 		return (0);
184847540Skarels 	return (error);
18497701Ssam }
18507701Ssam 
18517535Sroot /*
185264410Sbostic  * Make a directory file.
185312756Ssam  */
185454916Storek struct mkdir_args {
185564410Sbostic 	char	*path;
185664410Sbostic 	int	mode;
185754916Storek };
185842441Smckusick /* ARGSUSED */
185942441Smckusick mkdir(p, uap, retval)
186045914Smckusick 	struct proc *p;
186154916Storek 	register struct mkdir_args *uap;
186242441Smckusick 	int *retval;
186342441Smckusick {
186437741Smckusick 	register struct vnode *vp;
186537741Smckusick 	struct vattr vattr;
186637741Smckusick 	int error;
186747540Skarels 	struct nameidata nd;
186812756Ssam 
186964410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
187052322Smckusick 	if (error = namei(&nd))
187147540Skarels 		return (error);
187252322Smckusick 	vp = nd.ni_vp;
187337741Smckusick 	if (vp != NULL) {
187452322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
187552322Smckusick 		if (nd.ni_dvp == vp)
187652322Smckusick 			vrele(nd.ni_dvp);
187743344Smckusick 		else
187852322Smckusick 			vput(nd.ni_dvp);
187942465Smckusick 		vrele(vp);
188047540Skarels 		return (EEXIST);
188112756Ssam 	}
188241362Smckusick 	VATTR_NULL(&vattr);
188337741Smckusick 	vattr.va_type = VDIR;
188464410Sbostic 	vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask;
188567654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
188652322Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
188738145Smckusick 	if (!error)
188852322Smckusick 		vput(nd.ni_vp);
188947540Skarels 	return (error);
189012756Ssam }
189112756Ssam 
189212756Ssam /*
189364410Sbostic  * Remove a directory file.
189412756Ssam  */
189554916Storek struct rmdir_args {
189664410Sbostic 	char	*path;
189754916Storek };
189842441Smckusick /* ARGSUSED */
189942441Smckusick rmdir(p, uap, retval)
190045914Smckusick 	struct proc *p;
190154916Storek 	struct rmdir_args *uap;
190242441Smckusick 	int *retval;
190312756Ssam {
190437741Smckusick 	register struct vnode *vp;
190537741Smckusick 	int error;
190647540Skarels 	struct nameidata nd;
190712756Ssam 
190864410Sbostic 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p);
190952322Smckusick 	if (error = namei(&nd))
191047540Skarels 		return (error);
191152322Smckusick 	vp = nd.ni_vp;
191237741Smckusick 	if (vp->v_type != VDIR) {
191337741Smckusick 		error = ENOTDIR;
191412756Ssam 		goto out;
191512756Ssam 	}
191612756Ssam 	/*
191737741Smckusick 	 * No rmdir "." please.
191812756Ssam 	 */
191952322Smckusick 	if (nd.ni_dvp == vp) {
192037741Smckusick 		error = EINVAL;
192112756Ssam 		goto out;
192212756Ssam 	}
192312756Ssam 	/*
192449365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
192512756Ssam 	 */
192637741Smckusick 	if (vp->v_flag & VROOT)
192737741Smckusick 		error = EBUSY;
192812756Ssam out:
192942465Smckusick 	if (!error) {
193067654Smckusick 		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
193167654Smckusick 		VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
193252322Smckusick 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
193342465Smckusick 	} else {
193452322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
193552322Smckusick 		if (nd.ni_dvp == vp)
193652322Smckusick 			vrele(nd.ni_dvp);
193743344Smckusick 		else
193852322Smckusick 			vput(nd.ni_dvp);
193942465Smckusick 		vput(vp);
194042465Smckusick 	}
194147540Skarels 	return (error);
194212756Ssam }
194312756Ssam 
194454620Smckusick #ifdef COMPAT_43
194537741Smckusick /*
194649365Smckusick  * Read a block of directory entries in a file system independent format.
194737741Smckusick  */
194854916Storek struct ogetdirentries_args {
194954916Storek 	int	fd;
195054916Storek 	char	*buf;
195164410Sbostic 	u_int	count;
195254916Storek 	long	*basep;
195354916Storek };
195454620Smckusick ogetdirentries(p, uap, retval)
195554620Smckusick 	struct proc *p;
195654916Storek 	register struct ogetdirentries_args *uap;
195754620Smckusick 	int *retval;
195854620Smckusick {
195954620Smckusick 	register struct vnode *vp;
196054620Smckusick 	struct file *fp;
196154620Smckusick 	struct uio auio, kuio;
196254620Smckusick 	struct iovec aiov, kiov;
196354620Smckusick 	struct dirent *dp, *edp;
196454620Smckusick 	caddr_t dirbuf;
196567362Smckusick 	int error, eofflag, readcnt;
196654969Smckusick 	long loff;
196754620Smckusick 
196854620Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
196954620Smckusick 		return (error);
197054620Smckusick 	if ((fp->f_flag & FREAD) == 0)
197154620Smckusick 		return (EBADF);
197254620Smckusick 	vp = (struct vnode *)fp->f_data;
197367362Smckusick unionread:
197454620Smckusick 	if (vp->v_type != VDIR)
197554620Smckusick 		return (EINVAL);
197654620Smckusick 	aiov.iov_base = uap->buf;
197754620Smckusick 	aiov.iov_len = uap->count;
197854620Smckusick 	auio.uio_iov = &aiov;
197954620Smckusick 	auio.uio_iovcnt = 1;
198054620Smckusick 	auio.uio_rw = UIO_READ;
198154620Smckusick 	auio.uio_segflg = UIO_USERSPACE;
198254620Smckusick 	auio.uio_procp = p;
198354620Smckusick 	auio.uio_resid = uap->count;
198454620Smckusick 	VOP_LOCK(vp);
198554969Smckusick 	loff = auio.uio_offset = fp->f_offset;
198654620Smckusick #	if (BYTE_ORDER != LITTLE_ENDIAN)
198756339Smckusick 		if (vp->v_mount->mnt_maxsymlinklen <= 0) {
198867362Smckusick 			error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
198967362Smckusick 			    (u_long *)0, 0);
199056339Smckusick 			fp->f_offset = auio.uio_offset;
199156339Smckusick 		} else
199254620Smckusick #	endif
199354620Smckusick 	{
199454620Smckusick 		kuio = auio;
199554620Smckusick 		kuio.uio_iov = &kiov;
199654620Smckusick 		kuio.uio_segflg = UIO_SYSSPACE;
199754620Smckusick 		kiov.iov_len = uap->count;
199854620Smckusick 		MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK);
199954620Smckusick 		kiov.iov_base = dirbuf;
200067362Smckusick 		error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
200167362Smckusick 			    (u_long *)0, 0);
200256339Smckusick 		fp->f_offset = kuio.uio_offset;
200354620Smckusick 		if (error == 0) {
200454620Smckusick 			readcnt = uap->count - kuio.uio_resid;
200554620Smckusick 			edp = (struct dirent *)&dirbuf[readcnt];
200654620Smckusick 			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
200754620Smckusick #				if (BYTE_ORDER == LITTLE_ENDIAN)
200854969Smckusick 					/*
200955009Smckusick 					 * The expected low byte of
201055009Smckusick 					 * dp->d_namlen is our dp->d_type.
201155009Smckusick 					 * The high MBZ byte of dp->d_namlen
201255009Smckusick 					 * is our dp->d_namlen.
201354969Smckusick 					 */
201455009Smckusick 					dp->d_type = dp->d_namlen;
201555009Smckusick 					dp->d_namlen = 0;
201655009Smckusick #				else
201755009Smckusick 					/*
201855009Smckusick 					 * The dp->d_type is the high byte
201955009Smckusick 					 * of the expected dp->d_namlen,
202055009Smckusick 					 * so must be zero'ed.
202155009Smckusick 					 */
202255009Smckusick 					dp->d_type = 0;
202354620Smckusick #				endif
202454620Smckusick 				if (dp->d_reclen > 0) {
202554620Smckusick 					dp = (struct dirent *)
202654620Smckusick 					    ((char *)dp + dp->d_reclen);
202754620Smckusick 				} else {
202854620Smckusick 					error = EIO;
202954620Smckusick 					break;
203054620Smckusick 				}
203154620Smckusick 			}
203254620Smckusick 			if (dp >= edp)
203354620Smckusick 				error = uiomove(dirbuf, readcnt, &auio);
203454620Smckusick 		}
203554620Smckusick 		FREE(dirbuf, M_TEMP);
203654620Smckusick 	}
203754620Smckusick 	VOP_UNLOCK(vp);
203854620Smckusick 	if (error)
203954620Smckusick 		return (error);
204067362Smckusick 
204167362Smckusick #ifdef UNION
204267362Smckusick {
204367362Smckusick 	extern int (**union_vnodeop_p)();
204467362Smckusick 	extern struct vnode *union_lowervp __P((struct vnode *));
204567362Smckusick 
204667362Smckusick 	if ((uap->count == auio.uio_resid) &&
204767362Smckusick 	    (vp->v_op == union_vnodeop_p)) {
204867362Smckusick 		struct vnode *lvp;
204967362Smckusick 
205067362Smckusick 		lvp = union_lowervp(vp);
205167362Smckusick 		if (lvp != NULLVP) {
205267575Spendry 			struct vattr va;
205367575Spendry 
205467575Spendry 			/*
205567575Spendry 			 * If the directory is opaque,
205667575Spendry 			 * then don't show lower entries
205767575Spendry 			 */
205867575Spendry 			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
205967575Spendry 			if (va.va_flags & OPAQUE) {
206067575Spendry 				vrele(lvp);
206167575Spendry 				lvp = NULL;
206267575Spendry 			}
206367575Spendry 		}
206467575Spendry 
206567575Spendry 		if (lvp != NULLVP) {
206667362Smckusick 			VOP_LOCK(lvp);
206767362Smckusick 			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
206867362Smckusick 			VOP_UNLOCK(lvp);
206967362Smckusick 
207067362Smckusick 			if (error) {
207167362Smckusick 				vrele(lvp);
207267362Smckusick 				return (error);
207367362Smckusick 			}
207467362Smckusick 			fp->f_data = (caddr_t) lvp;
207567362Smckusick 			fp->f_offset = 0;
207667362Smckusick 			error = vn_close(vp, FREAD, fp->f_cred, p);
207767362Smckusick 			if (error)
207867362Smckusick 				return (error);
207967362Smckusick 			vp = lvp;
208067362Smckusick 			goto unionread;
208167362Smckusick 		}
208267362Smckusick 	}
208367362Smckusick }
208467362Smckusick #endif /* UNION */
208567362Smckusick 
208667362Smckusick 	if ((uap->count == auio.uio_resid) &&
208767362Smckusick 	    (vp->v_flag & VROOT) &&
208867362Smckusick 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
208967362Smckusick 		struct vnode *tvp = vp;
209067362Smckusick 		vp = vp->v_mount->mnt_vnodecovered;
209167362Smckusick 		VREF(vp);
209267362Smckusick 		fp->f_data = (caddr_t) vp;
209367362Smckusick 		fp->f_offset = 0;
209467362Smckusick 		vrele(tvp);
209567362Smckusick 		goto unionread;
209667362Smckusick 	}
209754969Smckusick 	error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
209854620Smckusick 	*retval = uap->count - auio.uio_resid;
209954620Smckusick 	return (error);
210054620Smckusick }
210167362Smckusick #endif /* COMPAT_43 */
210254620Smckusick 
210354620Smckusick /*
210454620Smckusick  * Read a block of directory entries in a file system independent format.
210554620Smckusick  */
210654916Storek struct getdirentries_args {
210754916Storek 	int	fd;
210854916Storek 	char	*buf;
210964410Sbostic 	u_int	count;
211054916Storek 	long	*basep;
211154916Storek };
211242441Smckusick getdirentries(p, uap, retval)
211345914Smckusick 	struct proc *p;
211454916Storek 	register struct getdirentries_args *uap;
211542441Smckusick 	int *retval;
211642441Smckusick {
211739592Smckusick 	register struct vnode *vp;
211816540Ssam 	struct file *fp;
211937741Smckusick 	struct uio auio;
212037741Smckusick 	struct iovec aiov;
212154969Smckusick 	long loff;
212267362Smckusick 	int error, eofflag;
212312756Ssam 
212445914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
212547540Skarels 		return (error);
212637741Smckusick 	if ((fp->f_flag & FREAD) == 0)
212747540Skarels 		return (EBADF);
212839592Smckusick 	vp = (struct vnode *)fp->f_data;
212955451Spendry unionread:
213039592Smckusick 	if (vp->v_type != VDIR)
213147540Skarels 		return (EINVAL);
213237741Smckusick 	aiov.iov_base = uap->buf;
213337741Smckusick 	aiov.iov_len = uap->count;
213437741Smckusick 	auio.uio_iov = &aiov;
213537741Smckusick 	auio.uio_iovcnt = 1;
213637741Smckusick 	auio.uio_rw = UIO_READ;
213737741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
213848026Smckusick 	auio.uio_procp = p;
213937741Smckusick 	auio.uio_resid = uap->count;
214039592Smckusick 	VOP_LOCK(vp);
214154969Smckusick 	loff = auio.uio_offset = fp->f_offset;
214267362Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *)0, 0);
214339592Smckusick 	fp->f_offset = auio.uio_offset;
214439592Smckusick 	VOP_UNLOCK(vp);
214539592Smckusick 	if (error)
214647540Skarels 		return (error);
214766095Spendry 
214866095Spendry #ifdef UNION
214966095Spendry {
215066095Spendry 	extern int (**union_vnodeop_p)();
215166095Spendry 	extern struct vnode *union_lowervp __P((struct vnode *));
215266095Spendry 
215355451Spendry 	if ((uap->count == auio.uio_resid) &&
215466095Spendry 	    (vp->v_op == union_vnodeop_p)) {
215567122Spendry 		struct vnode *lvp;
215666095Spendry 
215767122Spendry 		lvp = union_lowervp(vp);
215867122Spendry 		if (lvp != NULLVP) {
215967575Spendry 			struct vattr va;
216067575Spendry 
216167575Spendry 			/*
216267575Spendry 			 * If the directory is opaque,
216367575Spendry 			 * then don't show lower entries
216467575Spendry 			 */
216567575Spendry 			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
216667575Spendry 			if (va.va_flags & OPAQUE) {
216767575Spendry 				vrele(lvp);
216867575Spendry 				lvp = NULL;
216967575Spendry 			}
217067575Spendry 		}
217167575Spendry 
217267575Spendry 		if (lvp != NULLVP) {
217367122Spendry 			VOP_LOCK(lvp);
217467362Smckusick 			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
217567122Spendry 			VOP_UNLOCK(lvp);
217666095Spendry 
217766095Spendry 			if (error) {
217867122Spendry 				vrele(lvp);
217966095Spendry 				return (error);
218066095Spendry 			}
218167122Spendry 			fp->f_data = (caddr_t) lvp;
218266095Spendry 			fp->f_offset = 0;
218367122Spendry 			error = vn_close(vp, FREAD, fp->f_cred, p);
218466095Spendry 			if (error)
218566095Spendry 				return (error);
218667122Spendry 			vp = lvp;
218766095Spendry 			goto unionread;
218866095Spendry 		}
218966095Spendry 	}
219066095Spendry }
219166095Spendry #endif
219266095Spendry 
219366095Spendry 	if ((uap->count == auio.uio_resid) &&
219455451Spendry 	    (vp->v_flag & VROOT) &&
219555451Spendry 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
219655451Spendry 		struct vnode *tvp = vp;
219755451Spendry 		vp = vp->v_mount->mnt_vnodecovered;
219855451Spendry 		VREF(vp);
219955451Spendry 		fp->f_data = (caddr_t) vp;
220055451Spendry 		fp->f_offset = 0;
220155451Spendry 		vrele(tvp);
220255451Spendry 		goto unionread;
220355451Spendry 	}
220454969Smckusick 	error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
220542441Smckusick 	*retval = uap->count - auio.uio_resid;
220647540Skarels 	return (error);
220712756Ssam }
220812756Ssam 
220912756Ssam /*
221049365Smckusick  * Set the mode mask for creation of filesystem nodes.
221112756Ssam  */
221254916Storek struct umask_args {
221364410Sbostic 	int	newmask;
221454916Storek };
221554916Storek mode_t				/* XXX */
221642441Smckusick umask(p, uap, retval)
221745914Smckusick 	struct proc *p;
221854916Storek 	struct umask_args *uap;
221942441Smckusick 	int *retval;
222012756Ssam {
222164410Sbostic 	register struct filedesc *fdp;
222212756Ssam 
222364410Sbostic 	fdp = p->p_fd;
222445914Smckusick 	*retval = fdp->fd_cmask;
222564410Sbostic 	fdp->fd_cmask = uap->newmask & ALLPERMS;
222647540Skarels 	return (0);
222712756Ssam }
222837741Smckusick 
222939566Smarc /*
223039566Smarc  * Void all references to file by ripping underlying filesystem
223139566Smarc  * away from vnode.
223239566Smarc  */
223354916Storek struct revoke_args {
223464410Sbostic 	char	*path;
223554916Storek };
223642441Smckusick /* ARGSUSED */
223742441Smckusick revoke(p, uap, retval)
223845914Smckusick 	struct proc *p;
223954916Storek 	register struct revoke_args *uap;
224042441Smckusick 	int *retval;
224142441Smckusick {
224239566Smarc 	register struct vnode *vp;
224339566Smarc 	struct vattr vattr;
224439566Smarc 	int error;
224547540Skarels 	struct nameidata nd;
224639566Smarc 
224764410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
224852322Smckusick 	if (error = namei(&nd))
224947540Skarels 		return (error);
225052322Smckusick 	vp = nd.ni_vp;
225139566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
225239566Smarc 		error = EINVAL;
225339566Smarc 		goto out;
225439566Smarc 	}
225548026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
225639566Smarc 		goto out;
225747540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
225847540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
225939566Smarc 		goto out;
226039805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
226139632Smckusick 		vgoneall(vp);
226239566Smarc out:
226339566Smarc 	vrele(vp);
226447540Skarels 	return (error);
226539566Smarc }
226639566Smarc 
226749365Smckusick /*
226849365Smckusick  * Convert a user file descriptor to a kernel file entry.
226949365Smckusick  */
227064410Sbostic getvnode(fdp, fd, fpp)
227145914Smckusick 	struct filedesc *fdp;
227237741Smckusick 	struct file **fpp;
227364410Sbostic 	int fd;
227437741Smckusick {
227537741Smckusick 	struct file *fp;
227637741Smckusick 
227764410Sbostic 	if ((u_int)fd >= fdp->fd_nfiles ||
227864410Sbostic 	    (fp = fdp->fd_ofiles[fd]) == NULL)
227937741Smckusick 		return (EBADF);
228037741Smckusick 	if (fp->f_type != DTYPE_VNODE)
228137741Smckusick 		return (EINVAL);
228237741Smckusick 	*fpp = fp;
228337741Smckusick 	return (0);
228437741Smckusick }
2285