xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 65259)
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*65259Smckusick  *	@(#)vfs_syscalls.c	8.4 (Berkeley) 12/30/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 
2764410Sbostic static int change_dir __P((struct nameidata *ndp, struct proc *p));
2864410Sbostic 
2937741Smckusick /*
3037741Smckusick  * Virtual File System System Calls
3137741Smckusick  */
3212756Ssam 
339167Ssam /*
3464410Sbostic  * Mount a file system.
359167Ssam  */
3654916Storek struct mount_args {
3754916Storek 	int	type;
3864410Sbostic 	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 	 */
6164410Sbostic 	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 	}
9664410Sbostic 	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 	}
11364410Sbostic 	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 	 */
13664410Sbostic 	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 	 */
15037741Smckusick 	cache_purge(vp);
15137741Smckusick 	if (!error) {
152*65259Smckusick 		TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
15339335Smckusick 		VOP_UNLOCK(vp);
15437741Smckusick 		vfs_unlock(mp);
15548026Smckusick 		error = VFS_START(mp, 0, p);
15637741Smckusick 	} else {
157*65259Smckusick 		mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
158*65259Smckusick 		vfs_unlock(mp);
15937741Smckusick 		free((caddr_t)mp, M_MOUNT);
16039335Smckusick 		vput(vp);
16137741Smckusick 	}
16247540Skarels 	return (error);
1636254Sroot }
1646254Sroot 
1659167Ssam /*
16664410Sbostic  * Unmount a file system.
16737741Smckusick  *
16837741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
16937741Smckusick  * not special file (as before).
1709167Ssam  */
17154916Storek struct unmount_args {
17264410Sbostic 	char	*path;
17354916Storek 	int	flags;
17454916Storek };
17542441Smckusick /* ARGSUSED */
17642441Smckusick unmount(p, uap, retval)
17745914Smckusick 	struct proc *p;
17854916Storek 	register struct unmount_args *uap;
17942441Smckusick 	int *retval;
18042441Smckusick {
18137741Smckusick 	register struct vnode *vp;
18239356Smckusick 	struct mount *mp;
18337741Smckusick 	int error;
18447540Skarels 	struct nameidata nd;
1856254Sroot 
18637741Smckusick 	/*
18737741Smckusick 	 * Must be super user
18837741Smckusick 	 */
18947540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
19047540Skarels 		return (error);
19137741Smckusick 
19264410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
19352322Smckusick 	if (error = namei(&nd))
19447540Skarels 		return (error);
19552322Smckusick 	vp = nd.ni_vp;
19637741Smckusick 	/*
19737741Smckusick 	 * Must be the root of the filesystem
19837741Smckusick 	 */
19937741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
20037741Smckusick 		vput(vp);
20147540Skarels 		return (EINVAL);
20237741Smckusick 	}
20337741Smckusick 	mp = vp->v_mount;
20437741Smckusick 	vput(vp);
20548026Smckusick 	return (dounmount(mp, uap->flags, p));
20639356Smckusick }
20739356Smckusick 
20839356Smckusick /*
20964410Sbostic  * Do the actual file system unmount.
21039356Smckusick  */
21148026Smckusick dounmount(mp, flags, p)
21239356Smckusick 	register struct mount *mp;
21339356Smckusick 	int flags;
21448026Smckusick 	struct proc *p;
21539356Smckusick {
21639356Smckusick 	struct vnode *coveredvp;
21739356Smckusick 	int error;
21839356Smckusick 
21941400Smckusick 	coveredvp = mp->mnt_vnodecovered;
22041298Smckusick 	if (vfs_busy(mp))
22141298Smckusick 		return (EBUSY);
22241400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
22337741Smckusick 	if (error = vfs_lock(mp))
22439356Smckusick 		return (error);
22537741Smckusick 
22645738Smckusick 	vnode_pager_umount(mp);	/* release cached vnodes */
22737741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
22854441Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 ||
22954441Smckusick 	    (flags & MNT_FORCE))
23048026Smckusick 		error = VFS_UNMOUNT(mp, flags, p);
23141400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
23241298Smckusick 	vfs_unbusy(mp);
23337741Smckusick 	if (error) {
23437741Smckusick 		vfs_unlock(mp);
23537741Smckusick 	} else {
23637741Smckusick 		vrele(coveredvp);
237*65259Smckusick 		TAILQ_REMOVE(&mountlist, mp, mnt_list);
238*65259Smckusick 		mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
239*65259Smckusick 		vfs_unlock(mp);
240*65259Smckusick 		if (mp->mnt_vnodelist.lh_first != 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 {
264*65259Smckusick 	register struct mount *mp, *nmp;
26537741Smckusick 
266*65259Smckusick 	for (mp = mountlist.tqh_first; mp != NULL; mp = nmp) {
267*65259Smckusick 		nmp = mp->mnt_list.tqe_next;
26840343Smckusick 		/*
26940343Smckusick 		 * The lock check below is to avoid races with mount
27040343Smckusick 		 * and unmount.
27140343Smckusick 		 */
27241400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
27341298Smckusick 		    !vfs_busy(mp)) {
27454441Smckusick 			VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
275*65259Smckusick 			vfs_unbusy(mp);
276*65259Smckusick 		}
277*65259Smckusick 	}
27856352Smckusick #ifdef DIAGNOSTIC
27956352Smckusick 	if (syncprt)
28056352Smckusick 		vfs_bufstats();
28156352Smckusick #endif /* DIAGNOSTIC */
28247688Skarels 	return (0);
28337741Smckusick }
28437741Smckusick 
28537741Smckusick /*
28664410Sbostic  * Change filesystem quotas.
28741298Smckusick  */
28854916Storek struct quotactl_args {
28954916Storek 	char *path;
29054916Storek 	int cmd;
29154916Storek 	int uid;
29254916Storek 	caddr_t arg;
29354916Storek };
29442441Smckusick /* ARGSUSED */
29542441Smckusick quotactl(p, uap, retval)
29645914Smckusick 	struct proc *p;
29754916Storek 	register struct quotactl_args *uap;
29842441Smckusick 	int *retval;
29942441Smckusick {
30041298Smckusick 	register struct mount *mp;
30141298Smckusick 	int error;
30247540Skarels 	struct nameidata nd;
30341298Smckusick 
30452322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
30552322Smckusick 	if (error = namei(&nd))
30647540Skarels 		return (error);
30752322Smckusick 	mp = nd.ni_vp->v_mount;
30852322Smckusick 	vrele(nd.ni_vp);
30948026Smckusick 	return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p));
31041298Smckusick }
31141298Smckusick 
31241298Smckusick /*
31349365Smckusick  * Get filesystem statistics.
31437741Smckusick  */
31554916Storek struct statfs_args {
31654916Storek 	char *path;
31754916Storek 	struct statfs *buf;
31854916Storek };
31942441Smckusick /* ARGSUSED */
32042441Smckusick statfs(p, uap, retval)
32145914Smckusick 	struct proc *p;
32254916Storek 	register struct statfs_args *uap;
32342441Smckusick 	int *retval;
32442441Smckusick {
32539464Smckusick 	register struct mount *mp;
32640343Smckusick 	register struct statfs *sp;
32737741Smckusick 	int error;
32847540Skarels 	struct nameidata nd;
32937741Smckusick 
33052322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
33152322Smckusick 	if (error = namei(&nd))
33247540Skarels 		return (error);
33352322Smckusick 	mp = nd.ni_vp->v_mount;
33441400Smckusick 	sp = &mp->mnt_stat;
33552322Smckusick 	vrele(nd.ni_vp);
33648026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
33747540Skarels 		return (error);
33841400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
33947540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
34037741Smckusick }
34137741Smckusick 
34242441Smckusick /*
34349365Smckusick  * Get filesystem statistics.
34442441Smckusick  */
34554916Storek struct fstatfs_args {
34654916Storek 	int fd;
34754916Storek 	struct statfs *buf;
34854916Storek };
34942441Smckusick /* ARGSUSED */
35042441Smckusick fstatfs(p, uap, retval)
35145914Smckusick 	struct proc *p;
35254916Storek 	register struct fstatfs_args *uap;
35342441Smckusick 	int *retval;
35442441Smckusick {
35537741Smckusick 	struct file *fp;
35639464Smckusick 	struct mount *mp;
35740343Smckusick 	register struct statfs *sp;
35837741Smckusick 	int error;
35937741Smckusick 
36045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
36147540Skarels 		return (error);
36239464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
36341400Smckusick 	sp = &mp->mnt_stat;
36448026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
36547540Skarels 		return (error);
36641400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
36747540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
36837741Smckusick }
36937741Smckusick 
37037741Smckusick /*
37149365Smckusick  * Get statistics on all filesystems.
37238270Smckusick  */
37354916Storek struct getfsstat_args {
37454916Storek 	struct statfs *buf;
37554916Storek 	long bufsize;
37654916Storek 	int flags;
37754916Storek };
37842441Smckusick getfsstat(p, uap, retval)
37945914Smckusick 	struct proc *p;
38054916Storek 	register struct getfsstat_args *uap;
38142441Smckusick 	int *retval;
38242441Smckusick {
383*65259Smckusick 	register struct mount *mp, *nmp;
38440343Smckusick 	register struct statfs *sp;
38539606Smckusick 	caddr_t sfsp;
38638270Smckusick 	long count, maxcount, error;
38738270Smckusick 
38838270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
38939606Smckusick 	sfsp = (caddr_t)uap->buf;
390*65259Smckusick 	for (count = 0, mp = mountlist.tqh_first; mp != NULL; mp = nmp) {
391*65259Smckusick 		nmp = mp->mnt_list.tqe_next;
39241400Smckusick 		if (sfsp && count < maxcount &&
39341400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
39441400Smckusick 			sp = &mp->mnt_stat;
39540343Smckusick 			/*
39640343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
39740343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
39840343Smckusick 			 */
39940343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
40040343Smckusick 			    (uap->flags & MNT_WAIT)) &&
401*65259Smckusick 			    (error = VFS_STATFS(mp, sp, p)))
40239607Smckusick 				continue;
40341400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
40440343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
40547540Skarels 				return (error);
40640343Smckusick 			sfsp += sizeof(*sp);
40738270Smckusick 		}
40839606Smckusick 		count++;
409*65259Smckusick 	}
41038270Smckusick 	if (sfsp && count > maxcount)
41142441Smckusick 		*retval = maxcount;
41238270Smckusick 	else
41342441Smckusick 		*retval = count;
41447540Skarels 	return (0);
41538270Smckusick }
41638270Smckusick 
41738270Smckusick /*
41838259Smckusick  * Change current working directory to a given file descriptor.
41938259Smckusick  */
42054916Storek struct fchdir_args {
42154916Storek 	int	fd;
42254916Storek };
42342441Smckusick /* ARGSUSED */
42442441Smckusick fchdir(p, uap, retval)
42545914Smckusick 	struct proc *p;
42654916Storek 	struct fchdir_args *uap;
42742441Smckusick 	int *retval;
42838259Smckusick {
42945914Smckusick 	register struct filedesc *fdp = p->p_fd;
43038259Smckusick 	register struct vnode *vp;
43138259Smckusick 	struct file *fp;
43238259Smckusick 	int error;
43338259Smckusick 
43445914Smckusick 	if (error = getvnode(fdp, uap->fd, &fp))
43547540Skarels 		return (error);
43638259Smckusick 	vp = (struct vnode *)fp->f_data;
43738259Smckusick 	VOP_LOCK(vp);
43838259Smckusick 	if (vp->v_type != VDIR)
43938259Smckusick 		error = ENOTDIR;
44038259Smckusick 	else
44148026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
44238259Smckusick 	VOP_UNLOCK(vp);
44339860Smckusick 	if (error)
44447540Skarels 		return (error);
44539860Smckusick 	VREF(vp);
44645914Smckusick 	vrele(fdp->fd_cdir);
44745914Smckusick 	fdp->fd_cdir = vp;
44847540Skarels 	return (0);
44938259Smckusick }
45038259Smckusick 
45138259Smckusick /*
45237741Smckusick  * Change current working directory (``.'').
45337741Smckusick  */
45454916Storek struct chdir_args {
45564410Sbostic 	char	*path;
45654916Storek };
45742441Smckusick /* ARGSUSED */
45842441Smckusick chdir(p, uap, retval)
45945914Smckusick 	struct proc *p;
46054916Storek 	struct chdir_args *uap;
46142441Smckusick 	int *retval;
46237741Smckusick {
46345914Smckusick 	register struct filedesc *fdp = p->p_fd;
46437741Smckusick 	int error;
46547540Skarels 	struct nameidata nd;
4666254Sroot 
46764410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
46864410Sbostic 	if (error = change_dir(&nd, p))
46947540Skarels 		return (error);
47045914Smckusick 	vrele(fdp->fd_cdir);
47152322Smckusick 	fdp->fd_cdir = nd.ni_vp;
47247540Skarels 	return (0);
47337741Smckusick }
4746254Sroot 
47537741Smckusick /*
47637741Smckusick  * Change notion of root (``/'') directory.
47737741Smckusick  */
47854916Storek struct chroot_args {
47964410Sbostic 	char	*path;
48054916Storek };
48142441Smckusick /* ARGSUSED */
48242441Smckusick chroot(p, uap, retval)
48345914Smckusick 	struct proc *p;
48454916Storek 	struct chroot_args *uap;
48542441Smckusick 	int *retval;
48637741Smckusick {
48745914Smckusick 	register struct filedesc *fdp = p->p_fd;
48837741Smckusick 	int error;
48947540Skarels 	struct nameidata nd;
49037741Smckusick 
49147540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
49247540Skarels 		return (error);
49364410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
49464410Sbostic 	if (error = change_dir(&nd, p))
49547540Skarels 		return (error);
49645914Smckusick 	if (fdp->fd_rdir != NULL)
49745914Smckusick 		vrele(fdp->fd_rdir);
49852322Smckusick 	fdp->fd_rdir = nd.ni_vp;
49947540Skarels 	return (0);
5006254Sroot }
5016254Sroot 
50237Sbill /*
50337741Smckusick  * Common routine for chroot and chdir.
50437741Smckusick  */
50564410Sbostic static int
50664410Sbostic change_dir(ndp, p)
50752322Smckusick 	register struct nameidata *ndp;
50847540Skarels 	struct proc *p;
50937741Smckusick {
51037741Smckusick 	struct vnode *vp;
51137741Smckusick 	int error;
51237741Smckusick 
51352322Smckusick 	if (error = namei(ndp))
51437741Smckusick 		return (error);
51537741Smckusick 	vp = ndp->ni_vp;
51637741Smckusick 	if (vp->v_type != VDIR)
51737741Smckusick 		error = ENOTDIR;
51837741Smckusick 	else
51948026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
52037741Smckusick 	VOP_UNLOCK(vp);
52137741Smckusick 	if (error)
52237741Smckusick 		vrele(vp);
52337741Smckusick 	return (error);
52437741Smckusick }
52537741Smckusick 
52637741Smckusick /*
52742441Smckusick  * Check permissions, allocate an open file structure,
52842441Smckusick  * and call the device open routine if any.
5296254Sroot  */
53054916Storek struct open_args {
53164410Sbostic 	char	*path;
53264410Sbostic 	int	flags;
53354916Storek 	int	mode;
53454916Storek };
53542441Smckusick open(p, uap, retval)
53645914Smckusick 	struct proc *p;
53754916Storek 	register struct open_args *uap;
53842441Smckusick 	int *retval;
5396254Sroot {
54045914Smckusick 	register struct filedesc *fdp = p->p_fd;
54142441Smckusick 	register struct file *fp;
54250111Smckusick 	register struct vnode *vp;
54364410Sbostic 	int flags, cmode;
54437741Smckusick 	struct file *nfp;
54549945Smckusick 	int type, indx, error;
54649945Smckusick 	struct flock lf;
54747540Skarels 	struct nameidata nd;
54837741Smckusick 	extern struct fileops vnops;
5496254Sroot 
55045914Smckusick 	if (error = falloc(p, &nfp, &indx))
55147540Skarels 		return (error);
55237741Smckusick 	fp = nfp;
55364410Sbostic 	flags = FFLAGS(uap->flags);
55464410Sbostic 	cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
55564410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
55645202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
55764410Sbostic 	if (error = vn_open(&nd, flags, cmode)) {
55849980Smckusick 		ffree(fp);
55954723Smckusick 		if ((error == ENODEV || error == ENXIO) &&
56054723Smckusick 		    p->p_dupfd >= 0 && 			/* XXX from fdopen */
56164410Sbostic 		    (error =
56264410Sbostic 		        dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
56342441Smckusick 			*retval = indx;
56447540Skarels 			return (0);
56542441Smckusick 		}
56640884Smckusick 		if (error == ERESTART)
56740884Smckusick 			error = EINTR;
56847688Skarels 		fdp->fd_ofiles[indx] = NULL;
56947540Skarels 		return (error);
57012756Ssam 	}
57153828Spendry 	p->p_dupfd = 0;
57252322Smckusick 	vp = nd.ni_vp;
57364410Sbostic 	fp->f_flag = flags & FMASK;
57454348Smckusick 	fp->f_type = DTYPE_VNODE;
57554348Smckusick 	fp->f_ops = &vnops;
57654348Smckusick 	fp->f_data = (caddr_t)vp;
57764410Sbostic 	if (flags & (O_EXLOCK | O_SHLOCK)) {
57849945Smckusick 		lf.l_whence = SEEK_SET;
57949945Smckusick 		lf.l_start = 0;
58049945Smckusick 		lf.l_len = 0;
58164410Sbostic 		if (flags & O_EXLOCK)
58249945Smckusick 			lf.l_type = F_WRLCK;
58349945Smckusick 		else
58449945Smckusick 			lf.l_type = F_RDLCK;
58549945Smckusick 		type = F_FLOCK;
58664410Sbostic 		if ((flags & FNONBLOCK) == 0)
58749945Smckusick 			type |= F_WAIT;
58850111Smckusick 		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
58950111Smckusick 			VOP_UNLOCK(vp);
59050111Smckusick 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
59149980Smckusick 			ffree(fp);
59249945Smckusick 			fdp->fd_ofiles[indx] = NULL;
59349945Smckusick 			return (error);
59449945Smckusick 		}
59549949Smckusick 		fp->f_flag |= FHASLOCK;
59649945Smckusick 	}
59750111Smckusick 	VOP_UNLOCK(vp);
59842441Smckusick 	*retval = indx;
59947540Skarels 	return (0);
6006254Sroot }
6016254Sroot 
60242955Smckusick #ifdef COMPAT_43
6036254Sroot /*
60464410Sbostic  * Create a file.
6056254Sroot  */
60654916Storek struct ocreat_args {
60764410Sbostic 	char	*path;
60864410Sbostic 	int	mode;
60954916Storek };
61042955Smckusick ocreat(p, uap, retval)
61142441Smckusick 	struct proc *p;
61254916Storek 	register struct ocreat_args *uap;
61342441Smckusick 	int *retval;
6146254Sroot {
61554916Storek 	struct open_args openuap;
61642441Smckusick 
61764410Sbostic 	openuap.path = uap->path;
61864410Sbostic 	openuap.mode = uap->mode;
61964410Sbostic 	openuap.flags = O_WRONLY | O_CREAT | O_TRUNC;
62047540Skarels 	return (open(p, &openuap, retval));
62142441Smckusick }
62242955Smckusick #endif /* COMPAT_43 */
62342441Smckusick 
62442441Smckusick /*
62564410Sbostic  * Create a special file.
62642441Smckusick  */
62754916Storek struct mknod_args {
62864410Sbostic 	char	*path;
62964410Sbostic 	int	mode;
63054916Storek 	int	dev;
63154916Storek };
63242441Smckusick /* ARGSUSED */
63342441Smckusick mknod(p, uap, retval)
63445914Smckusick 	struct proc *p;
63554916Storek 	register struct mknod_args *uap;
63642441Smckusick 	int *retval;
63742441Smckusick {
63837741Smckusick 	register struct vnode *vp;
63937741Smckusick 	struct vattr vattr;
64037741Smckusick 	int error;
64147540Skarels 	struct nameidata nd;
6426254Sroot 
64347540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
64447540Skarels 		return (error);
64564410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
64652322Smckusick 	if (error = namei(&nd))
64747540Skarels 		return (error);
64852322Smckusick 	vp = nd.ni_vp;
64964585Sbostic 	if (vp != NULL)
65037741Smckusick 		error = EEXIST;
65164585Sbostic 	else {
65264585Sbostic 		VATTR_NULL(&vattr);
65364585Sbostic 		vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
65464585Sbostic 		vattr.va_rdev = uap->dev;
65564585Sbostic 
65664585Sbostic 		switch (uap->mode & S_IFMT) {
65764585Sbostic 		case S_IFMT:	/* used by badsect to flag bad sectors */
65864585Sbostic 			vattr.va_type = VBAD;
65964585Sbostic 			break;
66064585Sbostic 		case S_IFCHR:
66164585Sbostic 			vattr.va_type = VCHR;
66264585Sbostic 			break;
66364585Sbostic 		case S_IFBLK:
66464585Sbostic 			vattr.va_type = VBLK;
66564585Sbostic 			break;
66664585Sbostic 		default:
66764585Sbostic 			error = EINVAL;
66864585Sbostic 			break;
66964585Sbostic 		}
6706254Sroot 	}
67142465Smckusick 	if (!error) {
67252322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
67352322Smckusick 		error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
67442465Smckusick 	} else {
67552322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
67652322Smckusick 		if (nd.ni_dvp == vp)
67752322Smckusick 			vrele(nd.ni_dvp);
67843344Smckusick 		else
67952322Smckusick 			vput(nd.ni_dvp);
68042465Smckusick 		if (vp)
68142465Smckusick 			vrele(vp);
68242465Smckusick 	}
68347540Skarels 	return (error);
6846254Sroot }
6856254Sroot 
6866254Sroot /*
68764410Sbostic  * Create named pipe.
68840285Smckusick  */
68954916Storek struct mkfifo_args {
69064410Sbostic 	char	*path;
69164410Sbostic 	int	mode;
69254916Storek };
69342441Smckusick /* ARGSUSED */
69442441Smckusick mkfifo(p, uap, retval)
69545914Smckusick 	struct proc *p;
69654916Storek 	register struct mkfifo_args *uap;
69742441Smckusick 	int *retval;
69842441Smckusick {
69940285Smckusick 	struct vattr vattr;
70040285Smckusick 	int error;
70147540Skarels 	struct nameidata nd;
70240285Smckusick 
70340285Smckusick #ifndef FIFO
70447540Skarels 	return (EOPNOTSUPP);
70540285Smckusick #else
70664410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
70752322Smckusick 	if (error = namei(&nd))
70847540Skarels 		return (error);
70952322Smckusick 	if (nd.ni_vp != NULL) {
71052322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
71152322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
71252322Smckusick 			vrele(nd.ni_dvp);
71343344Smckusick 		else
71452322Smckusick 			vput(nd.ni_dvp);
71552322Smckusick 		vrele(nd.ni_vp);
71647540Skarels 		return (EEXIST);
71740285Smckusick 	}
71845785Sbostic 	VATTR_NULL(&vattr);
71945785Sbostic 	vattr.va_type = VFIFO;
72064410Sbostic 	vattr.va_mode = (uap->mode & ALLPERMS) &~ p->p_fd->fd_cmask;
72152322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
72252322Smckusick 	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
72340285Smckusick #endif /* FIFO */
72440285Smckusick }
72540285Smckusick 
72640285Smckusick /*
72764410Sbostic  * Make a hard file link.
7286254Sroot  */
72954916Storek struct link_args {
73064410Sbostic 	char	*path;
73164410Sbostic 	char	*link;
73254916Storek };
73342441Smckusick /* ARGSUSED */
73442441Smckusick link(p, uap, retval)
73545914Smckusick 	struct proc *p;
73654916Storek 	register struct link_args *uap;
73742441Smckusick 	int *retval;
73842441Smckusick {
73964410Sbostic 	register struct vnode *vp;
74064410Sbostic 	struct nameidata nd;
74137741Smckusick 	int error;
7426254Sroot 
74364410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
74452322Smckusick 	if (error = namei(&nd))
74547540Skarels 		return (error);
74652322Smckusick 	vp = nd.ni_vp;
74764585Sbostic 	if (vp->v_type != VDIR ||
74864585Sbostic 	    (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
74964585Sbostic 		nd.ni_cnd.cn_nameiop = CREATE;
75064585Sbostic 		nd.ni_cnd.cn_flags = LOCKPARENT;
75164585Sbostic 		nd.ni_dirp = uap->link;
75264585Sbostic 		if ((error = namei(&nd)) == 0) {
75364585Sbostic 			if (nd.ni_vp != NULL)
75464585Sbostic 				error = EEXIST;
75564585Sbostic 			if (!error) {
75664585Sbostic 				LEASE_CHECK(nd.ni_dvp,
75764585Sbostic 				    p, p->p_ucred, LEASE_WRITE);
75864585Sbostic 				LEASE_CHECK(vp,
75964585Sbostic 				    p, p->p_ucred, LEASE_WRITE);
76064585Sbostic 				error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
76164585Sbostic 			} else {
76264585Sbostic 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
76364585Sbostic 				if (nd.ni_dvp == nd.ni_vp)
76464585Sbostic 					vrele(nd.ni_dvp);
76564585Sbostic 				else
76664585Sbostic 					vput(nd.ni_dvp);
76764585Sbostic 				if (nd.ni_vp)
76864585Sbostic 					vrele(nd.ni_vp);
76964585Sbostic 			}
77064585Sbostic 		}
77142465Smckusick 	}
77264585Sbostic 	vrele(vp);
77347540Skarels 	return (error);
7746254Sroot }
7756254Sroot 
7766254Sroot /*
77749365Smckusick  * Make a symbolic link.
7786254Sroot  */
77954916Storek struct symlink_args {
78064410Sbostic 	char	*path;
78164410Sbostic 	char	*link;
78254916Storek };
78342441Smckusick /* ARGSUSED */
78442441Smckusick symlink(p, uap, retval)
78545914Smckusick 	struct proc *p;
78654916Storek 	register struct symlink_args *uap;
78742441Smckusick 	int *retval;
78842441Smckusick {
78937741Smckusick 	struct vattr vattr;
79064410Sbostic 	char *path;
79137741Smckusick 	int error;
79247540Skarels 	struct nameidata nd;
7936254Sroot 
79464410Sbostic 	MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
79564410Sbostic 	if (error = copyinstr(uap->path, path, MAXPATHLEN, NULL))
79642465Smckusick 		goto out;
79764410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->link, p);
79852322Smckusick 	if (error = namei(&nd))
79942465Smckusick 		goto out;
80052322Smckusick 	if (nd.ni_vp) {
80152322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
80252322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
80352322Smckusick 			vrele(nd.ni_dvp);
80443344Smckusick 		else
80552322Smckusick 			vput(nd.ni_dvp);
80652322Smckusick 		vrele(nd.ni_vp);
80737741Smckusick 		error = EEXIST;
80837741Smckusick 		goto out;
8096254Sroot 	}
81041362Smckusick 	VATTR_NULL(&vattr);
81164410Sbostic 	vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
81252322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
81364410Sbostic 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
81437741Smckusick out:
81564410Sbostic 	FREE(path, M_NAMEI);
81647540Skarels 	return (error);
8176254Sroot }
8186254Sroot 
8196254Sroot /*
82049365Smckusick  * Delete a name from the filesystem.
8216254Sroot  */
82254916Storek struct unlink_args {
82364410Sbostic 	char	*path;
82454916Storek };
82542441Smckusick /* ARGSUSED */
82642441Smckusick unlink(p, uap, retval)
82745914Smckusick 	struct proc *p;
82854916Storek 	struct unlink_args *uap;
82942441Smckusick 	int *retval;
8306254Sroot {
83137741Smckusick 	register struct vnode *vp;
83237741Smckusick 	int error;
83347540Skarels 	struct nameidata nd;
8346254Sroot 
83564410Sbostic 	NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
83652322Smckusick 	if (error = namei(&nd))
83747540Skarels 		return (error);
83852322Smckusick 	vp = nd.ni_vp;
83959382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
84059382Smckusick 	VOP_LOCK(vp);
84164410Sbostic 
84264585Sbostic 	if (vp->v_type != VDIR ||
84364585Sbostic 	    (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
84464585Sbostic 		/*
84564585Sbostic 		 * The root of a mounted filesystem cannot be deleted.
84664585Sbostic 		 */
84764585Sbostic 		if (vp->v_flag & VROOT)
84864585Sbostic 			error = EBUSY;
84964585Sbostic 		else
85064585Sbostic 			(void)vnode_pager_uncache(vp);
85164585Sbostic 	}
85264585Sbostic 
85364585Sbostic 	if (!error) {
85452322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
85552322Smckusick 		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
85642465Smckusick 	} else {
85752322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
85852322Smckusick 		if (nd.ni_dvp == vp)
85952322Smckusick 			vrele(nd.ni_dvp);
86043344Smckusick 		else
86152322Smckusick 			vput(nd.ni_dvp);
86242465Smckusick 		vput(vp);
86342465Smckusick 	}
86447540Skarels 	return (error);
8656254Sroot }
8666254Sroot 
86764410Sbostic /*
86864410Sbostic  * Reposition read/write file offset.
86964410Sbostic  */
87060428Smckusick struct lseek_args {
87164410Sbostic 	int	fd;
87254863Storek 	int	pad;
87364410Sbostic 	off_t	offset;
87464410Sbostic 	int	whence;
87554863Storek };
87660414Smckusick lseek(p, uap, retval)
87753468Smckusick 	struct proc *p;
87860428Smckusick 	register struct lseek_args *uap;
87954916Storek 	int *retval;
88042441Smckusick {
88147540Skarels 	struct ucred *cred = p->p_ucred;
88245914Smckusick 	register struct filedesc *fdp = p->p_fd;
88342441Smckusick 	register struct file *fp;
88437741Smckusick 	struct vattr vattr;
88537741Smckusick 	int error;
8866254Sroot 
88764410Sbostic 	if ((u_int)uap->fd >= fdp->fd_nfiles ||
88864410Sbostic 	    (fp = fdp->fd_ofiles[uap->fd]) == NULL)
88947540Skarels 		return (EBADF);
89037741Smckusick 	if (fp->f_type != DTYPE_VNODE)
89147540Skarels 		return (ESPIPE);
89264410Sbostic 	switch (uap->whence) {
89313878Ssam 	case L_INCR:
89464410Sbostic 		fp->f_offset += uap->offset;
89513878Ssam 		break;
89613878Ssam 	case L_XTND:
89764410Sbostic 		if (error =
89864410Sbostic 		    VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p))
89947540Skarels 			return (error);
90064410Sbostic 		fp->f_offset = uap->offset + vattr.va_size;
90113878Ssam 		break;
90213878Ssam 	case L_SET:
90364410Sbostic 		fp->f_offset = uap->offset;
90413878Ssam 		break;
90513878Ssam 	default:
90647540Skarels 		return (EINVAL);
90713878Ssam 	}
90854916Storek 	*(off_t *)retval = fp->f_offset;
90947540Skarels 	return (0);
9106254Sroot }
9116254Sroot 
91260414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
9136254Sroot /*
91464410Sbostic  * Reposition read/write file offset.
91560036Smckusick  */
91660428Smckusick struct olseek_args {
91764410Sbostic 	int	fd;
91864410Sbostic 	long	offset;
91964410Sbostic 	int	whence;
92060036Smckusick };
92160414Smckusick olseek(p, uap, retval)
92260036Smckusick 	struct proc *p;
92360428Smckusick 	register struct olseek_args *uap;
92460036Smckusick 	int *retval;
92560036Smckusick {
92660428Smckusick 	struct lseek_args nuap;
92760036Smckusick 	off_t qret;
92860036Smckusick 	int error;
92960036Smckusick 
93064410Sbostic 	nuap.fd = uap->fd;
93164410Sbostic 	nuap.offset = uap->offset;
93264410Sbostic 	nuap.whence = uap->whence;
93360428Smckusick 	error = lseek(p, &nuap, &qret);
93460036Smckusick 	*(long *)retval = qret;
93560036Smckusick 	return (error);
93660036Smckusick }
93760414Smckusick #endif /* COMPAT_43 */
93860036Smckusick 
93960036Smckusick /*
94049365Smckusick  * Check access permissions.
9416254Sroot  */
94263427Sbostic struct access_args {
94364410Sbostic 	char	*path;
94464410Sbostic 	int	flags;
94554916Storek };
94663427Sbostic access(p, uap, retval)
94745914Smckusick 	struct proc *p;
94863427Sbostic 	register struct access_args *uap;
94942441Smckusick 	int *retval;
95042441Smckusick {
95147540Skarels 	register struct ucred *cred = p->p_ucred;
95237741Smckusick 	register struct vnode *vp;
95364585Sbostic 	int error, flags, t_gid, t_uid;
95447540Skarels 	struct nameidata nd;
9556254Sroot 
95664585Sbostic 	t_uid = cred->cr_uid;
95764585Sbostic 	t_gid = cred->cr_groups[0];
95847540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
95947540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
96064410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
96152322Smckusick 	if (error = namei(&nd))
96237741Smckusick 		goto out1;
96352322Smckusick 	vp = nd.ni_vp;
96464410Sbostic 
96564410Sbostic 	/* Flags == 0 means only check for existence. */
96664410Sbostic 	if (uap->flags) {
96764410Sbostic 		flags = 0;
96864410Sbostic 		if (uap->flags & R_OK)
96964410Sbostic 			flags |= VREAD;
97064410Sbostic 		if (uap->flags & W_OK)
97164410Sbostic 			flags |= VWRITE;
97264410Sbostic 		if (uap->flags & X_OK)
97364410Sbostic 			flags |= VEXEC;
97464410Sbostic 		if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
97564410Sbostic 			error = VOP_ACCESS(vp, flags, cred, p);
9766254Sroot 	}
97737741Smckusick 	vput(vp);
97837741Smckusick out1:
97964585Sbostic 	cred->cr_uid = t_uid;
98064585Sbostic 	cred->cr_groups[0] = t_gid;
98147540Skarels 	return (error);
9826254Sroot }
9836254Sroot 
98454348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
9856254Sroot /*
98664410Sbostic  * Get file status; this version follows links.
98737Sbill  */
98854916Storek struct ostat_args {
98964410Sbostic 	char	*path;
99054916Storek 	struct ostat *ub;
99154916Storek };
99242441Smckusick /* ARGSUSED */
99353759Smckusick ostat(p, uap, retval)
99445914Smckusick 	struct proc *p;
99554916Storek 	register struct ostat_args *uap;
99653468Smckusick 	int *retval;
99753468Smckusick {
99853468Smckusick 	struct stat sb;
99953468Smckusick 	struct ostat osb;
100053468Smckusick 	int error;
100153468Smckusick 	struct nameidata nd;
100253468Smckusick 
100364410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
100453468Smckusick 	if (error = namei(&nd))
100553468Smckusick 		return (error);
100653468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
100753468Smckusick 	vput(nd.ni_vp);
100853468Smckusick 	if (error)
100953468Smckusick 		return (error);
101053468Smckusick 	cvtstat(&sb, &osb);
101153468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
101253468Smckusick 	return (error);
101353468Smckusick }
101453468Smckusick 
101553468Smckusick /*
101664410Sbostic  * Get file status; this version does not follow links.
101753468Smckusick  */
101854916Storek struct olstat_args {
101964410Sbostic 	char	*path;
102054916Storek 	struct ostat *ub;
102154916Storek };
102253468Smckusick /* ARGSUSED */
102353759Smckusick olstat(p, uap, retval)
102453468Smckusick 	struct proc *p;
102554916Storek 	register struct olstat_args *uap;
102653468Smckusick 	int *retval;
102753468Smckusick {
102853468Smckusick 	struct stat sb;
102953468Smckusick 	struct ostat osb;
103053468Smckusick 	int error;
103153468Smckusick 	struct nameidata nd;
103253468Smckusick 
103364410Sbostic 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
103453468Smckusick 	if (error = namei(&nd))
103553468Smckusick 		return (error);
103653468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
103753468Smckusick 	vput(nd.ni_vp);
103853468Smckusick 	if (error)
103953468Smckusick 		return (error);
104053468Smckusick 	cvtstat(&sb, &osb);
104153468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
104253468Smckusick 	return (error);
104353468Smckusick }
104453468Smckusick 
104553468Smckusick /*
104664410Sbostic  * Convert from an old to a new stat structure.
104753468Smckusick  */
104853468Smckusick cvtstat(st, ost)
104953468Smckusick 	struct stat *st;
105053468Smckusick 	struct ostat *ost;
105153468Smckusick {
105253468Smckusick 
105353468Smckusick 	ost->st_dev = st->st_dev;
105453468Smckusick 	ost->st_ino = st->st_ino;
105553468Smckusick 	ost->st_mode = st->st_mode;
105653468Smckusick 	ost->st_nlink = st->st_nlink;
105753468Smckusick 	ost->st_uid = st->st_uid;
105853468Smckusick 	ost->st_gid = st->st_gid;
105953468Smckusick 	ost->st_rdev = st->st_rdev;
106053468Smckusick 	if (st->st_size < (quad_t)1 << 32)
106153468Smckusick 		ost->st_size = st->st_size;
106253468Smckusick 	else
106353468Smckusick 		ost->st_size = -2;
106453468Smckusick 	ost->st_atime = st->st_atime;
106553468Smckusick 	ost->st_mtime = st->st_mtime;
106653468Smckusick 	ost->st_ctime = st->st_ctime;
106753468Smckusick 	ost->st_blksize = st->st_blksize;
106853468Smckusick 	ost->st_blocks = st->st_blocks;
106953468Smckusick 	ost->st_flags = st->st_flags;
107053468Smckusick 	ost->st_gen = st->st_gen;
107153468Smckusick }
107254348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
107353468Smckusick 
107453468Smckusick /*
107564410Sbostic  * Get file status; this version follows links.
107653468Smckusick  */
107754916Storek struct stat_args {
107864410Sbostic 	char	*path;
107954916Storek 	struct stat *ub;
108054916Storek };
108153468Smckusick /* ARGSUSED */
108253759Smckusick stat(p, uap, retval)
108353468Smckusick 	struct proc *p;
108454916Storek 	register struct stat_args *uap;
108542441Smckusick 	int *retval;
108637Sbill {
108742441Smckusick 	struct stat sb;
108842441Smckusick 	int error;
108947540Skarels 	struct nameidata nd;
109037Sbill 
109164410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
109252322Smckusick 	if (error = namei(&nd))
109347540Skarels 		return (error);
109452322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
109552322Smckusick 	vput(nd.ni_vp);
109642441Smckusick 	if (error)
109747540Skarels 		return (error);
109842441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
109947540Skarels 	return (error);
110037Sbill }
110137Sbill 
110237Sbill /*
110364410Sbostic  * Get file status; this version does not follow links.
11045992Swnj  */
110554916Storek struct lstat_args {
110664410Sbostic 	char	*path;
110754916Storek 	struct stat *ub;
110854916Storek };
110942441Smckusick /* ARGSUSED */
111053759Smckusick lstat(p, uap, retval)
111145914Smckusick 	struct proc *p;
111254916Storek 	register struct lstat_args *uap;
111342441Smckusick 	int *retval;
111442441Smckusick {
111537741Smckusick 	int error;
111659373Smckusick 	struct vnode *vp, *dvp;
111759373Smckusick 	struct stat sb, sb1;
111847540Skarels 	struct nameidata nd;
11195992Swnj 
112059373Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
112164410Sbostic 	    uap->path, p);
112252322Smckusick 	if (error = namei(&nd))
112347540Skarels 		return (error);
112459373Smckusick 	/*
112559373Smckusick 	 * For symbolic links, always return the attributes of its
112659373Smckusick 	 * containing directory, except for mode, size, and links.
112759373Smckusick 	 */
112859373Smckusick 	vp = nd.ni_vp;
112959373Smckusick 	dvp = nd.ni_dvp;
113059373Smckusick 	if (vp->v_type != VLNK) {
113159373Smckusick 		if (dvp == vp)
113259373Smckusick 			vrele(dvp);
113359373Smckusick 		else
113459373Smckusick 			vput(dvp);
113559373Smckusick 		error = vn_stat(vp, &sb, p);
113659373Smckusick 		vput(vp);
113759373Smckusick 		if (error)
113859373Smckusick 			return (error);
113959373Smckusick 	} else {
114059373Smckusick 		error = vn_stat(dvp, &sb, p);
114159373Smckusick 		vput(dvp);
114259373Smckusick 		if (error) {
114359373Smckusick 			vput(vp);
114459373Smckusick 			return (error);
114559373Smckusick 		}
114659373Smckusick 		error = vn_stat(vp, &sb1, p);
114759373Smckusick 		vput(vp);
114859373Smckusick 		if (error)
114959373Smckusick 			return (error);
115059373Smckusick 		sb.st_mode &= ~S_IFDIR;
115159373Smckusick 		sb.st_mode |= S_IFLNK;
115259373Smckusick 		sb.st_nlink = sb1.st_nlink;
115359373Smckusick 		sb.st_size = sb1.st_size;
115459373Smckusick 		sb.st_blocks = sb1.st_blocks;
115559373Smckusick 	}
115637741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
115747540Skarels 	return (error);
11585992Swnj }
11595992Swnj 
11605992Swnj /*
116164410Sbostic  * Get configurable pathname variables.
116260414Smckusick  */
116360414Smckusick struct pathconf_args {
116464410Sbostic 	char	*path;
116560414Smckusick 	int	name;
116660414Smckusick };
116760414Smckusick /* ARGSUSED */
116860414Smckusick pathconf(p, uap, retval)
116960414Smckusick 	struct proc *p;
117060414Smckusick 	register struct pathconf_args *uap;
117160414Smckusick 	int *retval;
117260414Smckusick {
117360414Smckusick 	int error;
117460414Smckusick 	struct nameidata nd;
117560414Smckusick 
117664410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
117760414Smckusick 	if (error = namei(&nd))
117860414Smckusick 		return (error);
117960414Smckusick 	error = VOP_PATHCONF(nd.ni_vp, uap->name, retval);
118060414Smckusick 	vput(nd.ni_vp);
118160414Smckusick 	return (error);
118260414Smckusick }
118360414Smckusick 
118460414Smckusick /*
118549365Smckusick  * Return target name of a symbolic link.
118637Sbill  */
118754916Storek struct readlink_args {
118864410Sbostic 	char	*path;
118954916Storek 	char	*buf;
119054916Storek 	int	count;
119154916Storek };
119242441Smckusick /* ARGSUSED */
119342441Smckusick readlink(p, uap, retval)
119445914Smckusick 	struct proc *p;
119554916Storek 	register struct readlink_args *uap;
119642441Smckusick 	int *retval;
119742441Smckusick {
119837741Smckusick 	register struct vnode *vp;
119937741Smckusick 	struct iovec aiov;
120037741Smckusick 	struct uio auio;
120137741Smckusick 	int error;
120247540Skarels 	struct nameidata nd;
12035992Swnj 
120464410Sbostic 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, p);
120552322Smckusick 	if (error = namei(&nd))
120647540Skarels 		return (error);
120752322Smckusick 	vp = nd.ni_vp;
120864410Sbostic 	if (vp->v_type != VLNK)
120937741Smckusick 		error = EINVAL;
121064410Sbostic 	else {
121164410Sbostic 		aiov.iov_base = uap->buf;
121264410Sbostic 		aiov.iov_len = uap->count;
121364410Sbostic 		auio.uio_iov = &aiov;
121464410Sbostic 		auio.uio_iovcnt = 1;
121564410Sbostic 		auio.uio_offset = 0;
121664410Sbostic 		auio.uio_rw = UIO_READ;
121764410Sbostic 		auio.uio_segflg = UIO_USERSPACE;
121864410Sbostic 		auio.uio_procp = p;
121964410Sbostic 		auio.uio_resid = uap->count;
122064410Sbostic 		error = VOP_READLINK(vp, &auio, p->p_ucred);
12215992Swnj 	}
122237741Smckusick 	vput(vp);
122342441Smckusick 	*retval = uap->count - auio.uio_resid;
122447540Skarels 	return (error);
12255992Swnj }
12265992Swnj 
12279167Ssam /*
122864410Sbostic  * Change flags of a file given a path name.
122938259Smckusick  */
123054916Storek struct chflags_args {
123164410Sbostic 	char	*path;
123254916Storek 	int	flags;
123354916Storek };
123442441Smckusick /* ARGSUSED */
123542441Smckusick chflags(p, uap, retval)
123645914Smckusick 	struct proc *p;
123754916Storek 	register struct chflags_args *uap;
123842441Smckusick 	int *retval;
123942441Smckusick {
124038259Smckusick 	register struct vnode *vp;
124138259Smckusick 	struct vattr vattr;
124238259Smckusick 	int error;
124347540Skarels 	struct nameidata nd;
124438259Smckusick 
124564410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
124652322Smckusick 	if (error = namei(&nd))
124747540Skarels 		return (error);
124852322Smckusick 	vp = nd.ni_vp;
124959382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
125059382Smckusick 	VOP_LOCK(vp);
125164410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
125238259Smckusick 		error = EROFS;
125364410Sbostic 	else {
125464410Sbostic 		VATTR_NULL(&vattr);
125564410Sbostic 		vattr.va_flags = uap->flags;
125664410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
125738259Smckusick 	}
125838259Smckusick 	vput(vp);
125947540Skarels 	return (error);
126038259Smckusick }
126138259Smckusick 
126238259Smckusick /*
126338259Smckusick  * Change flags of a file given a file descriptor.
126438259Smckusick  */
126554916Storek struct fchflags_args {
126654916Storek 	int	fd;
126754916Storek 	int	flags;
126854916Storek };
126942441Smckusick /* ARGSUSED */
127042441Smckusick fchflags(p, uap, retval)
127145914Smckusick 	struct proc *p;
127254916Storek 	register struct fchflags_args *uap;
127342441Smckusick 	int *retval;
127442441Smckusick {
127538259Smckusick 	struct vattr vattr;
127638259Smckusick 	struct vnode *vp;
127738259Smckusick 	struct file *fp;
127838259Smckusick 	int error;
127938259Smckusick 
128045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
128147540Skarels 		return (error);
128238259Smckusick 	vp = (struct vnode *)fp->f_data;
128359382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
128438259Smckusick 	VOP_LOCK(vp);
128564410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
128638259Smckusick 		error = EROFS;
128764410Sbostic 	else {
128864410Sbostic 		VATTR_NULL(&vattr);
128964410Sbostic 		vattr.va_flags = uap->flags;
129064410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
129138259Smckusick 	}
129238259Smckusick 	VOP_UNLOCK(vp);
129347540Skarels 	return (error);
129438259Smckusick }
129538259Smckusick 
129638259Smckusick /*
12979167Ssam  * Change mode of a file given path name.
12989167Ssam  */
129954916Storek struct chmod_args {
130064410Sbostic 	char	*path;
130164410Sbostic 	int	mode;
130254916Storek };
130342441Smckusick /* ARGSUSED */
130442441Smckusick chmod(p, uap, retval)
130545914Smckusick 	struct proc *p;
130654916Storek 	register struct chmod_args *uap;
130742441Smckusick 	int *retval;
130842441Smckusick {
130937741Smckusick 	register struct vnode *vp;
131037741Smckusick 	struct vattr vattr;
131137741Smckusick 	int error;
131247540Skarels 	struct nameidata nd;
13135992Swnj 
131464410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
131552322Smckusick 	if (error = namei(&nd))
131647540Skarels 		return (error);
131752322Smckusick 	vp = nd.ni_vp;
131859382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
131959382Smckusick 	VOP_LOCK(vp);
132064410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
132137741Smckusick 		error = EROFS;
132264410Sbostic 	else {
132364410Sbostic 		VATTR_NULL(&vattr);
132464410Sbostic 		vattr.va_mode = uap->mode & ALLPERMS;
132564410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
132637741Smckusick 	}
132737741Smckusick 	vput(vp);
132847540Skarels 	return (error);
13297701Ssam }
13307439Sroot 
13319167Ssam /*
13329167Ssam  * Change mode of a file given a file descriptor.
13339167Ssam  */
133454916Storek struct fchmod_args {
133554916Storek 	int	fd;
133664410Sbostic 	int	mode;
133754916Storek };
133842441Smckusick /* ARGSUSED */
133942441Smckusick fchmod(p, uap, retval)
134045914Smckusick 	struct proc *p;
134154916Storek 	register struct fchmod_args *uap;
134242441Smckusick 	int *retval;
134342441Smckusick {
134437741Smckusick 	struct vattr vattr;
134537741Smckusick 	struct vnode *vp;
134637741Smckusick 	struct file *fp;
134737741Smckusick 	int error;
13487701Ssam 
134945914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
135047540Skarels 		return (error);
135137741Smckusick 	vp = (struct vnode *)fp->f_data;
135259382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
135337741Smckusick 	VOP_LOCK(vp);
135464410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
135537741Smckusick 		error = EROFS;
135664410Sbostic 	else {
135764410Sbostic 		VATTR_NULL(&vattr);
135864410Sbostic 		vattr.va_mode = uap->mode & ALLPERMS;
135964410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
13607439Sroot 	}
136137741Smckusick 	VOP_UNLOCK(vp);
136247540Skarels 	return (error);
13635992Swnj }
13645992Swnj 
13659167Ssam /*
13669167Ssam  * Set ownership given a path name.
13679167Ssam  */
136854916Storek struct chown_args {
136964410Sbostic 	char	*path;
137054916Storek 	int	uid;
137154916Storek 	int	gid;
137254916Storek };
137342441Smckusick /* ARGSUSED */
137442441Smckusick chown(p, uap, retval)
137545914Smckusick 	struct proc *p;
137654916Storek 	register struct chown_args *uap;
137742441Smckusick 	int *retval;
137842441Smckusick {
137937741Smckusick 	register struct vnode *vp;
138037741Smckusick 	struct vattr vattr;
138137741Smckusick 	int error;
138247540Skarels 	struct nameidata nd;
138337Sbill 
138464410Sbostic 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, p);
138552322Smckusick 	if (error = namei(&nd))
138647540Skarels 		return (error);
138752322Smckusick 	vp = nd.ni_vp;
138859382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
138959382Smckusick 	VOP_LOCK(vp);
139064410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
139137741Smckusick 		error = EROFS;
139264410Sbostic 	else {
139364410Sbostic 		VATTR_NULL(&vattr);
139464410Sbostic 		vattr.va_uid = uap->uid;
139564410Sbostic 		vattr.va_gid = uap->gid;
139664410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
139737741Smckusick 	}
139837741Smckusick 	vput(vp);
139947540Skarels 	return (error);
14007701Ssam }
14017439Sroot 
14029167Ssam /*
14039167Ssam  * Set ownership given a file descriptor.
14049167Ssam  */
140554916Storek struct fchown_args {
140654916Storek 	int	fd;
140754916Storek 	int	uid;
140854916Storek 	int	gid;
140954916Storek };
141042441Smckusick /* ARGSUSED */
141142441Smckusick fchown(p, uap, retval)
141245914Smckusick 	struct proc *p;
141354916Storek 	register struct fchown_args *uap;
141442441Smckusick 	int *retval;
141542441Smckusick {
141637741Smckusick 	struct vattr vattr;
141737741Smckusick 	struct vnode *vp;
141837741Smckusick 	struct file *fp;
141937741Smckusick 	int error;
14207701Ssam 
142145914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
142247540Skarels 		return (error);
142337741Smckusick 	vp = (struct vnode *)fp->f_data;
142459382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
142537741Smckusick 	VOP_LOCK(vp);
142664410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
142737741Smckusick 		error = EROFS;
142864410Sbostic 	else {
142964410Sbostic 		VATTR_NULL(&vattr);
143064410Sbostic 		vattr.va_uid = uap->uid;
143164410Sbostic 		vattr.va_gid = uap->gid;
143264410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
143337741Smckusick 	}
143437741Smckusick 	VOP_UNLOCK(vp);
143547540Skarels 	return (error);
14367701Ssam }
14377701Ssam 
143842441Smckusick /*
143942441Smckusick  * Set the access and modification times of a file.
144042441Smckusick  */
144154916Storek struct utimes_args {
144264410Sbostic 	char	*path;
144354916Storek 	struct	timeval *tptr;
144454916Storek };
144542441Smckusick /* ARGSUSED */
144642441Smckusick utimes(p, uap, retval)
144745914Smckusick 	struct proc *p;
144854916Storek 	register struct utimes_args *uap;
144942441Smckusick 	int *retval;
145042441Smckusick {
145137741Smckusick 	register struct vnode *vp;
145211811Ssam 	struct timeval tv[2];
145337741Smckusick 	struct vattr vattr;
145458840Storek 	int error;
145547540Skarels 	struct nameidata nd;
145611811Ssam 
145758505Sbostic 	VATTR_NULL(&vattr);
145858505Sbostic 	if (uap->tptr == NULL) {
145958505Sbostic 		microtime(&tv[0]);
146058505Sbostic 		tv[1] = tv[0];
146158548Sbostic 		vattr.va_vaflags |= VA_UTIMES_NULL;
146258505Sbostic 	} else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
146358505Sbostic   		return (error);
146464410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
146552322Smckusick 	if (error = namei(&nd))
146647540Skarels 		return (error);
146752322Smckusick 	vp = nd.ni_vp;
146859382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
146959382Smckusick 	VOP_LOCK(vp);
147064410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
147137741Smckusick 		error = EROFS;
147264410Sbostic 	else {
147364410Sbostic 		vattr.va_atime.ts_sec = tv[0].tv_sec;
147464410Sbostic 		vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
147564410Sbostic 		vattr.va_mtime.ts_sec = tv[1].tv_sec;
147664410Sbostic 		vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
147764410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
147821015Smckusick 	}
147937741Smckusick 	vput(vp);
148047540Skarels 	return (error);
148111811Ssam }
148211811Ssam 
148364410Sbostic /*
148464410Sbostic  * Truncate a file given its path name.
148564410Sbostic  */
148660428Smckusick struct truncate_args {
148764410Sbostic 	char	*path;
148854863Storek 	int	pad;
148954863Storek 	off_t	length;
149054863Storek };
149153468Smckusick /* ARGSUSED */
149260414Smckusick truncate(p, uap, retval)
149353468Smckusick 	struct proc *p;
149460428Smckusick 	register struct truncate_args *uap;
149553468Smckusick 	int *retval;
149653468Smckusick {
149737741Smckusick 	register struct vnode *vp;
149837741Smckusick 	struct vattr vattr;
149937741Smckusick 	int error;
150047540Skarels 	struct nameidata nd;
15017701Ssam 
150264410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
150352322Smckusick 	if (error = namei(&nd))
150447540Skarels 		return (error);
150552322Smckusick 	vp = nd.ni_vp;
150659382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
150759382Smckusick 	VOP_LOCK(vp);
150864410Sbostic 	if (vp->v_type == VDIR)
150937741Smckusick 		error = EISDIR;
151064410Sbostic 	else if ((error = vn_writechk(vp)) == 0 &&
151164410Sbostic 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
151264410Sbostic 		VATTR_NULL(&vattr);
151364410Sbostic 		vattr.va_size = uap->length;
151464410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
15157701Ssam 	}
151637741Smckusick 	vput(vp);
151747540Skarels 	return (error);
15187701Ssam }
15197701Ssam 
152064410Sbostic /*
152164410Sbostic  * Truncate a file given a file descriptor.
152264410Sbostic  */
152360428Smckusick struct ftruncate_args {
152454863Storek 	int	fd;
152554863Storek 	int	pad;
152654863Storek 	off_t	length;
152754863Storek };
152842441Smckusick /* ARGSUSED */
152960414Smckusick ftruncate(p, uap, retval)
153045914Smckusick 	struct proc *p;
153160428Smckusick 	register struct ftruncate_args *uap;
153242441Smckusick 	int *retval;
153342441Smckusick {
153437741Smckusick 	struct vattr vattr;
153537741Smckusick 	struct vnode *vp;
15367701Ssam 	struct file *fp;
153737741Smckusick 	int error;
15387701Ssam 
153945914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
154047540Skarels 		return (error);
154137741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
154247540Skarels 		return (EINVAL);
154337741Smckusick 	vp = (struct vnode *)fp->f_data;
154459382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
154537741Smckusick 	VOP_LOCK(vp);
154664410Sbostic 	if (vp->v_type == VDIR)
154737741Smckusick 		error = EISDIR;
154864410Sbostic 	else if ((error = vn_writechk(vp)) == 0) {
154964410Sbostic 		VATTR_NULL(&vattr);
155064410Sbostic 		vattr.va_size = uap->length;
155164410Sbostic 		error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
15527701Ssam 	}
155337741Smckusick 	VOP_UNLOCK(vp);
155447540Skarels 	return (error);
15557701Ssam }
15567701Ssam 
155754863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
15589167Ssam /*
155954863Storek  * Truncate a file given its path name.
156054863Storek  */
156160428Smckusick struct otruncate_args {
156264410Sbostic 	char	*path;
156354916Storek 	long	length;
156454916Storek };
156554863Storek /* ARGSUSED */
156660105Smckusick otruncate(p, uap, retval)
156754863Storek 	struct proc *p;
156860428Smckusick 	register struct otruncate_args *uap;
156954863Storek 	int *retval;
157054863Storek {
157160428Smckusick 	struct truncate_args nuap;
157254863Storek 
157364410Sbostic 	nuap.path = uap->path;
157454863Storek 	nuap.length = uap->length;
157560428Smckusick 	return (truncate(p, &nuap, retval));
157654863Storek }
157754863Storek 
157854863Storek /*
157954863Storek  * Truncate a file given a file descriptor.
158054863Storek  */
158160428Smckusick struct oftruncate_args {
158254916Storek 	int	fd;
158354916Storek 	long	length;
158454916Storek };
158554863Storek /* ARGSUSED */
158660105Smckusick oftruncate(p, uap, retval)
158754863Storek 	struct proc *p;
158860428Smckusick 	register struct oftruncate_args *uap;
158954863Storek 	int *retval;
159054863Storek {
159160428Smckusick 	struct ftruncate_args nuap;
159254863Storek 
159354863Storek 	nuap.fd = uap->fd;
159454863Storek 	nuap.length = uap->length;
159560428Smckusick 	return (ftruncate(p, &nuap, retval));
159654863Storek }
159754863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */
159854863Storek 
159954863Storek /*
160064410Sbostic  * Sync an open file.
16019167Ssam  */
160254916Storek struct fsync_args {
160354916Storek 	int	fd;
160454916Storek };
160542441Smckusick /* ARGSUSED */
160642441Smckusick fsync(p, uap, retval)
160745914Smckusick 	struct proc *p;
160854916Storek 	struct fsync_args *uap;
160942441Smckusick 	int *retval;
16109167Ssam {
161139592Smckusick 	register struct vnode *vp;
16129167Ssam 	struct file *fp;
161337741Smckusick 	int error;
16149167Ssam 
161545914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
161647540Skarels 		return (error);
161739592Smckusick 	vp = (struct vnode *)fp->f_data;
161839592Smckusick 	VOP_LOCK(vp);
161954441Smckusick 	error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
162039592Smckusick 	VOP_UNLOCK(vp);
162147540Skarels 	return (error);
16229167Ssam }
16239167Ssam 
16249167Ssam /*
162564410Sbostic  * Rename files.  Source and destination must either both be directories,
162664410Sbostic  * or both not be directories.  If target is a directory, it must be empty.
16279167Ssam  */
162854916Storek struct rename_args {
162954916Storek 	char	*from;
163054916Storek 	char	*to;
163154916Storek };
163242441Smckusick /* ARGSUSED */
163342441Smckusick rename(p, uap, retval)
163445914Smckusick 	struct proc *p;
163554916Storek 	register struct rename_args *uap;
163642441Smckusick 	int *retval;
163742441Smckusick {
163837741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
163949735Smckusick 	struct nameidata fromnd, tond;
164037741Smckusick 	int error;
16417701Ssam 
164252322Smckusick 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
164352322Smckusick 		uap->from, p);
164452322Smckusick 	if (error = namei(&fromnd))
164547540Skarels 		return (error);
164649735Smckusick 	fvp = fromnd.ni_vp;
164752322Smckusick 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
164852322Smckusick 		UIO_USERSPACE, uap->to, p);
164952322Smckusick 	if (error = namei(&tond)) {
165052230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
165149735Smckusick 		vrele(fromnd.ni_dvp);
165242465Smckusick 		vrele(fvp);
165342465Smckusick 		goto out1;
165442465Smckusick 	}
165537741Smckusick 	tdvp = tond.ni_dvp;
165637741Smckusick 	tvp = tond.ni_vp;
165737741Smckusick 	if (tvp != NULL) {
165837741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
165939242Sbostic 			error = ENOTDIR;
166037741Smckusick 			goto out;
166137741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
166239242Sbostic 			error = EISDIR;
166337741Smckusick 			goto out;
16649167Ssam 		}
16659167Ssam 	}
166639286Smckusick 	if (fvp == tdvp)
166737741Smckusick 		error = EINVAL;
166839286Smckusick 	/*
166949735Smckusick 	 * If source is the same as the destination (that is the
167049735Smckusick 	 * same inode number with the same name in the same directory),
167139286Smckusick 	 * then there is nothing to do.
167239286Smckusick 	 */
167349735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
167452322Smckusick 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
167552322Smckusick 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
167652322Smckusick 	      fromnd.ni_cnd.cn_namelen))
167739286Smckusick 		error = -1;
167837741Smckusick out:
167942465Smckusick 	if (!error) {
168052192Smckusick 		LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE);
168152192Smckusick 		if (fromnd.ni_dvp != tdvp)
168252192Smckusick 			LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
168352192Smckusick 		if (tvp)
168452192Smckusick 			LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE);
168552230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
168652230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
168742465Smckusick 	} else {
168852230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
168943344Smckusick 		if (tdvp == tvp)
169043344Smckusick 			vrele(tdvp);
169143344Smckusick 		else
169243344Smckusick 			vput(tdvp);
169342465Smckusick 		if (tvp)
169442465Smckusick 			vput(tvp);
169552230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
169649735Smckusick 		vrele(fromnd.ni_dvp);
169742465Smckusick 		vrele(fvp);
16989167Ssam 	}
169949735Smckusick 	vrele(tond.ni_startdir);
170052322Smckusick 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
170137741Smckusick out1:
170249735Smckusick 	vrele(fromnd.ni_startdir);
170352322Smckusick 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
170439286Smckusick 	if (error == -1)
170547540Skarels 		return (0);
170647540Skarels 	return (error);
17077701Ssam }
17087701Ssam 
17097535Sroot /*
171064410Sbostic  * Make a directory file.
171112756Ssam  */
171254916Storek struct mkdir_args {
171364410Sbostic 	char	*path;
171464410Sbostic 	int	mode;
171554916Storek };
171642441Smckusick /* ARGSUSED */
171742441Smckusick mkdir(p, uap, retval)
171845914Smckusick 	struct proc *p;
171954916Storek 	register struct mkdir_args *uap;
172042441Smckusick 	int *retval;
172142441Smckusick {
172237741Smckusick 	register struct vnode *vp;
172337741Smckusick 	struct vattr vattr;
172437741Smckusick 	int error;
172547540Skarels 	struct nameidata nd;
172612756Ssam 
172764410Sbostic 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->path, p);
172852322Smckusick 	if (error = namei(&nd))
172947540Skarels 		return (error);
173052322Smckusick 	vp = nd.ni_vp;
173137741Smckusick 	if (vp != NULL) {
173252322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
173352322Smckusick 		if (nd.ni_dvp == vp)
173452322Smckusick 			vrele(nd.ni_dvp);
173543344Smckusick 		else
173652322Smckusick 			vput(nd.ni_dvp);
173742465Smckusick 		vrele(vp);
173847540Skarels 		return (EEXIST);
173912756Ssam 	}
174041362Smckusick 	VATTR_NULL(&vattr);
174137741Smckusick 	vattr.va_type = VDIR;
174264410Sbostic 	vattr.va_mode = (uap->mode & ACCESSPERMS) &~ p->p_fd->fd_cmask;
174352322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
174452322Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
174538145Smckusick 	if (!error)
174652322Smckusick 		vput(nd.ni_vp);
174747540Skarels 	return (error);
174812756Ssam }
174912756Ssam 
175012756Ssam /*
175164410Sbostic  * Remove a directory file.
175212756Ssam  */
175354916Storek struct rmdir_args {
175464410Sbostic 	char	*path;
175554916Storek };
175642441Smckusick /* ARGSUSED */
175742441Smckusick rmdir(p, uap, retval)
175845914Smckusick 	struct proc *p;
175954916Storek 	struct rmdir_args *uap;
176042441Smckusick 	int *retval;
176112756Ssam {
176237741Smckusick 	register struct vnode *vp;
176337741Smckusick 	int error;
176447540Skarels 	struct nameidata nd;
176512756Ssam 
176664410Sbostic 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->path, p);
176752322Smckusick 	if (error = namei(&nd))
176847540Skarels 		return (error);
176952322Smckusick 	vp = nd.ni_vp;
177037741Smckusick 	if (vp->v_type != VDIR) {
177137741Smckusick 		error = ENOTDIR;
177212756Ssam 		goto out;
177312756Ssam 	}
177412756Ssam 	/*
177537741Smckusick 	 * No rmdir "." please.
177612756Ssam 	 */
177752322Smckusick 	if (nd.ni_dvp == vp) {
177837741Smckusick 		error = EINVAL;
177912756Ssam 		goto out;
178012756Ssam 	}
178112756Ssam 	/*
178249365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
178312756Ssam 	 */
178437741Smckusick 	if (vp->v_flag & VROOT)
178537741Smckusick 		error = EBUSY;
178612756Ssam out:
178742465Smckusick 	if (!error) {
178852322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
178952192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
179052322Smckusick 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
179142465Smckusick 	} else {
179252322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
179352322Smckusick 		if (nd.ni_dvp == vp)
179452322Smckusick 			vrele(nd.ni_dvp);
179543344Smckusick 		else
179652322Smckusick 			vput(nd.ni_dvp);
179742465Smckusick 		vput(vp);
179842465Smckusick 	}
179947540Skarels 	return (error);
180012756Ssam }
180112756Ssam 
180254620Smckusick #ifdef COMPAT_43
180337741Smckusick /*
180449365Smckusick  * Read a block of directory entries in a file system independent format.
180537741Smckusick  */
180654916Storek struct ogetdirentries_args {
180754916Storek 	int	fd;
180854916Storek 	char	*buf;
180964410Sbostic 	u_int	count;
181054916Storek 	long	*basep;
181154916Storek };
181254620Smckusick ogetdirentries(p, uap, retval)
181354620Smckusick 	struct proc *p;
181454916Storek 	register struct ogetdirentries_args *uap;
181554620Smckusick 	int *retval;
181654620Smckusick {
181754620Smckusick 	register struct vnode *vp;
181854620Smckusick 	struct file *fp;
181954620Smckusick 	struct uio auio, kuio;
182054620Smckusick 	struct iovec aiov, kiov;
182154620Smckusick 	struct dirent *dp, *edp;
182254620Smckusick 	caddr_t dirbuf;
182354620Smckusick 	int error, readcnt;
182454969Smckusick 	long loff;
182554620Smckusick 
182654620Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
182754620Smckusick 		return (error);
182854620Smckusick 	if ((fp->f_flag & FREAD) == 0)
182954620Smckusick 		return (EBADF);
183054620Smckusick 	vp = (struct vnode *)fp->f_data;
183154620Smckusick 	if (vp->v_type != VDIR)
183254620Smckusick 		return (EINVAL);
183354620Smckusick 	aiov.iov_base = uap->buf;
183454620Smckusick 	aiov.iov_len = uap->count;
183554620Smckusick 	auio.uio_iov = &aiov;
183654620Smckusick 	auio.uio_iovcnt = 1;
183754620Smckusick 	auio.uio_rw = UIO_READ;
183854620Smckusick 	auio.uio_segflg = UIO_USERSPACE;
183954620Smckusick 	auio.uio_procp = p;
184054620Smckusick 	auio.uio_resid = uap->count;
184154620Smckusick 	VOP_LOCK(vp);
184254969Smckusick 	loff = auio.uio_offset = fp->f_offset;
184354620Smckusick #	if (BYTE_ORDER != LITTLE_ENDIAN)
184456339Smckusick 		if (vp->v_mount->mnt_maxsymlinklen <= 0) {
184554620Smckusick 			error = VOP_READDIR(vp, &auio, fp->f_cred);
184656339Smckusick 			fp->f_offset = auio.uio_offset;
184756339Smckusick 		} else
184854620Smckusick #	endif
184954620Smckusick 	{
185054620Smckusick 		kuio = auio;
185154620Smckusick 		kuio.uio_iov = &kiov;
185254620Smckusick 		kuio.uio_segflg = UIO_SYSSPACE;
185354620Smckusick 		kiov.iov_len = uap->count;
185454620Smckusick 		MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK);
185554620Smckusick 		kiov.iov_base = dirbuf;
185654620Smckusick 		error = VOP_READDIR(vp, &kuio, fp->f_cred);
185756339Smckusick 		fp->f_offset = kuio.uio_offset;
185854620Smckusick 		if (error == 0) {
185954620Smckusick 			readcnt = uap->count - kuio.uio_resid;
186054620Smckusick 			edp = (struct dirent *)&dirbuf[readcnt];
186154620Smckusick 			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
186254620Smckusick #				if (BYTE_ORDER == LITTLE_ENDIAN)
186354969Smckusick 					/*
186455009Smckusick 					 * The expected low byte of
186555009Smckusick 					 * dp->d_namlen is our dp->d_type.
186655009Smckusick 					 * The high MBZ byte of dp->d_namlen
186755009Smckusick 					 * is our dp->d_namlen.
186854969Smckusick 					 */
186955009Smckusick 					dp->d_type = dp->d_namlen;
187055009Smckusick 					dp->d_namlen = 0;
187155009Smckusick #				else
187255009Smckusick 					/*
187355009Smckusick 					 * The dp->d_type is the high byte
187455009Smckusick 					 * of the expected dp->d_namlen,
187555009Smckusick 					 * so must be zero'ed.
187655009Smckusick 					 */
187755009Smckusick 					dp->d_type = 0;
187854620Smckusick #				endif
187954620Smckusick 				if (dp->d_reclen > 0) {
188054620Smckusick 					dp = (struct dirent *)
188154620Smckusick 					    ((char *)dp + dp->d_reclen);
188254620Smckusick 				} else {
188354620Smckusick 					error = EIO;
188454620Smckusick 					break;
188554620Smckusick 				}
188654620Smckusick 			}
188754620Smckusick 			if (dp >= edp)
188854620Smckusick 				error = uiomove(dirbuf, readcnt, &auio);
188954620Smckusick 		}
189054620Smckusick 		FREE(dirbuf, M_TEMP);
189154620Smckusick 	}
189254620Smckusick 	VOP_UNLOCK(vp);
189354620Smckusick 	if (error)
189454620Smckusick 		return (error);
189554969Smckusick 	error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
189654620Smckusick 	*retval = uap->count - auio.uio_resid;
189754620Smckusick 	return (error);
189854620Smckusick }
189954620Smckusick #endif
190054620Smckusick 
190154620Smckusick /*
190254620Smckusick  * Read a block of directory entries in a file system independent format.
190354620Smckusick  */
190454916Storek struct getdirentries_args {
190554916Storek 	int	fd;
190654916Storek 	char	*buf;
190764410Sbostic 	u_int	count;
190854916Storek 	long	*basep;
190954916Storek };
191042441Smckusick getdirentries(p, uap, retval)
191145914Smckusick 	struct proc *p;
191254916Storek 	register struct getdirentries_args *uap;
191342441Smckusick 	int *retval;
191442441Smckusick {
191539592Smckusick 	register struct vnode *vp;
191616540Ssam 	struct file *fp;
191737741Smckusick 	struct uio auio;
191837741Smckusick 	struct iovec aiov;
191954969Smckusick 	long loff;
192054441Smckusick 	int error;
192112756Ssam 
192245914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
192347540Skarels 		return (error);
192437741Smckusick 	if ((fp->f_flag & FREAD) == 0)
192547540Skarels 		return (EBADF);
192639592Smckusick 	vp = (struct vnode *)fp->f_data;
192755451Spendry unionread:
192839592Smckusick 	if (vp->v_type != VDIR)
192947540Skarels 		return (EINVAL);
193037741Smckusick 	aiov.iov_base = uap->buf;
193137741Smckusick 	aiov.iov_len = uap->count;
193237741Smckusick 	auio.uio_iov = &aiov;
193337741Smckusick 	auio.uio_iovcnt = 1;
193437741Smckusick 	auio.uio_rw = UIO_READ;
193537741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
193648026Smckusick 	auio.uio_procp = p;
193737741Smckusick 	auio.uio_resid = uap->count;
193839592Smckusick 	VOP_LOCK(vp);
193954969Smckusick 	loff = auio.uio_offset = fp->f_offset;
194054441Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred);
194139592Smckusick 	fp->f_offset = auio.uio_offset;
194239592Smckusick 	VOP_UNLOCK(vp);
194339592Smckusick 	if (error)
194447540Skarels 		return (error);
194555451Spendry 	if ((uap->count == auio.uio_resid) &&
194655451Spendry 	    (vp->v_flag & VROOT) &&
194755451Spendry 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
194855451Spendry 		struct vnode *tvp = vp;
194955451Spendry 		vp = vp->v_mount->mnt_vnodecovered;
195055451Spendry 		VREF(vp);
195155451Spendry 		fp->f_data = (caddr_t) vp;
195255451Spendry 		fp->f_offset = 0;
195355451Spendry 		vrele(tvp);
195455451Spendry 		goto unionread;
195555451Spendry 	}
195654969Smckusick 	error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
195742441Smckusick 	*retval = uap->count - auio.uio_resid;
195847540Skarels 	return (error);
195912756Ssam }
196012756Ssam 
196112756Ssam /*
196249365Smckusick  * Set the mode mask for creation of filesystem nodes.
196312756Ssam  */
196454916Storek struct umask_args {
196564410Sbostic 	int	newmask;
196654916Storek };
196754916Storek mode_t				/* XXX */
196842441Smckusick umask(p, uap, retval)
196945914Smckusick 	struct proc *p;
197054916Storek 	struct umask_args *uap;
197142441Smckusick 	int *retval;
197212756Ssam {
197364410Sbostic 	register struct filedesc *fdp;
197412756Ssam 
197564410Sbostic 	fdp = p->p_fd;
197645914Smckusick 	*retval = fdp->fd_cmask;
197764410Sbostic 	fdp->fd_cmask = uap->newmask & ALLPERMS;
197847540Skarels 	return (0);
197912756Ssam }
198037741Smckusick 
198139566Smarc /*
198239566Smarc  * Void all references to file by ripping underlying filesystem
198339566Smarc  * away from vnode.
198439566Smarc  */
198554916Storek struct revoke_args {
198664410Sbostic 	char	*path;
198754916Storek };
198842441Smckusick /* ARGSUSED */
198942441Smckusick revoke(p, uap, retval)
199045914Smckusick 	struct proc *p;
199154916Storek 	register struct revoke_args *uap;
199242441Smckusick 	int *retval;
199342441Smckusick {
199439566Smarc 	register struct vnode *vp;
199539566Smarc 	struct vattr vattr;
199639566Smarc 	int error;
199747540Skarels 	struct nameidata nd;
199839566Smarc 
199964410Sbostic 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
200052322Smckusick 	if (error = namei(&nd))
200147540Skarels 		return (error);
200252322Smckusick 	vp = nd.ni_vp;
200339566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
200439566Smarc 		error = EINVAL;
200539566Smarc 		goto out;
200639566Smarc 	}
200748026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
200839566Smarc 		goto out;
200947540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
201047540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
201139566Smarc 		goto out;
201239805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
201339632Smckusick 		vgoneall(vp);
201439566Smarc out:
201539566Smarc 	vrele(vp);
201647540Skarels 	return (error);
201739566Smarc }
201839566Smarc 
201949365Smckusick /*
202049365Smckusick  * Convert a user file descriptor to a kernel file entry.
202149365Smckusick  */
202264410Sbostic getvnode(fdp, fd, fpp)
202345914Smckusick 	struct filedesc *fdp;
202437741Smckusick 	struct file **fpp;
202564410Sbostic 	int fd;
202637741Smckusick {
202737741Smckusick 	struct file *fp;
202837741Smckusick 
202964410Sbostic 	if ((u_int)fd >= fdp->fd_nfiles ||
203064410Sbostic 	    (fp = fdp->fd_ofiles[fd]) == NULL)
203137741Smckusick 		return (EBADF);
203237741Smckusick 	if (fp->f_type != DTYPE_VNODE)
203337741Smckusick 		return (EINVAL);
203437741Smckusick 	*fpp = fp;
203537741Smckusick 	return (0);
203637741Smckusick }
2037