xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 64410)
123405Smckusick /*
263428Sbostic  * Copyright (c) 1989, 1993
363428Sbostic  *	The Regents of the University of California.  All rights reserved.
423405Smckusick  *
544459Sbostic  * %sccs.include.redist.c%
637741Smckusick  *
7*64410Sbostic  *	@(#)vfs_syscalls.c	8.2 (Berkeley) 09/05/93
823405Smckusick  */
937Sbill 
1056517Sbostic #include <sys/param.h>
1156517Sbostic #include <sys/systm.h>
1256517Sbostic #include <sys/namei.h>
1356517Sbostic #include <sys/filedesc.h>
1456517Sbostic #include <sys/kernel.h>
1556517Sbostic #include <sys/file.h>
1656517Sbostic #include <sys/stat.h>
1756517Sbostic #include <sys/vnode.h>
1856517Sbostic #include <sys/mount.h>
1956517Sbostic #include <sys/proc.h>
2056517Sbostic #include <sys/uio.h>
2156517Sbostic #include <sys/malloc.h>
2256517Sbostic #include <sys/dirent.h>
2356517Sbostic 
2453468Smckusick #include <vm/vm.h>
2559875Smckusick #include <sys/sysctl.h>
2637Sbill 
27*64410Sbostic static int change_dir __P((struct nameidata *ndp, struct proc *p));
28*64410Sbostic 
2937741Smckusick /*
3037741Smckusick  * Virtual File System System Calls
3137741Smckusick  */
3212756Ssam 
339167Ssam /*
34*64410Sbostic  * Mount a file system.
359167Ssam  */
3654916Storek struct mount_args {
3754916Storek 	int	type;
38*64410Sbostic 	char	*path;
3954916Storek 	int	flags;
4054916Storek 	caddr_t	data;
4154916Storek };
4242441Smckusick /* ARGSUSED */
4342441Smckusick mount(p, uap, retval)
4445914Smckusick 	struct proc *p;
4554916Storek 	register struct mount_args *uap;
4642441Smckusick 	int *retval;
4742441Smckusick {
4839335Smckusick 	register struct vnode *vp;
4939335Smckusick 	register struct mount *mp;
5040111Smckusick 	int error, flag;
5147540Skarels 	struct nameidata nd;
526254Sroot 
5337741Smckusick 	/*
5437741Smckusick 	 * Must be super user
5537741Smckusick 	 */
5647540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
5747540Skarels 		return (error);
5837741Smckusick 	/*
5937741Smckusick 	 * Get vnode to be covered
6037741Smckusick 	 */
61*64410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
6252322Smckusick 	if (error = namei(&nd))
6347540Skarels 		return (error);
6452322Smckusick 	vp = nd.ni_vp;
6541400Smckusick 	if (uap->flags & MNT_UPDATE) {
6639335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
6739335Smckusick 			vput(vp);
6847540Skarels 			return (EINVAL);
6939335Smckusick 		}
7039335Smckusick 		mp = vp->v_mount;
7157047Smckusick 		flag = mp->mnt_flag;
7239335Smckusick 		/*
7357047Smckusick 		 * We only allow the filesystem to be reloaded if it
7457047Smckusick 		 * is currently mounted read-only.
7539335Smckusick 		 */
7657047Smckusick 		if ((uap->flags & MNT_RELOAD) &&
7757047Smckusick 		    ((mp->mnt_flag & MNT_RDONLY) == 0)) {
7839335Smckusick 			vput(vp);
7947540Skarels 			return (EOPNOTSUPP);	/* Needs translation */
8039335Smckusick 		}
8157047Smckusick 		mp->mnt_flag |=
8257047Smckusick 		    uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
8339335Smckusick 		VOP_UNLOCK(vp);
8439335Smckusick 		goto update;
8539335Smckusick 	}
8655451Spendry 	if (vp->v_usecount != 1 && (uap->flags & MNT_UNION) == 0) {
8737741Smckusick 		vput(vp);
8847540Skarels 		return (EBUSY);
8937741Smckusick 	}
9057793Smckusick 	if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0))
9154441Smckusick 		return (error);
9237741Smckusick 	if (vp->v_type != VDIR) {
9337741Smckusick 		vput(vp);
9447540Skarels 		return (ENOTDIR);
9537741Smckusick 	}
96*64410Sbostic 	if ((u_long)uap->type > MOUNT_MAXTYPE || vfssw[uap->type] == NULL) {
9737741Smckusick 		vput(vp);
9847540Skarels 		return (ENODEV);
9937741Smckusick 	}
10037741Smckusick 
10137741Smckusick 	/*
10239335Smckusick 	 * Allocate and initialize the file system.
10337741Smckusick 	 */
10437741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
10537741Smckusick 		M_MOUNT, M_WAITOK);
10654172Smckusick 	bzero((char *)mp, (u_long)sizeof(struct mount));
10741400Smckusick 	mp->mnt_op = vfssw[uap->type];
10839335Smckusick 	if (error = vfs_lock(mp)) {
10939335Smckusick 		free((caddr_t)mp, M_MOUNT);
11039335Smckusick 		vput(vp);
11147540Skarels 		return (error);
11239335Smckusick 	}
113*64410Sbostic 	if (vp->v_mountedhere != NULL) {
11439335Smckusick 		vfs_unlock(mp);
11539335Smckusick 		free((caddr_t)mp, M_MOUNT);
11639335Smckusick 		vput(vp);
11747540Skarels 		return (EBUSY);
11839335Smckusick 	}
11939335Smckusick 	vp->v_mountedhere = mp;
12041400Smckusick 	mp->mnt_vnodecovered = vp;
12139335Smckusick update:
12239335Smckusick 	/*
12339335Smckusick 	 * Set the mount level flags.
12439335Smckusick 	 */
12541400Smckusick 	if (uap->flags & MNT_RDONLY)
12641400Smckusick 		mp->mnt_flag |= MNT_RDONLY;
12757047Smckusick 	else if (mp->mnt_flag & MNT_RDONLY)
12857047Smckusick 		mp->mnt_flag |= MNT_WANTRDWR;
12957047Smckusick 	mp->mnt_flag &=~
13057047Smckusick 	    (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION);
13157047Smckusick 	mp->mnt_flag |= uap->flags &
13257047Smckusick 	    (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION);
13339335Smckusick 	/*
13439335Smckusick 	 * Mount the filesystem.
13539335Smckusick 	 */
136*64410Sbostic 	error = VFS_MOUNT(mp, uap->path, uap->data, &nd, p);
13741400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
13839335Smckusick 		vrele(vp);
13957047Smckusick 		if (mp->mnt_flag & MNT_WANTRDWR)
14057047Smckusick 			mp->mnt_flag &= ~MNT_RDONLY;
14157047Smckusick 		mp->mnt_flag &=~
14257047Smckusick 		    (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
14340111Smckusick 		if (error)
14441400Smckusick 			mp->mnt_flag = flag;
14547540Skarels 		return (error);
14639335Smckusick 	}
14740110Smckusick 	/*
14840110Smckusick 	 * Put the new filesystem on the mount list after root.
14940110Smckusick 	 */
15041400Smckusick 	mp->mnt_next = rootfs->mnt_next;
15141400Smckusick 	mp->mnt_prev = rootfs;
15241400Smckusick 	rootfs->mnt_next = mp;
15341400Smckusick 	mp->mnt_next->mnt_prev = mp;
15437741Smckusick 	cache_purge(vp);
15537741Smckusick 	if (!error) {
15639335Smckusick 		VOP_UNLOCK(vp);
15737741Smckusick 		vfs_unlock(mp);
15848026Smckusick 		error = VFS_START(mp, 0, p);
15937741Smckusick 	} else {
16037741Smckusick 		vfs_remove(mp);
16137741Smckusick 		free((caddr_t)mp, M_MOUNT);
16239335Smckusick 		vput(vp);
16337741Smckusick 	}
16447540Skarels 	return (error);
1656254Sroot }
1666254Sroot 
1679167Ssam /*
168*64410Sbostic  * Unmount a file system.
16937741Smckusick  *
17037741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
17137741Smckusick  * not special file (as before).
1729167Ssam  */
17354916Storek struct unmount_args {
174*64410Sbostic 	char	*path;
17554916Storek 	int	flags;
17654916Storek };
17742441Smckusick /* ARGSUSED */
17842441Smckusick unmount(p, uap, retval)
17945914Smckusick 	struct proc *p;
18054916Storek 	register struct unmount_args *uap;
18142441Smckusick 	int *retval;
18242441Smckusick {
18337741Smckusick 	register struct vnode *vp;
18439356Smckusick 	struct mount *mp;
18537741Smckusick 	int error;
18647540Skarels 	struct nameidata nd;
1876254Sroot 
18837741Smckusick 	/*
18937741Smckusick 	 * Must be super user
19037741Smckusick 	 */
19147540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
19247540Skarels 		return (error);
19337741Smckusick 
194*64410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
19552322Smckusick 	if (error = namei(&nd))
19647540Skarels 		return (error);
19752322Smckusick 	vp = nd.ni_vp;
19837741Smckusick 	/*
19937741Smckusick 	 * Must be the root of the filesystem
20037741Smckusick 	 */
20137741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
20237741Smckusick 		vput(vp);
20347540Skarels 		return (EINVAL);
20437741Smckusick 	}
20537741Smckusick 	mp = vp->v_mount;
20637741Smckusick 	vput(vp);
20748026Smckusick 	return (dounmount(mp, uap->flags, p));
20839356Smckusick }
20939356Smckusick 
21039356Smckusick /*
211*64410Sbostic  * Do the actual file system unmount.
21239356Smckusick  */
21348026Smckusick dounmount(mp, flags, p)
21439356Smckusick 	register struct mount *mp;
21539356Smckusick 	int flags;
21648026Smckusick 	struct proc *p;
21739356Smckusick {
21839356Smckusick 	struct vnode *coveredvp;
21939356Smckusick 	int error;
22039356Smckusick 
22141400Smckusick 	coveredvp = mp->mnt_vnodecovered;
22241298Smckusick 	if (vfs_busy(mp))
22341298Smckusick 		return (EBUSY);
22441400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
22537741Smckusick 	if (error = vfs_lock(mp))
22639356Smckusick 		return (error);
22737741Smckusick 
22845738Smckusick 	vnode_pager_umount(mp);	/* release cached vnodes */
22937741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
23054441Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 ||
23154441Smckusick 	    (flags & MNT_FORCE))
23248026Smckusick 		error = VFS_UNMOUNT(mp, flags, p);
23341400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
23441298Smckusick 	vfs_unbusy(mp);
23537741Smckusick 	if (error) {
23637741Smckusick 		vfs_unlock(mp);
23737741Smckusick 	} else {
23837741Smckusick 		vrele(coveredvp);
23937741Smckusick 		vfs_remove(mp);
24052287Smckusick 		if (mp->mnt_mounth != NULL)
24152287Smckusick 			panic("unmount: dangling vnode");
24237741Smckusick 		free((caddr_t)mp, M_MOUNT);
24337741Smckusick 	}
24439356Smckusick 	return (error);
2456254Sroot }
2466254Sroot 
2479167Ssam /*
24837741Smckusick  * Sync each mounted filesystem.
2499167Ssam  */
25056352Smckusick #ifdef DIAGNOSTIC
25156352Smckusick int syncprt = 0;
25259875Smckusick struct ctldebug debug0 = { "syncprt", &syncprt };
25356352Smckusick #endif
25456352Smckusick 
25554916Storek struct sync_args {
25654916Storek 	int	dummy;
25754916Storek };
25839491Smckusick /* ARGSUSED */
25942441Smckusick sync(p, uap, retval)
26045914Smckusick 	struct proc *p;
26154916Storek 	struct sync_args *uap;
26242441Smckusick 	int *retval;
2636254Sroot {
26437741Smckusick 	register struct mount *mp;
26541298Smckusick 	struct mount *omp;
26637741Smckusick 
26737741Smckusick 	mp = rootfs;
26837741Smckusick 	do {
26940343Smckusick 		/*
27040343Smckusick 		 * The lock check below is to avoid races with mount
27140343Smckusick 		 * and unmount.
27240343Smckusick 		 */
27341400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
27441298Smckusick 		    !vfs_busy(mp)) {
27554441Smckusick 			VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
27641298Smckusick 			omp = mp;
27741400Smckusick 			mp = mp->mnt_next;
27841298Smckusick 			vfs_unbusy(omp);
27941298Smckusick 		} else
28041400Smckusick 			mp = mp->mnt_next;
28137741Smckusick 	} while (mp != rootfs);
28256352Smckusick #ifdef DIAGNOSTIC
28356352Smckusick 	if (syncprt)
28456352Smckusick 		vfs_bufstats();
28556352Smckusick #endif /* DIAGNOSTIC */
28647688Skarels 	return (0);
28737741Smckusick }
28837741Smckusick 
28937741Smckusick /*
290*64410Sbostic  * Change filesystem quotas.
29141298Smckusick  */
29254916Storek struct quotactl_args {
29354916Storek 	char *path;
29454916Storek 	int cmd;
29554916Storek 	int uid;
29654916Storek 	caddr_t arg;
29754916Storek };
29842441Smckusick /* ARGSUSED */
29942441Smckusick quotactl(p, uap, retval)
30045914Smckusick 	struct proc *p;
30154916Storek 	register struct quotactl_args *uap;
30242441Smckusick 	int *retval;
30342441Smckusick {
30441298Smckusick 	register struct mount *mp;
30541298Smckusick 	int error;
30647540Skarels 	struct nameidata nd;
30741298Smckusick 
30852322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
30952322Smckusick 	if (error = namei(&nd))
31047540Skarels 		return (error);
31152322Smckusick 	mp = nd.ni_vp->v_mount;
31252322Smckusick 	vrele(nd.ni_vp);
31348026Smckusick 	return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p));
31441298Smckusick }
31541298Smckusick 
31641298Smckusick /*
31749365Smckusick  * Get filesystem statistics.
31837741Smckusick  */
31954916Storek struct statfs_args {
32054916Storek 	char *path;
32154916Storek 	struct statfs *buf;
32254916Storek };
32342441Smckusick /* ARGSUSED */
32442441Smckusick statfs(p, uap, retval)
32545914Smckusick 	struct proc *p;
32654916Storek 	register struct statfs_args *uap;
32742441Smckusick 	int *retval;
32842441Smckusick {
32939464Smckusick 	register struct mount *mp;
33040343Smckusick 	register struct statfs *sp;
33137741Smckusick 	int error;
33247540Skarels 	struct nameidata nd;
33337741Smckusick 
33452322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
33552322Smckusick 	if (error = namei(&nd))
33647540Skarels 		return (error);
33752322Smckusick 	mp = nd.ni_vp->v_mount;
33841400Smckusick 	sp = &mp->mnt_stat;
33952322Smckusick 	vrele(nd.ni_vp);
34048026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
34147540Skarels 		return (error);
34241400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
34347540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
34437741Smckusick }
34537741Smckusick 
34642441Smckusick /*
34749365Smckusick  * Get filesystem statistics.
34842441Smckusick  */
34954916Storek struct fstatfs_args {
35054916Storek 	int fd;
35154916Storek 	struct statfs *buf;
35254916Storek };
35342441Smckusick /* ARGSUSED */
35442441Smckusick fstatfs(p, uap, retval)
35545914Smckusick 	struct proc *p;
35654916Storek 	register struct fstatfs_args *uap;
35742441Smckusick 	int *retval;
35842441Smckusick {
35937741Smckusick 	struct file *fp;
36039464Smckusick 	struct mount *mp;
36140343Smckusick 	register struct statfs *sp;
36237741Smckusick 	int error;
36337741Smckusick 
36445914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
36547540Skarels 		return (error);
36639464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
36741400Smckusick 	sp = &mp->mnt_stat;
36848026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
36947540Skarels 		return (error);
37041400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
37147540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
37237741Smckusick }
37337741Smckusick 
37437741Smckusick /*
37549365Smckusick  * Get statistics on all filesystems.
37638270Smckusick  */
37754916Storek struct getfsstat_args {
37854916Storek 	struct statfs *buf;
37954916Storek 	long bufsize;
38054916Storek 	int flags;
38154916Storek };
38242441Smckusick getfsstat(p, uap, retval)
38345914Smckusick 	struct proc *p;
38454916Storek 	register struct getfsstat_args *uap;
38542441Smckusick 	int *retval;
38642441Smckusick {
38738270Smckusick 	register struct mount *mp;
38840343Smckusick 	register struct statfs *sp;
38939606Smckusick 	caddr_t sfsp;
39038270Smckusick 	long count, maxcount, error;
39138270Smckusick 
39238270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
39339606Smckusick 	sfsp = (caddr_t)uap->buf;
39438270Smckusick 	mp = rootfs;
39538270Smckusick 	count = 0;
39638270Smckusick 	do {
39741400Smckusick 		if (sfsp && count < maxcount &&
39841400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
39941400Smckusick 			sp = &mp->mnt_stat;
40040343Smckusick 			/*
40140343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
40240343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
40340343Smckusick 			 */
40440343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
40540343Smckusick 			    (uap->flags & MNT_WAIT)) &&
40648026Smckusick 			    (error = VFS_STATFS(mp, sp, p))) {
40741400Smckusick 				mp = mp->mnt_prev;
40839607Smckusick 				continue;
40939607Smckusick 			}
41041400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
41140343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
41247540Skarels 				return (error);
41340343Smckusick 			sfsp += sizeof(*sp);
41438270Smckusick 		}
41539606Smckusick 		count++;
41641400Smckusick 		mp = mp->mnt_prev;
41738270Smckusick 	} while (mp != rootfs);
41838270Smckusick 	if (sfsp && count > maxcount)
41942441Smckusick 		*retval = maxcount;
42038270Smckusick 	else
42142441Smckusick 		*retval = count;
42247540Skarels 	return (0);
42338270Smckusick }
42438270Smckusick 
42538270Smckusick /*
42638259Smckusick  * Change current working directory to a given file descriptor.
42738259Smckusick  */
42854916Storek struct fchdir_args {
42954916Storek 	int	fd;
43054916Storek };
43142441Smckusick /* ARGSUSED */
43242441Smckusick fchdir(p, uap, retval)
43345914Smckusick 	struct proc *p;
43454916Storek 	struct fchdir_args *uap;
43542441Smckusick 	int *retval;
43638259Smckusick {
43745914Smckusick 	register struct filedesc *fdp = p->p_fd;
43838259Smckusick 	register struct vnode *vp;
43938259Smckusick 	struct file *fp;
44038259Smckusick 	int error;
44138259Smckusick 
44245914Smckusick 	if (error = getvnode(fdp, uap->fd, &fp))
44347540Skarels 		return (error);
44438259Smckusick 	vp = (struct vnode *)fp->f_data;
44538259Smckusick 	VOP_LOCK(vp);
44638259Smckusick 	if (vp->v_type != VDIR)
44738259Smckusick 		error = ENOTDIR;
44838259Smckusick 	else
44948026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
45038259Smckusick 	VOP_UNLOCK(vp);
45139860Smckusick 	if (error)
45247540Skarels 		return (error);
45339860Smckusick 	VREF(vp);
45445914Smckusick 	vrele(fdp->fd_cdir);
45545914Smckusick 	fdp->fd_cdir = vp;
45647540Skarels 	return (0);
45738259Smckusick }
45838259Smckusick 
45938259Smckusick /*
46037741Smckusick  * Change current working directory (``.'').
46137741Smckusick  */
46254916Storek struct chdir_args {
463*64410Sbostic 	char	*path;
46454916Storek };
46542441Smckusick /* ARGSUSED */
46642441Smckusick chdir(p, uap, retval)
46745914Smckusick 	struct proc *p;
46854916Storek 	struct chdir_args *uap;
46942441Smckusick 	int *retval;
47037741Smckusick {
47145914Smckusick 	register struct filedesc *fdp = p->p_fd;
47237741Smckusick 	int error;
47347540Skarels 	struct nameidata nd;
4746254Sroot 
475*64410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
476*64410Sbostic 	if (error = change_dir(&nd, p))
47747540Skarels 		return (error);
47845914Smckusick 	vrele(fdp->fd_cdir);
47952322Smckusick 	fdp->fd_cdir = nd.ni_vp;
48047540Skarels 	return (0);
48137741Smckusick }
4826254Sroot 
48337741Smckusick /*
48437741Smckusick  * Change notion of root (``/'') directory.
48537741Smckusick  */
48654916Storek struct chroot_args {
487*64410Sbostic 	char	*path;
48854916Storek };
48942441Smckusick /* ARGSUSED */
49042441Smckusick chroot(p, uap, retval)
49145914Smckusick 	struct proc *p;
49254916Storek 	struct chroot_args *uap;
49342441Smckusick 	int *retval;
49437741Smckusick {
49545914Smckusick 	register struct filedesc *fdp = p->p_fd;
49637741Smckusick 	int error;
49747540Skarels 	struct nameidata nd;
49837741Smckusick 
49947540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
50047540Skarels 		return (error);
501*64410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
502*64410Sbostic 	if (error = change_dir(&nd, p))
50347540Skarels 		return (error);
50445914Smckusick 	if (fdp->fd_rdir != NULL)
50545914Smckusick 		vrele(fdp->fd_rdir);
50652322Smckusick 	fdp->fd_rdir = nd.ni_vp;
50747540Skarels 	return (0);
5086254Sroot }
5096254Sroot 
51037Sbill /*
51137741Smckusick  * Common routine for chroot and chdir.
51237741Smckusick  */
513*64410Sbostic static int
514*64410Sbostic change_dir(ndp, p)
51552322Smckusick 	register struct nameidata *ndp;
51647540Skarels 	struct proc *p;
51737741Smckusick {
51837741Smckusick 	struct vnode *vp;
51937741Smckusick 	int error;
52037741Smckusick 
52152322Smckusick 	if (error = namei(ndp))
52237741Smckusick 		return (error);
52337741Smckusick 	vp = ndp->ni_vp;
52437741Smckusick 	if (vp->v_type != VDIR)
52537741Smckusick 		error = ENOTDIR;
52637741Smckusick 	else
52748026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
52837741Smckusick 	VOP_UNLOCK(vp);
52937741Smckusick 	if (error)
53037741Smckusick 		vrele(vp);
53137741Smckusick 	return (error);
53237741Smckusick }
53337741Smckusick 
53437741Smckusick /*
53542441Smckusick  * Check permissions, allocate an open file structure,
53642441Smckusick  * and call the device open routine if any.
5376254Sroot  */
53854916Storek struct open_args {
539*64410Sbostic 	char	*path;
540*64410Sbostic 	int	flags;
54154916Storek 	int	mode;
54254916Storek };
54342441Smckusick open(p, uap, retval)
54445914Smckusick 	struct proc *p;
54554916Storek 	register struct open_args *uap;
54642441Smckusick 	int *retval;
5476254Sroot {
54845914Smckusick 	register struct filedesc *fdp = p->p_fd;
54942441Smckusick 	register struct file *fp;
55050111Smckusick 	register struct vnode *vp;
551*64410Sbostic 	int flags, cmode;
55237741Smckusick 	struct file *nfp;
55349945Smckusick 	int type, indx, error;
55449945Smckusick 	struct flock lf;
55547540Skarels 	struct nameidata nd;
55637741Smckusick 	extern struct fileops vnops;
5576254Sroot 
55845914Smckusick 	if (error = falloc(p, &nfp, &indx))
55947540Skarels 		return (error);
56037741Smckusick 	fp = nfp;
561*64410Sbostic 	flags = FFLAGS(uap->flags);
562*64410Sbostic 	cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
563*64410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
56445202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
565*64410Sbostic 	if (error = vn_open(&nd, flags, cmode)) {
56649980Smckusick 		ffree(fp);
56754723Smckusick 		if ((error == ENODEV || error == ENXIO) &&
56854723Smckusick 		    p->p_dupfd >= 0 && 			/* XXX from fdopen */
569*64410Sbostic 		    (error =
570*64410Sbostic 		        dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
57142441Smckusick 			*retval = indx;
57247540Skarels 			return (0);
57342441Smckusick 		}
57440884Smckusick 		if (error == ERESTART)
57540884Smckusick 			error = EINTR;
57647688Skarels 		fdp->fd_ofiles[indx] = NULL;
57747540Skarels 		return (error);
57812756Ssam 	}
57953828Spendry 	p->p_dupfd = 0;
58052322Smckusick 	vp = nd.ni_vp;
581*64410Sbostic 	fp->f_flag = flags & FMASK;
58254348Smckusick 	fp->f_type = DTYPE_VNODE;
58354348Smckusick 	fp->f_ops = &vnops;
58454348Smckusick 	fp->f_data = (caddr_t)vp;
585*64410Sbostic 	if (flags & (O_EXLOCK | O_SHLOCK)) {
58649945Smckusick 		lf.l_whence = SEEK_SET;
58749945Smckusick 		lf.l_start = 0;
58849945Smckusick 		lf.l_len = 0;
589*64410Sbostic 		if (flags & O_EXLOCK)
59049945Smckusick 			lf.l_type = F_WRLCK;
59149945Smckusick 		else
59249945Smckusick 			lf.l_type = F_RDLCK;
59349945Smckusick 		type = F_FLOCK;
594*64410Sbostic 		if ((flags & FNONBLOCK) == 0)
59549945Smckusick 			type |= F_WAIT;
59650111Smckusick 		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
59750111Smckusick 			VOP_UNLOCK(vp);
59850111Smckusick 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
59949980Smckusick 			ffree(fp);
60049945Smckusick 			fdp->fd_ofiles[indx] = NULL;
60149945Smckusick 			return (error);
60249945Smckusick 		}
60349949Smckusick 		fp->f_flag |= FHASLOCK;
60449945Smckusick 	}
60550111Smckusick 	VOP_UNLOCK(vp);
60642441Smckusick 	*retval = indx;
60747540Skarels 	return (0);
6086254Sroot }
6096254Sroot 
61042955Smckusick #ifdef COMPAT_43
6116254Sroot /*
612*64410Sbostic  * Create a file.
6136254Sroot  */
61454916Storek struct ocreat_args {
615*64410Sbostic 	char	*path;
616*64410Sbostic 	int	mode;
61754916Storek };
61842955Smckusick ocreat(p, uap, retval)
61942441Smckusick 	struct proc *p;
62054916Storek 	register struct ocreat_args *uap;
62142441Smckusick 	int *retval;
6226254Sroot {
62354916Storek 	struct open_args openuap;
62442441Smckusick 
625*64410Sbostic 	openuap.path = uap->path;
626*64410Sbostic 	openuap.mode = uap->mode;
627*64410Sbostic 	openuap.flags = O_WRONLY | O_CREAT | O_TRUNC;
62847540Skarels 	return (open(p, &openuap, retval));
62942441Smckusick }
63042955Smckusick #endif /* COMPAT_43 */
63142441Smckusick 
63242441Smckusick /*
633*64410Sbostic  * Create a special file.
63442441Smckusick  */
63554916Storek struct mknod_args {
636*64410Sbostic 	char	*path;
637*64410Sbostic 	int	mode;
63854916Storek 	int	dev;
63954916Storek };
64042441Smckusick /* ARGSUSED */
64142441Smckusick mknod(p, uap, retval)
64245914Smckusick 	struct proc *p;
64354916Storek 	register struct mknod_args *uap;
64442441Smckusick 	int *retval;
64542441Smckusick {
64637741Smckusick 	register struct vnode *vp;
64737741Smckusick 	struct vattr vattr;
64837741Smckusick 	int error;
64947540Skarels 	struct nameidata nd;
6506254Sroot 
65147540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
65247540Skarels 		return (error);
653*64410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
65452322Smckusick 	if (error = namei(&nd))
65547540Skarels 		return (error);
65652322Smckusick 	vp = nd.ni_vp;
65737741Smckusick 	if (vp != NULL) {
65837741Smckusick 		error = EEXIST;
65912756Ssam 		goto out;
6606254Sroot 	}
66141362Smckusick 	VATTR_NULL(&vattr);
662*64410Sbostic 	switch (uap->mode & S_IFMT) {
66340635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
66437741Smckusick 		vattr.va_type = VBAD;
66537741Smckusick 		break;
66640635Smckusick 	case S_IFCHR:
66737741Smckusick 		vattr.va_type = VCHR;
66837741Smckusick 		break;
66940635Smckusick 	case S_IFBLK:
67037741Smckusick 		vattr.va_type = VBLK;
67137741Smckusick 		break;
67237741Smckusick 	default:
67337741Smckusick 		error = EINVAL;
67437741Smckusick 		goto out;
6756254Sroot 	}
676*64410Sbostic 	vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
67737741Smckusick 	vattr.va_rdev = uap->dev;
6786254Sroot out:
67942465Smckusick 	if (!error) {
68052322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
68152322Smckusick 		error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
68242465Smckusick 	} else {
68352322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
68452322Smckusick 		if (nd.ni_dvp == vp)
68552322Smckusick 			vrele(nd.ni_dvp);
68643344Smckusick 		else
68752322Smckusick 			vput(nd.ni_dvp);
68842465Smckusick 		if (vp)
68942465Smckusick 			vrele(vp);
69042465Smckusick 	}
69147540Skarels 	return (error);
6926254Sroot }
6936254Sroot 
6946254Sroot /*
695*64410Sbostic  * Create named pipe.
69640285Smckusick  */
69754916Storek struct mkfifo_args {
698*64410Sbostic 	char	*path;
699*64410Sbostic 	int	mode;
70054916Storek };
70142441Smckusick /* ARGSUSED */
70242441Smckusick mkfifo(p, uap, retval)
70345914Smckusick 	struct proc *p;
70454916Storek 	register struct mkfifo_args *uap;
70542441Smckusick 	int *retval;
70642441Smckusick {
70740285Smckusick 	struct vattr vattr;
70840285Smckusick 	int error;
70947540Skarels 	struct nameidata nd;
71040285Smckusick 
71140285Smckusick #ifndef FIFO
71247540Skarels 	return (EOPNOTSUPP);
71340285Smckusick #else
714*64410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
71552322Smckusick 	if (error = namei(&nd))
71647540Skarels 		return (error);
71752322Smckusick 	if (nd.ni_vp != NULL) {
71852322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
71952322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
72052322Smckusick 			vrele(nd.ni_dvp);
72143344Smckusick 		else
72252322Smckusick 			vput(nd.ni_dvp);
72352322Smckusick 		vrele(nd.ni_vp);
72447540Skarels 		return (EEXIST);
72540285Smckusick 	}
72645785Sbostic 	VATTR_NULL(&vattr);
72745785Sbostic 	vattr.va_type = VFIFO;
728*64410Sbostic 	vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
72952322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
73052322Smckusick 	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
73140285Smckusick #endif /* FIFO */
73240285Smckusick }
73340285Smckusick 
73440285Smckusick /*
735*64410Sbostic  * Make a hard file link.
7366254Sroot  */
73754916Storek struct link_args {
738*64410Sbostic 	char	*path;
739*64410Sbostic 	char	*link;
74054916Storek };
74142441Smckusick /* ARGSUSED */
74242441Smckusick link(p, uap, retval)
74345914Smckusick 	struct proc *p;
74454916Storek 	register struct link_args *uap;
74542441Smckusick 	int *retval;
74642441Smckusick {
747*64410Sbostic 	register struct vnode *vp;
748*64410Sbostic 	struct nameidata nd;
74937741Smckusick 	int error;
7506254Sroot 
751*64410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
75252322Smckusick 	if (error = namei(&nd))
75347540Skarels 		return (error);
75452322Smckusick 	vp = nd.ni_vp;
75537741Smckusick 	if (vp->v_type == VDIR &&
75647540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
757*64410Sbostic 		goto out;
75852322Smckusick 	nd.ni_cnd.cn_nameiop = CREATE;
75952322Smckusick 	nd.ni_cnd.cn_flags = LOCKPARENT;
760*64410Sbostic 	nd.ni_dirp = uap->link;
76152322Smckusick 	if (error = namei(&nd))
762*64410Sbostic 		goto out;
763*64410Sbostic 	if (nd.ni_vp != NULL)
76437741Smckusick 		error = EEXIST;
76542465Smckusick 	if (!error) {
766*64410Sbostic 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
76752192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
76852821Smckusick 		error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
76942465Smckusick 	} else {
77052322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
77152322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
77252322Smckusick 			vrele(nd.ni_dvp);
77343344Smckusick 		else
77452322Smckusick 			vput(nd.ni_dvp);
77552322Smckusick 		if (nd.ni_vp)
77652322Smckusick 			vrele(nd.ni_vp);
77742465Smckusick 	}
778*64410Sbostic out:	vrele(vp);
77947540Skarels 	return (error);
7806254Sroot }
7816254Sroot 
7826254Sroot /*
78349365Smckusick  * Make a symbolic link.
7846254Sroot  */
78554916Storek struct symlink_args {
786*64410Sbostic 	char	*path;
787*64410Sbostic 	char	*link;
78854916Storek };
78942441Smckusick /* ARGSUSED */
79042441Smckusick symlink(p, uap, retval)
79145914Smckusick 	struct proc *p;
79254916Storek 	register struct symlink_args *uap;
79342441Smckusick 	int *retval;
79442441Smckusick {
79537741Smckusick 	struct vattr vattr;
796*64410Sbostic 	char *path;
79737741Smckusick 	int error;
79847540Skarels 	struct nameidata nd;
7996254Sroot 
800*64410Sbostic 	MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
801*64410Sbostic 	if (error = copyinstr(uap->path, path, MAXPATHLEN, NULL))
80242465Smckusick 		goto out;
803*64410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p);
80452322Smckusick 	if (error = namei(&nd))
80542465Smckusick 		goto out;
80652322Smckusick 	if (nd.ni_vp) {
80752322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
80852322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
80952322Smckusick 			vrele(nd.ni_dvp);
81043344Smckusick 		else
81152322Smckusick 			vput(nd.ni_dvp);
81252322Smckusick 		vrele(nd.ni_vp);
81337741Smckusick 		error = EEXIST;
81437741Smckusick 		goto out;
8156254Sroot 	}
81641362Smckusick 	VATTR_NULL(&vattr);
817*64410Sbostic 	vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
81852322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
819*64410Sbostic 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
82037741Smckusick out:
821*64410Sbostic 	FREE(path, M_NAMEI);
82247540Skarels 	return (error);
8236254Sroot }
8246254Sroot 
8256254Sroot /*
82649365Smckusick  * Delete a name from the filesystem.
8276254Sroot  */
82854916Storek struct unlink_args {
829*64410Sbostic 	char	*path;
83054916Storek };
83142441Smckusick /* ARGSUSED */
83242441Smckusick unlink(p, uap, retval)
83345914Smckusick 	struct proc *p;
83454916Storek 	struct unlink_args *uap;
83542441Smckusick 	int *retval;
8366254Sroot {
83737741Smckusick 	register struct vnode *vp;
83837741Smckusick 	int error;
83947540Skarels 	struct nameidata nd;
8406254Sroot 
841*64410Sbostic 	NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
84252322Smckusick 	if (error = namei(&nd))
84347540Skarels 		return (error);
84452322Smckusick 	vp = nd.ni_vp;
84559382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
84659382Smckusick 	VOP_LOCK(vp);
84737741Smckusick 	if (vp->v_type == VDIR &&
84847540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
8496254Sroot 		goto out;
8506254Sroot 	/*
85149365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
8526254Sroot 	 */
853*64410Sbostic 	if (vp->v_flag & VROOT)
85437741Smckusick 		error = EBUSY;
855*64410Sbostic 	else
856*64410Sbostic 		(void)vnode_pager_uncache(vp);
857*64410Sbostic 
858*64410Sbostic out:	if (!error) {
85952322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
86052322Smckusick 		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
86142465Smckusick 	} else {
86252322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
86352322Smckusick 		if (nd.ni_dvp == vp)
86452322Smckusick 			vrele(nd.ni_dvp);
86543344Smckusick 		else
86652322Smckusick 			vput(nd.ni_dvp);
86742465Smckusick 		vput(vp);
86842465Smckusick 	}
86947540Skarels 	return (error);
8706254Sroot }
8716254Sroot 
872*64410Sbostic /*
873*64410Sbostic  * Reposition read/write file offset.
874*64410Sbostic  */
87560428Smckusick struct lseek_args {
876*64410Sbostic 	int	fd;
87754863Storek 	int	pad;
878*64410Sbostic 	off_t	offset;
879*64410Sbostic 	int	whence;
88054863Storek };
88160414Smckusick lseek(p, uap, retval)
88253468Smckusick 	struct proc *p;
88360428Smckusick 	register struct lseek_args *uap;
88454916Storek 	int *retval;
88542441Smckusick {
88647540Skarels 	struct ucred *cred = p->p_ucred;
88745914Smckusick 	register struct filedesc *fdp = p->p_fd;
88842441Smckusick 	register struct file *fp;
88937741Smckusick 	struct vattr vattr;
89037741Smckusick 	int error;
8916254Sroot 
892*64410Sbostic 	if ((u_int)uap->fd >= fdp->fd_nfiles ||
893*64410Sbostic 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
89447540Skarels 		return (EBADF);
89537741Smckusick 	if (fp->f_type != DTYPE_VNODE)
89647540Skarels 		return (ESPIPE);
897*64410Sbostic 	switch (uap->whence) {
89813878Ssam 	case L_INCR:
899*64410Sbostic 		fp->f_offset += uap->offset;
90013878Ssam 		break;
90113878Ssam 	case L_XTND:
902*64410Sbostic 		if (error =
903*64410Sbostic 		    VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p))
90447540Skarels 			return (error);
905*64410Sbostic 		fp->f_offset = uap->offset + vattr.va_size;
90613878Ssam 		break;
90713878Ssam 	case L_SET:
908*64410Sbostic 		fp->f_offset = uap->offset;
90913878Ssam 		break;
91013878Ssam 	default:
91147540Skarels 		return (EINVAL);
91213878Ssam 	}
91354916Storek 	*(off_t *)retval = fp->f_offset;
91447540Skarels 	return (0);
9156254Sroot }
9166254Sroot 
91760414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
9186254Sroot /*
919*64410Sbostic  * Reposition read/write file offset.
92060036Smckusick  */
92160428Smckusick struct olseek_args {
922*64410Sbostic 	int	fd;
923*64410Sbostic 	long	offset;
924*64410Sbostic 	int	whence;
92560036Smckusick };
92660414Smckusick olseek(p, uap, retval)
92760036Smckusick 	struct proc *p;
92860428Smckusick 	register struct olseek_args *uap;
92960036Smckusick 	int *retval;
93060036Smckusick {
93160428Smckusick 	struct lseek_args nuap;
93260036Smckusick 	off_t qret;
93360036Smckusick 	int error;
93460036Smckusick 
935*64410Sbostic 	nuap.fd = uap->fd;
936*64410Sbostic 	nuap.offset = uap->offset;
937*64410Sbostic 	nuap.whence = uap->whence;
93860428Smckusick 	error = lseek(p, &nuap, &qret);
93960036Smckusick 	*(long *)retval = qret;
94060036Smckusick 	return (error);
94160036Smckusick }
94260414Smckusick #endif /* COMPAT_43 */
94360036Smckusick 
94460036Smckusick /*
94549365Smckusick  * Check access permissions.
9466254Sroot  */
94763427Sbostic struct access_args {
948*64410Sbostic 	char	*path;
949*64410Sbostic 	int	flags;
95054916Storek };
95163427Sbostic access(p, uap, retval)
95245914Smckusick 	struct proc *p;
95363427Sbostic 	register struct access_args *uap;
95442441Smckusick 	int *retval;
95542441Smckusick {
95647540Skarels 	register struct ucred *cred = p->p_ucred;
95737741Smckusick 	register struct vnode *vp;
958*64410Sbostic 	int error, flags, saved_uid, saved_gid;
95947540Skarels 	struct nameidata nd;
9606254Sroot 
961*64410Sbostic 	saved_uid = cred->cr_uid;
962*64410Sbostic 	saved_gid = cred->cr_groups[0];
96347540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
96447540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
965*64410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
96652322Smckusick 	if (error = namei(&nd))
96737741Smckusick 		goto out1;
96852322Smckusick 	vp = nd.ni_vp;
969*64410Sbostic 
970*64410Sbostic 	/* Flags == 0 means only check for existence. */
971*64410Sbostic 	if (uap->flags) {
972*64410Sbostic 		flags = 0;
973*64410Sbostic 		if (uap->flags & R_OK)
974*64410Sbostic 			flags |= VREAD;
975*64410Sbostic 		if (uap->flags & W_OK)
976*64410Sbostic 			flags |= VWRITE;
977*64410Sbostic 		if (uap->flags & X_OK)
978*64410Sbostic 			flags |= VEXEC;
979*64410Sbostic 		if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
980*64410Sbostic 			error = VOP_ACCESS(vp, flags, cred, p);
9816254Sroot 	}
98237741Smckusick 	vput(vp);
98337741Smckusick out1:
984*64410Sbostic 	cred->cr_uid = saved_uid;
985*64410Sbostic 	cred->cr_groups[0] = saved_gid;
98647540Skarels 	return (error);
9876254Sroot }
9886254Sroot 
98954348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
9906254Sroot /*
991*64410Sbostic  * Get file status; this version follows links.
99237Sbill  */
99354916Storek struct ostat_args {
994*64410Sbostic 	char	*path;
99554916Storek 	struct ostat *ub;
99654916Storek };
99742441Smckusick /* ARGSUSED */
99853759Smckusick ostat(p, uap, retval)
99945914Smckusick 	struct proc *p;
100054916Storek 	register struct ostat_args *uap;
100153468Smckusick 	int *retval;
100253468Smckusick {
100353468Smckusick 	struct stat sb;
100453468Smckusick 	struct ostat osb;
100553468Smckusick 	int error;
100653468Smckusick 	struct nameidata nd;
100753468Smckusick 
1008*64410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
100953468Smckusick 	if (error = namei(&nd))
101053468Smckusick 		return (error);
101153468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
101253468Smckusick 	vput(nd.ni_vp);
101353468Smckusick 	if (error)
101453468Smckusick 		return (error);
101553468Smckusick 	cvtstat(&sb, &osb);
101653468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
101753468Smckusick 	return (error);
101853468Smckusick }
101953468Smckusick 
102053468Smckusick /*
1021*64410Sbostic  * Get file status; this version does not follow links.
102253468Smckusick  */
102354916Storek struct olstat_args {
1024*64410Sbostic 	char	*path;
102554916Storek 	struct ostat *ub;
102654916Storek };
102753468Smckusick /* ARGSUSED */
102853759Smckusick olstat(p, uap, retval)
102953468Smckusick 	struct proc *p;
103054916Storek 	register struct olstat_args *uap;
103153468Smckusick 	int *retval;
103253468Smckusick {
103353468Smckusick 	struct stat sb;
103453468Smckusick 	struct ostat osb;
103553468Smckusick 	int error;
103653468Smckusick 	struct nameidata nd;
103753468Smckusick 
1038*64410Sbostic 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
103953468Smckusick 	if (error = namei(&nd))
104053468Smckusick 		return (error);
104153468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
104253468Smckusick 	vput(nd.ni_vp);
104353468Smckusick 	if (error)
104453468Smckusick 		return (error);
104553468Smckusick 	cvtstat(&sb, &osb);
104653468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
104753468Smckusick 	return (error);
104853468Smckusick }
104953468Smckusick 
105053468Smckusick /*
1051*64410Sbostic  * Convert from an old to a new stat structure.
105253468Smckusick  */
105353468Smckusick cvtstat(st, ost)
105453468Smckusick 	struct stat *st;
105553468Smckusick 	struct ostat *ost;
105653468Smckusick {
105753468Smckusick 
105853468Smckusick 	ost->st_dev = st->st_dev;
105953468Smckusick 	ost->st_ino = st->st_ino;
106053468Smckusick 	ost->st_mode = st->st_mode;
106153468Smckusick 	ost->st_nlink = st->st_nlink;
106253468Smckusick 	ost->st_uid = st->st_uid;
106353468Smckusick 	ost->st_gid = st->st_gid;
106453468Smckusick 	ost->st_rdev = st->st_rdev;
106553468Smckusick 	if (st->st_size < (quad_t)1 << 32)
106653468Smckusick 		ost->st_size = st->st_size;
106753468Smckusick 	else
106853468Smckusick 		ost->st_size = -2;
106953468Smckusick 	ost->st_atime = st->st_atime;
107053468Smckusick 	ost->st_mtime = st->st_mtime;
107153468Smckusick 	ost->st_ctime = st->st_ctime;
107253468Smckusick 	ost->st_blksize = st->st_blksize;
107353468Smckusick 	ost->st_blocks = st->st_blocks;
107453468Smckusick 	ost->st_flags = st->st_flags;
107553468Smckusick 	ost->st_gen = st->st_gen;
107653468Smckusick }
107754348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
107853468Smckusick 
107953468Smckusick /*
1080*64410Sbostic  * Get file status; this version follows links.
108153468Smckusick  */
108254916Storek struct stat_args {
1083*64410Sbostic 	char	*path;
108454916Storek 	struct stat *ub;
108554916Storek };
108653468Smckusick /* ARGSUSED */
108753759Smckusick stat(p, uap, retval)
108853468Smckusick 	struct proc *p;
108954916Storek 	register struct stat_args *uap;
109042441Smckusick 	int *retval;
109137Sbill {
109242441Smckusick 	struct stat sb;
109342441Smckusick 	int error;
109447540Skarels 	struct nameidata nd;
109537Sbill 
1096*64410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
109752322Smckusick 	if (error = namei(&nd))
109847540Skarels 		return (error);
109952322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
110052322Smckusick 	vput(nd.ni_vp);
110142441Smckusick 	if (error)
110247540Skarels 		return (error);
110342441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
110447540Skarels 	return (error);
110537Sbill }
110637Sbill 
110737Sbill /*
1108*64410Sbostic  * Get file status; this version does not follow links.
11095992Swnj  */
111054916Storek struct lstat_args {
1111*64410Sbostic 	char	*path;
111254916Storek 	struct stat *ub;
111354916Storek };
111442441Smckusick /* ARGSUSED */
111553759Smckusick lstat(p, uap, retval)
111645914Smckusick 	struct proc *p;
111754916Storek 	register struct lstat_args *uap;
111842441Smckusick 	int *retval;
111942441Smckusick {
112037741Smckusick 	int error;
112159373Smckusick 	struct vnode *vp, *dvp;
112259373Smckusick 	struct stat sb, sb1;
112347540Skarels 	struct nameidata nd;
11245992Swnj 
112559373Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
1126*64410Sbostic 	    uap->path, p);
112752322Smckusick 	if (error = namei(&nd))
112847540Skarels 		return (error);
112959373Smckusick 	/*
113059373Smckusick 	 * For symbolic links, always return the attributes of its
113159373Smckusick 	 * containing directory, except for mode, size, and links.
113259373Smckusick 	 */
113359373Smckusick 	vp = nd.ni_vp;
113459373Smckusick 	dvp = nd.ni_dvp;
113559373Smckusick 	if (vp->v_type != VLNK) {
113659373Smckusick 		if (dvp == vp)
113759373Smckusick 			vrele(dvp);
113859373Smckusick 		else
113959373Smckusick 			vput(dvp);
114059373Smckusick 		error = vn_stat(vp, &sb, p);
114159373Smckusick 		vput(vp);
114259373Smckusick 		if (error)
114359373Smckusick 			return (error);
114459373Smckusick 	} else {
114559373Smckusick 		error = vn_stat(dvp, &sb, p);
114659373Smckusick 		vput(dvp);
114759373Smckusick 		if (error) {
114859373Smckusick 			vput(vp);
114959373Smckusick 			return (error);
115059373Smckusick 		}
115159373Smckusick 		error = vn_stat(vp, &sb1, p);
115259373Smckusick 		vput(vp);
115359373Smckusick 		if (error)
115459373Smckusick 			return (error);
115559373Smckusick 		sb.st_mode &= ~S_IFDIR;
115659373Smckusick 		sb.st_mode |= S_IFLNK;
115759373Smckusick 		sb.st_nlink = sb1.st_nlink;
115859373Smckusick 		sb.st_size = sb1.st_size;
115959373Smckusick 		sb.st_blocks = sb1.st_blocks;
116059373Smckusick 	}
116137741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
116247540Skarels 	return (error);
11635992Swnj }
11645992Swnj 
11655992Swnj /*
1166*64410Sbostic  * Get configurable pathname variables.
116760414Smckusick  */
116860414Smckusick struct pathconf_args {
1169*64410Sbostic 	char	*path;
117060414Smckusick 	int	name;
117160414Smckusick };
117260414Smckusick /* ARGSUSED */
117360414Smckusick pathconf(p, uap, retval)
117460414Smckusick 	struct proc *p;
117560414Smckusick 	register struct pathconf_args *uap;
117660414Smckusick 	int *retval;
117760414Smckusick {
117860414Smckusick 	int error;
117960414Smckusick 	struct nameidata nd;
118060414Smckusick 
1181*64410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
118260414Smckusick 	if (error = namei(&nd))
118360414Smckusick 		return (error);
118460414Smckusick 	error = VOP_PATHCONF(nd.ni_vp, uap->name, retval);
118560414Smckusick 	vput(nd.ni_vp);
118660414Smckusick 	return (error);
118760414Smckusick }
118860414Smckusick 
118960414Smckusick /*
119049365Smckusick  * Return target name of a symbolic link.
119137Sbill  */
119254916Storek struct readlink_args {
1193*64410Sbostic 	char	*path;
119454916Storek 	char	*buf;
119554916Storek 	int	count;
119654916Storek };
119742441Smckusick /* ARGSUSED */
119842441Smckusick readlink(p, uap, retval)
119945914Smckusick 	struct proc *p;
120054916Storek 	register struct readlink_args *uap;
120142441Smckusick 	int *retval;
120242441Smckusick {
120337741Smckusick 	register struct vnode *vp;
120437741Smckusick 	struct iovec aiov;
120537741Smckusick 	struct uio auio;
120637741Smckusick 	int error;
120747540Skarels 	struct nameidata nd;
12085992Swnj 
1209*64410Sbostic 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
121052322Smckusick 	if (error = namei(&nd))
121147540Skarels 		return (error);
121252322Smckusick 	vp = nd.ni_vp;
1213*64410Sbostic 	if (vp->v_type != VLNK)
121437741Smckusick 		error = EINVAL;
1215*64410Sbostic 	else {
1216*64410Sbostic 		aiov.iov_base = uap->buf;
1217*64410Sbostic 		aiov.iov_len = uap->count;
1218*64410Sbostic 		auio.uio_iov = &aiov;
1219*64410Sbostic 		auio.uio_iovcnt = 1;
1220*64410Sbostic 		auio.uio_offset = 0;
1221*64410Sbostic 		auio.uio_rw = UIO_READ;
1222*64410Sbostic 		auio.uio_segflg = UIO_USERSPACE;
1223*64410Sbostic 		auio.uio_procp = p;
1224*64410Sbostic 		auio.uio_resid = uap->count;
1225*64410Sbostic 		error = VOP_READLINK(vp, &auio, p->p_ucred);
12265992Swnj 	}
122737741Smckusick 	vput(vp);
122842441Smckusick 	*retval = uap->count - auio.uio_resid;
122947540Skarels 	return (error);
12305992Swnj }
12315992Swnj 
12329167Ssam /*
1233*64410Sbostic  * Change flags of a file given a path name.
123438259Smckusick  */
123554916Storek struct chflags_args {
1236*64410Sbostic 	char	*path;
123754916Storek 	int	flags;
123854916Storek };
123942441Smckusick /* ARGSUSED */
124042441Smckusick chflags(p, uap, retval)
124145914Smckusick 	struct proc *p;
124254916Storek 	register struct chflags_args *uap;
124342441Smckusick 	int *retval;
124442441Smckusick {
124538259Smckusick 	register struct vnode *vp;
124638259Smckusick 	struct vattr vattr;
124738259Smckusick 	int error;
124847540Skarels 	struct nameidata nd;
124938259Smckusick 
1250*64410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
125152322Smckusick 	if (error = namei(&nd))
125247540Skarels 		return (error);
125352322Smckusick 	vp = nd.ni_vp;
125459382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
125559382Smckusick 	VOP_LOCK(vp);
1256*64410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
125738259Smckusick 		error = EROFS;
1258*64410Sbostic 	else {
1259*64410Sbostic 		VATTR_NULL(&vattr);
1260*64410Sbostic 		vattr.va_flags = uap->flags;
1261*64410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
126238259Smckusick 	}
126338259Smckusick 	vput(vp);
126447540Skarels 	return (error);
126538259Smckusick }
126638259Smckusick 
126738259Smckusick /*
126838259Smckusick  * Change flags of a file given a file descriptor.
126938259Smckusick  */
127054916Storek struct fchflags_args {
127154916Storek 	int	fd;
127254916Storek 	int	flags;
127354916Storek };
127442441Smckusick /* ARGSUSED */
127542441Smckusick fchflags(p, uap, retval)
127645914Smckusick 	struct proc *p;
127754916Storek 	register struct fchflags_args *uap;
127842441Smckusick 	int *retval;
127942441Smckusick {
128038259Smckusick 	struct vattr vattr;
128138259Smckusick 	struct vnode *vp;
128238259Smckusick 	struct file *fp;
128338259Smckusick 	int error;
128438259Smckusick 
128545914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
128647540Skarels 		return (error);
128738259Smckusick 	vp = (struct vnode *)fp->f_data;
128859382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
128938259Smckusick 	VOP_LOCK(vp);
1290*64410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
129138259Smckusick 		error = EROFS;
1292*64410Sbostic 	else {
1293*64410Sbostic 		VATTR_NULL(&vattr);
1294*64410Sbostic 		vattr.va_flags = uap->flags;
1295*64410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
129638259Smckusick 	}
129738259Smckusick 	VOP_UNLOCK(vp);
129847540Skarels 	return (error);
129938259Smckusick }
130038259Smckusick 
130138259Smckusick /*
13029167Ssam  * Change mode of a file given path name.
13039167Ssam  */
130454916Storek struct chmod_args {
1305*64410Sbostic 	char	*path;
1306*64410Sbostic 	int	mode;
130754916Storek };
130842441Smckusick /* ARGSUSED */
130942441Smckusick chmod(p, uap, retval)
131045914Smckusick 	struct proc *p;
131154916Storek 	register struct chmod_args *uap;
131242441Smckusick 	int *retval;
131342441Smckusick {
131437741Smckusick 	register struct vnode *vp;
131537741Smckusick 	struct vattr vattr;
131637741Smckusick 	int error;
131747540Skarels 	struct nameidata nd;
13185992Swnj 
1319*64410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
132052322Smckusick 	if (error = namei(&nd))
132147540Skarels 		return (error);
132252322Smckusick 	vp = nd.ni_vp;
132359382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
132459382Smckusick 	VOP_LOCK(vp);
1325*64410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
132637741Smckusick 		error = EROFS;
1327*64410Sbostic 	else {
1328*64410Sbostic 		VATTR_NULL(&vattr);
1329*64410Sbostic 		vattr.va_mode = uap->mode & ALLPERMS;
1330*64410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
133137741Smckusick 	}
133237741Smckusick 	vput(vp);
133347540Skarels 	return (error);
13347701Ssam }
13357439Sroot 
13369167Ssam /*
13379167Ssam  * Change mode of a file given a file descriptor.
13389167Ssam  */
133954916Storek struct fchmod_args {
134054916Storek 	int	fd;
1341*64410Sbostic 	int	mode;
134254916Storek };
134342441Smckusick /* ARGSUSED */
134442441Smckusick fchmod(p, uap, retval)
134545914Smckusick 	struct proc *p;
134654916Storek 	register struct fchmod_args *uap;
134742441Smckusick 	int *retval;
134842441Smckusick {
134937741Smckusick 	struct vattr vattr;
135037741Smckusick 	struct vnode *vp;
135137741Smckusick 	struct file *fp;
135237741Smckusick 	int error;
13537701Ssam 
135445914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
135547540Skarels 		return (error);
135637741Smckusick 	vp = (struct vnode *)fp->f_data;
135759382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
135837741Smckusick 	VOP_LOCK(vp);
1359*64410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
136037741Smckusick 		error = EROFS;
1361*64410Sbostic 	else {
1362*64410Sbostic 		VATTR_NULL(&vattr);
1363*64410Sbostic 		vattr.va_mode = uap->mode & ALLPERMS;
1364*64410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
13657439Sroot 	}
136637741Smckusick 	VOP_UNLOCK(vp);
136747540Skarels 	return (error);
13685992Swnj }
13695992Swnj 
13709167Ssam /*
13719167Ssam  * Set ownership given a path name.
13729167Ssam  */
137354916Storek struct chown_args {
1374*64410Sbostic 	char	*path;
137554916Storek 	int	uid;
137654916Storek 	int	gid;
137754916Storek };
137842441Smckusick /* ARGSUSED */
137942441Smckusick chown(p, uap, retval)
138045914Smckusick 	struct proc *p;
138154916Storek 	register struct chown_args *uap;
138242441Smckusick 	int *retval;
138342441Smckusick {
138437741Smckusick 	register struct vnode *vp;
138537741Smckusick 	struct vattr vattr;
138637741Smckusick 	int error;
138747540Skarels 	struct nameidata nd;
138837Sbill 
1389*64410Sbostic 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, p);
139052322Smckusick 	if (error = namei(&nd))
139147540Skarels 		return (error);
139252322Smckusick 	vp = nd.ni_vp;
139359382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
139459382Smckusick 	VOP_LOCK(vp);
1395*64410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
139637741Smckusick 		error = EROFS;
1397*64410Sbostic 	else {
1398*64410Sbostic 		VATTR_NULL(&vattr);
1399*64410Sbostic 		vattr.va_uid = uap->uid;
1400*64410Sbostic 		vattr.va_gid = uap->gid;
1401*64410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
140237741Smckusick 	}
140337741Smckusick 	vput(vp);
140447540Skarels 	return (error);
14057701Ssam }
14067439Sroot 
14079167Ssam /*
14089167Ssam  * Set ownership given a file descriptor.
14099167Ssam  */
141054916Storek struct fchown_args {
141154916Storek 	int	fd;
141254916Storek 	int	uid;
141354916Storek 	int	gid;
141454916Storek };
141542441Smckusick /* ARGSUSED */
141642441Smckusick fchown(p, uap, retval)
141745914Smckusick 	struct proc *p;
141854916Storek 	register struct fchown_args *uap;
141942441Smckusick 	int *retval;
142042441Smckusick {
142137741Smckusick 	struct vattr vattr;
142237741Smckusick 	struct vnode *vp;
142337741Smckusick 	struct file *fp;
142437741Smckusick 	int error;
14257701Ssam 
142645914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
142747540Skarels 		return (error);
142837741Smckusick 	vp = (struct vnode *)fp->f_data;
142959382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
143037741Smckusick 	VOP_LOCK(vp);
1431*64410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
143237741Smckusick 		error = EROFS;
1433*64410Sbostic 	else {
1434*64410Sbostic 		VATTR_NULL(&vattr);
1435*64410Sbostic 		vattr.va_uid = uap->uid;
1436*64410Sbostic 		vattr.va_gid = uap->gid;
1437*64410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
143837741Smckusick 	}
143937741Smckusick 	VOP_UNLOCK(vp);
144047540Skarels 	return (error);
14417701Ssam }
14427701Ssam 
144342441Smckusick /*
144442441Smckusick  * Set the access and modification times of a file.
144542441Smckusick  */
144654916Storek struct utimes_args {
1447*64410Sbostic 	char	*path;
144854916Storek 	struct	timeval *tptr;
144954916Storek };
145042441Smckusick /* ARGSUSED */
145142441Smckusick utimes(p, uap, retval)
145245914Smckusick 	struct proc *p;
145354916Storek 	register struct utimes_args *uap;
145442441Smckusick 	int *retval;
145542441Smckusick {
145637741Smckusick 	register struct vnode *vp;
145711811Ssam 	struct timeval tv[2];
145837741Smckusick 	struct vattr vattr;
145958840Storek 	int error;
146047540Skarels 	struct nameidata nd;
146111811Ssam 
146258505Sbostic 	VATTR_NULL(&vattr);
146358505Sbostic 	if (uap->tptr == NULL) {
146458505Sbostic 		microtime(&tv[0]);
146558505Sbostic 		tv[1] = tv[0];
146658548Sbostic 		vattr.va_vaflags |= VA_UTIMES_NULL;
146758505Sbostic 	} else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
146858505Sbostic   		return (error);
1469*64410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
147052322Smckusick 	if (error = namei(&nd))
147147540Skarels 		return (error);
147252322Smckusick 	vp = nd.ni_vp;
147359382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
147459382Smckusick 	VOP_LOCK(vp);
1475*64410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
147637741Smckusick 		error = EROFS;
1477*64410Sbostic 	else {
1478*64410Sbostic 		vattr.va_atime.ts_sec = tv[0].tv_sec;
1479*64410Sbostic 		vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
1480*64410Sbostic 		vattr.va_mtime.ts_sec = tv[1].tv_sec;
1481*64410Sbostic 		vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
1482*64410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
148321015Smckusick 	}
148437741Smckusick 	vput(vp);
148547540Skarels 	return (error);
148611811Ssam }
148711811Ssam 
1488*64410Sbostic /*
1489*64410Sbostic  * Truncate a file given its path name.
1490*64410Sbostic  */
149160428Smckusick struct truncate_args {
1492*64410Sbostic 	char	*path;
149354863Storek 	int	pad;
149454863Storek 	off_t	length;
149554863Storek };
149653468Smckusick /* ARGSUSED */
149760414Smckusick truncate(p, uap, retval)
149853468Smckusick 	struct proc *p;
149960428Smckusick 	register struct truncate_args *uap;
150053468Smckusick 	int *retval;
150153468Smckusick {
150237741Smckusick 	register struct vnode *vp;
150337741Smckusick 	struct vattr vattr;
150437741Smckusick 	int error;
150547540Skarels 	struct nameidata nd;
15067701Ssam 
1507*64410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
150852322Smckusick 	if (error = namei(&nd))
150947540Skarels 		return (error);
151052322Smckusick 	vp = nd.ni_vp;
151159382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
151259382Smckusick 	VOP_LOCK(vp);
1513*64410Sbostic 	if (vp->v_type == VDIR)
151437741Smckusick 		error = EISDIR;
1515*64410Sbostic 	else if ((error = vn_writechk(vp)) == 0 &&
1516*64410Sbostic 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
1517*64410Sbostic 		VATTR_NULL(&vattr);
1518*64410Sbostic 		vattr.va_size = uap->length;
1519*64410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
15207701Ssam 	}
152137741Smckusick 	vput(vp);
152247540Skarels 	return (error);
15237701Ssam }
15247701Ssam 
1525*64410Sbostic /*
1526*64410Sbostic  * Truncate a file given a file descriptor.
1527*64410Sbostic  */
152860428Smckusick struct ftruncate_args {
152954863Storek 	int	fd;
153054863Storek 	int	pad;
153154863Storek 	off_t	length;
153254863Storek };
153342441Smckusick /* ARGSUSED */
153460414Smckusick ftruncate(p, uap, retval)
153545914Smckusick 	struct proc *p;
153660428Smckusick 	register struct ftruncate_args *uap;
153742441Smckusick 	int *retval;
153842441Smckusick {
153937741Smckusick 	struct vattr vattr;
154037741Smckusick 	struct vnode *vp;
15417701Ssam 	struct file *fp;
154237741Smckusick 	int error;
15437701Ssam 
154445914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
154547540Skarels 		return (error);
154637741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
154747540Skarels 		return (EINVAL);
154837741Smckusick 	vp = (struct vnode *)fp->f_data;
154959382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
155037741Smckusick 	VOP_LOCK(vp);
1551*64410Sbostic 	if (vp->v_type == VDIR)
155237741Smckusick 		error = EISDIR;
1553*64410Sbostic 	else if ((error = vn_writechk(vp)) == 0) {
1554*64410Sbostic 		VATTR_NULL(&vattr);
1555*64410Sbostic 		vattr.va_size = uap->length;
1556*64410Sbostic 		error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
15577701Ssam 	}
155837741Smckusick 	VOP_UNLOCK(vp);
155947540Skarels 	return (error);
15607701Ssam }
15617701Ssam 
156254863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
15639167Ssam /*
156454863Storek  * Truncate a file given its path name.
156554863Storek  */
156660428Smckusick struct otruncate_args {
1567*64410Sbostic 	char	*path;
156854916Storek 	long	length;
156954916Storek };
157054863Storek /* ARGSUSED */
157160105Smckusick otruncate(p, uap, retval)
157254863Storek 	struct proc *p;
157360428Smckusick 	register struct otruncate_args *uap;
157454863Storek 	int *retval;
157554863Storek {
157660428Smckusick 	struct truncate_args nuap;
157754863Storek 
1578*64410Sbostic 	nuap.path = uap->path;
157954863Storek 	nuap.length = uap->length;
158060428Smckusick 	return (truncate(p, &nuap, retval));
158154863Storek }
158254863Storek 
158354863Storek /*
158454863Storek  * Truncate a file given a file descriptor.
158554863Storek  */
158660428Smckusick struct oftruncate_args {
158754916Storek 	int	fd;
158854916Storek 	long	length;
158954916Storek };
159054863Storek /* ARGSUSED */
159160105Smckusick oftruncate(p, uap, retval)
159254863Storek 	struct proc *p;
159360428Smckusick 	register struct oftruncate_args *uap;
159454863Storek 	int *retval;
159554863Storek {
159660428Smckusick 	struct ftruncate_args nuap;
159754863Storek 
159854863Storek 	nuap.fd = uap->fd;
159954863Storek 	nuap.length = uap->length;
160060428Smckusick 	return (ftruncate(p, &nuap, retval));
160154863Storek }
160254863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */
160354863Storek 
160454863Storek /*
1605*64410Sbostic  * Sync an open file.
16069167Ssam  */
160754916Storek struct fsync_args {
160854916Storek 	int	fd;
160954916Storek };
161042441Smckusick /* ARGSUSED */
161142441Smckusick fsync(p, uap, retval)
161245914Smckusick 	struct proc *p;
161354916Storek 	struct fsync_args *uap;
161442441Smckusick 	int *retval;
16159167Ssam {
161639592Smckusick 	register struct vnode *vp;
16179167Ssam 	struct file *fp;
161837741Smckusick 	int error;
16199167Ssam 
162045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
162147540Skarels 		return (error);
162239592Smckusick 	vp = (struct vnode *)fp->f_data;
162339592Smckusick 	VOP_LOCK(vp);
162454441Smckusick 	error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
162539592Smckusick 	VOP_UNLOCK(vp);
162647540Skarels 	return (error);
16279167Ssam }
16289167Ssam 
16299167Ssam /*
1630*64410Sbostic  * Rename files.  Source and destination must either both be directories,
1631*64410Sbostic  * or both not be directories.  If target is a directory, it must be empty.
16329167Ssam  */
163354916Storek struct rename_args {
163454916Storek 	char	*from;
163554916Storek 	char	*to;
163654916Storek };
163742441Smckusick /* ARGSUSED */
163842441Smckusick rename(p, uap, retval)
163945914Smckusick 	struct proc *p;
164054916Storek 	register struct rename_args *uap;
164142441Smckusick 	int *retval;
164242441Smckusick {
164337741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
164449735Smckusick 	struct nameidata fromnd, tond;
164537741Smckusick 	int error;
16467701Ssam 
164752322Smckusick 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
164852322Smckusick 		uap->from, p);
164952322Smckusick 	if (error = namei(&fromnd))
165047540Skarels 		return (error);
165149735Smckusick 	fvp = fromnd.ni_vp;
165252322Smckusick 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
165352322Smckusick 		UIO_USERSPACE, uap->to, p);
165452322Smckusick 	if (error = namei(&tond)) {
165552230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
165649735Smckusick 		vrele(fromnd.ni_dvp);
165742465Smckusick 		vrele(fvp);
165842465Smckusick 		goto out1;
165942465Smckusick 	}
166037741Smckusick 	tdvp = tond.ni_dvp;
166137741Smckusick 	tvp = tond.ni_vp;
166237741Smckusick 	if (tvp != NULL) {
166337741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
166439242Sbostic 			error = ENOTDIR;
166537741Smckusick 			goto out;
166637741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
166739242Sbostic 			error = EISDIR;
166837741Smckusick 			goto out;
16699167Ssam 		}
16709167Ssam 	}
167139286Smckusick 	if (fvp == tdvp)
167237741Smckusick 		error = EINVAL;
167339286Smckusick 	/*
167449735Smckusick 	 * If source is the same as the destination (that is the
167549735Smckusick 	 * same inode number with the same name in the same directory),
167639286Smckusick 	 * then there is nothing to do.
167739286Smckusick 	 */
167849735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
167952322Smckusick 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
168052322Smckusick 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
168152322Smckusick 	      fromnd.ni_cnd.cn_namelen))
168239286Smckusick 		error = -1;
168337741Smckusick out:
168442465Smckusick 	if (!error) {
168552192Smckusick 		LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE);
168652192Smckusick 		if (fromnd.ni_dvp != tdvp)
168752192Smckusick 			LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
168852192Smckusick 		if (tvp)
168952192Smckusick 			LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE);
169052230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
169152230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
169242465Smckusick 	} else {
169352230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
169443344Smckusick 		if (tdvp == tvp)
169543344Smckusick 			vrele(tdvp);
169643344Smckusick 		else
169743344Smckusick 			vput(tdvp);
169842465Smckusick 		if (tvp)
169942465Smckusick 			vput(tvp);
170052230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
170149735Smckusick 		vrele(fromnd.ni_dvp);
170242465Smckusick 		vrele(fvp);
17039167Ssam 	}
170449735Smckusick 	vrele(tond.ni_startdir);
170552322Smckusick 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
170637741Smckusick out1:
170749735Smckusick 	vrele(fromnd.ni_startdir);
170852322Smckusick 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
170939286Smckusick 	if (error == -1)
171047540Skarels 		return (0);
171147540Skarels 	return (error);
17127701Ssam }
17137701Ssam 
17147535Sroot /*
1715*64410Sbostic  * Make a directory file.
171612756Ssam  */
171754916Storek struct mkdir_args {
1718*64410Sbostic 	char	*path;
1719*64410Sbostic 	int	mode;
172054916Storek };
172142441Smckusick /* ARGSUSED */
172242441Smckusick mkdir(p, uap, retval)
172345914Smckusick 	struct proc *p;
172454916Storek 	register struct mkdir_args *uap;
172542441Smckusick 	int *retval;
172642441Smckusick {
172737741Smckusick 	register struct vnode *vp;
172837741Smckusick 	struct vattr vattr;
172937741Smckusick 	int error;
173047540Skarels 	struct nameidata nd;
173112756Ssam 
1732*64410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
173352322Smckusick 	if (error = namei(&nd))
173447540Skarels 		return (error);
173552322Smckusick 	vp = nd.ni_vp;
173637741Smckusick 	if (vp != NULL) {
173752322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
173852322Smckusick 		if (nd.ni_dvp == vp)
173952322Smckusick 			vrele(nd.ni_dvp);
174043344Smckusick 		else
174152322Smckusick 			vput(nd.ni_dvp);
174242465Smckusick 		vrele(vp);
174347540Skarels 		return (EEXIST);
174412756Ssam 	}
174541362Smckusick 	VATTR_NULL(&vattr);
174637741Smckusick 	vattr.va_type = VDIR;
1747*64410Sbostic 	vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask;
174852322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
174952322Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
175038145Smckusick 	if (!error)
175152322Smckusick 		vput(nd.ni_vp);
175247540Skarels 	return (error);
175312756Ssam }
175412756Ssam 
175512756Ssam /*
1756*64410Sbostic  * Remove a directory file.
175712756Ssam  */
175854916Storek struct rmdir_args {
1759*64410Sbostic 	char	*path;
176054916Storek };
176142441Smckusick /* ARGSUSED */
176242441Smckusick rmdir(p, uap, retval)
176345914Smckusick 	struct proc *p;
176454916Storek 	struct rmdir_args *uap;
176542441Smckusick 	int *retval;
176612756Ssam {
176737741Smckusick 	register struct vnode *vp;
176837741Smckusick 	int error;
176947540Skarels 	struct nameidata nd;
177012756Ssam 
1771*64410Sbostic 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p);
177252322Smckusick 	if (error = namei(&nd))
177347540Skarels 		return (error);
177452322Smckusick 	vp = nd.ni_vp;
177537741Smckusick 	if (vp->v_type != VDIR) {
177637741Smckusick 		error = ENOTDIR;
177712756Ssam 		goto out;
177812756Ssam 	}
177912756Ssam 	/*
178037741Smckusick 	 * No rmdir "." please.
178112756Ssam 	 */
178252322Smckusick 	if (nd.ni_dvp == vp) {
178337741Smckusick 		error = EINVAL;
178412756Ssam 		goto out;
178512756Ssam 	}
178612756Ssam 	/*
178749365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
178812756Ssam 	 */
178937741Smckusick 	if (vp->v_flag & VROOT)
179037741Smckusick 		error = EBUSY;
179112756Ssam out:
179242465Smckusick 	if (!error) {
179352322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
179452192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
179552322Smckusick 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
179642465Smckusick 	} else {
179752322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
179852322Smckusick 		if (nd.ni_dvp == vp)
179952322Smckusick 			vrele(nd.ni_dvp);
180043344Smckusick 		else
180152322Smckusick 			vput(nd.ni_dvp);
180242465Smckusick 		vput(vp);
180342465Smckusick 	}
180447540Skarels 	return (error);
180512756Ssam }
180612756Ssam 
180754620Smckusick #ifdef COMPAT_43
180837741Smckusick /*
180949365Smckusick  * Read a block of directory entries in a file system independent format.
181037741Smckusick  */
181154916Storek struct ogetdirentries_args {
181254916Storek 	int	fd;
181354916Storek 	char	*buf;
1814*64410Sbostic 	u_int	count;
181554916Storek 	long	*basep;
181654916Storek };
181754620Smckusick ogetdirentries(p, uap, retval)
181854620Smckusick 	struct proc *p;
181954916Storek 	register struct ogetdirentries_args *uap;
182054620Smckusick 	int *retval;
182154620Smckusick {
182254620Smckusick 	register struct vnode *vp;
182354620Smckusick 	struct file *fp;
182454620Smckusick 	struct uio auio, kuio;
182554620Smckusick 	struct iovec aiov, kiov;
182654620Smckusick 	struct dirent *dp, *edp;
182754620Smckusick 	caddr_t dirbuf;
182854620Smckusick 	int error, readcnt;
182954969Smckusick 	long loff;
183054620Smckusick 
183154620Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
183254620Smckusick 		return (error);
183354620Smckusick 	if ((fp->f_flag & FREAD) == 0)
183454620Smckusick 		return (EBADF);
183554620Smckusick 	vp = (struct vnode *)fp->f_data;
183654620Smckusick 	if (vp->v_type != VDIR)
183754620Smckusick 		return (EINVAL);
183854620Smckusick 	aiov.iov_base = uap->buf;
183954620Smckusick 	aiov.iov_len = uap->count;
184054620Smckusick 	auio.uio_iov = &aiov;
184154620Smckusick 	auio.uio_iovcnt = 1;
184254620Smckusick 	auio.uio_rw = UIO_READ;
184354620Smckusick 	auio.uio_segflg = UIO_USERSPACE;
184454620Smckusick 	auio.uio_procp = p;
184554620Smckusick 	auio.uio_resid = uap->count;
184654620Smckusick 	VOP_LOCK(vp);
184754969Smckusick 	loff = auio.uio_offset = fp->f_offset;
184854620Smckusick #	if (BYTE_ORDER != LITTLE_ENDIAN)
184956339Smckusick 		if (vp->v_mount->mnt_maxsymlinklen <= 0) {
185054620Smckusick 			error = VOP_READDIR(vp, &auio, fp->f_cred);
185156339Smckusick 			fp->f_offset = auio.uio_offset;
185256339Smckusick 		} else
185354620Smckusick #	endif
185454620Smckusick 	{
185554620Smckusick 		kuio = auio;
185654620Smckusick 		kuio.uio_iov = &kiov;
185754620Smckusick 		kuio.uio_segflg = UIO_SYSSPACE;
185854620Smckusick 		kiov.iov_len = uap->count;
185954620Smckusick 		MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK);
186054620Smckusick 		kiov.iov_base = dirbuf;
186154620Smckusick 		error = VOP_READDIR(vp, &kuio, fp->f_cred);
186256339Smckusick 		fp->f_offset = kuio.uio_offset;
186354620Smckusick 		if (error == 0) {
186454620Smckusick 			readcnt = uap->count - kuio.uio_resid;
186554620Smckusick 			edp = (struct dirent *)&dirbuf[readcnt];
186654620Smckusick 			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
186754620Smckusick #				if (BYTE_ORDER == LITTLE_ENDIAN)
186854969Smckusick 					/*
186955009Smckusick 					 * The expected low byte of
187055009Smckusick 					 * dp->d_namlen is our dp->d_type.
187155009Smckusick 					 * The high MBZ byte of dp->d_namlen
187255009Smckusick 					 * is our dp->d_namlen.
187354969Smckusick 					 */
187455009Smckusick 					dp->d_type = dp->d_namlen;
187555009Smckusick 					dp->d_namlen = 0;
187655009Smckusick #				else
187755009Smckusick 					/*
187855009Smckusick 					 * The dp->d_type is the high byte
187955009Smckusick 					 * of the expected dp->d_namlen,
188055009Smckusick 					 * so must be zero'ed.
188155009Smckusick 					 */
188255009Smckusick 					dp->d_type = 0;
188354620Smckusick #				endif
188454620Smckusick 				if (dp->d_reclen > 0) {
188554620Smckusick 					dp = (struct dirent *)
188654620Smckusick 					    ((char *)dp + dp->d_reclen);
188754620Smckusick 				} else {
188854620Smckusick 					error = EIO;
188954620Smckusick 					break;
189054620Smckusick 				}
189154620Smckusick 			}
189254620Smckusick 			if (dp >= edp)
189354620Smckusick 				error = uiomove(dirbuf, readcnt, &auio);
189454620Smckusick 		}
189554620Smckusick 		FREE(dirbuf, M_TEMP);
189654620Smckusick 	}
189754620Smckusick 	VOP_UNLOCK(vp);
189854620Smckusick 	if (error)
189954620Smckusick 		return (error);
190054969Smckusick 	error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
190154620Smckusick 	*retval = uap->count - auio.uio_resid;
190254620Smckusick 	return (error);
190354620Smckusick }
190454620Smckusick #endif
190554620Smckusick 
190654620Smckusick /*
190754620Smckusick  * Read a block of directory entries in a file system independent format.
190854620Smckusick  */
190954916Storek struct getdirentries_args {
191054916Storek 	int	fd;
191154916Storek 	char	*buf;
1912*64410Sbostic 	u_int	count;
191354916Storek 	long	*basep;
191454916Storek };
191542441Smckusick getdirentries(p, uap, retval)
191645914Smckusick 	struct proc *p;
191754916Storek 	register struct getdirentries_args *uap;
191842441Smckusick 	int *retval;
191942441Smckusick {
192039592Smckusick 	register struct vnode *vp;
192116540Ssam 	struct file *fp;
192237741Smckusick 	struct uio auio;
192337741Smckusick 	struct iovec aiov;
192454969Smckusick 	long loff;
192554441Smckusick 	int error;
192612756Ssam 
192745914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
192847540Skarels 		return (error);
192937741Smckusick 	if ((fp->f_flag & FREAD) == 0)
193047540Skarels 		return (EBADF);
193139592Smckusick 	vp = (struct vnode *)fp->f_data;
193255451Spendry unionread:
193339592Smckusick 	if (vp->v_type != VDIR)
193447540Skarels 		return (EINVAL);
193537741Smckusick 	aiov.iov_base = uap->buf;
193637741Smckusick 	aiov.iov_len = uap->count;
193737741Smckusick 	auio.uio_iov = &aiov;
193837741Smckusick 	auio.uio_iovcnt = 1;
193937741Smckusick 	auio.uio_rw = UIO_READ;
194037741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
194148026Smckusick 	auio.uio_procp = p;
194237741Smckusick 	auio.uio_resid = uap->count;
194339592Smckusick 	VOP_LOCK(vp);
194454969Smckusick 	loff = auio.uio_offset = fp->f_offset;
194554441Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred);
194639592Smckusick 	fp->f_offset = auio.uio_offset;
194739592Smckusick 	VOP_UNLOCK(vp);
194839592Smckusick 	if (error)
194947540Skarels 		return (error);
195055451Spendry 	if ((uap->count == auio.uio_resid) &&
195155451Spendry 	    (vp->v_flag & VROOT) &&
195255451Spendry 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
195355451Spendry 		struct vnode *tvp = vp;
195455451Spendry 		vp = vp->v_mount->mnt_vnodecovered;
195555451Spendry 		VREF(vp);
195655451Spendry 		fp->f_data = (caddr_t) vp;
195755451Spendry 		fp->f_offset = 0;
195855451Spendry 		vrele(tvp);
195955451Spendry 		goto unionread;
196055451Spendry 	}
196154969Smckusick 	error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
196242441Smckusick 	*retval = uap->count - auio.uio_resid;
196347540Skarels 	return (error);
196412756Ssam }
196512756Ssam 
196612756Ssam /*
196749365Smckusick  * Set the mode mask for creation of filesystem nodes.
196812756Ssam  */
196954916Storek struct umask_args {
1970*64410Sbostic 	int	newmask;
197154916Storek };
197254916Storek mode_t				/* XXX */
197342441Smckusick umask(p, uap, retval)
197445914Smckusick 	struct proc *p;
197554916Storek 	struct umask_args *uap;
197642441Smckusick 	int *retval;
197712756Ssam {
1978*64410Sbostic 	register struct filedesc *fdp;
197912756Ssam 
1980*64410Sbostic 	fdp = p->p_fd;
198145914Smckusick 	*retval = fdp->fd_cmask;
1982*64410Sbostic 	fdp->fd_cmask = uap->newmask & ALLPERMS;
198347540Skarels 	return (0);
198412756Ssam }
198537741Smckusick 
198639566Smarc /*
198739566Smarc  * Void all references to file by ripping underlying filesystem
198839566Smarc  * away from vnode.
198939566Smarc  */
199054916Storek struct revoke_args {
1991*64410Sbostic 	char	*path;
199254916Storek };
199342441Smckusick /* ARGSUSED */
199442441Smckusick revoke(p, uap, retval)
199545914Smckusick 	struct proc *p;
199654916Storek 	register struct revoke_args *uap;
199742441Smckusick 	int *retval;
199842441Smckusick {
199939566Smarc 	register struct vnode *vp;
200039566Smarc 	struct vattr vattr;
200139566Smarc 	int error;
200247540Skarels 	struct nameidata nd;
200339566Smarc 
2004*64410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
200552322Smckusick 	if (error = namei(&nd))
200647540Skarels 		return (error);
200752322Smckusick 	vp = nd.ni_vp;
200839566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
200939566Smarc 		error = EINVAL;
201039566Smarc 		goto out;
201139566Smarc 	}
201248026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
201339566Smarc 		goto out;
201447540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
201547540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
201639566Smarc 		goto out;
201739805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
201839632Smckusick 		vgoneall(vp);
201939566Smarc out:
202039566Smarc 	vrele(vp);
202147540Skarels 	return (error);
202239566Smarc }
202339566Smarc 
202449365Smckusick /*
202549365Smckusick  * Convert a user file descriptor to a kernel file entry.
202649365Smckusick  */
2027*64410Sbostic getvnode(fdp, fd, fpp)
202845914Smckusick 	struct filedesc *fdp;
202937741Smckusick 	struct file **fpp;
2030*64410Sbostic 	int fd;
203137741Smckusick {
203237741Smckusick 	struct file *fp;
203337741Smckusick 
2034*64410Sbostic 	if ((u_int)fd >= fdp->fd_nfiles ||
2035*64410Sbostic 	    (fp = fdp->fd_ofiles[fd]) == NULL)
203637741Smckusick 		return (EBADF);
203737741Smckusick 	if (fp->f_type != DTYPE_VNODE)
203837741Smckusick 		return (EINVAL);
203937741Smckusick 	*fpp = fp;
204037741Smckusick 	return (0);
204137741Smckusick }
2042