xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 40884)
123405Smckusick /*
237741Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337741Smckusick  * All rights reserved.
423405Smckusick  *
537741Smckusick  * Redistribution and use in source and binary forms are permitted
637741Smckusick  * provided that the above copyright notice and this paragraph are
737741Smckusick  * duplicated in all such forms and that any documentation,
837741Smckusick  * advertising materials, and other materials related to such
937741Smckusick  * distribution and use acknowledge that the software was developed
1037741Smckusick  * by the University of California, Berkeley.  The name of the
1137741Smckusick  * University may not be used to endorse or promote products derived
1237741Smckusick  * from this software without specific prior written permission.
1337741Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1437741Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1537741Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1637741Smckusick  *
17*40884Smckusick  *	@(#)vfs_syscalls.c	7.43 (Berkeley) 04/10/90
1823405Smckusick  */
1937Sbill 
2017101Sbloom #include "param.h"
2117101Sbloom #include "systm.h"
2237741Smckusick #include "syscontext.h"
2317101Sbloom #include "kernel.h"
2417101Sbloom #include "file.h"
2517101Sbloom #include "stat.h"
2637741Smckusick #include "vnode.h"
2737741Smckusick #include "mount.h"
2817101Sbloom #include "proc.h"
2917101Sbloom #include "uio.h"
3037741Smckusick #include "malloc.h"
3137Sbill 
3239797Smckusick #undef RETURN
3339797Smckusick #define RETURN(val)	{ scp->u_error = (val); if (scp->u_spare[0] != 0) panic("lock count"); return; }
3439797Smckusick 
3537741Smckusick /*
3637741Smckusick  * Virtual File System System Calls
3737741Smckusick  */
3812756Ssam 
399167Ssam /*
4037741Smckusick  * mount system call
419167Ssam  */
4238408Smckusick mount(scp)
4338408Smckusick 	register struct syscontext *scp;
446254Sroot {
4537741Smckusick 	register struct a {
4637741Smckusick 		int	type;
4737741Smckusick 		char	*dir;
4837741Smckusick 		int	flags;
4937741Smckusick 		caddr_t	data;
5038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
5138408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
5239335Smckusick 	register struct vnode *vp;
5339335Smckusick 	register struct mount *mp;
5440111Smckusick 	int error, flag;
556254Sroot 
5637741Smckusick 	/*
5737741Smckusick 	 * Must be super user
5837741Smckusick 	 */
5938408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
6037741Smckusick 		RETURN (error);
6137741Smckusick 	/*
6237741Smckusick 	 * Get vnode to be covered
6337741Smckusick 	 */
6437741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
6537741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
6637741Smckusick 	ndp->ni_dirp = uap->dir;
6737741Smckusick 	if (error = namei(ndp))
6837741Smckusick 		RETURN (error);
6937741Smckusick 	vp = ndp->ni_vp;
7039335Smckusick 	if (uap->flags & M_UPDATE) {
7139335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
7239335Smckusick 			vput(vp);
7339335Smckusick 			RETURN (EINVAL);
7439335Smckusick 		}
7539335Smckusick 		mp = vp->v_mount;
7639335Smckusick 		/*
7739335Smckusick 		 * We allow going from read-only to read-write,
7839335Smckusick 		 * but not from read-write to read-only.
7939335Smckusick 		 */
8039335Smckusick 		if ((mp->m_flag & M_RDONLY) == 0 &&
8139335Smckusick 		    (uap->flags & M_RDONLY) != 0) {
8239335Smckusick 			vput(vp);
8339335Smckusick 			RETURN (EOPNOTSUPP);	/* Needs translation */
8439335Smckusick 		}
8540111Smckusick 		flag = mp->m_flag;
8639335Smckusick 		mp->m_flag |= M_UPDATE;
8739335Smckusick 		VOP_UNLOCK(vp);
8839335Smckusick 		goto update;
8939335Smckusick 	}
9039665Smckusick 	vinvalbuf(vp, 1);
9139805Smckusick 	if (vp->v_usecount != 1) {
9237741Smckusick 		vput(vp);
9337741Smckusick 		RETURN (EBUSY);
9437741Smckusick 	}
9537741Smckusick 	if (vp->v_type != VDIR) {
9637741Smckusick 		vput(vp);
9737741Smckusick 		RETURN (ENOTDIR);
9837741Smckusick 	}
9939741Smckusick 	if ((unsigned long)uap->type > MOUNT_MAXTYPE ||
10037741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
10137741Smckusick 		vput(vp);
10237741Smckusick 		RETURN (ENODEV);
10337741Smckusick 	}
10437741Smckusick 
10537741Smckusick 	/*
10639335Smckusick 	 * Allocate and initialize the file system.
10737741Smckusick 	 */
10837741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
10937741Smckusick 		M_MOUNT, M_WAITOK);
11037741Smckusick 	mp->m_op = vfssw[uap->type];
11137741Smckusick 	mp->m_flag = 0;
11237741Smckusick 	mp->m_exroot = 0;
11339381Smckusick 	mp->m_mounth = (struct vnode *)0;
11439335Smckusick 	if (error = vfs_lock(mp)) {
11539335Smckusick 		free((caddr_t)mp, M_MOUNT);
11639335Smckusick 		vput(vp);
11739335Smckusick 		RETURN (error);
11839335Smckusick 	}
11939335Smckusick 	if (vp->v_mountedhere != (struct mount *)0) {
12039335Smckusick 		vfs_unlock(mp);
12139335Smckusick 		free((caddr_t)mp, M_MOUNT);
12239335Smckusick 		vput(vp);
12339335Smckusick 		RETURN (EBUSY);
12439335Smckusick 	}
12539335Smckusick 	vp->v_mountedhere = mp;
12639335Smckusick 	mp->m_vnodecovered = vp;
12739335Smckusick update:
12839335Smckusick 	/*
12939335Smckusick 	 * Set the mount level flags.
13039335Smckusick 	 */
13139335Smckusick 	if (uap->flags & M_RDONLY)
13239335Smckusick 		mp->m_flag |= M_RDONLY;
13339335Smckusick 	else
13439335Smckusick 		mp->m_flag &= ~M_RDONLY;
13539335Smckusick 	if (uap->flags & M_NOSUID)
13639335Smckusick 		mp->m_flag |= M_NOSUID;
13739335Smckusick 	else
13839335Smckusick 		mp->m_flag &= ~M_NOSUID;
13939335Smckusick 	if (uap->flags & M_NOEXEC)
14039335Smckusick 		mp->m_flag |= M_NOEXEC;
14139335Smckusick 	else
14239335Smckusick 		mp->m_flag &= ~M_NOEXEC;
14339335Smckusick 	if (uap->flags & M_NODEV)
14439335Smckusick 		mp->m_flag |= M_NODEV;
14539335Smckusick 	else
14639335Smckusick 		mp->m_flag &= ~M_NODEV;
14739335Smckusick 	if (uap->flags & M_SYNCHRONOUS)
14839335Smckusick 		mp->m_flag |= M_SYNCHRONOUS;
14939335Smckusick 	else
15039335Smckusick 		mp->m_flag &= ~M_SYNCHRONOUS;
15139335Smckusick 	/*
15239335Smckusick 	 * Mount the filesystem.
15339335Smckusick 	 */
15439335Smckusick 	error = VFS_MOUNT(mp, uap->dir, uap->data, ndp);
15539335Smckusick 	if (mp->m_flag & M_UPDATE) {
15639335Smckusick 		mp->m_flag &= ~M_UPDATE;
15739335Smckusick 		vrele(vp);
15840111Smckusick 		if (error)
15940111Smckusick 			mp->m_flag = flag;
16039335Smckusick 		RETURN (error);
16139335Smckusick 	}
16240110Smckusick 	/*
16340110Smckusick 	 * Put the new filesystem on the mount list after root.
16440110Smckusick 	 */
16540110Smckusick 	mp->m_next = rootfs->m_next;
16640110Smckusick 	mp->m_prev = rootfs;
16740110Smckusick 	rootfs->m_next = mp;
16840110Smckusick 	mp->m_next->m_prev = mp;
16937741Smckusick 	cache_purge(vp);
17037741Smckusick 	if (!error) {
17139335Smckusick 		VOP_UNLOCK(vp);
17237741Smckusick 		vfs_unlock(mp);
17339044Smckusick 		error = VFS_START(mp, 0);
17437741Smckusick 	} else {
17537741Smckusick 		vfs_remove(mp);
17637741Smckusick 		free((caddr_t)mp, M_MOUNT);
17739335Smckusick 		vput(vp);
17837741Smckusick 	}
17937741Smckusick 	RETURN (error);
1806254Sroot }
1816254Sroot 
1829167Ssam /*
18337741Smckusick  * Unmount system call.
18437741Smckusick  *
18537741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
18637741Smckusick  * not special file (as before).
1879167Ssam  */
18838408Smckusick unmount(scp)
18938408Smckusick 	register struct syscontext *scp;
1906254Sroot {
19137741Smckusick 	struct a {
19237741Smckusick 		char	*pathp;
19337741Smckusick 		int	flags;
19438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
19537741Smckusick 	register struct vnode *vp;
19638408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
19739356Smckusick 	struct mount *mp;
19837741Smckusick 	int error;
1996254Sroot 
20037741Smckusick 	/*
20137741Smckusick 	 * Must be super user
20237741Smckusick 	 */
20338408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
20437741Smckusick 		RETURN (error);
20537741Smckusick 
20637741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
20737741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
20837741Smckusick 	ndp->ni_dirp = uap->pathp;
20937741Smckusick 	if (error = namei(ndp))
21037741Smckusick 		RETURN (error);
21137741Smckusick 	vp = ndp->ni_vp;
21237741Smckusick 	/*
21337741Smckusick 	 * Must be the root of the filesystem
21437741Smckusick 	 */
21537741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
21637741Smckusick 		vput(vp);
21737741Smckusick 		RETURN (EINVAL);
21837741Smckusick 	}
21937741Smckusick 	mp = vp->v_mount;
22037741Smckusick 	vput(vp);
22139356Smckusick 	RETURN (dounmount(mp, uap->flags));
22239356Smckusick }
22339356Smckusick 
22439356Smckusick /*
22539356Smckusick  * Do an unmount.
22639356Smckusick  */
22739356Smckusick dounmount(mp, flags)
22839356Smckusick 	register struct mount *mp;
22939356Smckusick 	int flags;
23039356Smckusick {
23139356Smckusick 	struct vnode *coveredvp;
23239356Smckusick 	int error;
23339356Smckusick 
23437741Smckusick 	coveredvp = mp->m_vnodecovered;
23537741Smckusick 	if (error = vfs_lock(mp))
23639356Smckusick 		return (error);
23737741Smckusick 
23837741Smckusick 	xumount(mp);		/* remove unused sticky files from text table */
23937741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
24037741Smckusick 	VFS_SYNC(mp, MNT_WAIT);
24137741Smckusick 
24239356Smckusick 	error = VFS_UNMOUNT(mp, flags);
24337741Smckusick 	if (error) {
24437741Smckusick 		vfs_unlock(mp);
24537741Smckusick 	} else {
24637741Smckusick 		vrele(coveredvp);
24737741Smckusick 		vfs_remove(mp);
24837741Smckusick 		free((caddr_t)mp, M_MOUNT);
24937741Smckusick 	}
25039356Smckusick 	return (error);
2516254Sroot }
2526254Sroot 
2539167Ssam /*
25437741Smckusick  * Sync system call.
25537741Smckusick  * Sync each mounted filesystem.
2569167Ssam  */
25739491Smckusick /* ARGSUSED */
25838408Smckusick sync(scp)
25939491Smckusick 	struct syscontext *scp;
2606254Sroot {
26137741Smckusick 	register struct mount *mp;
26237741Smckusick 
26337741Smckusick 	mp = rootfs;
26437741Smckusick 	do {
26540343Smckusick 		/*
26640343Smckusick 		 * The lock check below is to avoid races with mount
26740343Smckusick 		 * and unmount.
26840343Smckusick 		 */
26940110Smckusick 		if ((mp->m_flag & (M_MLOCK|M_RDONLY)) == 0)
27037741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
27140343Smckusick 		mp = mp->m_next;
27237741Smckusick 	} while (mp != rootfs);
27337741Smckusick }
27437741Smckusick 
27537741Smckusick /*
27637741Smckusick  * get filesystem statistics
27737741Smckusick  */
27838408Smckusick statfs(scp)
27938408Smckusick 	register struct syscontext *scp;
28037741Smckusick {
2816254Sroot 	struct a {
28237741Smckusick 		char *path;
28337741Smckusick 		struct statfs *buf;
28438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
28539464Smckusick 	register struct mount *mp;
28638408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
28740343Smckusick 	register struct statfs *sp;
28837741Smckusick 	int error;
28937741Smckusick 
29039544Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
29137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
29237741Smckusick 	ndp->ni_dirp = uap->path;
29337741Smckusick 	if (error = namei(ndp))
29437741Smckusick 		RETURN (error);
29539544Smckusick 	mp = ndp->ni_vp->v_mount;
29640343Smckusick 	sp = &mp->m_stat;
29739544Smckusick 	vrele(ndp->ni_vp);
29840343Smckusick 	if (error = VFS_STATFS(mp, sp))
29939544Smckusick 		RETURN (error);
30040343Smckusick 	sp->f_flags = mp->m_flag & M_VISFLAGMASK;
30140343Smckusick 	RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
30237741Smckusick }
30337741Smckusick 
30438408Smckusick fstatfs(scp)
30538408Smckusick 	register struct syscontext *scp;
30637741Smckusick {
30737741Smckusick 	struct a {
30837741Smckusick 		int fd;
30937741Smckusick 		struct statfs *buf;
31038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
31137741Smckusick 	struct file *fp;
31239464Smckusick 	struct mount *mp;
31340343Smckusick 	register struct statfs *sp;
31437741Smckusick 	int error;
31537741Smckusick 
31638408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
31737741Smckusick 		RETURN (error);
31839464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
31940343Smckusick 	sp = &mp->m_stat;
32040343Smckusick 	if (error = VFS_STATFS(mp, sp))
32137741Smckusick 		RETURN (error);
32240343Smckusick 	sp->f_flags = mp->m_flag & M_VISFLAGMASK;
32340343Smckusick 	RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
32437741Smckusick }
32537741Smckusick 
32637741Smckusick /*
32738270Smckusick  * get statistics on all filesystems
32838270Smckusick  */
32938408Smckusick getfsstat(scp)
33038408Smckusick 	register struct syscontext *scp;
33138270Smckusick {
33238270Smckusick 	struct a {
33338270Smckusick 		struct statfs *buf;
33438270Smckusick 		long bufsize;
33540343Smckusick 		int flags;
33638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
33738270Smckusick 	register struct mount *mp;
33840343Smckusick 	register struct statfs *sp;
33939606Smckusick 	caddr_t sfsp;
34038270Smckusick 	long count, maxcount, error;
34138270Smckusick 
34238270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
34339606Smckusick 	sfsp = (caddr_t)uap->buf;
34438270Smckusick 	mp = rootfs;
34538270Smckusick 	count = 0;
34638270Smckusick 	do {
34739606Smckusick 		if (sfsp && count < maxcount && ((mp->m_flag & M_MLOCK) == 0)) {
34840343Smckusick 			sp = &mp->m_stat;
34940343Smckusick 			/*
35040343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
35140343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
35240343Smckusick 			 */
35340343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
35440343Smckusick 			    (uap->flags & MNT_WAIT)) &&
35540343Smckusick 			    (error = VFS_STATFS(mp, sp))) {
35639607Smckusick 				mp = mp->m_prev;
35739607Smckusick 				continue;
35839607Smckusick 			}
35940343Smckusick 			sp->f_flags = mp->m_flag & M_VISFLAGMASK;
36040343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
36139606Smckusick 				RETURN (error);
36240343Smckusick 			sfsp += sizeof(*sp);
36338270Smckusick 		}
36439606Smckusick 		count++;
36538270Smckusick 		mp = mp->m_prev;
36638270Smckusick 	} while (mp != rootfs);
36738270Smckusick 	if (sfsp && count > maxcount)
36838408Smckusick 		scp->sc_retval1 = maxcount;
36938270Smckusick 	else
37038408Smckusick 		scp->sc_retval1 = count;
37138270Smckusick 	RETURN (0);
37238270Smckusick }
37338270Smckusick 
37438270Smckusick /*
37538259Smckusick  * Change current working directory to a given file descriptor.
37638259Smckusick  */
37738408Smckusick fchdir(scp)
37838408Smckusick 	register struct syscontext *scp;
37938259Smckusick {
38038259Smckusick 	struct a {
38138259Smckusick 		int	fd;
38238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
38338259Smckusick 	register struct vnode *vp;
38438259Smckusick 	struct file *fp;
38538259Smckusick 	int error;
38638259Smckusick 
38738408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
38838259Smckusick 		RETURN (error);
38938259Smckusick 	vp = (struct vnode *)fp->f_data;
39038259Smckusick 	VOP_LOCK(vp);
39138259Smckusick 	if (vp->v_type != VDIR)
39238259Smckusick 		error = ENOTDIR;
39338259Smckusick 	else
39438408Smckusick 		error = VOP_ACCESS(vp, VEXEC, scp->sc_cred);
39538259Smckusick 	VOP_UNLOCK(vp);
39639860Smckusick 	if (error)
39739860Smckusick 		RETURN (error);
39839860Smckusick 	VREF(vp);
39938408Smckusick 	vrele(scp->sc_cdir);
40038408Smckusick 	scp->sc_cdir = vp;
40139860Smckusick 	RETURN (0);
40238259Smckusick }
40338259Smckusick 
40438259Smckusick /*
40537741Smckusick  * Change current working directory (``.'').
40637741Smckusick  */
40738408Smckusick chdir(scp)
40838408Smckusick 	register struct syscontext *scp;
40937741Smckusick {
41037741Smckusick 	struct a {
4116254Sroot 		char	*fname;
41238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
41338408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
41437741Smckusick 	int error;
4156254Sroot 
41637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
41716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
41816694Smckusick 	ndp->ni_dirp = uap->fname;
41937741Smckusick 	if (error = chdirec(ndp))
42037741Smckusick 		RETURN (error);
42138408Smckusick 	vrele(scp->sc_cdir);
42238408Smckusick 	scp->sc_cdir = ndp->ni_vp;
42337741Smckusick 	RETURN (0);
42437741Smckusick }
4256254Sroot 
42637741Smckusick /*
42737741Smckusick  * Change notion of root (``/'') directory.
42837741Smckusick  */
42938408Smckusick chroot(scp)
43038408Smckusick 	register struct syscontext *scp;
43137741Smckusick {
43237741Smckusick 	struct a {
43337741Smckusick 		char	*fname;
43438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
43538408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
43637741Smckusick 	int error;
43737741Smckusick 
43838408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
43937741Smckusick 		RETURN (error);
44037741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
44137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
44237741Smckusick 	ndp->ni_dirp = uap->fname;
44337741Smckusick 	if (error = chdirec(ndp))
44437741Smckusick 		RETURN (error);
44539515Smckusick 	if (scp->sc_rdir != NULL)
44639515Smckusick 		vrele(scp->sc_rdir);
44738408Smckusick 	scp->sc_rdir = ndp->ni_vp;
44837741Smckusick 	RETURN (0);
4496254Sroot }
4506254Sroot 
45137Sbill /*
45237741Smckusick  * Common routine for chroot and chdir.
45337741Smckusick  */
45437741Smckusick chdirec(ndp)
45537741Smckusick 	register struct nameidata *ndp;
45637741Smckusick {
45737741Smckusick 	struct vnode *vp;
45837741Smckusick 	int error;
45937741Smckusick 
46037741Smckusick 	if (error = namei(ndp))
46137741Smckusick 		return (error);
46237741Smckusick 	vp = ndp->ni_vp;
46337741Smckusick 	if (vp->v_type != VDIR)
46437741Smckusick 		error = ENOTDIR;
46537741Smckusick 	else
46638399Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
46737741Smckusick 	VOP_UNLOCK(vp);
46837741Smckusick 	if (error)
46937741Smckusick 		vrele(vp);
47037741Smckusick 	return (error);
47137741Smckusick }
47237741Smckusick 
47337741Smckusick /*
4746254Sroot  * Open system call.
4756254Sroot  */
47638408Smckusick open(scp)
47738408Smckusick 	register struct syscontext *scp;
4786254Sroot {
47912756Ssam 	struct a {
4806254Sroot 		char	*fname;
4817701Ssam 		int	mode;
48212756Ssam 		int	crtmode;
48338408Smckusick 	} *uap = (struct a *) scp->sc_ap;
48438408Smckusick 	struct nameidata *ndp = &scp->sc_nd;
4856254Sroot 
48637741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
48737741Smckusick 	ndp->ni_dirp = uap->fname;
48838408Smckusick 	RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp,
48938408Smckusick 		&scp->sc_retval1));
4906254Sroot }
4916254Sroot 
4926254Sroot /*
4936254Sroot  * Creat system call.
4946254Sroot  */
49538408Smckusick creat(scp)
49638408Smckusick 	register struct syscontext *scp;
4976254Sroot {
49812756Ssam 	struct a {
4996254Sroot 		char	*fname;
5006254Sroot 		int	fmode;
50138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
50238408Smckusick 	struct nameidata *ndp = &scp->sc_nd;
5036254Sroot 
50437741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
50537741Smckusick 	ndp->ni_dirp = uap->fname;
50638408Smckusick 	RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask,
50738408Smckusick 		ndp, &scp->sc_retval1));
5086254Sroot }
5096254Sroot 
5106254Sroot /*
5116254Sroot  * Common code for open and creat.
51212756Ssam  * Check permissions, allocate an open file structure,
51312756Ssam  * and call the device open routine if any.
5146254Sroot  */
51538408Smckusick copen(scp, fmode, cmode, ndp, resultfd)
51638408Smckusick 	register struct syscontext *scp;
51737741Smckusick 	int fmode, cmode;
51837741Smckusick 	struct nameidata *ndp;
51937741Smckusick 	int *resultfd;
52012756Ssam {
5216254Sroot 	register struct file *fp;
52237741Smckusick 	struct file *nfp;
52337741Smckusick 	int indx, error;
52437741Smckusick 	extern struct fileops vnops;
5256254Sroot 
52637741Smckusick 	if (error = falloc(&nfp, &indx))
52737741Smckusick 		return (error);
52837741Smckusick 	fp = nfp;
52938408Smckusick 	scp->sc_retval1 = indx;	/* XXX for fdopen() */
53040635Smckusick 	if (error = vn_open(ndp, fmode, (cmode & 07777) &~ S_ISVTX)) {
53137741Smckusick 		crfree(fp->f_cred);
53237741Smckusick 		fp->f_count--;
533*40884Smckusick 		if (error == EJUSTRETURN)	/* XXX from fdopen */
534*40884Smckusick 			return (0);		/* XXX from fdopen */
535*40884Smckusick 		if (error == ERESTART)
536*40884Smckusick 			error = EINTR;
53739499Smckusick 		scp->sc_ofile[indx] = NULL;
53837741Smckusick 		return (error);
53912756Ssam 	}
54037741Smckusick 	fp->f_flag = fmode & FMASK;
54137741Smckusick 	fp->f_type = DTYPE_VNODE;
54237741Smckusick 	fp->f_ops = &vnops;
54337741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
54437741Smckusick 	if (resultfd)
54537741Smckusick 		*resultfd = indx;
54637741Smckusick 	return (0);
5476254Sroot }
5486254Sroot 
5496254Sroot /*
5506254Sroot  * Mknod system call
5516254Sroot  */
55238408Smckusick mknod(scp)
55338408Smckusick 	register struct syscontext *scp;
5546254Sroot {
5556254Sroot 	register struct a {
5566254Sroot 		char	*fname;
5576254Sroot 		int	fmode;
5586254Sroot 		int	dev;
55938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
56038408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
56137741Smckusick 	register struct vnode *vp;
56237741Smckusick 	struct vattr vattr;
56337741Smckusick 	int error;
5646254Sroot 
56538408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
56637741Smckusick 		RETURN (error);
56737741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
56816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
56916694Smckusick 	ndp->ni_dirp = uap->fname;
57037741Smckusick 	if (error = namei(ndp))
57137741Smckusick 		RETURN (error);
57237741Smckusick 	vp = ndp->ni_vp;
57337741Smckusick 	if (vp != NULL) {
57437741Smckusick 		error = EEXIST;
57512756Ssam 		goto out;
5766254Sroot 	}
57737741Smckusick 	vattr_null(&vattr);
57840635Smckusick 	switch (uap->fmode & S_IFMT) {
57912756Ssam 
58040635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
58137741Smckusick 		vattr.va_type = VBAD;
58237741Smckusick 		break;
58340635Smckusick 	case S_IFCHR:
58437741Smckusick 		vattr.va_type = VCHR;
58537741Smckusick 		break;
58640635Smckusick 	case S_IFBLK:
58737741Smckusick 		vattr.va_type = VBLK;
58837741Smckusick 		break;
58937741Smckusick 	default:
59037741Smckusick 		error = EINVAL;
59137741Smckusick 		goto out;
5926254Sroot 	}
59338408Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask;
59437741Smckusick 	vattr.va_rdev = uap->dev;
5956254Sroot out:
59637741Smckusick 	if (error)
59737741Smckusick 		VOP_ABORTOP(ndp);
59837741Smckusick 	else
59937741Smckusick 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
60037741Smckusick 	RETURN (error);
6016254Sroot }
6026254Sroot 
6036254Sroot /*
60440285Smckusick  * Mkfifo system call
60540285Smckusick  */
60640285Smckusick mkfifo(scp)
60740285Smckusick 	register struct syscontext *scp;
60840285Smckusick {
60940285Smckusick 	register struct a {
61040285Smckusick 		char	*fname;
61140285Smckusick 		int	fmode;
61240285Smckusick 	} *uap = (struct a *)scp->sc_ap;
61340285Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
61440285Smckusick 	struct vattr vattr;
61540285Smckusick 	int error;
61640285Smckusick 
61740285Smckusick #ifndef FIFO
61840285Smckusick 	RETURN (EOPNOTSUPP);
61940285Smckusick #else
62040285Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
62140285Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
62240285Smckusick 	ndp->ni_dirp = uap->fname;
62340285Smckusick 	if (error = namei(ndp))
62440285Smckusick 		RETURN (error);
62540285Smckusick 	if (ndp->ni_vp != NULL) {
62640285Smckusick 		VOP_ABORTOP(ndp);
62740285Smckusick 		RETURN (EEXIST);
62840285Smckusick 	} else {
62940285Smckusick 		vattr_null(&vattr);
63040285Smckusick 		vattr.va_type = VFIFO;
63140285Smckusick 		vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask;
63240285Smckusick 	}
63340285Smckusick 	RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred));
63440285Smckusick #endif /* FIFO */
63540285Smckusick }
63640285Smckusick 
63740285Smckusick /*
6386254Sroot  * link system call
6396254Sroot  */
64038408Smckusick link(scp)
64138408Smckusick 	register struct syscontext *scp;
6426254Sroot {
6436254Sroot 	register struct a {
6446254Sroot 		char	*target;
6456254Sroot 		char	*linkname;
64638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
64738408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
64837741Smckusick 	register struct vnode *vp, *xp;
64937741Smckusick 	int error;
6506254Sroot 
65116694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
65216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
65316694Smckusick 	ndp->ni_dirp = uap->target;
65437741Smckusick 	if (error = namei(ndp))
65537741Smckusick 		RETURN (error);
65637741Smckusick 	vp = ndp->ni_vp;
65737741Smckusick 	if (vp->v_type == VDIR &&
65838408Smckusick 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
65937741Smckusick 		goto out1;
66037741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
66116694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
66237741Smckusick 	if (error = namei(ndp))
66337741Smckusick 		goto out1;
66437741Smckusick 	xp = ndp->ni_vp;
6656254Sroot 	if (xp != NULL) {
66637741Smckusick 		error = EEXIST;
6676254Sroot 		goto out;
6686254Sroot 	}
66937741Smckusick 	xp = ndp->ni_dvp;
67037741Smckusick 	if (vp->v_mount != xp->v_mount)
67137741Smckusick 		error = EXDEV;
6726254Sroot out:
67337741Smckusick 	if (error)
67437741Smckusick 		VOP_ABORTOP(ndp);
67537741Smckusick 	else
67637741Smckusick 		error = VOP_LINK(vp, ndp);
67737741Smckusick out1:
67837741Smckusick 	vrele(vp);
67937741Smckusick 	RETURN (error);
6806254Sroot }
6816254Sroot 
6826254Sroot /*
6836254Sroot  * symlink -- make a symbolic link
6846254Sroot  */
68538408Smckusick symlink(scp)
68638408Smckusick 	register struct syscontext *scp;
6876254Sroot {
68837741Smckusick 	struct a {
6896254Sroot 		char	*target;
6906254Sroot 		char	*linkname;
69138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
69238408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
69337741Smckusick 	register struct vnode *vp;
69437741Smckusick 	struct vattr vattr;
69537741Smckusick 	char *target;
69637741Smckusick 	int error;
6976254Sroot 
69816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
69916694Smckusick 	ndp->ni_dirp = uap->linkname;
70037741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
70137741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
70237741Smckusick 		goto out1;
70337741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
70437741Smckusick 	if (error = namei(ndp))
70537741Smckusick 		goto out1;
70637741Smckusick 	vp = ndp->ni_vp;
70737741Smckusick 	if (vp) {
70837741Smckusick 		error = EEXIST;
70937741Smckusick 		goto out;
7106254Sroot 	}
71137741Smckusick 	vp = ndp->ni_dvp;
71237741Smckusick 	vattr_null(&vattr);
71338408Smckusick 	vattr.va_mode = 0777 &~ scp->sc_cmask;
71437741Smckusick out:
71537741Smckusick 	if (error)
71637741Smckusick 		VOP_ABORTOP(ndp);
71737741Smckusick 	else
71837741Smckusick 		error = VOP_SYMLINK(ndp, &vattr, target);
71937741Smckusick out1:
72037741Smckusick 	FREE(target, M_NAMEI);
72137741Smckusick 	RETURN (error);
7226254Sroot }
7236254Sroot 
7246254Sroot /*
7256254Sroot  * Unlink system call.
7266254Sroot  * Hard to avoid races here, especially
7276254Sroot  * in unlinking directories.
7286254Sroot  */
72938408Smckusick unlink(scp)
73038408Smckusick 	register struct syscontext *scp;
7316254Sroot {
7326254Sroot 	struct a {
7336254Sroot 		char	*fname;
73438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
73538408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
73637741Smckusick 	register struct vnode *vp;
73737741Smckusick 	int error;
7386254Sroot 
73937741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
74016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
74116694Smckusick 	ndp->ni_dirp = uap->fname;
74237741Smckusick 	if (error = namei(ndp))
74337741Smckusick 		RETURN (error);
74437741Smckusick 	vp = ndp->ni_vp;
74537741Smckusick 	if (vp->v_type == VDIR &&
74638408Smckusick 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
7476254Sroot 		goto out;
7486254Sroot 	/*
7496254Sroot 	 * Don't unlink a mounted file.
7506254Sroot 	 */
75137741Smckusick 	if (vp->v_flag & VROOT) {
75237741Smckusick 		error = EBUSY;
7536254Sroot 		goto out;
7546254Sroot 	}
75537741Smckusick 	if (vp->v_flag & VTEXT)
75637741Smckusick 		xrele(vp);	/* try once to free text */
7576254Sroot out:
75837741Smckusick 	if (error)
75937741Smckusick 		VOP_ABORTOP(ndp);
7607142Smckusick 	else
76137741Smckusick 		error = VOP_REMOVE(ndp);
76237741Smckusick 	RETURN (error);
7636254Sroot }
7646254Sroot 
7656254Sroot /*
7666254Sroot  * Seek system call
7676254Sroot  */
76838408Smckusick lseek(scp)
76938408Smckusick 	register struct syscontext *scp;
7706254Sroot {
7716254Sroot 	register struct file *fp;
7726254Sroot 	register struct a {
77337741Smckusick 		int	fdes;
7746254Sroot 		off_t	off;
7756254Sroot 		int	sbase;
77638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
77737741Smckusick 	struct vattr vattr;
77837741Smckusick 	int error;
7796254Sroot 
78037741Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
78138408Smckusick 	    (fp = scp->sc_ofile[uap->fdes]) == NULL)
78237741Smckusick 		RETURN (EBADF);
78337741Smckusick 	if (fp->f_type != DTYPE_VNODE)
78437741Smckusick 		RETURN (ESPIPE);
78513878Ssam 	switch (uap->sbase) {
78613878Ssam 
78713878Ssam 	case L_INCR:
78813878Ssam 		fp->f_offset += uap->off;
78913878Ssam 		break;
79013878Ssam 
79113878Ssam 	case L_XTND:
79237741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
79338408Smckusick 		    &vattr, scp->sc_cred))
79437741Smckusick 			RETURN (error);
79537741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
79613878Ssam 		break;
79713878Ssam 
79813878Ssam 	case L_SET:
79913878Ssam 		fp->f_offset = uap->off;
80013878Ssam 		break;
80113878Ssam 
80213878Ssam 	default:
80337741Smckusick 		RETURN (EINVAL);
80413878Ssam 	}
80538408Smckusick 	scp->sc_offset = fp->f_offset;
80637741Smckusick 	RETURN (0);
8076254Sroot }
8086254Sroot 
8096254Sroot /*
8106254Sroot  * Access system call
8116254Sroot  */
81238408Smckusick saccess(scp)
81338408Smckusick 	register struct syscontext *scp;
8146254Sroot {
8156254Sroot 	register struct a {
8166254Sroot 		char	*fname;
8176254Sroot 		int	fmode;
81838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
81938408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
82037741Smckusick 	register struct vnode *vp;
82137741Smckusick 	int error, mode, svuid, svgid;
8226254Sroot 
82338408Smckusick 	svuid = scp->sc_uid;
82438408Smckusick 	svgid = scp->sc_gid;
82538408Smckusick 	scp->sc_uid = scp->sc_ruid;
82638408Smckusick 	scp->sc_gid = scp->sc_rgid;
82737741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
82816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
82916694Smckusick 	ndp->ni_dirp = uap->fname;
83037741Smckusick 	if (error = namei(ndp))
83137741Smckusick 		goto out1;
83237741Smckusick 	vp = ndp->ni_vp;
83337741Smckusick 	/*
83437741Smckusick 	 * fmode == 0 means only check for exist
83537741Smckusick 	 */
83637741Smckusick 	if (uap->fmode) {
83737741Smckusick 		mode = 0;
83837741Smckusick 		if (uap->fmode & R_OK)
83937741Smckusick 			mode |= VREAD;
84037741Smckusick 		if (uap->fmode & W_OK)
84137741Smckusick 			mode |= VWRITE;
84237741Smckusick 		if (uap->fmode & X_OK)
84337741Smckusick 			mode |= VEXEC;
84439543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
84538399Smckusick 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
8466254Sroot 	}
84737741Smckusick 	vput(vp);
84837741Smckusick out1:
84938408Smckusick 	scp->sc_uid = svuid;
85038408Smckusick 	scp->sc_gid = svgid;
85137741Smckusick 	RETURN (error);
8526254Sroot }
8536254Sroot 
8546254Sroot /*
8556574Smckusic  * Stat system call.  This version follows links.
85637Sbill  */
85738408Smckusick stat(scp)
85838408Smckusick 	struct syscontext *scp;
85937Sbill {
86037Sbill 
86138408Smckusick 	stat1(scp, FOLLOW);
86237Sbill }
86337Sbill 
86437Sbill /*
8656574Smckusic  * Lstat system call.  This version does not follow links.
8665992Swnj  */
86738408Smckusick lstat(scp)
86838408Smckusick 	struct syscontext *scp;
8695992Swnj {
87012756Ssam 
87138408Smckusick 	stat1(scp, NOFOLLOW);
87212756Ssam }
87312756Ssam 
87438408Smckusick stat1(scp, follow)
87538408Smckusick 	register struct syscontext *scp;
87612756Ssam 	int follow;
87712756Ssam {
8785992Swnj 	register struct a {
8795992Swnj 		char	*fname;
88012756Ssam 		struct stat *ub;
88138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
88238408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
88312756Ssam 	struct stat sb;
88437741Smckusick 	int error;
8855992Swnj 
88637741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
88716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
88816694Smckusick 	ndp->ni_dirp = uap->fname;
88937741Smckusick 	if (error = namei(ndp))
89037741Smckusick 		RETURN (error);
89137741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
89237741Smckusick 	vput(ndp->ni_vp);
89337741Smckusick 	if (error)
89437741Smckusick 		RETURN (error);
89537741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
89637741Smckusick 	RETURN (error);
8975992Swnj }
8985992Swnj 
8995992Swnj /*
9005992Swnj  * Return target name of a symbolic link
90137Sbill  */
90238408Smckusick readlink(scp)
90338408Smckusick 	register struct syscontext *scp;
9045992Swnj {
9055992Swnj 	register struct a {
9065992Swnj 		char	*name;
9075992Swnj 		char	*buf;
9085992Swnj 		int	count;
90938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
91038408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
91137741Smckusick 	register struct vnode *vp;
91237741Smckusick 	struct iovec aiov;
91337741Smckusick 	struct uio auio;
91437741Smckusick 	int error;
9155992Swnj 
91637741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
91716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
91816694Smckusick 	ndp->ni_dirp = uap->name;
91937741Smckusick 	if (error = namei(ndp))
92037741Smckusick 		RETURN (error);
92137741Smckusick 	vp = ndp->ni_vp;
92237741Smckusick 	if (vp->v_type != VLNK) {
92337741Smckusick 		error = EINVAL;
9245992Swnj 		goto out;
9255992Swnj 	}
92637741Smckusick 	aiov.iov_base = uap->buf;
92737741Smckusick 	aiov.iov_len = uap->count;
92837741Smckusick 	auio.uio_iov = &aiov;
92937741Smckusick 	auio.uio_iovcnt = 1;
93037741Smckusick 	auio.uio_offset = 0;
93137741Smckusick 	auio.uio_rw = UIO_READ;
93237741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
93337741Smckusick 	auio.uio_resid = uap->count;
93437741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
9355992Swnj out:
93637741Smckusick 	vput(vp);
93738408Smckusick 	scp->sc_retval1 = uap->count - auio.uio_resid;
93837741Smckusick 	RETURN (error);
9395992Swnj }
9405992Swnj 
9419167Ssam /*
94238259Smckusick  * Change flags of a file given path name.
94338259Smckusick  */
94438408Smckusick chflags(scp)
94538408Smckusick 	register struct syscontext *scp;
94638259Smckusick {
94738259Smckusick 	struct a {
94838259Smckusick 		char	*fname;
94938259Smckusick 		int	flags;
95038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
95138408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
95238259Smckusick 	register struct vnode *vp;
95338259Smckusick 	struct vattr vattr;
95438259Smckusick 	int error;
95538259Smckusick 
95638259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
95738259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
95838259Smckusick 	ndp->ni_dirp = uap->fname;
95938259Smckusick 	vattr_null(&vattr);
96038259Smckusick 	vattr.va_flags = uap->flags;
96138259Smckusick 	if (error = namei(ndp))
96238259Smckusick 		RETURN (error);
96338259Smckusick 	vp = ndp->ni_vp;
96438259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
96538259Smckusick 		error = EROFS;
96638259Smckusick 		goto out;
96738259Smckusick 	}
96838259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
96938259Smckusick out:
97038259Smckusick 	vput(vp);
97138259Smckusick 	RETURN (error);
97238259Smckusick }
97338259Smckusick 
97438259Smckusick /*
97538259Smckusick  * Change flags of a file given a file descriptor.
97638259Smckusick  */
97738408Smckusick fchflags(scp)
97838408Smckusick 	register struct syscontext *scp;
97938259Smckusick {
98038259Smckusick 	struct a {
98138259Smckusick 		int	fd;
98238259Smckusick 		int	flags;
98338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
98438259Smckusick 	struct vattr vattr;
98538259Smckusick 	struct vnode *vp;
98638259Smckusick 	struct file *fp;
98738259Smckusick 	int error;
98838259Smckusick 
98938408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
99038259Smckusick 		RETURN (error);
99138259Smckusick 	vattr_null(&vattr);
99238259Smckusick 	vattr.va_flags = uap->flags;
99338259Smckusick 	vp = (struct vnode *)fp->f_data;
99438259Smckusick 	VOP_LOCK(vp);
99538259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
99638259Smckusick 		error = EROFS;
99738259Smckusick 		goto out;
99838259Smckusick 	}
99938259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
100038259Smckusick out:
100138259Smckusick 	VOP_UNLOCK(vp);
100238259Smckusick 	RETURN (error);
100338259Smckusick }
100438259Smckusick 
100538259Smckusick /*
10069167Ssam  * Change mode of a file given path name.
10079167Ssam  */
100838408Smckusick chmod(scp)
100938408Smckusick 	register struct syscontext *scp;
10105992Swnj {
10117701Ssam 	struct a {
10126254Sroot 		char	*fname;
10136254Sroot 		int	fmode;
101438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
101538408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
101637741Smckusick 	register struct vnode *vp;
101737741Smckusick 	struct vattr vattr;
101837741Smckusick 	int error;
10195992Swnj 
102037741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
102137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
102237741Smckusick 	ndp->ni_dirp = uap->fname;
102337741Smckusick 	vattr_null(&vattr);
102437741Smckusick 	vattr.va_mode = uap->fmode & 07777;
102537741Smckusick 	if (error = namei(ndp))
102637741Smckusick 		RETURN (error);
102737741Smckusick 	vp = ndp->ni_vp;
102837741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
102937741Smckusick 		error = EROFS;
103037741Smckusick 		goto out;
103137741Smckusick 	}
103237741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
103337741Smckusick out:
103437741Smckusick 	vput(vp);
103537741Smckusick 	RETURN (error);
10367701Ssam }
10377439Sroot 
10389167Ssam /*
10399167Ssam  * Change mode of a file given a file descriptor.
10409167Ssam  */
104138408Smckusick fchmod(scp)
104238408Smckusick 	register struct syscontext *scp;
10437701Ssam {
10447701Ssam 	struct a {
10457701Ssam 		int	fd;
10467701Ssam 		int	fmode;
104738408Smckusick 	} *uap = (struct a *)scp->sc_ap;
104837741Smckusick 	struct vattr vattr;
104937741Smckusick 	struct vnode *vp;
105037741Smckusick 	struct file *fp;
105137741Smckusick 	int error;
10527701Ssam 
105338408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
105437741Smckusick 		RETURN (error);
105537741Smckusick 	vattr_null(&vattr);
105637741Smckusick 	vattr.va_mode = uap->fmode & 07777;
105737741Smckusick 	vp = (struct vnode *)fp->f_data;
105837741Smckusick 	VOP_LOCK(vp);
105937741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
106037741Smckusick 		error = EROFS;
106137741Smckusick 		goto out;
10627439Sroot 	}
106337741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
106437741Smckusick out:
106537741Smckusick 	VOP_UNLOCK(vp);
106637741Smckusick 	RETURN (error);
10675992Swnj }
10685992Swnj 
10699167Ssam /*
10709167Ssam  * Set ownership given a path name.
10719167Ssam  */
107238408Smckusick chown(scp)
107338408Smckusick 	register struct syscontext *scp;
107437Sbill {
10757701Ssam 	struct a {
10766254Sroot 		char	*fname;
10776254Sroot 		int	uid;
10786254Sroot 		int	gid;
107938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
108038408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
108137741Smckusick 	register struct vnode *vp;
108237741Smckusick 	struct vattr vattr;
108337741Smckusick 	int error;
108437Sbill 
108537741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
108636614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
108736614Sbostic 	ndp->ni_dirp = uap->fname;
108837741Smckusick 	vattr_null(&vattr);
108937741Smckusick 	vattr.va_uid = uap->uid;
109037741Smckusick 	vattr.va_gid = uap->gid;
109137741Smckusick 	if (error = namei(ndp))
109237741Smckusick 		RETURN (error);
109337741Smckusick 	vp = ndp->ni_vp;
109437741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
109537741Smckusick 		error = EROFS;
109637741Smckusick 		goto out;
109737741Smckusick 	}
109837741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
109937741Smckusick out:
110037741Smckusick 	vput(vp);
110137741Smckusick 	RETURN (error);
11027701Ssam }
11037439Sroot 
11049167Ssam /*
11059167Ssam  * Set ownership given a file descriptor.
11069167Ssam  */
110738408Smckusick fchown(scp)
110838408Smckusick 	register struct syscontext *scp;
11097701Ssam {
11107701Ssam 	struct a {
11117701Ssam 		int	fd;
11127701Ssam 		int	uid;
11137701Ssam 		int	gid;
111438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
111537741Smckusick 	struct vattr vattr;
111637741Smckusick 	struct vnode *vp;
111737741Smckusick 	struct file *fp;
111837741Smckusick 	int error;
11197701Ssam 
112038408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
112137741Smckusick 		RETURN (error);
112237741Smckusick 	vattr_null(&vattr);
112337741Smckusick 	vattr.va_uid = uap->uid;
112437741Smckusick 	vattr.va_gid = uap->gid;
112537741Smckusick 	vp = (struct vnode *)fp->f_data;
112637741Smckusick 	VOP_LOCK(vp);
112737741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
112837741Smckusick 		error = EROFS;
112937741Smckusick 		goto out;
113037741Smckusick 	}
113137741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
113237741Smckusick out:
113337741Smckusick 	VOP_UNLOCK(vp);
113437741Smckusick 	RETURN (error);
11357701Ssam }
11367701Ssam 
113738408Smckusick utimes(scp)
113838408Smckusick 	register struct syscontext *scp;
113911811Ssam {
114011811Ssam 	register struct a {
114111811Ssam 		char	*fname;
114211811Ssam 		struct	timeval *tptr;
114338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
114438408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
114537741Smckusick 	register struct vnode *vp;
114611811Ssam 	struct timeval tv[2];
114737741Smckusick 	struct vattr vattr;
114837741Smckusick 	int error;
114911811Ssam 
115037741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
115137741Smckusick 		RETURN (error);
115237741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
115337741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
115437741Smckusick 	ndp->ni_dirp = uap->fname;
115537741Smckusick 	vattr_null(&vattr);
115637741Smckusick 	vattr.va_atime = tv[0];
115737741Smckusick 	vattr.va_mtime = tv[1];
115837741Smckusick 	if (error = namei(ndp))
115937741Smckusick 		RETURN (error);
116037741Smckusick 	vp = ndp->ni_vp;
116137741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
116237741Smckusick 		error = EROFS;
116337741Smckusick 		goto out;
116421015Smckusick 	}
116537741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
116637741Smckusick out:
116737741Smckusick 	vput(vp);
116837741Smckusick 	RETURN (error);
116911811Ssam }
117011811Ssam 
11719167Ssam /*
11729167Ssam  * Truncate a file given its path name.
11739167Ssam  */
117438408Smckusick truncate(scp)
117538408Smckusick 	register struct syscontext *scp;
11767701Ssam {
11777701Ssam 	struct a {
11787701Ssam 		char	*fname;
117926473Skarels 		off_t	length;
118038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
118138408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
118237741Smckusick 	register struct vnode *vp;
118337741Smckusick 	struct vattr vattr;
118437741Smckusick 	int error;
11857701Ssam 
118637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
118716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
118816694Smckusick 	ndp->ni_dirp = uap->fname;
118937741Smckusick 	vattr_null(&vattr);
119037741Smckusick 	vattr.va_size = uap->length;
119137741Smckusick 	if (error = namei(ndp))
119237741Smckusick 		RETURN (error);
119337741Smckusick 	vp = ndp->ni_vp;
119437741Smckusick 	if (vp->v_type == VDIR) {
119537741Smckusick 		error = EISDIR;
119637741Smckusick 		goto out;
11977701Ssam 	}
119838399Smckusick 	if ((error = vn_writechk(vp)) ||
119938399Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
120037741Smckusick 		goto out;
120137741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
120237741Smckusick out:
120337741Smckusick 	vput(vp);
120437741Smckusick 	RETURN (error);
12057701Ssam }
12067701Ssam 
12079167Ssam /*
12089167Ssam  * Truncate a file given a file descriptor.
12099167Ssam  */
121038408Smckusick ftruncate(scp)
121138408Smckusick 	register struct syscontext *scp;
12127701Ssam {
12137701Ssam 	struct a {
12147701Ssam 		int	fd;
121526473Skarels 		off_t	length;
121638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
121737741Smckusick 	struct vattr vattr;
121837741Smckusick 	struct vnode *vp;
12197701Ssam 	struct file *fp;
122037741Smckusick 	int error;
12217701Ssam 
122238408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
122337741Smckusick 		RETURN (error);
122437741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
122537741Smckusick 		RETURN (EINVAL);
122637741Smckusick 	vattr_null(&vattr);
122737741Smckusick 	vattr.va_size = uap->length;
122837741Smckusick 	vp = (struct vnode *)fp->f_data;
122937741Smckusick 	VOP_LOCK(vp);
123037741Smckusick 	if (vp->v_type == VDIR) {
123137741Smckusick 		error = EISDIR;
123237741Smckusick 		goto out;
12337701Ssam 	}
123438399Smckusick 	if (error = vn_writechk(vp))
123537741Smckusick 		goto out;
123637741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
123737741Smckusick out:
123837741Smckusick 	VOP_UNLOCK(vp);
123937741Smckusick 	RETURN (error);
12407701Ssam }
12417701Ssam 
12429167Ssam /*
12439167Ssam  * Synch an open file.
12449167Ssam  */
124538408Smckusick fsync(scp)
124638408Smckusick 	register struct syscontext *scp;
12479167Ssam {
12489167Ssam 	struct a {
12499167Ssam 		int	fd;
125038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
125139592Smckusick 	register struct vnode *vp;
12529167Ssam 	struct file *fp;
125337741Smckusick 	int error;
12549167Ssam 
125538408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
125637741Smckusick 		RETURN (error);
125739592Smckusick 	vp = (struct vnode *)fp->f_data;
125839592Smckusick 	VOP_LOCK(vp);
125939592Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT);
126039592Smckusick 	VOP_UNLOCK(vp);
126137741Smckusick 	RETURN (error);
12629167Ssam }
12639167Ssam 
12649167Ssam /*
12659167Ssam  * Rename system call.
12669167Ssam  *
12679167Ssam  * Source and destination must either both be directories, or both
12689167Ssam  * not be directories.  If target is a directory, it must be empty.
12699167Ssam  */
127038408Smckusick rename(scp)
127138408Smckusick 	register struct syscontext *scp;
12727701Ssam {
12737701Ssam 	struct a {
12747701Ssam 		char	*from;
12757701Ssam 		char	*to;
127638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
127737741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
127838408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
127937741Smckusick 	struct nameidata tond;
128037741Smckusick 	int error;
12817701Ssam 
128237741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
128316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
128416694Smckusick 	ndp->ni_dirp = uap->from;
128537741Smckusick 	if (error = namei(ndp))
128637741Smckusick 		RETURN (error);
128737741Smckusick 	fvp = ndp->ni_vp;
128838266Smckusick 	nddup(ndp, &tond);
128937741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
129037741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
129137741Smckusick 	tond.ni_dirp = uap->to;
129237741Smckusick 	error = namei(&tond);
129337741Smckusick 	tdvp = tond.ni_dvp;
129437741Smckusick 	tvp = tond.ni_vp;
129537741Smckusick 	if (tvp != NULL) {
129637741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
129739242Sbostic 			error = ENOTDIR;
129837741Smckusick 			goto out;
129937741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
130039242Sbostic 			error = EISDIR;
130137741Smckusick 			goto out;
13029167Ssam 		}
13039167Ssam 	}
130437741Smckusick 	if (error) {
130537741Smckusick 		VOP_ABORTOP(ndp);
130637741Smckusick 		goto out1;
130737741Smckusick 	}
130837741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
130937741Smckusick 		error = EXDEV;
13109167Ssam 		goto out;
131110051Ssam 	}
131239286Smckusick 	if (fvp == tdvp)
131337741Smckusick 		error = EINVAL;
131439286Smckusick 	/*
131539286Smckusick 	 * If source is the same as the destination,
131639286Smckusick 	 * then there is nothing to do.
131739286Smckusick 	 */
131839286Smckusick 	if (fvp == tvp)
131939286Smckusick 		error = -1;
132037741Smckusick out:
132137741Smckusick 	if (error) {
132237741Smckusick 		VOP_ABORTOP(&tond);
132337741Smckusick 		VOP_ABORTOP(ndp);
13249167Ssam 	} else {
132537741Smckusick 		error = VOP_RENAME(ndp, &tond);
13269167Ssam 	}
132737741Smckusick out1:
132838266Smckusick 	ndrele(&tond);
132939286Smckusick 	if (error == -1)
133039286Smckusick 		RETURN (0);
133137741Smckusick 	RETURN (error);
13327701Ssam }
13337701Ssam 
13347535Sroot /*
133512756Ssam  * Mkdir system call
133612756Ssam  */
133738408Smckusick mkdir(scp)
133838408Smckusick 	register struct syscontext *scp;
133912756Ssam {
134012756Ssam 	struct a {
134112756Ssam 		char	*name;
134212756Ssam 		int	dmode;
134338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
134438408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
134537741Smckusick 	register struct vnode *vp;
134637741Smckusick 	struct vattr vattr;
134737741Smckusick 	int error;
134812756Ssam 
134937741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
135016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
135116694Smckusick 	ndp->ni_dirp = uap->name;
135237741Smckusick 	if (error = namei(ndp))
135337741Smckusick 		RETURN (error);
135437741Smckusick 	vp = ndp->ni_vp;
135537741Smckusick 	if (vp != NULL) {
135637741Smckusick 		VOP_ABORTOP(ndp);
135737741Smckusick 		RETURN (EEXIST);
135812756Ssam 	}
135937741Smckusick 	vattr_null(&vattr);
136037741Smckusick 	vattr.va_type = VDIR;
136138408Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask;
136237741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
136338145Smckusick 	if (!error)
136438145Smckusick 		vput(ndp->ni_vp);
136537741Smckusick 	RETURN (error);
136612756Ssam }
136712756Ssam 
136812756Ssam /*
136912756Ssam  * Rmdir system call.
137012756Ssam  */
137138408Smckusick rmdir(scp)
137238408Smckusick 	register struct syscontext *scp;
137312756Ssam {
137412756Ssam 	struct a {
137512756Ssam 		char	*name;
137638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
137738408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
137837741Smckusick 	register struct vnode *vp;
137937741Smckusick 	int error;
138012756Ssam 
138137741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
138216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
138316694Smckusick 	ndp->ni_dirp = uap->name;
138437741Smckusick 	if (error = namei(ndp))
138537741Smckusick 		RETURN (error);
138637741Smckusick 	vp = ndp->ni_vp;
138737741Smckusick 	if (vp->v_type != VDIR) {
138837741Smckusick 		error = ENOTDIR;
138912756Ssam 		goto out;
139012756Ssam 	}
139112756Ssam 	/*
139237741Smckusick 	 * No rmdir "." please.
139312756Ssam 	 */
139437741Smckusick 	if (ndp->ni_dvp == vp) {
139537741Smckusick 		error = EINVAL;
139612756Ssam 		goto out;
139712756Ssam 	}
139812756Ssam 	/*
139937741Smckusick 	 * Don't unlink a mounted file.
140012756Ssam 	 */
140137741Smckusick 	if (vp->v_flag & VROOT)
140237741Smckusick 		error = EBUSY;
140312756Ssam out:
140437741Smckusick 	if (error)
140537741Smckusick 		VOP_ABORTOP(ndp);
140637741Smckusick 	else
140737741Smckusick 		error = VOP_RMDIR(ndp);
140837741Smckusick 	RETURN (error);
140912756Ssam }
141012756Ssam 
141137741Smckusick /*
141237741Smckusick  * Read a block of directory entries in a file system independent format
141337741Smckusick  */
141438408Smckusick getdirentries(scp)
141538408Smckusick 	register struct syscontext *scp;
141612756Ssam {
141737741Smckusick 	register struct a {
141837741Smckusick 		int	fd;
141937741Smckusick 		char	*buf;
142037741Smckusick 		unsigned count;
142137741Smckusick 		long	*basep;
142238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
142339592Smckusick 	register struct vnode *vp;
142416540Ssam 	struct file *fp;
142537741Smckusick 	struct uio auio;
142637741Smckusick 	struct iovec aiov;
142738129Smckusick 	off_t off;
142840321Smckusick 	int error, eofflag;
142912756Ssam 
143038408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
143137741Smckusick 		RETURN (error);
143237741Smckusick 	if ((fp->f_flag & FREAD) == 0)
143337741Smckusick 		RETURN (EBADF);
143439592Smckusick 	vp = (struct vnode *)fp->f_data;
143539592Smckusick 	if (vp->v_type != VDIR)
143639592Smckusick 		RETURN (EINVAL);
143737741Smckusick 	aiov.iov_base = uap->buf;
143837741Smckusick 	aiov.iov_len = uap->count;
143937741Smckusick 	auio.uio_iov = &aiov;
144037741Smckusick 	auio.uio_iovcnt = 1;
144137741Smckusick 	auio.uio_rw = UIO_READ;
144237741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
144337741Smckusick 	auio.uio_resid = uap->count;
144439592Smckusick 	VOP_LOCK(vp);
144539592Smckusick 	auio.uio_offset = off = fp->f_offset;
144640321Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
144739592Smckusick 	fp->f_offset = auio.uio_offset;
144839592Smckusick 	VOP_UNLOCK(vp);
144939592Smckusick 	if (error)
145037741Smckusick 		RETURN (error);
145139592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
145238408Smckusick 	scp->sc_retval1 = uap->count - auio.uio_resid;
145337741Smckusick 	RETURN (error);
145412756Ssam }
145512756Ssam 
145612756Ssam /*
145712756Ssam  * mode mask for creation of files
145812756Ssam  */
145938408Smckusick umask(scp)
146038408Smckusick 	register struct syscontext *scp;
146112756Ssam {
146212756Ssam 	register struct a {
146312756Ssam 		int	mask;
146438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
146512756Ssam 
146638408Smckusick 	scp->sc_retval1 = scp->sc_cmask;
146738408Smckusick 	scp->sc_cmask = uap->mask & 07777;
146837741Smckusick 	RETURN (0);
146912756Ssam }
147037741Smckusick 
147139566Smarc /*
147239566Smarc  * Void all references to file by ripping underlying filesystem
147339566Smarc  * away from vnode.
147439566Smarc  */
147539566Smarc revoke(scp)
147639566Smarc 	register struct syscontext *scp;
147739566Smarc {
147839566Smarc 	struct a {
147939566Smarc 		char	*fname;
148039566Smarc 	} *uap = (struct a *)scp->sc_ap;
148139566Smarc 	register struct nameidata *ndp = &scp->sc_nd;
148239566Smarc 	register struct vnode *vp;
148339566Smarc 	struct vattr vattr;
148439566Smarc 	int error;
148539566Smarc 
148639566Smarc 	ndp->ni_nameiop = LOOKUP | FOLLOW;
148739566Smarc 	ndp->ni_segflg = UIO_USERSPACE;
148839566Smarc 	ndp->ni_dirp = uap->fname;
148939566Smarc 	if (error = namei(ndp))
149039566Smarc 		RETURN (error);
149139566Smarc 	vp = ndp->ni_vp;
149239566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
149339566Smarc 		error = EINVAL;
149439566Smarc 		goto out;
149539566Smarc 	}
149639566Smarc 	if (error = VOP_GETATTR(vp, &vattr, scp->sc_cred))
149739566Smarc 		goto out;
149839566Smarc 	if (scp->sc_uid != vattr.va_uid ||
149939566Smarc 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
150039566Smarc 		goto out;
150139805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
150239632Smckusick 		vgoneall(vp);
150339566Smarc out:
150439566Smarc 	vrele(vp);
150539566Smarc 	RETURN (error);
150639566Smarc }
150739566Smarc 
150838408Smckusick getvnode(ofile, fdes, fpp)
150938408Smckusick 	struct file *ofile[];
151037741Smckusick 	struct file **fpp;
151137741Smckusick 	int fdes;
151237741Smckusick {
151337741Smckusick 	struct file *fp;
151437741Smckusick 
151538408Smckusick 	if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
151637741Smckusick 		return (EBADF);
151737741Smckusick 	if (fp->f_type != DTYPE_VNODE)
151837741Smckusick 		return (EINVAL);
151937741Smckusick 	*fpp = fp;
152037741Smckusick 	return (0);
152137741Smckusick }
1522