xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 67518)
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*67518Spendry  *	@(#)vfs_syscalls.c	8.17 (Berkeley) 07/12/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;
5647540Skarels 	struct nameidata nd;
576254Sroot 
5837741Smckusick 	/*
5937741Smckusick 	 * Must be super user
6037741Smckusick 	 */
6147540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
6247540Skarels 		return (error);
6337741Smckusick 	/*
6437741Smckusick 	 * Get vnode to be covered
6537741Smckusick 	 */
6664410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
6752322Smckusick 	if (error = namei(&nd))
6847540Skarels 		return (error);
6952322Smckusick 	vp = nd.ni_vp;
7041400Smckusick 	if (uap->flags & MNT_UPDATE) {
7139335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
7239335Smckusick 			vput(vp);
7347540Skarels 			return (EINVAL);
7439335Smckusick 		}
7539335Smckusick 		mp = vp->v_mount;
7657047Smckusick 		flag = mp->mnt_flag;
7739335Smckusick 		/*
7857047Smckusick 		 * We only allow the filesystem to be reloaded if it
7957047Smckusick 		 * is currently mounted read-only.
8039335Smckusick 		 */
8157047Smckusick 		if ((uap->flags & MNT_RELOAD) &&
8257047Smckusick 		    ((mp->mnt_flag & MNT_RDONLY) == 0)) {
8339335Smckusick 			vput(vp);
8447540Skarels 			return (EOPNOTSUPP);	/* Needs translation */
8539335Smckusick 		}
8657047Smckusick 		mp->mnt_flag |=
8757047Smckusick 		    uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
8839335Smckusick 		VOP_UNLOCK(vp);
8939335Smckusick 		goto update;
9039335Smckusick 	}
9157793Smckusick 	if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0))
9254441Smckusick 		return (error);
9337741Smckusick 	if (vp->v_type != VDIR) {
9437741Smckusick 		vput(vp);
9547540Skarels 		return (ENOTDIR);
9637741Smckusick 	}
9764410Sbostic 	if ((u_long)uap->type > MOUNT_MAXTYPE || vfssw[uap->type] == NULL) {
9837741Smckusick 		vput(vp);
9947540Skarels 		return (ENODEV);
10037741Smckusick 	}
10137741Smckusick 
10237741Smckusick 	/*
10339335Smckusick 	 * Allocate and initialize the file system.
10437741Smckusick 	 */
10537741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
10637741Smckusick 		M_MOUNT, M_WAITOK);
10754172Smckusick 	bzero((char *)mp, (u_long)sizeof(struct mount));
10841400Smckusick 	mp->mnt_op = vfssw[uap->type];
10939335Smckusick 	if (error = vfs_lock(mp)) {
11039335Smckusick 		free((caddr_t)mp, M_MOUNT);
11139335Smckusick 		vput(vp);
11247540Skarels 		return (error);
11339335Smckusick 	}
11464410Sbostic 	if (vp->v_mountedhere != NULL) {
11539335Smckusick 		vfs_unlock(mp);
11639335Smckusick 		free((caddr_t)mp, M_MOUNT);
11739335Smckusick 		vput(vp);
11847540Skarels 		return (EBUSY);
11939335Smckusick 	}
12039335Smckusick 	vp->v_mountedhere = mp;
12141400Smckusick 	mp->mnt_vnodecovered = vp;
12239335Smckusick update:
12339335Smckusick 	/*
12439335Smckusick 	 * Set the mount level flags.
12539335Smckusick 	 */
12641400Smckusick 	if (uap->flags & MNT_RDONLY)
12741400Smckusick 		mp->mnt_flag |= MNT_RDONLY;
12857047Smckusick 	else if (mp->mnt_flag & MNT_RDONLY)
12957047Smckusick 		mp->mnt_flag |= MNT_WANTRDWR;
13065613Smckusick 	mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
13165613Smckusick 	    MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);
13265613Smckusick 	mp->mnt_flag |= uap->flags & (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
13365613Smckusick 	    MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);
13439335Smckusick 	/*
13539335Smckusick 	 * Mount the filesystem.
13639335Smckusick 	 */
13764410Sbostic 	error = VFS_MOUNT(mp, uap->path, uap->data, &nd, p);
13841400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
13939335Smckusick 		vrele(vp);
14057047Smckusick 		if (mp->mnt_flag & MNT_WANTRDWR)
14157047Smckusick 			mp->mnt_flag &= ~MNT_RDONLY;
14257047Smckusick 		mp->mnt_flag &=~
14357047Smckusick 		    (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
14440111Smckusick 		if (error)
14541400Smckusick 			mp->mnt_flag = flag;
14647540Skarels 		return (error);
14739335Smckusick 	}
14840110Smckusick 	/*
14940110Smckusick 	 * Put the new filesystem on the mount list after root.
15040110Smckusick 	 */
15137741Smckusick 	cache_purge(vp);
15237741Smckusick 	if (!error) {
15365259Smckusick 		TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
15439335Smckusick 		VOP_UNLOCK(vp);
15537741Smckusick 		vfs_unlock(mp);
15648026Smckusick 		error = VFS_START(mp, 0, p);
15737741Smckusick 	} else {
15865259Smckusick 		mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
15965259Smckusick 		vfs_unlock(mp);
16037741Smckusick 		free((caddr_t)mp, M_MOUNT);
16139335Smckusick 		vput(vp);
16237741Smckusick 	}
16347540Skarels 	return (error);
1646254Sroot }
1656254Sroot 
1669167Ssam /*
16764410Sbostic  * Unmount a file system.
16837741Smckusick  *
16937741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
17037741Smckusick  * not special file (as before).
1719167Ssam  */
17254916Storek struct unmount_args {
17364410Sbostic 	char	*path;
17454916Storek 	int	flags;
17554916Storek };
17642441Smckusick /* ARGSUSED */
17742441Smckusick unmount(p, uap, retval)
17845914Smckusick 	struct proc *p;
17954916Storek 	register struct unmount_args *uap;
18042441Smckusick 	int *retval;
18142441Smckusick {
18237741Smckusick 	register struct vnode *vp;
18339356Smckusick 	struct mount *mp;
18437741Smckusick 	int error;
18547540Skarels 	struct nameidata nd;
1866254Sroot 
18764410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
18852322Smckusick 	if (error = namei(&nd))
18947540Skarels 		return (error);
19052322Smckusick 	vp = nd.ni_vp;
19166172Spendry 
19237741Smckusick 	/*
19366172Spendry 	 * Unless this is a user mount, then must
19466172Spendry 	 * have suser privilege.
19566172Spendry 	 */
19666172Spendry 	if (((vp->v_mount->mnt_flag & MNT_USER) == 0) &&
19766172Spendry 	    (error = suser(p->p_ucred, &p->p_acflag))) {
19866172Spendry 		vput(vp);
19966172Spendry 		return (error);
20066172Spendry 	}
20166172Spendry 
20266172Spendry 	/*
20337741Smckusick 	 * Must be the root of the filesystem
20437741Smckusick 	 */
20537741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
20637741Smckusick 		vput(vp);
20747540Skarels 		return (EINVAL);
20837741Smckusick 	}
20937741Smckusick 	mp = vp->v_mount;
21037741Smckusick 	vput(vp);
21148026Smckusick 	return (dounmount(mp, uap->flags, p));
21239356Smckusick }
21339356Smckusick 
21439356Smckusick /*
21564410Sbostic  * Do the actual file system unmount.
21639356Smckusick  */
21748026Smckusick dounmount(mp, flags, p)
21839356Smckusick 	register struct mount *mp;
21939356Smckusick 	int flags;
22048026Smckusick 	struct proc *p;
22139356Smckusick {
22239356Smckusick 	struct vnode *coveredvp;
22339356Smckusick 	int error;
22439356Smckusick 
22541400Smckusick 	coveredvp = mp->mnt_vnodecovered;
22641298Smckusick 	if (vfs_busy(mp))
22741298Smckusick 		return (EBUSY);
22841400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
22937741Smckusick 	if (error = vfs_lock(mp))
23039356Smckusick 		return (error);
23137741Smckusick 
23265859Smckusick 	mp->mnt_flag &=~ MNT_ASYNC;
23345738Smckusick 	vnode_pager_umount(mp);	/* release cached vnodes */
23437741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
23554441Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 ||
23654441Smckusick 	    (flags & MNT_FORCE))
23748026Smckusick 		error = VFS_UNMOUNT(mp, flags, p);
23841400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
23941298Smckusick 	vfs_unbusy(mp);
24037741Smckusick 	if (error) {
24137741Smckusick 		vfs_unlock(mp);
24237741Smckusick 	} else {
24337741Smckusick 		vrele(coveredvp);
24465259Smckusick 		TAILQ_REMOVE(&mountlist, mp, mnt_list);
24565259Smckusick 		mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
24665259Smckusick 		vfs_unlock(mp);
24765259Smckusick 		if (mp->mnt_vnodelist.lh_first != NULL)
24852287Smckusick 			panic("unmount: dangling vnode");
24937741Smckusick 		free((caddr_t)mp, M_MOUNT);
25037741Smckusick 	}
25139356Smckusick 	return (error);
2526254Sroot }
2536254Sroot 
2549167Ssam /*
25537741Smckusick  * Sync each mounted filesystem.
2569167Ssam  */
25767403Smckusick #ifdef DEBUG
25856352Smckusick int syncprt = 0;
25959875Smckusick struct ctldebug debug0 = { "syncprt", &syncprt };
26056352Smckusick #endif
26156352Smckusick 
26254916Storek struct sync_args {
26354916Storek 	int	dummy;
26454916Storek };
26539491Smckusick /* ARGSUSED */
26642441Smckusick sync(p, uap, retval)
26745914Smckusick 	struct proc *p;
26854916Storek 	struct sync_args *uap;
26942441Smckusick 	int *retval;
2706254Sroot {
27165259Smckusick 	register struct mount *mp, *nmp;
27265859Smckusick 	int asyncflag;
27337741Smckusick 
27465259Smckusick 	for (mp = mountlist.tqh_first; mp != NULL; mp = nmp) {
27565259Smckusick 		nmp = mp->mnt_list.tqe_next;
27640343Smckusick 		/*
27740343Smckusick 		 * The lock check below is to avoid races with mount
27840343Smckusick 		 * and unmount.
27940343Smckusick 		 */
28041400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
28141298Smckusick 		    !vfs_busy(mp)) {
28265859Smckusick 			asyncflag = mp->mnt_flag & MNT_ASYNC;
28365859Smckusick 			mp->mnt_flag &= ~MNT_ASYNC;
28454441Smckusick 			VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
28565859Smckusick 			if (asyncflag)
28665859Smckusick 				mp->mnt_flag |= MNT_ASYNC;
28765259Smckusick 			vfs_unbusy(mp);
28865259Smckusick 		}
28965259Smckusick 	}
29056352Smckusick #ifdef DIAGNOSTIC
29156352Smckusick 	if (syncprt)
29256352Smckusick 		vfs_bufstats();
29356352Smckusick #endif /* DIAGNOSTIC */
29447688Skarels 	return (0);
29537741Smckusick }
29637741Smckusick 
29737741Smckusick /*
29864410Sbostic  * Change filesystem quotas.
29941298Smckusick  */
30054916Storek struct quotactl_args {
30154916Storek 	char *path;
30254916Storek 	int cmd;
30354916Storek 	int uid;
30454916Storek 	caddr_t arg;
30554916Storek };
30642441Smckusick /* ARGSUSED */
30742441Smckusick quotactl(p, uap, retval)
30845914Smckusick 	struct proc *p;
30954916Storek 	register struct quotactl_args *uap;
31042441Smckusick 	int *retval;
31142441Smckusick {
31241298Smckusick 	register struct mount *mp;
31341298Smckusick 	int error;
31447540Skarels 	struct nameidata nd;
31541298Smckusick 
31652322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
31752322Smckusick 	if (error = namei(&nd))
31847540Skarels 		return (error);
31952322Smckusick 	mp = nd.ni_vp->v_mount;
32052322Smckusick 	vrele(nd.ni_vp);
32148026Smckusick 	return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p));
32241298Smckusick }
32341298Smckusick 
32441298Smckusick /*
32549365Smckusick  * Get filesystem statistics.
32637741Smckusick  */
32754916Storek struct statfs_args {
32854916Storek 	char *path;
32954916Storek 	struct statfs *buf;
33054916Storek };
33142441Smckusick /* ARGSUSED */
33242441Smckusick statfs(p, uap, retval)
33345914Smckusick 	struct proc *p;
33454916Storek 	register struct statfs_args *uap;
33542441Smckusick 	int *retval;
33642441Smckusick {
33739464Smckusick 	register struct mount *mp;
33840343Smckusick 	register struct statfs *sp;
33937741Smckusick 	int error;
34047540Skarels 	struct nameidata nd;
34137741Smckusick 
34252322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
34352322Smckusick 	if (error = namei(&nd))
34447540Skarels 		return (error);
34552322Smckusick 	mp = nd.ni_vp->v_mount;
34641400Smckusick 	sp = &mp->mnt_stat;
34752322Smckusick 	vrele(nd.ni_vp);
34848026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
34947540Skarels 		return (error);
35041400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
35147540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
35237741Smckusick }
35337741Smckusick 
35442441Smckusick /*
35549365Smckusick  * Get filesystem statistics.
35642441Smckusick  */
35754916Storek struct fstatfs_args {
35854916Storek 	int fd;
35954916Storek 	struct statfs *buf;
36054916Storek };
36142441Smckusick /* ARGSUSED */
36242441Smckusick fstatfs(p, uap, retval)
36345914Smckusick 	struct proc *p;
36454916Storek 	register struct fstatfs_args *uap;
36542441Smckusick 	int *retval;
36642441Smckusick {
36737741Smckusick 	struct file *fp;
36839464Smckusick 	struct mount *mp;
36940343Smckusick 	register struct statfs *sp;
37037741Smckusick 	int error;
37137741Smckusick 
37245914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
37347540Skarels 		return (error);
37439464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
37541400Smckusick 	sp = &mp->mnt_stat;
37648026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
37747540Skarels 		return (error);
37841400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
37947540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
38037741Smckusick }
38137741Smckusick 
38237741Smckusick /*
38349365Smckusick  * Get statistics on all filesystems.
38438270Smckusick  */
38554916Storek struct getfsstat_args {
38654916Storek 	struct statfs *buf;
38754916Storek 	long bufsize;
38854916Storek 	int flags;
38954916Storek };
39042441Smckusick getfsstat(p, uap, retval)
39145914Smckusick 	struct proc *p;
39254916Storek 	register struct getfsstat_args *uap;
39342441Smckusick 	int *retval;
39442441Smckusick {
39565259Smckusick 	register struct mount *mp, *nmp;
39640343Smckusick 	register struct statfs *sp;
39739606Smckusick 	caddr_t sfsp;
39838270Smckusick 	long count, maxcount, error;
39938270Smckusick 
40038270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
40139606Smckusick 	sfsp = (caddr_t)uap->buf;
40265259Smckusick 	for (count = 0, mp = mountlist.tqh_first; mp != NULL; mp = nmp) {
40365259Smckusick 		nmp = mp->mnt_list.tqe_next;
40441400Smckusick 		if (sfsp && count < maxcount &&
40541400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
40641400Smckusick 			sp = &mp->mnt_stat;
40740343Smckusick 			/*
40840343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
40940343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
41040343Smckusick 			 */
41140343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
41240343Smckusick 			    (uap->flags & MNT_WAIT)) &&
41365259Smckusick 			    (error = VFS_STATFS(mp, sp, p)))
41439607Smckusick 				continue;
41541400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
41640343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
41747540Skarels 				return (error);
41840343Smckusick 			sfsp += sizeof(*sp);
41938270Smckusick 		}
42039606Smckusick 		count++;
42165259Smckusick 	}
42238270Smckusick 	if (sfsp && count > maxcount)
42342441Smckusick 		*retval = maxcount;
42438270Smckusick 	else
42542441Smckusick 		*retval = count;
42647540Skarels 	return (0);
42738270Smckusick }
42838270Smckusick 
42938270Smckusick /*
43038259Smckusick  * Change current working directory to a given file descriptor.
43138259Smckusick  */
43254916Storek struct fchdir_args {
43354916Storek 	int	fd;
43454916Storek };
43542441Smckusick /* ARGSUSED */
43642441Smckusick fchdir(p, uap, retval)
43745914Smckusick 	struct proc *p;
43854916Storek 	struct fchdir_args *uap;
43942441Smckusick 	int *retval;
44038259Smckusick {
44145914Smckusick 	register struct filedesc *fdp = p->p_fd;
44238259Smckusick 	register struct vnode *vp;
44338259Smckusick 	struct file *fp;
44438259Smckusick 	int error;
44538259Smckusick 
44645914Smckusick 	if (error = getvnode(fdp, uap->fd, &fp))
44747540Skarels 		return (error);
44838259Smckusick 	vp = (struct vnode *)fp->f_data;
44938259Smckusick 	VOP_LOCK(vp);
45038259Smckusick 	if (vp->v_type != VDIR)
45138259Smckusick 		error = ENOTDIR;
45238259Smckusick 	else
45348026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
45438259Smckusick 	VOP_UNLOCK(vp);
45539860Smckusick 	if (error)
45647540Skarels 		return (error);
45739860Smckusick 	VREF(vp);
45845914Smckusick 	vrele(fdp->fd_cdir);
45945914Smckusick 	fdp->fd_cdir = vp;
46047540Skarels 	return (0);
46138259Smckusick }
46238259Smckusick 
46338259Smckusick /*
46437741Smckusick  * Change current working directory (``.'').
46537741Smckusick  */
46654916Storek struct chdir_args {
46764410Sbostic 	char	*path;
46854916Storek };
46942441Smckusick /* ARGSUSED */
47042441Smckusick chdir(p, uap, retval)
47145914Smckusick 	struct proc *p;
47254916Storek 	struct chdir_args *uap;
47342441Smckusick 	int *retval;
47437741Smckusick {
47545914Smckusick 	register struct filedesc *fdp = p->p_fd;
47637741Smckusick 	int error;
47747540Skarels 	struct nameidata nd;
4786254Sroot 
47964410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
48064410Sbostic 	if (error = change_dir(&nd, p))
48147540Skarels 		return (error);
48245914Smckusick 	vrele(fdp->fd_cdir);
48352322Smckusick 	fdp->fd_cdir = nd.ni_vp;
48447540Skarels 	return (0);
48537741Smckusick }
4866254Sroot 
48737741Smckusick /*
48837741Smckusick  * Change notion of root (``/'') directory.
48937741Smckusick  */
49054916Storek struct chroot_args {
49164410Sbostic 	char	*path;
49254916Storek };
49342441Smckusick /* ARGSUSED */
49442441Smckusick chroot(p, uap, retval)
49545914Smckusick 	struct proc *p;
49654916Storek 	struct chroot_args *uap;
49742441Smckusick 	int *retval;
49837741Smckusick {
49945914Smckusick 	register struct filedesc *fdp = p->p_fd;
50037741Smckusick 	int error;
50147540Skarels 	struct nameidata nd;
50237741Smckusick 
50347540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
50447540Skarels 		return (error);
50564410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
50664410Sbostic 	if (error = change_dir(&nd, p))
50747540Skarels 		return (error);
50845914Smckusick 	if (fdp->fd_rdir != NULL)
50945914Smckusick 		vrele(fdp->fd_rdir);
51052322Smckusick 	fdp->fd_rdir = nd.ni_vp;
51147540Skarels 	return (0);
5126254Sroot }
5136254Sroot 
51437Sbill /*
51537741Smckusick  * Common routine for chroot and chdir.
51637741Smckusick  */
51764410Sbostic static int
51864410Sbostic change_dir(ndp, p)
51952322Smckusick 	register struct nameidata *ndp;
52047540Skarels 	struct proc *p;
52137741Smckusick {
52237741Smckusick 	struct vnode *vp;
52337741Smckusick 	int error;
52437741Smckusick 
52552322Smckusick 	if (error = namei(ndp))
52637741Smckusick 		return (error);
52737741Smckusick 	vp = ndp->ni_vp;
52837741Smckusick 	if (vp->v_type != VDIR)
52937741Smckusick 		error = ENOTDIR;
53037741Smckusick 	else
53148026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
53237741Smckusick 	VOP_UNLOCK(vp);
53337741Smckusick 	if (error)
53437741Smckusick 		vrele(vp);
53537741Smckusick 	return (error);
53637741Smckusick }
53737741Smckusick 
53837741Smckusick /*
53942441Smckusick  * Check permissions, allocate an open file structure,
54042441Smckusick  * and call the device open routine if any.
5416254Sroot  */
54254916Storek struct open_args {
54364410Sbostic 	char	*path;
54464410Sbostic 	int	flags;
54554916Storek 	int	mode;
54654916Storek };
54742441Smckusick open(p, uap, retval)
54845914Smckusick 	struct proc *p;
54954916Storek 	register struct open_args *uap;
55042441Smckusick 	int *retval;
5516254Sroot {
55245914Smckusick 	register struct filedesc *fdp = p->p_fd;
55342441Smckusick 	register struct file *fp;
55450111Smckusick 	register struct vnode *vp;
55564410Sbostic 	int flags, cmode;
55637741Smckusick 	struct file *nfp;
55749945Smckusick 	int type, indx, error;
55849945Smckusick 	struct flock lf;
55947540Skarels 	struct nameidata nd;
56037741Smckusick 	extern struct fileops vnops;
5616254Sroot 
56245914Smckusick 	if (error = falloc(p, &nfp, &indx))
56347540Skarels 		return (error);
56437741Smckusick 	fp = nfp;
56564410Sbostic 	flags = FFLAGS(uap->flags);
56664410Sbostic 	cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
56764410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
56845202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
56964410Sbostic 	if (error = vn_open(&nd, flags, cmode)) {
57049980Smckusick 		ffree(fp);
57154723Smckusick 		if ((error == ENODEV || error == ENXIO) &&
57254723Smckusick 		    p->p_dupfd >= 0 && 			/* XXX from fdopen */
57364410Sbostic 		    (error =
57464410Sbostic 		        dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
57542441Smckusick 			*retval = indx;
57647540Skarels 			return (0);
57742441Smckusick 		}
57840884Smckusick 		if (error == ERESTART)
57940884Smckusick 			error = EINTR;
58047688Skarels 		fdp->fd_ofiles[indx] = NULL;
58147540Skarels 		return (error);
58212756Ssam 	}
58353828Spendry 	p->p_dupfd = 0;
58452322Smckusick 	vp = nd.ni_vp;
58564410Sbostic 	fp->f_flag = flags & FMASK;
58654348Smckusick 	fp->f_type = DTYPE_VNODE;
58754348Smckusick 	fp->f_ops = &vnops;
58854348Smckusick 	fp->f_data = (caddr_t)vp;
58964410Sbostic 	if (flags & (O_EXLOCK | O_SHLOCK)) {
59049945Smckusick 		lf.l_whence = SEEK_SET;
59149945Smckusick 		lf.l_start = 0;
59249945Smckusick 		lf.l_len = 0;
59364410Sbostic 		if (flags & O_EXLOCK)
59449945Smckusick 			lf.l_type = F_WRLCK;
59549945Smckusick 		else
59649945Smckusick 			lf.l_type = F_RDLCK;
59749945Smckusick 		type = F_FLOCK;
59864410Sbostic 		if ((flags & FNONBLOCK) == 0)
59949945Smckusick 			type |= F_WAIT;
60065757Smckusick 		VOP_UNLOCK(vp);
60150111Smckusick 		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
60250111Smckusick 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
60349980Smckusick 			ffree(fp);
60449945Smckusick 			fdp->fd_ofiles[indx] = NULL;
60549945Smckusick 			return (error);
60649945Smckusick 		}
60765757Smckusick 		VOP_LOCK(vp);
60849949Smckusick 		fp->f_flag |= FHASLOCK;
60949945Smckusick 	}
61050111Smckusick 	VOP_UNLOCK(vp);
61142441Smckusick 	*retval = indx;
61247540Skarels 	return (0);
6136254Sroot }
6146254Sroot 
61542955Smckusick #ifdef COMPAT_43
6166254Sroot /*
61764410Sbostic  * Create a file.
6186254Sroot  */
61954916Storek struct ocreat_args {
62064410Sbostic 	char	*path;
62164410Sbostic 	int	mode;
62254916Storek };
62342955Smckusick ocreat(p, uap, retval)
62442441Smckusick 	struct proc *p;
62554916Storek 	register struct ocreat_args *uap;
62642441Smckusick 	int *retval;
6276254Sroot {
62854916Storek 	struct open_args openuap;
62942441Smckusick 
63064410Sbostic 	openuap.path = uap->path;
63164410Sbostic 	openuap.mode = uap->mode;
63264410Sbostic 	openuap.flags = O_WRONLY | O_CREAT | O_TRUNC;
63347540Skarels 	return (open(p, &openuap, retval));
63442441Smckusick }
63542955Smckusick #endif /* COMPAT_43 */
63642441Smckusick 
63742441Smckusick /*
63864410Sbostic  * Create a special file.
63942441Smckusick  */
64054916Storek struct mknod_args {
64164410Sbostic 	char	*path;
64264410Sbostic 	int	mode;
64354916Storek 	int	dev;
64454916Storek };
64542441Smckusick /* ARGSUSED */
64642441Smckusick mknod(p, uap, retval)
64745914Smckusick 	struct proc *p;
64854916Storek 	register struct mknod_args *uap;
64942441Smckusick 	int *retval;
65042441Smckusick {
65137741Smckusick 	register struct vnode *vp;
65237741Smckusick 	struct vattr vattr;
65337741Smckusick 	int error;
65447540Skarels 	struct nameidata nd;
6556254Sroot 
65647540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
65747540Skarels 		return (error);
65864410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
65952322Smckusick 	if (error = namei(&nd))
66047540Skarels 		return (error);
66152322Smckusick 	vp = nd.ni_vp;
66264585Sbostic 	if (vp != NULL)
66337741Smckusick 		error = EEXIST;
66464585Sbostic 	else {
66564585Sbostic 		VATTR_NULL(&vattr);
66664585Sbostic 		vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
66764585Sbostic 		vattr.va_rdev = uap->dev;
66864585Sbostic 
66964585Sbostic 		switch (uap->mode & S_IFMT) {
67064585Sbostic 		case S_IFMT:	/* used by badsect to flag bad sectors */
67164585Sbostic 			vattr.va_type = VBAD;
67264585Sbostic 			break;
67364585Sbostic 		case S_IFCHR:
67464585Sbostic 			vattr.va_type = VCHR;
67564585Sbostic 			break;
67664585Sbostic 		case S_IFBLK:
67764585Sbostic 			vattr.va_type = VBLK;
67864585Sbostic 			break;
67964585Sbostic 		default:
68064585Sbostic 			error = EINVAL;
68164585Sbostic 			break;
68264585Sbostic 		}
6836254Sroot 	}
68442465Smckusick 	if (!error) {
68552322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
68652322Smckusick 		error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
68742465Smckusick 	} else {
68852322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
68952322Smckusick 		if (nd.ni_dvp == vp)
69052322Smckusick 			vrele(nd.ni_dvp);
69143344Smckusick 		else
69252322Smckusick 			vput(nd.ni_dvp);
69342465Smckusick 		if (vp)
69442465Smckusick 			vrele(vp);
69542465Smckusick 	}
69647540Skarels 	return (error);
6976254Sroot }
6986254Sroot 
6996254Sroot /*
70064410Sbostic  * Create named pipe.
70140285Smckusick  */
70254916Storek struct mkfifo_args {
70364410Sbostic 	char	*path;
70464410Sbostic 	int	mode;
70554916Storek };
70642441Smckusick /* ARGSUSED */
70742441Smckusick mkfifo(p, uap, retval)
70845914Smckusick 	struct proc *p;
70954916Storek 	register struct mkfifo_args *uap;
71042441Smckusick 	int *retval;
71142441Smckusick {
71240285Smckusick 	struct vattr vattr;
71340285Smckusick 	int error;
71447540Skarels 	struct nameidata nd;
71540285Smckusick 
71640285Smckusick #ifndef FIFO
71747540Skarels 	return (EOPNOTSUPP);
71840285Smckusick #else
71964410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
72052322Smckusick 	if (error = namei(&nd))
72147540Skarels 		return (error);
72252322Smckusick 	if (nd.ni_vp != NULL) {
72352322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
72452322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
72552322Smckusick 			vrele(nd.ni_dvp);
72643344Smckusick 		else
72752322Smckusick 			vput(nd.ni_dvp);
72852322Smckusick 		vrele(nd.ni_vp);
72947540Skarels 		return (EEXIST);
73040285Smckusick 	}
73145785Sbostic 	VATTR_NULL(&vattr);
73245785Sbostic 	vattr.va_type = VFIFO;
73364410Sbostic 	vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
73452322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
73552322Smckusick 	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
73640285Smckusick #endif /* FIFO */
73740285Smckusick }
73840285Smckusick 
73940285Smckusick /*
74064410Sbostic  * Make a hard file link.
7416254Sroot  */
74254916Storek struct link_args {
74364410Sbostic 	char	*path;
74464410Sbostic 	char	*link;
74554916Storek };
74642441Smckusick /* ARGSUSED */
74742441Smckusick link(p, uap, retval)
74845914Smckusick 	struct proc *p;
74954916Storek 	register struct link_args *uap;
75042441Smckusick 	int *retval;
75142441Smckusick {
75264410Sbostic 	register struct vnode *vp;
75364410Sbostic 	struct nameidata nd;
75437741Smckusick 	int error;
7556254Sroot 
75664410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
75752322Smckusick 	if (error = namei(&nd))
75847540Skarels 		return (error);
75952322Smckusick 	vp = nd.ni_vp;
76064585Sbostic 	if (vp->v_type != VDIR ||
76164585Sbostic 	    (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
76264585Sbostic 		nd.ni_cnd.cn_nameiop = CREATE;
76364585Sbostic 		nd.ni_cnd.cn_flags = LOCKPARENT;
76464585Sbostic 		nd.ni_dirp = uap->link;
76564585Sbostic 		if ((error = namei(&nd)) == 0) {
76664585Sbostic 			if (nd.ni_vp != NULL)
76764585Sbostic 				error = EEXIST;
76864585Sbostic 			if (!error) {
76964585Sbostic 				LEASE_CHECK(nd.ni_dvp,
77064585Sbostic 				    p, p->p_ucred, LEASE_WRITE);
77164585Sbostic 				LEASE_CHECK(vp,
77264585Sbostic 				    p, p->p_ucred, LEASE_WRITE);
77364585Sbostic 				error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
77464585Sbostic 			} else {
77564585Sbostic 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
77664585Sbostic 				if (nd.ni_dvp == nd.ni_vp)
77764585Sbostic 					vrele(nd.ni_dvp);
77864585Sbostic 				else
77964585Sbostic 					vput(nd.ni_dvp);
78064585Sbostic 				if (nd.ni_vp)
78164585Sbostic 					vrele(nd.ni_vp);
78264585Sbostic 			}
78364585Sbostic 		}
78442465Smckusick 	}
78564585Sbostic 	vrele(vp);
78647540Skarels 	return (error);
7876254Sroot }
7886254Sroot 
7896254Sroot /*
79049365Smckusick  * Make a symbolic link.
7916254Sroot  */
79254916Storek struct symlink_args {
79364410Sbostic 	char	*path;
79464410Sbostic 	char	*link;
79554916Storek };
79642441Smckusick /* ARGSUSED */
79742441Smckusick symlink(p, uap, retval)
79845914Smckusick 	struct proc *p;
79954916Storek 	register struct symlink_args *uap;
80042441Smckusick 	int *retval;
80142441Smckusick {
80237741Smckusick 	struct vattr vattr;
80364410Sbostic 	char *path;
80437741Smckusick 	int error;
80547540Skarels 	struct nameidata nd;
8066254Sroot 
80764410Sbostic 	MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
80864410Sbostic 	if (error = copyinstr(uap->path, path, MAXPATHLEN, NULL))
80942465Smckusick 		goto out;
81064410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p);
81152322Smckusick 	if (error = namei(&nd))
81242465Smckusick 		goto out;
81352322Smckusick 	if (nd.ni_vp) {
81452322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
81552322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
81652322Smckusick 			vrele(nd.ni_dvp);
81743344Smckusick 		else
81852322Smckusick 			vput(nd.ni_dvp);
81952322Smckusick 		vrele(nd.ni_vp);
82037741Smckusick 		error = EEXIST;
82137741Smckusick 		goto out;
8226254Sroot 	}
82341362Smckusick 	VATTR_NULL(&vattr);
82464410Sbostic 	vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
82552322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
82664410Sbostic 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
82737741Smckusick out:
82864410Sbostic 	FREE(path, M_NAMEI);
82947540Skarels 	return (error);
8306254Sroot }
8316254Sroot 
8326254Sroot /*
833*67518Spendry  * Delete a whiteout from the filesystem.
834*67518Spendry  */
835*67518Spendry struct unwhiteout_args {
836*67518Spendry 	char	*path;
837*67518Spendry };
838*67518Spendry /* ARGSUSED */
839*67518Spendry unwhiteout(p, uap, retval)
840*67518Spendry 	struct proc *p;
841*67518Spendry 	struct unwhiteout_args *uap;
842*67518Spendry 	int *retval;
843*67518Spendry {
844*67518Spendry 	int error;
845*67518Spendry 	struct nameidata nd;
846*67518Spendry 
847*67518Spendry 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
848*67518Spendry 	if (error = namei(&nd))
849*67518Spendry 		return (error);
850*67518Spendry 	if (nd.ni_vp || !(nd.ni_cnd.cn_flags & WHITEOUT)) {
851*67518Spendry 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
852*67518Spendry 		if (nd.ni_dvp == nd.ni_vp)
853*67518Spendry 			vrele(nd.ni_dvp);
854*67518Spendry 		else
855*67518Spendry 			vput(nd.ni_dvp);
856*67518Spendry 		if (nd.ni_vp)
857*67518Spendry 			vrele(nd.ni_vp);
858*67518Spendry 		return (EEXIST);
859*67518Spendry 	}
860*67518Spendry 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
861*67518Spendry 	error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE);
862*67518Spendry 	vput(nd.ni_dvp);
863*67518Spendry 	return (error);
864*67518Spendry }
865*67518Spendry 
866*67518Spendry /*
86749365Smckusick  * Delete a name from the filesystem.
8686254Sroot  */
86954916Storek struct unlink_args {
87064410Sbostic 	char	*path;
87154916Storek };
87242441Smckusick /* ARGSUSED */
87342441Smckusick unlink(p, uap, retval)
87445914Smckusick 	struct proc *p;
87554916Storek 	struct unlink_args *uap;
87642441Smckusick 	int *retval;
8776254Sroot {
87837741Smckusick 	register struct vnode *vp;
87937741Smckusick 	int error;
88047540Skarels 	struct nameidata nd;
8816254Sroot 
88264410Sbostic 	NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
88352322Smckusick 	if (error = namei(&nd))
88447540Skarels 		return (error);
88552322Smckusick 	vp = nd.ni_vp;
88659382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
88759382Smckusick 	VOP_LOCK(vp);
88864410Sbostic 
88964585Sbostic 	if (vp->v_type != VDIR ||
89064585Sbostic 	    (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
89164585Sbostic 		/*
89264585Sbostic 		 * The root of a mounted filesystem cannot be deleted.
89364585Sbostic 		 */
89464585Sbostic 		if (vp->v_flag & VROOT)
89564585Sbostic 			error = EBUSY;
89664585Sbostic 		else
89764585Sbostic 			(void)vnode_pager_uncache(vp);
89864585Sbostic 	}
89964585Sbostic 
90064585Sbostic 	if (!error) {
90152322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
90252322Smckusick 		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
90342465Smckusick 	} else {
90452322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
90552322Smckusick 		if (nd.ni_dvp == vp)
90652322Smckusick 			vrele(nd.ni_dvp);
90743344Smckusick 		else
90852322Smckusick 			vput(nd.ni_dvp);
90942465Smckusick 		vput(vp);
91042465Smckusick 	}
91147540Skarels 	return (error);
9126254Sroot }
9136254Sroot 
91464410Sbostic /*
91564410Sbostic  * Reposition read/write file offset.
91664410Sbostic  */
91760428Smckusick struct lseek_args {
91864410Sbostic 	int	fd;
91954863Storek 	int	pad;
92064410Sbostic 	off_t	offset;
92164410Sbostic 	int	whence;
92254863Storek };
92360414Smckusick lseek(p, uap, retval)
92453468Smckusick 	struct proc *p;
92560428Smckusick 	register struct lseek_args *uap;
92654916Storek 	int *retval;
92742441Smckusick {
92847540Skarels 	struct ucred *cred = p->p_ucred;
92945914Smckusick 	register struct filedesc *fdp = p->p_fd;
93042441Smckusick 	register struct file *fp;
93137741Smckusick 	struct vattr vattr;
93237741Smckusick 	int error;
9336254Sroot 
93464410Sbostic 	if ((u_int)uap->fd >= fdp->fd_nfiles ||
93564410Sbostic 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
93647540Skarels 		return (EBADF);
93737741Smckusick 	if (fp->f_type != DTYPE_VNODE)
93847540Skarels 		return (ESPIPE);
93964410Sbostic 	switch (uap->whence) {
94013878Ssam 	case L_INCR:
94164410Sbostic 		fp->f_offset += uap->offset;
94213878Ssam 		break;
94313878Ssam 	case L_XTND:
94464410Sbostic 		if (error =
94564410Sbostic 		    VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p))
94647540Skarels 			return (error);
94764410Sbostic 		fp->f_offset = uap->offset + vattr.va_size;
94813878Ssam 		break;
94913878Ssam 	case L_SET:
95064410Sbostic 		fp->f_offset = uap->offset;
95113878Ssam 		break;
95213878Ssam 	default:
95347540Skarels 		return (EINVAL);
95413878Ssam 	}
95554916Storek 	*(off_t *)retval = fp->f_offset;
95647540Skarels 	return (0);
9576254Sroot }
9586254Sroot 
95960414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
9606254Sroot /*
96164410Sbostic  * Reposition read/write file offset.
96260036Smckusick  */
96360428Smckusick struct olseek_args {
96464410Sbostic 	int	fd;
96564410Sbostic 	long	offset;
96664410Sbostic 	int	whence;
96760036Smckusick };
96860414Smckusick olseek(p, uap, retval)
96960036Smckusick 	struct proc *p;
97060428Smckusick 	register struct olseek_args *uap;
97160036Smckusick 	int *retval;
97260036Smckusick {
97360428Smckusick 	struct lseek_args nuap;
97460036Smckusick 	off_t qret;
97560036Smckusick 	int error;
97660036Smckusick 
97764410Sbostic 	nuap.fd = uap->fd;
97864410Sbostic 	nuap.offset = uap->offset;
97964410Sbostic 	nuap.whence = uap->whence;
98060428Smckusick 	error = lseek(p, &nuap, &qret);
98160036Smckusick 	*(long *)retval = qret;
98260036Smckusick 	return (error);
98360036Smckusick }
98460414Smckusick #endif /* COMPAT_43 */
98560036Smckusick 
98660036Smckusick /*
98749365Smckusick  * Check access permissions.
9886254Sroot  */
98963427Sbostic struct access_args {
99064410Sbostic 	char	*path;
99164410Sbostic 	int	flags;
99254916Storek };
99363427Sbostic access(p, uap, retval)
99445914Smckusick 	struct proc *p;
99563427Sbostic 	register struct access_args *uap;
99642441Smckusick 	int *retval;
99742441Smckusick {
99847540Skarels 	register struct ucred *cred = p->p_ucred;
99937741Smckusick 	register struct vnode *vp;
100064585Sbostic 	int error, flags, t_gid, t_uid;
100147540Skarels 	struct nameidata nd;
10026254Sroot 
100364585Sbostic 	t_uid = cred->cr_uid;
100464585Sbostic 	t_gid = cred->cr_groups[0];
100547540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
100647540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
100764410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
100852322Smckusick 	if (error = namei(&nd))
100937741Smckusick 		goto out1;
101052322Smckusick 	vp = nd.ni_vp;
101164410Sbostic 
101264410Sbostic 	/* Flags == 0 means only check for existence. */
101364410Sbostic 	if (uap->flags) {
101464410Sbostic 		flags = 0;
101564410Sbostic 		if (uap->flags & R_OK)
101664410Sbostic 			flags |= VREAD;
101764410Sbostic 		if (uap->flags & W_OK)
101864410Sbostic 			flags |= VWRITE;
101964410Sbostic 		if (uap->flags & X_OK)
102064410Sbostic 			flags |= VEXEC;
102164410Sbostic 		if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
102264410Sbostic 			error = VOP_ACCESS(vp, flags, cred, p);
10236254Sroot 	}
102437741Smckusick 	vput(vp);
102537741Smckusick out1:
102664585Sbostic 	cred->cr_uid = t_uid;
102764585Sbostic 	cred->cr_groups[0] = t_gid;
102847540Skarels 	return (error);
10296254Sroot }
10306254Sroot 
103154348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
10326254Sroot /*
103364410Sbostic  * Get file status; this version follows links.
103437Sbill  */
103554916Storek struct ostat_args {
103664410Sbostic 	char	*path;
103754916Storek 	struct ostat *ub;
103854916Storek };
103942441Smckusick /* ARGSUSED */
104053759Smckusick ostat(p, uap, retval)
104145914Smckusick 	struct proc *p;
104254916Storek 	register struct ostat_args *uap;
104353468Smckusick 	int *retval;
104453468Smckusick {
104553468Smckusick 	struct stat sb;
104653468Smckusick 	struct ostat osb;
104753468Smckusick 	int error;
104853468Smckusick 	struct nameidata nd;
104953468Smckusick 
105064410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
105153468Smckusick 	if (error = namei(&nd))
105253468Smckusick 		return (error);
105353468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
105453468Smckusick 	vput(nd.ni_vp);
105553468Smckusick 	if (error)
105653468Smckusick 		return (error);
105753468Smckusick 	cvtstat(&sb, &osb);
105853468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
105953468Smckusick 	return (error);
106053468Smckusick }
106153468Smckusick 
106253468Smckusick /*
106364410Sbostic  * Get file status; this version does not follow links.
106453468Smckusick  */
106554916Storek struct olstat_args {
106664410Sbostic 	char	*path;
106754916Storek 	struct ostat *ub;
106854916Storek };
106953468Smckusick /* ARGSUSED */
107053759Smckusick olstat(p, uap, retval)
107153468Smckusick 	struct proc *p;
107254916Storek 	register struct olstat_args *uap;
107353468Smckusick 	int *retval;
107453468Smckusick {
107553468Smckusick 	struct stat sb;
107653468Smckusick 	struct ostat osb;
107753468Smckusick 	int error;
107853468Smckusick 	struct nameidata nd;
107953468Smckusick 
108064410Sbostic 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
108153468Smckusick 	if (error = namei(&nd))
108253468Smckusick 		return (error);
108353468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
108453468Smckusick 	vput(nd.ni_vp);
108553468Smckusick 	if (error)
108653468Smckusick 		return (error);
108753468Smckusick 	cvtstat(&sb, &osb);
108853468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
108953468Smckusick 	return (error);
109053468Smckusick }
109153468Smckusick 
109253468Smckusick /*
109364410Sbostic  * Convert from an old to a new stat structure.
109453468Smckusick  */
109553468Smckusick cvtstat(st, ost)
109653468Smckusick 	struct stat *st;
109753468Smckusick 	struct ostat *ost;
109853468Smckusick {
109953468Smckusick 
110053468Smckusick 	ost->st_dev = st->st_dev;
110153468Smckusick 	ost->st_ino = st->st_ino;
110253468Smckusick 	ost->st_mode = st->st_mode;
110353468Smckusick 	ost->st_nlink = st->st_nlink;
110453468Smckusick 	ost->st_uid = st->st_uid;
110553468Smckusick 	ost->st_gid = st->st_gid;
110653468Smckusick 	ost->st_rdev = st->st_rdev;
110753468Smckusick 	if (st->st_size < (quad_t)1 << 32)
110853468Smckusick 		ost->st_size = st->st_size;
110953468Smckusick 	else
111053468Smckusick 		ost->st_size = -2;
111153468Smckusick 	ost->st_atime = st->st_atime;
111253468Smckusick 	ost->st_mtime = st->st_mtime;
111353468Smckusick 	ost->st_ctime = st->st_ctime;
111453468Smckusick 	ost->st_blksize = st->st_blksize;
111553468Smckusick 	ost->st_blocks = st->st_blocks;
111653468Smckusick 	ost->st_flags = st->st_flags;
111753468Smckusick 	ost->st_gen = st->st_gen;
111853468Smckusick }
111954348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
112053468Smckusick 
112153468Smckusick /*
112264410Sbostic  * Get file status; this version follows links.
112353468Smckusick  */
112454916Storek struct stat_args {
112564410Sbostic 	char	*path;
112654916Storek 	struct stat *ub;
112754916Storek };
112853468Smckusick /* ARGSUSED */
112953759Smckusick stat(p, uap, retval)
113053468Smckusick 	struct proc *p;
113154916Storek 	register struct stat_args *uap;
113242441Smckusick 	int *retval;
113337Sbill {
113442441Smckusick 	struct stat sb;
113542441Smckusick 	int error;
113647540Skarels 	struct nameidata nd;
113737Sbill 
113864410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
113952322Smckusick 	if (error = namei(&nd))
114047540Skarels 		return (error);
114152322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
114252322Smckusick 	vput(nd.ni_vp);
114342441Smckusick 	if (error)
114447540Skarels 		return (error);
114542441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
114647540Skarels 	return (error);
114737Sbill }
114837Sbill 
114937Sbill /*
115064410Sbostic  * Get file status; this version does not follow links.
11515992Swnj  */
115254916Storek struct lstat_args {
115364410Sbostic 	char	*path;
115454916Storek 	struct stat *ub;
115554916Storek };
115642441Smckusick /* ARGSUSED */
115753759Smckusick lstat(p, uap, retval)
115845914Smckusick 	struct proc *p;
115954916Storek 	register struct lstat_args *uap;
116042441Smckusick 	int *retval;
116142441Smckusick {
116237741Smckusick 	int error;
116359373Smckusick 	struct vnode *vp, *dvp;
116459373Smckusick 	struct stat sb, sb1;
116547540Skarels 	struct nameidata nd;
11665992Swnj 
116759373Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
116864410Sbostic 	    uap->path, p);
116952322Smckusick 	if (error = namei(&nd))
117047540Skarels 		return (error);
117159373Smckusick 	/*
117259373Smckusick 	 * For symbolic links, always return the attributes of its
117359373Smckusick 	 * containing directory, except for mode, size, and links.
117459373Smckusick 	 */
117559373Smckusick 	vp = nd.ni_vp;
117659373Smckusick 	dvp = nd.ni_dvp;
117759373Smckusick 	if (vp->v_type != VLNK) {
117859373Smckusick 		if (dvp == vp)
117959373Smckusick 			vrele(dvp);
118059373Smckusick 		else
118159373Smckusick 			vput(dvp);
118259373Smckusick 		error = vn_stat(vp, &sb, p);
118359373Smckusick 		vput(vp);
118459373Smckusick 		if (error)
118559373Smckusick 			return (error);
118659373Smckusick 	} else {
118759373Smckusick 		error = vn_stat(dvp, &sb, p);
118859373Smckusick 		vput(dvp);
118959373Smckusick 		if (error) {
119059373Smckusick 			vput(vp);
119159373Smckusick 			return (error);
119259373Smckusick 		}
119359373Smckusick 		error = vn_stat(vp, &sb1, p);
119459373Smckusick 		vput(vp);
119559373Smckusick 		if (error)
119659373Smckusick 			return (error);
119759373Smckusick 		sb.st_mode &= ~S_IFDIR;
119859373Smckusick 		sb.st_mode |= S_IFLNK;
119959373Smckusick 		sb.st_nlink = sb1.st_nlink;
120059373Smckusick 		sb.st_size = sb1.st_size;
120159373Smckusick 		sb.st_blocks = sb1.st_blocks;
120259373Smckusick 	}
120337741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
120447540Skarels 	return (error);
12055992Swnj }
12065992Swnj 
12075992Swnj /*
120864410Sbostic  * Get configurable pathname variables.
120960414Smckusick  */
121060414Smckusick struct pathconf_args {
121164410Sbostic 	char	*path;
121260414Smckusick 	int	name;
121360414Smckusick };
121460414Smckusick /* ARGSUSED */
121560414Smckusick pathconf(p, uap, retval)
121660414Smckusick 	struct proc *p;
121760414Smckusick 	register struct pathconf_args *uap;
121860414Smckusick 	int *retval;
121960414Smckusick {
122060414Smckusick 	int error;
122160414Smckusick 	struct nameidata nd;
122260414Smckusick 
122364410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
122460414Smckusick 	if (error = namei(&nd))
122560414Smckusick 		return (error);
122660414Smckusick 	error = VOP_PATHCONF(nd.ni_vp, uap->name, retval);
122760414Smckusick 	vput(nd.ni_vp);
122860414Smckusick 	return (error);
122960414Smckusick }
123060414Smckusick 
123160414Smckusick /*
123249365Smckusick  * Return target name of a symbolic link.
123337Sbill  */
123454916Storek struct readlink_args {
123564410Sbostic 	char	*path;
123654916Storek 	char	*buf;
123754916Storek 	int	count;
123854916Storek };
123942441Smckusick /* ARGSUSED */
124042441Smckusick readlink(p, uap, retval)
124145914Smckusick 	struct proc *p;
124254916Storek 	register struct readlink_args *uap;
124342441Smckusick 	int *retval;
124442441Smckusick {
124537741Smckusick 	register struct vnode *vp;
124637741Smckusick 	struct iovec aiov;
124737741Smckusick 	struct uio auio;
124837741Smckusick 	int error;
124947540Skarels 	struct nameidata nd;
12505992Swnj 
125164410Sbostic 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
125252322Smckusick 	if (error = namei(&nd))
125347540Skarels 		return (error);
125452322Smckusick 	vp = nd.ni_vp;
125564410Sbostic 	if (vp->v_type != VLNK)
125637741Smckusick 		error = EINVAL;
125764410Sbostic 	else {
125864410Sbostic 		aiov.iov_base = uap->buf;
125964410Sbostic 		aiov.iov_len = uap->count;
126064410Sbostic 		auio.uio_iov = &aiov;
126164410Sbostic 		auio.uio_iovcnt = 1;
126264410Sbostic 		auio.uio_offset = 0;
126364410Sbostic 		auio.uio_rw = UIO_READ;
126464410Sbostic 		auio.uio_segflg = UIO_USERSPACE;
126564410Sbostic 		auio.uio_procp = p;
126664410Sbostic 		auio.uio_resid = uap->count;
126764410Sbostic 		error = VOP_READLINK(vp, &auio, p->p_ucred);
12685992Swnj 	}
126937741Smckusick 	vput(vp);
127042441Smckusick 	*retval = uap->count - auio.uio_resid;
127147540Skarels 	return (error);
12725992Swnj }
12735992Swnj 
12749167Ssam /*
127564410Sbostic  * Change flags of a file given a path name.
127638259Smckusick  */
127754916Storek struct chflags_args {
127864410Sbostic 	char	*path;
127954916Storek 	int	flags;
128054916Storek };
128142441Smckusick /* ARGSUSED */
128242441Smckusick chflags(p, uap, retval)
128345914Smckusick 	struct proc *p;
128454916Storek 	register struct chflags_args *uap;
128542441Smckusick 	int *retval;
128642441Smckusick {
128738259Smckusick 	register struct vnode *vp;
128838259Smckusick 	struct vattr vattr;
128938259Smckusick 	int error;
129047540Skarels 	struct nameidata nd;
129138259Smckusick 
129264410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
129352322Smckusick 	if (error = namei(&nd))
129447540Skarels 		return (error);
129552322Smckusick 	vp = nd.ni_vp;
129659382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
129759382Smckusick 	VOP_LOCK(vp);
129864410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
129938259Smckusick 		error = EROFS;
130064410Sbostic 	else {
130164410Sbostic 		VATTR_NULL(&vattr);
130264410Sbostic 		vattr.va_flags = uap->flags;
130364410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
130438259Smckusick 	}
130538259Smckusick 	vput(vp);
130647540Skarels 	return (error);
130738259Smckusick }
130838259Smckusick 
130938259Smckusick /*
131038259Smckusick  * Change flags of a file given a file descriptor.
131138259Smckusick  */
131254916Storek struct fchflags_args {
131354916Storek 	int	fd;
131454916Storek 	int	flags;
131554916Storek };
131642441Smckusick /* ARGSUSED */
131742441Smckusick fchflags(p, uap, retval)
131845914Smckusick 	struct proc *p;
131954916Storek 	register struct fchflags_args *uap;
132042441Smckusick 	int *retval;
132142441Smckusick {
132238259Smckusick 	struct vattr vattr;
132338259Smckusick 	struct vnode *vp;
132438259Smckusick 	struct file *fp;
132538259Smckusick 	int error;
132638259Smckusick 
132745914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
132847540Skarels 		return (error);
132938259Smckusick 	vp = (struct vnode *)fp->f_data;
133059382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
133138259Smckusick 	VOP_LOCK(vp);
133264410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
133338259Smckusick 		error = EROFS;
133464410Sbostic 	else {
133564410Sbostic 		VATTR_NULL(&vattr);
133664410Sbostic 		vattr.va_flags = uap->flags;
133764410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
133838259Smckusick 	}
133938259Smckusick 	VOP_UNLOCK(vp);
134047540Skarels 	return (error);
134138259Smckusick }
134238259Smckusick 
134338259Smckusick /*
13449167Ssam  * Change mode of a file given path name.
13459167Ssam  */
134654916Storek struct chmod_args {
134764410Sbostic 	char	*path;
134864410Sbostic 	int	mode;
134954916Storek };
135042441Smckusick /* ARGSUSED */
135142441Smckusick chmod(p, uap, retval)
135245914Smckusick 	struct proc *p;
135354916Storek 	register struct chmod_args *uap;
135442441Smckusick 	int *retval;
135542441Smckusick {
135637741Smckusick 	register struct vnode *vp;
135737741Smckusick 	struct vattr vattr;
135837741Smckusick 	int error;
135947540Skarels 	struct nameidata nd;
13605992Swnj 
136164410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
136252322Smckusick 	if (error = namei(&nd))
136347540Skarels 		return (error);
136452322Smckusick 	vp = nd.ni_vp;
136559382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
136659382Smckusick 	VOP_LOCK(vp);
136764410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
136837741Smckusick 		error = EROFS;
136964410Sbostic 	else {
137064410Sbostic 		VATTR_NULL(&vattr);
137164410Sbostic 		vattr.va_mode = uap->mode & ALLPERMS;
137264410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
137337741Smckusick 	}
137437741Smckusick 	vput(vp);
137547540Skarels 	return (error);
13767701Ssam }
13777439Sroot 
13789167Ssam /*
13799167Ssam  * Change mode of a file given a file descriptor.
13809167Ssam  */
138154916Storek struct fchmod_args {
138254916Storek 	int	fd;
138364410Sbostic 	int	mode;
138454916Storek };
138542441Smckusick /* ARGSUSED */
138642441Smckusick fchmod(p, uap, retval)
138745914Smckusick 	struct proc *p;
138854916Storek 	register struct fchmod_args *uap;
138942441Smckusick 	int *retval;
139042441Smckusick {
139137741Smckusick 	struct vattr vattr;
139237741Smckusick 	struct vnode *vp;
139337741Smckusick 	struct file *fp;
139437741Smckusick 	int error;
13957701Ssam 
139645914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
139747540Skarels 		return (error);
139837741Smckusick 	vp = (struct vnode *)fp->f_data;
139959382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
140037741Smckusick 	VOP_LOCK(vp);
140164410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
140237741Smckusick 		error = EROFS;
140364410Sbostic 	else {
140464410Sbostic 		VATTR_NULL(&vattr);
140564410Sbostic 		vattr.va_mode = uap->mode & ALLPERMS;
140664410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
14077439Sroot 	}
140837741Smckusick 	VOP_UNLOCK(vp);
140947540Skarels 	return (error);
14105992Swnj }
14115992Swnj 
14129167Ssam /*
14139167Ssam  * Set ownership given a path name.
14149167Ssam  */
141554916Storek struct chown_args {
141664410Sbostic 	char	*path;
141754916Storek 	int	uid;
141854916Storek 	int	gid;
141954916Storek };
142042441Smckusick /* ARGSUSED */
142142441Smckusick chown(p, uap, retval)
142245914Smckusick 	struct proc *p;
142354916Storek 	register struct chown_args *uap;
142442441Smckusick 	int *retval;
142542441Smckusick {
142637741Smckusick 	register struct vnode *vp;
142737741Smckusick 	struct vattr vattr;
142837741Smckusick 	int error;
142947540Skarels 	struct nameidata nd;
143037Sbill 
143166510Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
143252322Smckusick 	if (error = namei(&nd))
143347540Skarels 		return (error);
143452322Smckusick 	vp = nd.ni_vp;
143559382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
143659382Smckusick 	VOP_LOCK(vp);
143764410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
143837741Smckusick 		error = EROFS;
143964410Sbostic 	else {
144064410Sbostic 		VATTR_NULL(&vattr);
144164410Sbostic 		vattr.va_uid = uap->uid;
144264410Sbostic 		vattr.va_gid = uap->gid;
144364410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
144437741Smckusick 	}
144537741Smckusick 	vput(vp);
144647540Skarels 	return (error);
14477701Ssam }
14487439Sroot 
14499167Ssam /*
14509167Ssam  * Set ownership given a file descriptor.
14519167Ssam  */
145254916Storek struct fchown_args {
145354916Storek 	int	fd;
145454916Storek 	int	uid;
145554916Storek 	int	gid;
145654916Storek };
145742441Smckusick /* ARGSUSED */
145842441Smckusick fchown(p, uap, retval)
145945914Smckusick 	struct proc *p;
146054916Storek 	register struct fchown_args *uap;
146142441Smckusick 	int *retval;
146242441Smckusick {
146337741Smckusick 	struct vattr vattr;
146437741Smckusick 	struct vnode *vp;
146537741Smckusick 	struct file *fp;
146637741Smckusick 	int error;
14677701Ssam 
146845914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
146947540Skarels 		return (error);
147037741Smckusick 	vp = (struct vnode *)fp->f_data;
147159382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
147237741Smckusick 	VOP_LOCK(vp);
147364410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
147437741Smckusick 		error = EROFS;
147564410Sbostic 	else {
147664410Sbostic 		VATTR_NULL(&vattr);
147764410Sbostic 		vattr.va_uid = uap->uid;
147864410Sbostic 		vattr.va_gid = uap->gid;
147964410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
148037741Smckusick 	}
148137741Smckusick 	VOP_UNLOCK(vp);
148247540Skarels 	return (error);
14837701Ssam }
14847701Ssam 
148542441Smckusick /*
148642441Smckusick  * Set the access and modification times of a file.
148742441Smckusick  */
148854916Storek struct utimes_args {
148964410Sbostic 	char	*path;
149054916Storek 	struct	timeval *tptr;
149154916Storek };
149242441Smckusick /* ARGSUSED */
149342441Smckusick utimes(p, uap, retval)
149445914Smckusick 	struct proc *p;
149554916Storek 	register struct utimes_args *uap;
149642441Smckusick 	int *retval;
149742441Smckusick {
149837741Smckusick 	register struct vnode *vp;
149911811Ssam 	struct timeval tv[2];
150037741Smckusick 	struct vattr vattr;
150158840Storek 	int error;
150247540Skarels 	struct nameidata nd;
150311811Ssam 
150458505Sbostic 	VATTR_NULL(&vattr);
150558505Sbostic 	if (uap->tptr == NULL) {
150658505Sbostic 		microtime(&tv[0]);
150758505Sbostic 		tv[1] = tv[0];
150858548Sbostic 		vattr.va_vaflags |= VA_UTIMES_NULL;
150958505Sbostic 	} else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
151058505Sbostic   		return (error);
151164410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
151252322Smckusick 	if (error = namei(&nd))
151347540Skarels 		return (error);
151452322Smckusick 	vp = nd.ni_vp;
151559382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
151659382Smckusick 	VOP_LOCK(vp);
151764410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
151837741Smckusick 		error = EROFS;
151964410Sbostic 	else {
152064410Sbostic 		vattr.va_atime.ts_sec = tv[0].tv_sec;
152164410Sbostic 		vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
152264410Sbostic 		vattr.va_mtime.ts_sec = tv[1].tv_sec;
152364410Sbostic 		vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
152464410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
152521015Smckusick 	}
152637741Smckusick 	vput(vp);
152747540Skarels 	return (error);
152811811Ssam }
152911811Ssam 
153064410Sbostic /*
153164410Sbostic  * Truncate a file given its path name.
153264410Sbostic  */
153360428Smckusick struct truncate_args {
153464410Sbostic 	char	*path;
153554863Storek 	int	pad;
153654863Storek 	off_t	length;
153754863Storek };
153853468Smckusick /* ARGSUSED */
153960414Smckusick truncate(p, uap, retval)
154053468Smckusick 	struct proc *p;
154160428Smckusick 	register struct truncate_args *uap;
154253468Smckusick 	int *retval;
154353468Smckusick {
154437741Smckusick 	register struct vnode *vp;
154537741Smckusick 	struct vattr vattr;
154637741Smckusick 	int error;
154747540Skarels 	struct nameidata nd;
15487701Ssam 
154964410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
155052322Smckusick 	if (error = namei(&nd))
155147540Skarels 		return (error);
155252322Smckusick 	vp = nd.ni_vp;
155359382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
155459382Smckusick 	VOP_LOCK(vp);
155564410Sbostic 	if (vp->v_type == VDIR)
155637741Smckusick 		error = EISDIR;
155764410Sbostic 	else if ((error = vn_writechk(vp)) == 0 &&
155864410Sbostic 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
155964410Sbostic 		VATTR_NULL(&vattr);
156064410Sbostic 		vattr.va_size = uap->length;
156164410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
15627701Ssam 	}
156337741Smckusick 	vput(vp);
156447540Skarels 	return (error);
15657701Ssam }
15667701Ssam 
156764410Sbostic /*
156864410Sbostic  * Truncate a file given a file descriptor.
156964410Sbostic  */
157060428Smckusick struct ftruncate_args {
157154863Storek 	int	fd;
157254863Storek 	int	pad;
157354863Storek 	off_t	length;
157454863Storek };
157542441Smckusick /* ARGSUSED */
157660414Smckusick ftruncate(p, uap, retval)
157745914Smckusick 	struct proc *p;
157860428Smckusick 	register struct ftruncate_args *uap;
157942441Smckusick 	int *retval;
158042441Smckusick {
158137741Smckusick 	struct vattr vattr;
158237741Smckusick 	struct vnode *vp;
15837701Ssam 	struct file *fp;
158437741Smckusick 	int error;
15857701Ssam 
158645914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
158747540Skarels 		return (error);
158837741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
158947540Skarels 		return (EINVAL);
159037741Smckusick 	vp = (struct vnode *)fp->f_data;
159159382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
159237741Smckusick 	VOP_LOCK(vp);
159364410Sbostic 	if (vp->v_type == VDIR)
159437741Smckusick 		error = EISDIR;
159564410Sbostic 	else if ((error = vn_writechk(vp)) == 0) {
159664410Sbostic 		VATTR_NULL(&vattr);
159764410Sbostic 		vattr.va_size = uap->length;
159864410Sbostic 		error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
15997701Ssam 	}
160037741Smckusick 	VOP_UNLOCK(vp);
160147540Skarels 	return (error);
16027701Ssam }
16037701Ssam 
160454863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
16059167Ssam /*
160654863Storek  * Truncate a file given its path name.
160754863Storek  */
160860428Smckusick struct otruncate_args {
160964410Sbostic 	char	*path;
161054916Storek 	long	length;
161154916Storek };
161254863Storek /* ARGSUSED */
161360105Smckusick otruncate(p, uap, retval)
161454863Storek 	struct proc *p;
161560428Smckusick 	register struct otruncate_args *uap;
161654863Storek 	int *retval;
161754863Storek {
161860428Smckusick 	struct truncate_args nuap;
161954863Storek 
162064410Sbostic 	nuap.path = uap->path;
162154863Storek 	nuap.length = uap->length;
162260428Smckusick 	return (truncate(p, &nuap, retval));
162354863Storek }
162454863Storek 
162554863Storek /*
162654863Storek  * Truncate a file given a file descriptor.
162754863Storek  */
162860428Smckusick struct oftruncate_args {
162954916Storek 	int	fd;
163054916Storek 	long	length;
163154916Storek };
163254863Storek /* ARGSUSED */
163360105Smckusick oftruncate(p, uap, retval)
163454863Storek 	struct proc *p;
163560428Smckusick 	register struct oftruncate_args *uap;
163654863Storek 	int *retval;
163754863Storek {
163860428Smckusick 	struct ftruncate_args nuap;
163954863Storek 
164054863Storek 	nuap.fd = uap->fd;
164154863Storek 	nuap.length = uap->length;
164260428Smckusick 	return (ftruncate(p, &nuap, retval));
164354863Storek }
164454863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */
164554863Storek 
164654863Storek /*
164764410Sbostic  * Sync an open file.
16489167Ssam  */
164954916Storek struct fsync_args {
165054916Storek 	int	fd;
165154916Storek };
165242441Smckusick /* ARGSUSED */
165342441Smckusick fsync(p, uap, retval)
165445914Smckusick 	struct proc *p;
165554916Storek 	struct fsync_args *uap;
165642441Smckusick 	int *retval;
16579167Ssam {
165839592Smckusick 	register struct vnode *vp;
16599167Ssam 	struct file *fp;
166037741Smckusick 	int error;
16619167Ssam 
166245914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
166347540Skarels 		return (error);
166439592Smckusick 	vp = (struct vnode *)fp->f_data;
166539592Smckusick 	VOP_LOCK(vp);
166654441Smckusick 	error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
166739592Smckusick 	VOP_UNLOCK(vp);
166847540Skarels 	return (error);
16699167Ssam }
16709167Ssam 
16719167Ssam /*
167264410Sbostic  * Rename files.  Source and destination must either both be directories,
167364410Sbostic  * or both not be directories.  If target is a directory, it must be empty.
16749167Ssam  */
167554916Storek struct rename_args {
167654916Storek 	char	*from;
167754916Storek 	char	*to;
167854916Storek };
167942441Smckusick /* ARGSUSED */
168042441Smckusick rename(p, uap, retval)
168145914Smckusick 	struct proc *p;
168254916Storek 	register struct rename_args *uap;
168342441Smckusick 	int *retval;
168442441Smckusick {
168537741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
168649735Smckusick 	struct nameidata fromnd, tond;
168737741Smckusick 	int error;
16887701Ssam 
168952322Smckusick 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
169052322Smckusick 		uap->from, p);
169152322Smckusick 	if (error = namei(&fromnd))
169247540Skarels 		return (error);
169349735Smckusick 	fvp = fromnd.ni_vp;
169452322Smckusick 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
169552322Smckusick 		UIO_USERSPACE, uap->to, p);
169652322Smckusick 	if (error = namei(&tond)) {
169752230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
169849735Smckusick 		vrele(fromnd.ni_dvp);
169942465Smckusick 		vrele(fvp);
170042465Smckusick 		goto out1;
170142465Smckusick 	}
170237741Smckusick 	tdvp = tond.ni_dvp;
170337741Smckusick 	tvp = tond.ni_vp;
170437741Smckusick 	if (tvp != NULL) {
170537741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
170639242Sbostic 			error = ENOTDIR;
170737741Smckusick 			goto out;
170837741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
170939242Sbostic 			error = EISDIR;
171037741Smckusick 			goto out;
17119167Ssam 		}
17129167Ssam 	}
171339286Smckusick 	if (fvp == tdvp)
171437741Smckusick 		error = EINVAL;
171539286Smckusick 	/*
171649735Smckusick 	 * If source is the same as the destination (that is the
171749735Smckusick 	 * same inode number with the same name in the same directory),
171839286Smckusick 	 * then there is nothing to do.
171939286Smckusick 	 */
172049735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
172152322Smckusick 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
172252322Smckusick 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
172352322Smckusick 	      fromnd.ni_cnd.cn_namelen))
172439286Smckusick 		error = -1;
172537741Smckusick out:
172642465Smckusick 	if (!error) {
172752192Smckusick 		LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE);
172852192Smckusick 		if (fromnd.ni_dvp != tdvp)
172952192Smckusick 			LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
173052192Smckusick 		if (tvp)
173152192Smckusick 			LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE);
173252230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
173352230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
173442465Smckusick 	} else {
173552230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
173643344Smckusick 		if (tdvp == tvp)
173743344Smckusick 			vrele(tdvp);
173843344Smckusick 		else
173943344Smckusick 			vput(tdvp);
174042465Smckusick 		if (tvp)
174142465Smckusick 			vput(tvp);
174252230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
174349735Smckusick 		vrele(fromnd.ni_dvp);
174442465Smckusick 		vrele(fvp);
17459167Ssam 	}
174649735Smckusick 	vrele(tond.ni_startdir);
174752322Smckusick 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
174837741Smckusick out1:
174966801Smckusick 	if (fromnd.ni_startdir)
175066801Smckusick 		vrele(fromnd.ni_startdir);
175152322Smckusick 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
175239286Smckusick 	if (error == -1)
175347540Skarels 		return (0);
175447540Skarels 	return (error);
17557701Ssam }
17567701Ssam 
17577535Sroot /*
175864410Sbostic  * Make a directory file.
175912756Ssam  */
176054916Storek struct mkdir_args {
176164410Sbostic 	char	*path;
176264410Sbostic 	int	mode;
176354916Storek };
176442441Smckusick /* ARGSUSED */
176542441Smckusick mkdir(p, uap, retval)
176645914Smckusick 	struct proc *p;
176754916Storek 	register struct mkdir_args *uap;
176842441Smckusick 	int *retval;
176942441Smckusick {
177037741Smckusick 	register struct vnode *vp;
177137741Smckusick 	struct vattr vattr;
177237741Smckusick 	int error;
177347540Skarels 	struct nameidata nd;
177412756Ssam 
177564410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
177652322Smckusick 	if (error = namei(&nd))
177747540Skarels 		return (error);
177852322Smckusick 	vp = nd.ni_vp;
177937741Smckusick 	if (vp != NULL) {
178052322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
178152322Smckusick 		if (nd.ni_dvp == vp)
178252322Smckusick 			vrele(nd.ni_dvp);
178343344Smckusick 		else
178452322Smckusick 			vput(nd.ni_dvp);
178542465Smckusick 		vrele(vp);
178647540Skarels 		return (EEXIST);
178712756Ssam 	}
178841362Smckusick 	VATTR_NULL(&vattr);
178937741Smckusick 	vattr.va_type = VDIR;
179064410Sbostic 	vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask;
179152322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
179252322Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
179338145Smckusick 	if (!error)
179452322Smckusick 		vput(nd.ni_vp);
179547540Skarels 	return (error);
179612756Ssam }
179712756Ssam 
179812756Ssam /*
179964410Sbostic  * Remove a directory file.
180012756Ssam  */
180154916Storek struct rmdir_args {
180264410Sbostic 	char	*path;
180354916Storek };
180442441Smckusick /* ARGSUSED */
180542441Smckusick rmdir(p, uap, retval)
180645914Smckusick 	struct proc *p;
180754916Storek 	struct rmdir_args *uap;
180842441Smckusick 	int *retval;
180912756Ssam {
181037741Smckusick 	register struct vnode *vp;
181137741Smckusick 	int error;
181247540Skarels 	struct nameidata nd;
181312756Ssam 
181464410Sbostic 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p);
181552322Smckusick 	if (error = namei(&nd))
181647540Skarels 		return (error);
181752322Smckusick 	vp = nd.ni_vp;
181837741Smckusick 	if (vp->v_type != VDIR) {
181937741Smckusick 		error = ENOTDIR;
182012756Ssam 		goto out;
182112756Ssam 	}
182212756Ssam 	/*
182337741Smckusick 	 * No rmdir "." please.
182412756Ssam 	 */
182552322Smckusick 	if (nd.ni_dvp == vp) {
182637741Smckusick 		error = EINVAL;
182712756Ssam 		goto out;
182812756Ssam 	}
182912756Ssam 	/*
183049365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
183112756Ssam 	 */
183237741Smckusick 	if (vp->v_flag & VROOT)
183337741Smckusick 		error = EBUSY;
183412756Ssam out:
183542465Smckusick 	if (!error) {
183652322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
183752192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
183852322Smckusick 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
183942465Smckusick 	} else {
184052322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
184152322Smckusick 		if (nd.ni_dvp == vp)
184252322Smckusick 			vrele(nd.ni_dvp);
184343344Smckusick 		else
184452322Smckusick 			vput(nd.ni_dvp);
184542465Smckusick 		vput(vp);
184642465Smckusick 	}
184747540Skarels 	return (error);
184812756Ssam }
184912756Ssam 
185054620Smckusick #ifdef COMPAT_43
185137741Smckusick /*
185249365Smckusick  * Read a block of directory entries in a file system independent format.
185337741Smckusick  */
185454916Storek struct ogetdirentries_args {
185554916Storek 	int	fd;
185654916Storek 	char	*buf;
185764410Sbostic 	u_int	count;
185854916Storek 	long	*basep;
185954916Storek };
186054620Smckusick ogetdirentries(p, uap, retval)
186154620Smckusick 	struct proc *p;
186254916Storek 	register struct ogetdirentries_args *uap;
186354620Smckusick 	int *retval;
186454620Smckusick {
186554620Smckusick 	register struct vnode *vp;
186654620Smckusick 	struct file *fp;
186754620Smckusick 	struct uio auio, kuio;
186854620Smckusick 	struct iovec aiov, kiov;
186954620Smckusick 	struct dirent *dp, *edp;
187054620Smckusick 	caddr_t dirbuf;
187167362Smckusick 	int error, eofflag, readcnt;
187254969Smckusick 	long loff;
187354620Smckusick 
187454620Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
187554620Smckusick 		return (error);
187654620Smckusick 	if ((fp->f_flag & FREAD) == 0)
187754620Smckusick 		return (EBADF);
187854620Smckusick 	vp = (struct vnode *)fp->f_data;
187967362Smckusick unionread:
188054620Smckusick 	if (vp->v_type != VDIR)
188154620Smckusick 		return (EINVAL);
188254620Smckusick 	aiov.iov_base = uap->buf;
188354620Smckusick 	aiov.iov_len = uap->count;
188454620Smckusick 	auio.uio_iov = &aiov;
188554620Smckusick 	auio.uio_iovcnt = 1;
188654620Smckusick 	auio.uio_rw = UIO_READ;
188754620Smckusick 	auio.uio_segflg = UIO_USERSPACE;
188854620Smckusick 	auio.uio_procp = p;
188954620Smckusick 	auio.uio_resid = uap->count;
189054620Smckusick 	VOP_LOCK(vp);
189154969Smckusick 	loff = auio.uio_offset = fp->f_offset;
189254620Smckusick #	if (BYTE_ORDER != LITTLE_ENDIAN)
189356339Smckusick 		if (vp->v_mount->mnt_maxsymlinklen <= 0) {
189467362Smckusick 			error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
189567362Smckusick 			    (u_long *)0, 0);
189656339Smckusick 			fp->f_offset = auio.uio_offset;
189756339Smckusick 		} else
189854620Smckusick #	endif
189954620Smckusick 	{
190054620Smckusick 		kuio = auio;
190154620Smckusick 		kuio.uio_iov = &kiov;
190254620Smckusick 		kuio.uio_segflg = UIO_SYSSPACE;
190354620Smckusick 		kiov.iov_len = uap->count;
190454620Smckusick 		MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK);
190554620Smckusick 		kiov.iov_base = dirbuf;
190667362Smckusick 		error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
190767362Smckusick 			    (u_long *)0, 0);
190856339Smckusick 		fp->f_offset = kuio.uio_offset;
190954620Smckusick 		if (error == 0) {
191054620Smckusick 			readcnt = uap->count - kuio.uio_resid;
191154620Smckusick 			edp = (struct dirent *)&dirbuf[readcnt];
191254620Smckusick 			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
191354620Smckusick #				if (BYTE_ORDER == LITTLE_ENDIAN)
191454969Smckusick 					/*
191555009Smckusick 					 * The expected low byte of
191655009Smckusick 					 * dp->d_namlen is our dp->d_type.
191755009Smckusick 					 * The high MBZ byte of dp->d_namlen
191855009Smckusick 					 * is our dp->d_namlen.
191954969Smckusick 					 */
192055009Smckusick 					dp->d_type = dp->d_namlen;
192155009Smckusick 					dp->d_namlen = 0;
192255009Smckusick #				else
192355009Smckusick 					/*
192455009Smckusick 					 * The dp->d_type is the high byte
192555009Smckusick 					 * of the expected dp->d_namlen,
192655009Smckusick 					 * so must be zero'ed.
192755009Smckusick 					 */
192855009Smckusick 					dp->d_type = 0;
192954620Smckusick #				endif
193054620Smckusick 				if (dp->d_reclen > 0) {
193154620Smckusick 					dp = (struct dirent *)
193254620Smckusick 					    ((char *)dp + dp->d_reclen);
193354620Smckusick 				} else {
193454620Smckusick 					error = EIO;
193554620Smckusick 					break;
193654620Smckusick 				}
193754620Smckusick 			}
193854620Smckusick 			if (dp >= edp)
193954620Smckusick 				error = uiomove(dirbuf, readcnt, &auio);
194054620Smckusick 		}
194154620Smckusick 		FREE(dirbuf, M_TEMP);
194254620Smckusick 	}
194354620Smckusick 	VOP_UNLOCK(vp);
194454620Smckusick 	if (error)
194554620Smckusick 		return (error);
194667362Smckusick 
194767362Smckusick #ifdef UNION
194867362Smckusick {
194967362Smckusick 	extern int (**union_vnodeop_p)();
195067362Smckusick 	extern struct vnode *union_lowervp __P((struct vnode *));
195167362Smckusick 
195267362Smckusick 	if ((uap->count == auio.uio_resid) &&
195367362Smckusick 	    (vp->v_op == union_vnodeop_p)) {
195467362Smckusick 		struct vnode *lvp;
195567362Smckusick 
195667362Smckusick 		lvp = union_lowervp(vp);
195767362Smckusick 		if (lvp != NULLVP) {
195867362Smckusick 			VOP_LOCK(lvp);
195967362Smckusick 			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
196067362Smckusick 			VOP_UNLOCK(lvp);
196167362Smckusick 
196267362Smckusick 			if (error) {
196367362Smckusick 				vrele(lvp);
196467362Smckusick 				return (error);
196567362Smckusick 			}
196667362Smckusick 			fp->f_data = (caddr_t) lvp;
196767362Smckusick 			fp->f_offset = 0;
196867362Smckusick 			error = vn_close(vp, FREAD, fp->f_cred, p);
196967362Smckusick 			if (error)
197067362Smckusick 				return (error);
197167362Smckusick 			vp = lvp;
197267362Smckusick 			goto unionread;
197367362Smckusick 		}
197467362Smckusick 	}
197567362Smckusick }
197667362Smckusick #endif /* UNION */
197767362Smckusick 
197867362Smckusick 	if ((uap->count == auio.uio_resid) &&
197967362Smckusick 	    (vp->v_flag & VROOT) &&
198067362Smckusick 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
198167362Smckusick 		struct vnode *tvp = vp;
198267362Smckusick 		vp = vp->v_mount->mnt_vnodecovered;
198367362Smckusick 		VREF(vp);
198467362Smckusick 		fp->f_data = (caddr_t) vp;
198567362Smckusick 		fp->f_offset = 0;
198667362Smckusick 		vrele(tvp);
198767362Smckusick 		goto unionread;
198867362Smckusick 	}
198954969Smckusick 	error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
199054620Smckusick 	*retval = uap->count - auio.uio_resid;
199154620Smckusick 	return (error);
199254620Smckusick }
199367362Smckusick #endif /* COMPAT_43 */
199454620Smckusick 
199554620Smckusick /*
199654620Smckusick  * Read a block of directory entries in a file system independent format.
199754620Smckusick  */
199854916Storek struct getdirentries_args {
199954916Storek 	int	fd;
200054916Storek 	char	*buf;
200164410Sbostic 	u_int	count;
200254916Storek 	long	*basep;
200354916Storek };
200442441Smckusick getdirentries(p, uap, retval)
200545914Smckusick 	struct proc *p;
200654916Storek 	register struct getdirentries_args *uap;
200742441Smckusick 	int *retval;
200842441Smckusick {
200939592Smckusick 	register struct vnode *vp;
201016540Ssam 	struct file *fp;
201137741Smckusick 	struct uio auio;
201237741Smckusick 	struct iovec aiov;
201354969Smckusick 	long loff;
201467362Smckusick 	int error, eofflag;
201512756Ssam 
201645914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
201747540Skarels 		return (error);
201837741Smckusick 	if ((fp->f_flag & FREAD) == 0)
201947540Skarels 		return (EBADF);
202039592Smckusick 	vp = (struct vnode *)fp->f_data;
202155451Spendry unionread:
202239592Smckusick 	if (vp->v_type != VDIR)
202347540Skarels 		return (EINVAL);
202437741Smckusick 	aiov.iov_base = uap->buf;
202537741Smckusick 	aiov.iov_len = uap->count;
202637741Smckusick 	auio.uio_iov = &aiov;
202737741Smckusick 	auio.uio_iovcnt = 1;
202837741Smckusick 	auio.uio_rw = UIO_READ;
202937741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
203048026Smckusick 	auio.uio_procp = p;
203137741Smckusick 	auio.uio_resid = uap->count;
203239592Smckusick 	VOP_LOCK(vp);
203354969Smckusick 	loff = auio.uio_offset = fp->f_offset;
203467362Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *)0, 0);
203539592Smckusick 	fp->f_offset = auio.uio_offset;
203639592Smckusick 	VOP_UNLOCK(vp);
203739592Smckusick 	if (error)
203847540Skarels 		return (error);
203966095Spendry 
204066095Spendry #ifdef UNION
204166095Spendry {
204266095Spendry 	extern int (**union_vnodeop_p)();
204366095Spendry 	extern struct vnode *union_lowervp __P((struct vnode *));
204466095Spendry 
204555451Spendry 	if ((uap->count == auio.uio_resid) &&
204666095Spendry 	    (vp->v_op == union_vnodeop_p)) {
204767122Spendry 		struct vnode *lvp;
204866095Spendry 
204967122Spendry 		lvp = union_lowervp(vp);
205067122Spendry 		if (lvp != NULLVP) {
205167122Spendry 			VOP_LOCK(lvp);
205267362Smckusick 			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
205367122Spendry 			VOP_UNLOCK(lvp);
205466095Spendry 
205566095Spendry 			if (error) {
205667122Spendry 				vrele(lvp);
205766095Spendry 				return (error);
205866095Spendry 			}
205967122Spendry 			fp->f_data = (caddr_t) lvp;
206066095Spendry 			fp->f_offset = 0;
206167122Spendry 			error = vn_close(vp, FREAD, fp->f_cred, p);
206266095Spendry 			if (error)
206366095Spendry 				return (error);
206467122Spendry 			vp = lvp;
206566095Spendry 			goto unionread;
206666095Spendry 		}
206766095Spendry 	}
206866095Spendry }
206966095Spendry #endif
207066095Spendry 
207166095Spendry 	if ((uap->count == auio.uio_resid) &&
207255451Spendry 	    (vp->v_flag & VROOT) &&
207355451Spendry 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
207455451Spendry 		struct vnode *tvp = vp;
207555451Spendry 		vp = vp->v_mount->mnt_vnodecovered;
207655451Spendry 		VREF(vp);
207755451Spendry 		fp->f_data = (caddr_t) vp;
207855451Spendry 		fp->f_offset = 0;
207955451Spendry 		vrele(tvp);
208055451Spendry 		goto unionread;
208155451Spendry 	}
208254969Smckusick 	error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
208342441Smckusick 	*retval = uap->count - auio.uio_resid;
208447540Skarels 	return (error);
208512756Ssam }
208612756Ssam 
208712756Ssam /*
208849365Smckusick  * Set the mode mask for creation of filesystem nodes.
208912756Ssam  */
209054916Storek struct umask_args {
209164410Sbostic 	int	newmask;
209254916Storek };
209354916Storek mode_t				/* XXX */
209442441Smckusick umask(p, uap, retval)
209545914Smckusick 	struct proc *p;
209654916Storek 	struct umask_args *uap;
209742441Smckusick 	int *retval;
209812756Ssam {
209964410Sbostic 	register struct filedesc *fdp;
210012756Ssam 
210164410Sbostic 	fdp = p->p_fd;
210245914Smckusick 	*retval = fdp->fd_cmask;
210364410Sbostic 	fdp->fd_cmask = uap->newmask & ALLPERMS;
210447540Skarels 	return (0);
210512756Ssam }
210637741Smckusick 
210739566Smarc /*
210839566Smarc  * Void all references to file by ripping underlying filesystem
210939566Smarc  * away from vnode.
211039566Smarc  */
211154916Storek struct revoke_args {
211264410Sbostic 	char	*path;
211354916Storek };
211442441Smckusick /* ARGSUSED */
211542441Smckusick revoke(p, uap, retval)
211645914Smckusick 	struct proc *p;
211754916Storek 	register struct revoke_args *uap;
211842441Smckusick 	int *retval;
211942441Smckusick {
212039566Smarc 	register struct vnode *vp;
212139566Smarc 	struct vattr vattr;
212239566Smarc 	int error;
212347540Skarels 	struct nameidata nd;
212439566Smarc 
212564410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
212652322Smckusick 	if (error = namei(&nd))
212747540Skarels 		return (error);
212852322Smckusick 	vp = nd.ni_vp;
212939566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
213039566Smarc 		error = EINVAL;
213139566Smarc 		goto out;
213239566Smarc 	}
213348026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
213439566Smarc 		goto out;
213547540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
213647540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
213739566Smarc 		goto out;
213839805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
213939632Smckusick 		vgoneall(vp);
214039566Smarc out:
214139566Smarc 	vrele(vp);
214247540Skarels 	return (error);
214339566Smarc }
214439566Smarc 
214549365Smckusick /*
214649365Smckusick  * Convert a user file descriptor to a kernel file entry.
214749365Smckusick  */
214864410Sbostic getvnode(fdp, fd, fpp)
214945914Smckusick 	struct filedesc *fdp;
215037741Smckusick 	struct file **fpp;
215164410Sbostic 	int fd;
215237741Smckusick {
215337741Smckusick 	struct file *fp;
215437741Smckusick 
215564410Sbostic 	if ((u_int)fd >= fdp->fd_nfiles ||
215664410Sbostic 	    (fp = fdp->fd_ofiles[fd]) == NULL)
215737741Smckusick 		return (EBADF);
215837741Smckusick 	if (fp->f_type != DTYPE_VNODE)
215937741Smckusick 		return (EINVAL);
216037741Smckusick 	*fpp = fp;
216137741Smckusick 	return (0);
216237741Smckusick }
2163