xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 39356)
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*39356Smckusick  *	@(#)vfs_syscalls.c	7.19 (Berkeley) 10/20/89
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 "../ufs/inode.h"
2837741Smckusick #include "mount.h"
2917101Sbloom #include "proc.h"
3017101Sbloom #include "uio.h"
3137741Smckusick #include "malloc.h"
3237Sbill 
3337741Smckusick /*
3437741Smckusick  * Virtual File System System Calls
3537741Smckusick  */
3612756Ssam 
379167Ssam /*
3837741Smckusick  * mount system call
399167Ssam  */
4038408Smckusick mount(scp)
4138408Smckusick 	register struct syscontext *scp;
426254Sroot {
4337741Smckusick 	register struct a {
4437741Smckusick 		int	type;
4537741Smckusick 		char	*dir;
4637741Smckusick 		int	flags;
4737741Smckusick 		caddr_t	data;
4838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
4938408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
5039335Smckusick 	register struct vnode *vp;
5139335Smckusick 	register struct mount *mp;
5237741Smckusick 	int error;
536254Sroot 
5437741Smckusick 	/*
5537741Smckusick 	 * Must be super user
5637741Smckusick 	 */
5738408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
5837741Smckusick 		RETURN (error);
5937741Smckusick 	/*
6037741Smckusick 	 * Get vnode to be covered
6137741Smckusick 	 */
6237741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
6337741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
6437741Smckusick 	ndp->ni_dirp = uap->dir;
6537741Smckusick 	if (error = namei(ndp))
6637741Smckusick 		RETURN (error);
6737741Smckusick 	vp = ndp->ni_vp;
6839335Smckusick 	if (uap->flags & M_UPDATE) {
6939335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
7039335Smckusick 			vput(vp);
7139335Smckusick 			RETURN (EINVAL);
7239335Smckusick 		}
7339335Smckusick 		mp = vp->v_mount;
7439335Smckusick 		/*
7539335Smckusick 		 * We allow going from read-only to read-write,
7639335Smckusick 		 * but not from read-write to read-only.
7739335Smckusick 		 */
7839335Smckusick 		if ((mp->m_flag & M_RDONLY) == 0 &&
7939335Smckusick 		    (uap->flags & M_RDONLY) != 0) {
8039335Smckusick 			vput(vp);
8139335Smckusick 			RETURN (EOPNOTSUPP);	/* Needs translation */
8239335Smckusick 		}
8339335Smckusick 		mp->m_flag |= M_UPDATE;
8439335Smckusick 		VOP_UNLOCK(vp);
8539335Smckusick 		goto update;
8639335Smckusick 	}
8737741Smckusick 	if (vp->v_count != 1) {
8837741Smckusick 		vput(vp);
8937741Smckusick 		RETURN (EBUSY);
9037741Smckusick 	}
9137741Smckusick 	if (vp->v_type != VDIR) {
9237741Smckusick 		vput(vp);
9337741Smckusick 		RETURN (ENOTDIR);
9437741Smckusick 	}
9537741Smckusick 	if (uap->type > MOUNT_MAXTYPE ||
9637741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
9737741Smckusick 		vput(vp);
9837741Smckusick 		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);
10637741Smckusick 	mp->m_op = vfssw[uap->type];
10737741Smckusick 	mp->m_flag = 0;
10837741Smckusick 	mp->m_exroot = 0;
10939335Smckusick 	if (error = vfs_lock(mp)) {
11039335Smckusick 		free((caddr_t)mp, M_MOUNT);
11139335Smckusick 		vput(vp);
11239335Smckusick 		RETURN (error);
11339335Smckusick 	}
11439335Smckusick 	if (vp->v_mountedhere != (struct mount *)0) {
11539335Smckusick 		vfs_unlock(mp);
11639335Smckusick 		free((caddr_t)mp, M_MOUNT);
11739335Smckusick 		vput(vp);
11839335Smckusick 		RETURN (EBUSY);
11939335Smckusick 	}
12039335Smckusick 	/*
12139335Smckusick 	 * Put the new filesystem on the mount list after root.
12239335Smckusick 	 */
12339335Smckusick 	mp->m_next = rootfs->m_next;
12439335Smckusick 	mp->m_prev = rootfs;
12539335Smckusick 	rootfs->m_next = mp;
12639335Smckusick 	mp->m_next->m_prev = mp;
12739335Smckusick 	vp->v_mountedhere = mp;
12839335Smckusick 	mp->m_vnodecovered = vp;
12939335Smckusick update:
13039335Smckusick 	/*
13139335Smckusick 	 * Set the mount level flags.
13239335Smckusick 	 */
13339335Smckusick 	if (uap->flags & M_RDONLY)
13439335Smckusick 		mp->m_flag |= M_RDONLY;
13539335Smckusick 	else
13639335Smckusick 		mp->m_flag &= ~M_RDONLY;
13739335Smckusick 	if (uap->flags & M_NOSUID)
13839335Smckusick 		mp->m_flag |= M_NOSUID;
13939335Smckusick 	else
14039335Smckusick 		mp->m_flag &= ~M_NOSUID;
14139335Smckusick 	if (uap->flags & M_NOEXEC)
14239335Smckusick 		mp->m_flag |= M_NOEXEC;
14339335Smckusick 	else
14439335Smckusick 		mp->m_flag &= ~M_NOEXEC;
14539335Smckusick 	if (uap->flags & M_NODEV)
14639335Smckusick 		mp->m_flag |= M_NODEV;
14739335Smckusick 	else
14839335Smckusick 		mp->m_flag &= ~M_NODEV;
14939335Smckusick 	if (uap->flags & M_SYNCHRONOUS)
15039335Smckusick 		mp->m_flag |= M_SYNCHRONOUS;
15139335Smckusick 	else
15239335Smckusick 		mp->m_flag &= ~M_SYNCHRONOUS;
15339335Smckusick 	/*
15439335Smckusick 	 * Mount the filesystem.
15539335Smckusick 	 */
15639335Smckusick 	error = VFS_MOUNT(mp, uap->dir, uap->data, ndp);
15739335Smckusick 	if (mp->m_flag & M_UPDATE) {
15839335Smckusick 		mp->m_flag &= ~M_UPDATE;
15939335Smckusick 		vrele(vp);
16039335Smckusick 		RETURN (error);
16139335Smckusick 	}
16237741Smckusick 	cache_purge(vp);
16337741Smckusick 	if (!error) {
16439335Smckusick 		VOP_UNLOCK(vp);
16537741Smckusick 		vfs_unlock(mp);
16639044Smckusick 		error = VFS_START(mp, 0);
16737741Smckusick 	} else {
16837741Smckusick 		vfs_remove(mp);
16937741Smckusick 		free((caddr_t)mp, M_MOUNT);
17039335Smckusick 		vput(vp);
17137741Smckusick 	}
17237741Smckusick 	RETURN (error);
1736254Sroot }
1746254Sroot 
1759167Ssam /*
17637741Smckusick  * Unmount system call.
17737741Smckusick  *
17837741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
17937741Smckusick  * not special file (as before).
1809167Ssam  */
18138408Smckusick unmount(scp)
18238408Smckusick 	register struct syscontext *scp;
1836254Sroot {
18437741Smckusick 	struct a {
18537741Smckusick 		char	*pathp;
18637741Smckusick 		int	flags;
18738408Smckusick 	} *uap = (struct a *)scp->sc_ap;
18837741Smckusick 	register struct vnode *vp;
18938408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
190*39356Smckusick 	struct mount *mp;
19137741Smckusick 	int error;
1926254Sroot 
19337741Smckusick 	/*
19437741Smckusick 	 * Must be super user
19537741Smckusick 	 */
19638408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
19737741Smckusick 		RETURN (error);
19837741Smckusick 
19937741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
20037741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
20137741Smckusick 	ndp->ni_dirp = uap->pathp;
20237741Smckusick 	if (error = namei(ndp))
20337741Smckusick 		RETURN (error);
20437741Smckusick 	vp = ndp->ni_vp;
20537741Smckusick 	/*
20637741Smckusick 	 * Must be the root of the filesystem
20737741Smckusick 	 */
20837741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
20937741Smckusick 		vput(vp);
21037741Smckusick 		RETURN (EINVAL);
21137741Smckusick 	}
21237741Smckusick 	mp = vp->v_mount;
21337741Smckusick 	vput(vp);
214*39356Smckusick 	RETURN (dounmount(mp, uap->flags));
215*39356Smckusick }
216*39356Smckusick 
217*39356Smckusick /*
218*39356Smckusick  * Do an unmount.
219*39356Smckusick  */
220*39356Smckusick dounmount(mp, flags)
221*39356Smckusick 	register struct mount *mp;
222*39356Smckusick 	int flags;
223*39356Smckusick {
224*39356Smckusick 	struct vnode *coveredvp;
225*39356Smckusick 	int error;
226*39356Smckusick 
22737741Smckusick 	coveredvp = mp->m_vnodecovered;
22837741Smckusick 	if (error = vfs_lock(mp))
229*39356Smckusick 		return (error);
23037741Smckusick 
23137741Smckusick 	xumount(mp);		/* remove unused sticky files from text table */
23237741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
23337741Smckusick 	VFS_SYNC(mp, MNT_WAIT);
23437741Smckusick 
235*39356Smckusick 	error = VFS_UNMOUNT(mp, flags);
23637741Smckusick 	if (error) {
23737741Smckusick 		vfs_unlock(mp);
23837741Smckusick 	} else {
23937741Smckusick 		vrele(coveredvp);
24037741Smckusick 		vfs_remove(mp);
24137741Smckusick 		free((caddr_t)mp, M_MOUNT);
24237741Smckusick 	}
243*39356Smckusick 	return (error);
2446254Sroot }
2456254Sroot 
2469167Ssam /*
24737741Smckusick  * Sync system call.
24837741Smckusick  * Sync each mounted filesystem.
2499167Ssam  */
25038408Smckusick sync(scp)
25138408Smckusick 	register struct syscontext *scp;
2526254Sroot {
25337741Smckusick 	register struct mount *mp;
25437741Smckusick 
25537741Smckusick 	mp = rootfs;
25637741Smckusick 	do {
25737741Smckusick 		if ((mp->m_flag & M_RDONLY) == 0)
25837741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
25937741Smckusick 		mp = mp->m_next;
26037741Smckusick 	} while (mp != rootfs);
26137741Smckusick }
26237741Smckusick 
26337741Smckusick /*
26437741Smckusick  * get filesystem statistics
26537741Smckusick  */
26638408Smckusick statfs(scp)
26738408Smckusick 	register struct syscontext *scp;
26837741Smckusick {
2696254Sroot 	struct a {
27037741Smckusick 		char *path;
27137741Smckusick 		struct statfs *buf;
27238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
27337741Smckusick 	register struct vnode *vp;
27438408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
27537741Smckusick 	struct statfs sb;
27637741Smckusick 	int error;
27737741Smckusick 
27837741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
27937741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
28037741Smckusick 	ndp->ni_dirp = uap->path;
28137741Smckusick 	if (error = namei(ndp))
28237741Smckusick 		RETURN (error);
28337741Smckusick 	vp = ndp->ni_vp;
28437741Smckusick 	if (error = VFS_STATFS(vp->v_mount, &sb))
28537741Smckusick 		goto out;
28637741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb));
28737741Smckusick out:
28837741Smckusick 	vput(vp);
28937741Smckusick 	RETURN (error);
29037741Smckusick }
29137741Smckusick 
29238408Smckusick fstatfs(scp)
29338408Smckusick 	register struct syscontext *scp;
29437741Smckusick {
29537741Smckusick 	struct a {
29637741Smckusick 		int fd;
29737741Smckusick 		struct statfs *buf;
29838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
29937741Smckusick 	struct file *fp;
30037741Smckusick 	struct statfs sb;
30137741Smckusick 	int error;
30237741Smckusick 
30338408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
30437741Smckusick 		RETURN (error);
30537741Smckusick 	if (error = VFS_STATFS(((struct vnode *)fp->f_data)->v_mount, &sb))
30637741Smckusick 		RETURN (error);
30737741Smckusick 	RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)));
30837741Smckusick }
30937741Smckusick 
31037741Smckusick /*
31138270Smckusick  * get statistics on all filesystems
31238270Smckusick  */
31338408Smckusick getfsstat(scp)
31438408Smckusick 	register struct syscontext *scp;
31538270Smckusick {
31638270Smckusick 	struct a {
31738270Smckusick 		struct statfs *buf;
31838270Smckusick 		long bufsize;
31938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
32038270Smckusick 	register struct mount *mp;
32138270Smckusick 	register struct statfs *sfsp;
32238270Smckusick 	long count, maxcount, error;
32338270Smckusick 
32438270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
32538270Smckusick 	sfsp = uap->buf;
32638270Smckusick 	mp = rootfs;
32738270Smckusick 	count = 0;
32838270Smckusick 	do {
32938270Smckusick 		count++;
33039044Smckusick 		if (sfsp && count <= maxcount &&
33139044Smckusick 		    ((mp->m_flag & M_MLOCK) == 0)) {
33238270Smckusick 			if (error = VFS_STATFS(mp, sfsp))
33338270Smckusick 				RETURN (error);
33438270Smckusick 			sfsp++;
33538270Smckusick 		}
33638270Smckusick 		mp = mp->m_prev;
33738270Smckusick 	} while (mp != rootfs);
33838270Smckusick 	if (sfsp && count > maxcount)
33938408Smckusick 		scp->sc_retval1 = maxcount;
34038270Smckusick 	else
34138408Smckusick 		scp->sc_retval1 = count;
34238270Smckusick 	RETURN (0);
34338270Smckusick }
34438270Smckusick 
34538270Smckusick /*
34638259Smckusick  * Change current working directory to a given file descriptor.
34738259Smckusick  */
34838408Smckusick fchdir(scp)
34938408Smckusick 	register struct syscontext *scp;
35038259Smckusick {
35138259Smckusick 	struct a {
35238259Smckusick 		int	fd;
35338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
35438259Smckusick 	register struct vnode *vp;
35538259Smckusick 	struct file *fp;
35638259Smckusick 	int error;
35738259Smckusick 
35838408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
35938259Smckusick 		RETURN (error);
36038259Smckusick 	vp = (struct vnode *)fp->f_data;
36138259Smckusick 	VOP_LOCK(vp);
36238259Smckusick 	if (vp->v_type != VDIR)
36338259Smckusick 		error = ENOTDIR;
36438259Smckusick 	else
36538408Smckusick 		error = VOP_ACCESS(vp, VEXEC, scp->sc_cred);
36638259Smckusick 	VOP_UNLOCK(vp);
36738408Smckusick 	vrele(scp->sc_cdir);
36838408Smckusick 	scp->sc_cdir = vp;
36938259Smckusick 	RETURN (error);
37038259Smckusick }
37138259Smckusick 
37238259Smckusick /*
37337741Smckusick  * Change current working directory (``.'').
37437741Smckusick  */
37538408Smckusick chdir(scp)
37638408Smckusick 	register struct syscontext *scp;
37737741Smckusick {
37837741Smckusick 	struct a {
3796254Sroot 		char	*fname;
38038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
38138408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
38237741Smckusick 	int error;
3836254Sroot 
38437741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
38516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
38616694Smckusick 	ndp->ni_dirp = uap->fname;
38737741Smckusick 	if (error = chdirec(ndp))
38837741Smckusick 		RETURN (error);
38938408Smckusick 	vrele(scp->sc_cdir);
39038408Smckusick 	scp->sc_cdir = ndp->ni_vp;
39137741Smckusick 	RETURN (0);
39237741Smckusick }
3936254Sroot 
39437741Smckusick /*
39537741Smckusick  * Change notion of root (``/'') directory.
39637741Smckusick  */
39738408Smckusick chroot(scp)
39838408Smckusick 	register struct syscontext *scp;
39937741Smckusick {
40037741Smckusick 	struct a {
40137741Smckusick 		char	*fname;
40238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
40338408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
40437741Smckusick 	int error;
40537741Smckusick 
40638408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
40737741Smckusick 		RETURN (error);
40837741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
40937741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
41037741Smckusick 	ndp->ni_dirp = uap->fname;
41137741Smckusick 	if (error = chdirec(ndp))
41237741Smckusick 		RETURN (error);
41338408Smckusick 	vrele(scp->sc_rdir);
41438408Smckusick 	scp->sc_rdir = ndp->ni_vp;
41537741Smckusick 	RETURN (0);
4166254Sroot }
4176254Sroot 
41837Sbill /*
41937741Smckusick  * Common routine for chroot and chdir.
42037741Smckusick  */
42137741Smckusick chdirec(ndp)
42237741Smckusick 	register struct nameidata *ndp;
42337741Smckusick {
42437741Smckusick 	struct vnode *vp;
42537741Smckusick 	int error;
42637741Smckusick 
42737741Smckusick 	if (error = namei(ndp))
42837741Smckusick 		return (error);
42937741Smckusick 	vp = ndp->ni_vp;
43037741Smckusick 	if (vp->v_type != VDIR)
43137741Smckusick 		error = ENOTDIR;
43237741Smckusick 	else
43338399Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
43437741Smckusick 	VOP_UNLOCK(vp);
43537741Smckusick 	if (error)
43637741Smckusick 		vrele(vp);
43737741Smckusick 	return (error);
43837741Smckusick }
43937741Smckusick 
44037741Smckusick /*
4416254Sroot  * Open system call.
4426254Sroot  */
44338408Smckusick open(scp)
44438408Smckusick 	register struct syscontext *scp;
4456254Sroot {
44612756Ssam 	struct a {
4476254Sroot 		char	*fname;
4487701Ssam 		int	mode;
44912756Ssam 		int	crtmode;
45038408Smckusick 	} *uap = (struct a *) scp->sc_ap;
45138408Smckusick 	struct nameidata *ndp = &scp->sc_nd;
4526254Sroot 
45337741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
45437741Smckusick 	ndp->ni_dirp = uap->fname;
45538408Smckusick 	RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp,
45638408Smckusick 		&scp->sc_retval1));
4576254Sroot }
4586254Sroot 
4596254Sroot /*
4606254Sroot  * Creat system call.
4616254Sroot  */
46238408Smckusick creat(scp)
46338408Smckusick 	register struct syscontext *scp;
4646254Sroot {
46512756Ssam 	struct a {
4666254Sroot 		char	*fname;
4676254Sroot 		int	fmode;
46838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
46938408Smckusick 	struct nameidata *ndp = &scp->sc_nd;
4706254Sroot 
47137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
47237741Smckusick 	ndp->ni_dirp = uap->fname;
47338408Smckusick 	RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask,
47438408Smckusick 		ndp, &scp->sc_retval1));
4756254Sroot }
4766254Sroot 
4776254Sroot /*
4786254Sroot  * Common code for open and creat.
47912756Ssam  * Check permissions, allocate an open file structure,
48012756Ssam  * and call the device open routine if any.
4816254Sroot  */
48238408Smckusick copen(scp, fmode, cmode, ndp, resultfd)
48338408Smckusick 	register struct syscontext *scp;
48437741Smckusick 	int fmode, cmode;
48537741Smckusick 	struct nameidata *ndp;
48637741Smckusick 	int *resultfd;
48712756Ssam {
4886254Sroot 	register struct file *fp;
48937741Smckusick 	struct file *nfp;
49037741Smckusick 	int indx, error;
49137741Smckusick 	extern struct fileops vnops;
4926254Sroot 
49337741Smckusick 	if (error = falloc(&nfp, &indx))
49437741Smckusick 		return (error);
49537741Smckusick 	fp = nfp;
49638408Smckusick 	scp->sc_retval1 = indx;	/* XXX for fdopen() */
49737741Smckusick 	if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) {
49838408Smckusick 		scp->sc_ofile[indx] = NULL;
49937741Smckusick 		crfree(fp->f_cred);
50037741Smckusick 		fp->f_count--;
50137741Smckusick 		return (error);
50212756Ssam 	}
50337741Smckusick 	fp->f_flag = fmode & FMASK;
50437741Smckusick 	fp->f_type = DTYPE_VNODE;
50537741Smckusick 	fp->f_ops = &vnops;
50637741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
50737741Smckusick 	if (resultfd)
50837741Smckusick 		*resultfd = indx;
50937741Smckusick 	return (0);
5106254Sroot }
5116254Sroot 
5126254Sroot /*
5136254Sroot  * Mknod system call
5146254Sroot  */
51538408Smckusick mknod(scp)
51638408Smckusick 	register struct syscontext *scp;
5176254Sroot {
5186254Sroot 	register struct a {
5196254Sroot 		char	*fname;
5206254Sroot 		int	fmode;
5216254Sroot 		int	dev;
52238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
52338408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
52437741Smckusick 	register struct vnode *vp;
52537741Smckusick 	struct vattr vattr;
52637741Smckusick 	int error;
5276254Sroot 
52838408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
52937741Smckusick 		RETURN (error);
53037741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
53116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
53216694Smckusick 	ndp->ni_dirp = uap->fname;
53337741Smckusick 	if (error = namei(ndp))
53437741Smckusick 		RETURN (error);
53537741Smckusick 	vp = ndp->ni_vp;
53637741Smckusick 	if (vp != NULL) {
53737741Smckusick 		error = EEXIST;
53812756Ssam 		goto out;
5396254Sroot 	}
54037741Smckusick 	vattr_null(&vattr);
54137741Smckusick 	switch (uap->fmode & IFMT) {
54212756Ssam 
54315093Smckusick 	case IFMT:	/* used by badsect to flag bad sectors */
54437741Smckusick 		vattr.va_type = VBAD;
54537741Smckusick 		break;
54612756Ssam 	case IFCHR:
54737741Smckusick 		vattr.va_type = VCHR;
54837741Smckusick 		break;
54912756Ssam 	case IFBLK:
55037741Smckusick 		vattr.va_type = VBLK;
55137741Smckusick 		break;
55237741Smckusick 	default:
55337741Smckusick 		error = EINVAL;
55437741Smckusick 		goto out;
5556254Sroot 	}
55638408Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask;
55737741Smckusick 	vattr.va_rdev = uap->dev;
5586254Sroot out:
55937741Smckusick 	if (error)
56037741Smckusick 		VOP_ABORTOP(ndp);
56137741Smckusick 	else
56237741Smckusick 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
56337741Smckusick 	RETURN (error);
5646254Sroot }
5656254Sroot 
5666254Sroot /*
5676254Sroot  * link system call
5686254Sroot  */
56938408Smckusick link(scp)
57038408Smckusick 	register struct syscontext *scp;
5716254Sroot {
5726254Sroot 	register struct a {
5736254Sroot 		char	*target;
5746254Sroot 		char	*linkname;
57538408Smckusick 	} *uap = (struct a *)scp->sc_ap;
57638408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
57737741Smckusick 	register struct vnode *vp, *xp;
57837741Smckusick 	int error;
5796254Sroot 
58016694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
58116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
58216694Smckusick 	ndp->ni_dirp = uap->target;
58337741Smckusick 	if (error = namei(ndp))
58437741Smckusick 		RETURN (error);
58537741Smckusick 	vp = ndp->ni_vp;
58637741Smckusick 	if (vp->v_type == VDIR &&
58738408Smckusick 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
58837741Smckusick 		goto out1;
58937741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
59016694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
59137741Smckusick 	if (error = namei(ndp))
59237741Smckusick 		goto out1;
59337741Smckusick 	xp = ndp->ni_vp;
5946254Sroot 	if (xp != NULL) {
59537741Smckusick 		error = EEXIST;
5966254Sroot 		goto out;
5976254Sroot 	}
59837741Smckusick 	xp = ndp->ni_dvp;
59937741Smckusick 	if (vp->v_mount != xp->v_mount)
60037741Smckusick 		error = EXDEV;
6016254Sroot out:
60237741Smckusick 	if (error)
60337741Smckusick 		VOP_ABORTOP(ndp);
60437741Smckusick 	else
60537741Smckusick 		error = VOP_LINK(vp, ndp);
60637741Smckusick out1:
60737741Smckusick 	vrele(vp);
60837741Smckusick 	RETURN (error);
6096254Sroot }
6106254Sroot 
6116254Sroot /*
6126254Sroot  * symlink -- make a symbolic link
6136254Sroot  */
61438408Smckusick symlink(scp)
61538408Smckusick 	register struct syscontext *scp;
6166254Sroot {
61737741Smckusick 	struct a {
6186254Sroot 		char	*target;
6196254Sroot 		char	*linkname;
62038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
62138408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
62237741Smckusick 	register struct vnode *vp;
62337741Smckusick 	struct vattr vattr;
62437741Smckusick 	char *target;
62537741Smckusick 	int error;
6266254Sroot 
62716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
62816694Smckusick 	ndp->ni_dirp = uap->linkname;
62937741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
63037741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
63137741Smckusick 		goto out1;
63237741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
63337741Smckusick 	if (error = namei(ndp))
63437741Smckusick 		goto out1;
63537741Smckusick 	vp = ndp->ni_vp;
63637741Smckusick 	if (vp) {
63737741Smckusick 		error = EEXIST;
63837741Smckusick 		goto out;
6396254Sroot 	}
64037741Smckusick 	vp = ndp->ni_dvp;
64137741Smckusick 	vattr_null(&vattr);
64238408Smckusick 	vattr.va_mode = 0777 &~ scp->sc_cmask;
64337741Smckusick out:
64437741Smckusick 	if (error)
64537741Smckusick 		VOP_ABORTOP(ndp);
64637741Smckusick 	else
64737741Smckusick 		error = VOP_SYMLINK(ndp, &vattr, target);
64837741Smckusick out1:
64937741Smckusick 	FREE(target, M_NAMEI);
65037741Smckusick 	RETURN (error);
6516254Sroot }
6526254Sroot 
6536254Sroot /*
6546254Sroot  * Unlink system call.
6556254Sroot  * Hard to avoid races here, especially
6566254Sroot  * in unlinking directories.
6576254Sroot  */
65838408Smckusick unlink(scp)
65938408Smckusick 	register struct syscontext *scp;
6606254Sroot {
6616254Sroot 	struct a {
6626254Sroot 		char	*fname;
66338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
66438408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
66537741Smckusick 	register struct vnode *vp;
66637741Smckusick 	int error;
6676254Sroot 
66837741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
66916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
67016694Smckusick 	ndp->ni_dirp = uap->fname;
67137741Smckusick 	if (error = namei(ndp))
67237741Smckusick 		RETURN (error);
67337741Smckusick 	vp = ndp->ni_vp;
67437741Smckusick 	if (vp->v_type == VDIR &&
67538408Smckusick 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
6766254Sroot 		goto out;
6776254Sroot 	/*
6786254Sroot 	 * Don't unlink a mounted file.
6796254Sroot 	 */
68037741Smckusick 	if (vp->v_flag & VROOT) {
68137741Smckusick 		error = EBUSY;
6826254Sroot 		goto out;
6836254Sroot 	}
68437741Smckusick 	if (vp->v_flag & VTEXT)
68537741Smckusick 		xrele(vp);	/* try once to free text */
6866254Sroot out:
68737741Smckusick 	if (error)
68837741Smckusick 		VOP_ABORTOP(ndp);
6897142Smckusick 	else
69037741Smckusick 		error = VOP_REMOVE(ndp);
69137741Smckusick 	RETURN (error);
6926254Sroot }
6936254Sroot 
6946254Sroot /*
6956254Sroot  * Seek system call
6966254Sroot  */
69738408Smckusick lseek(scp)
69838408Smckusick 	register struct syscontext *scp;
6996254Sroot {
7006254Sroot 	register struct file *fp;
7016254Sroot 	register struct a {
70237741Smckusick 		int	fdes;
7036254Sroot 		off_t	off;
7046254Sroot 		int	sbase;
70538408Smckusick 	} *uap = (struct a *)scp->sc_ap;
70637741Smckusick 	struct vattr vattr;
70737741Smckusick 	int error;
7086254Sroot 
70937741Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
71038408Smckusick 	    (fp = scp->sc_ofile[uap->fdes]) == NULL)
71137741Smckusick 		RETURN (EBADF);
71237741Smckusick 	if (fp->f_type != DTYPE_VNODE)
71337741Smckusick 		RETURN (ESPIPE);
71413878Ssam 	switch (uap->sbase) {
71513878Ssam 
71613878Ssam 	case L_INCR:
71713878Ssam 		fp->f_offset += uap->off;
71813878Ssam 		break;
71913878Ssam 
72013878Ssam 	case L_XTND:
72137741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
72238408Smckusick 		    &vattr, scp->sc_cred))
72337741Smckusick 			RETURN (error);
72437741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
72513878Ssam 		break;
72613878Ssam 
72713878Ssam 	case L_SET:
72813878Ssam 		fp->f_offset = uap->off;
72913878Ssam 		break;
73013878Ssam 
73113878Ssam 	default:
73237741Smckusick 		RETURN (EINVAL);
73313878Ssam 	}
73438408Smckusick 	scp->sc_offset = fp->f_offset;
73537741Smckusick 	RETURN (0);
7366254Sroot }
7376254Sroot 
7386254Sroot /*
7396254Sroot  * Access system call
7406254Sroot  */
74138408Smckusick saccess(scp)
74238408Smckusick 	register struct syscontext *scp;
7436254Sroot {
7446254Sroot 	register struct a {
7456254Sroot 		char	*fname;
7466254Sroot 		int	fmode;
74738408Smckusick 	} *uap = (struct a *)scp->sc_ap;
74838408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
74937741Smckusick 	register struct vnode *vp;
75037741Smckusick 	int error, mode, svuid, svgid;
7516254Sroot 
75238408Smckusick 	svuid = scp->sc_uid;
75338408Smckusick 	svgid = scp->sc_gid;
75438408Smckusick 	scp->sc_uid = scp->sc_ruid;
75538408Smckusick 	scp->sc_gid = scp->sc_rgid;
75637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
75716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
75816694Smckusick 	ndp->ni_dirp = uap->fname;
75937741Smckusick 	if (error = namei(ndp))
76037741Smckusick 		goto out1;
76137741Smckusick 	vp = ndp->ni_vp;
76237741Smckusick 	/*
76337741Smckusick 	 * fmode == 0 means only check for exist
76437741Smckusick 	 */
76537741Smckusick 	if (uap->fmode) {
76637741Smckusick 		mode = 0;
76737741Smckusick 		if (uap->fmode & R_OK)
76837741Smckusick 			mode |= VREAD;
76937741Smckusick 		if (uap->fmode & W_OK)
77037741Smckusick 			mode |= VWRITE;
77137741Smckusick 		if (uap->fmode & X_OK)
77237741Smckusick 			mode |= VEXEC;
77338399Smckusick 		if ((error = vn_writechk(vp)) == 0)
77438399Smckusick 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
7756254Sroot 	}
77637741Smckusick 	vput(vp);
77737741Smckusick out1:
77838408Smckusick 	scp->sc_uid = svuid;
77938408Smckusick 	scp->sc_gid = svgid;
78037741Smckusick 	RETURN (error);
7816254Sroot }
7826254Sroot 
7836254Sroot /*
7846574Smckusic  * Stat system call.  This version follows links.
78537Sbill  */
78638408Smckusick stat(scp)
78738408Smckusick 	struct syscontext *scp;
78837Sbill {
78937Sbill 
79038408Smckusick 	stat1(scp, FOLLOW);
79137Sbill }
79237Sbill 
79337Sbill /*
7946574Smckusic  * Lstat system call.  This version does not follow links.
7955992Swnj  */
79638408Smckusick lstat(scp)
79738408Smckusick 	struct syscontext *scp;
7985992Swnj {
79912756Ssam 
80038408Smckusick 	stat1(scp, NOFOLLOW);
80112756Ssam }
80212756Ssam 
80338408Smckusick stat1(scp, follow)
80438408Smckusick 	register struct syscontext *scp;
80512756Ssam 	int follow;
80612756Ssam {
8075992Swnj 	register struct a {
8085992Swnj 		char	*fname;
80912756Ssam 		struct stat *ub;
81038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
81138408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
81212756Ssam 	struct stat sb;
81337741Smckusick 	int error;
8145992Swnj 
81537741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
81616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
81716694Smckusick 	ndp->ni_dirp = uap->fname;
81837741Smckusick 	if (error = namei(ndp))
81937741Smckusick 		RETURN (error);
82037741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
82137741Smckusick 	vput(ndp->ni_vp);
82237741Smckusick 	if (error)
82337741Smckusick 		RETURN (error);
82437741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
82537741Smckusick 	RETURN (error);
8265992Swnj }
8275992Swnj 
8285992Swnj /*
8295992Swnj  * Return target name of a symbolic link
83037Sbill  */
83138408Smckusick readlink(scp)
83238408Smckusick 	register struct syscontext *scp;
8335992Swnj {
8345992Swnj 	register struct a {
8355992Swnj 		char	*name;
8365992Swnj 		char	*buf;
8375992Swnj 		int	count;
83838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
83938408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
84037741Smckusick 	register struct vnode *vp;
84137741Smckusick 	struct iovec aiov;
84237741Smckusick 	struct uio auio;
84337741Smckusick 	int error;
8445992Swnj 
84537741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
84616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
84716694Smckusick 	ndp->ni_dirp = uap->name;
84837741Smckusick 	if (error = namei(ndp))
84937741Smckusick 		RETURN (error);
85037741Smckusick 	vp = ndp->ni_vp;
85137741Smckusick 	if (vp->v_type != VLNK) {
85237741Smckusick 		error = EINVAL;
8535992Swnj 		goto out;
8545992Swnj 	}
85537741Smckusick 	aiov.iov_base = uap->buf;
85637741Smckusick 	aiov.iov_len = uap->count;
85737741Smckusick 	auio.uio_iov = &aiov;
85837741Smckusick 	auio.uio_iovcnt = 1;
85937741Smckusick 	auio.uio_offset = 0;
86037741Smckusick 	auio.uio_rw = UIO_READ;
86137741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
86237741Smckusick 	auio.uio_resid = uap->count;
86337741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
8645992Swnj out:
86537741Smckusick 	vput(vp);
86638408Smckusick 	scp->sc_retval1 = uap->count - auio.uio_resid;
86737741Smckusick 	RETURN (error);
8685992Swnj }
8695992Swnj 
8709167Ssam /*
87138259Smckusick  * Change flags of a file given path name.
87238259Smckusick  */
87338408Smckusick chflags(scp)
87438408Smckusick 	register struct syscontext *scp;
87538259Smckusick {
87638259Smckusick 	struct a {
87738259Smckusick 		char	*fname;
87838259Smckusick 		int	flags;
87938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
88038408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
88138259Smckusick 	register struct vnode *vp;
88238259Smckusick 	struct vattr vattr;
88338259Smckusick 	int error;
88438259Smckusick 
88538259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
88638259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
88738259Smckusick 	ndp->ni_dirp = uap->fname;
88838259Smckusick 	vattr_null(&vattr);
88938259Smckusick 	vattr.va_flags = uap->flags;
89038259Smckusick 	if (error = namei(ndp))
89138259Smckusick 		RETURN (error);
89238259Smckusick 	vp = ndp->ni_vp;
89338259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
89438259Smckusick 		error = EROFS;
89538259Smckusick 		goto out;
89638259Smckusick 	}
89738259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
89838259Smckusick out:
89938259Smckusick 	vput(vp);
90038259Smckusick 	RETURN (error);
90138259Smckusick }
90238259Smckusick 
90338259Smckusick /*
90438259Smckusick  * Change flags of a file given a file descriptor.
90538259Smckusick  */
90638408Smckusick fchflags(scp)
90738408Smckusick 	register struct syscontext *scp;
90838259Smckusick {
90938259Smckusick 	struct a {
91038259Smckusick 		int	fd;
91138259Smckusick 		int	flags;
91238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
91338259Smckusick 	struct vattr vattr;
91438259Smckusick 	struct vnode *vp;
91538259Smckusick 	struct file *fp;
91638259Smckusick 	int error;
91738259Smckusick 
91838408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
91938259Smckusick 		RETURN (error);
92038259Smckusick 	vattr_null(&vattr);
92138259Smckusick 	vattr.va_flags = uap->flags;
92238259Smckusick 	vp = (struct vnode *)fp->f_data;
92338259Smckusick 	VOP_LOCK(vp);
92438259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
92538259Smckusick 		error = EROFS;
92638259Smckusick 		goto out;
92738259Smckusick 	}
92838259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
92938259Smckusick out:
93038259Smckusick 	VOP_UNLOCK(vp);
93138259Smckusick 	RETURN (error);
93238259Smckusick }
93338259Smckusick 
93438259Smckusick /*
9359167Ssam  * Change mode of a file given path name.
9369167Ssam  */
93738408Smckusick chmod(scp)
93838408Smckusick 	register struct syscontext *scp;
9395992Swnj {
9407701Ssam 	struct a {
9416254Sroot 		char	*fname;
9426254Sroot 		int	fmode;
94338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
94438408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
94537741Smckusick 	register struct vnode *vp;
94637741Smckusick 	struct vattr vattr;
94737741Smckusick 	int error;
9485992Swnj 
94937741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
95037741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
95137741Smckusick 	ndp->ni_dirp = uap->fname;
95237741Smckusick 	vattr_null(&vattr);
95337741Smckusick 	vattr.va_mode = uap->fmode & 07777;
95437741Smckusick 	if (error = namei(ndp))
95537741Smckusick 		RETURN (error);
95637741Smckusick 	vp = ndp->ni_vp;
95737741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
95837741Smckusick 		error = EROFS;
95937741Smckusick 		goto out;
96037741Smckusick 	}
96137741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
96237741Smckusick out:
96337741Smckusick 	vput(vp);
96437741Smckusick 	RETURN (error);
9657701Ssam }
9667439Sroot 
9679167Ssam /*
9689167Ssam  * Change mode of a file given a file descriptor.
9699167Ssam  */
97038408Smckusick fchmod(scp)
97138408Smckusick 	register struct syscontext *scp;
9727701Ssam {
9737701Ssam 	struct a {
9747701Ssam 		int	fd;
9757701Ssam 		int	fmode;
97638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
97737741Smckusick 	struct vattr vattr;
97837741Smckusick 	struct vnode *vp;
97937741Smckusick 	struct file *fp;
98037741Smckusick 	int error;
9817701Ssam 
98238408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
98337741Smckusick 		RETURN (error);
98437741Smckusick 	vattr_null(&vattr);
98537741Smckusick 	vattr.va_mode = uap->fmode & 07777;
98637741Smckusick 	vp = (struct vnode *)fp->f_data;
98737741Smckusick 	VOP_LOCK(vp);
98837741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
98937741Smckusick 		error = EROFS;
99037741Smckusick 		goto out;
9917439Sroot 	}
99237741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
99337741Smckusick out:
99437741Smckusick 	VOP_UNLOCK(vp);
99537741Smckusick 	RETURN (error);
9965992Swnj }
9975992Swnj 
9989167Ssam /*
9999167Ssam  * Set ownership given a path name.
10009167Ssam  */
100138408Smckusick chown(scp)
100238408Smckusick 	register struct syscontext *scp;
100337Sbill {
10047701Ssam 	struct a {
10056254Sroot 		char	*fname;
10066254Sroot 		int	uid;
10076254Sroot 		int	gid;
100838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
100938408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
101037741Smckusick 	register struct vnode *vp;
101137741Smckusick 	struct vattr vattr;
101237741Smckusick 	int error;
101337Sbill 
101437741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
101536614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
101636614Sbostic 	ndp->ni_dirp = uap->fname;
101737741Smckusick 	vattr_null(&vattr);
101837741Smckusick 	vattr.va_uid = uap->uid;
101937741Smckusick 	vattr.va_gid = uap->gid;
102037741Smckusick 	if (error = namei(ndp))
102137741Smckusick 		RETURN (error);
102237741Smckusick 	vp = ndp->ni_vp;
102337741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
102437741Smckusick 		error = EROFS;
102537741Smckusick 		goto out;
102637741Smckusick 	}
102737741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
102837741Smckusick out:
102937741Smckusick 	vput(vp);
103037741Smckusick 	RETURN (error);
10317701Ssam }
10327439Sroot 
10339167Ssam /*
10349167Ssam  * Set ownership given a file descriptor.
10359167Ssam  */
103638408Smckusick fchown(scp)
103738408Smckusick 	register struct syscontext *scp;
10387701Ssam {
10397701Ssam 	struct a {
10407701Ssam 		int	fd;
10417701Ssam 		int	uid;
10427701Ssam 		int	gid;
104338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
104437741Smckusick 	struct vattr vattr;
104537741Smckusick 	struct vnode *vp;
104637741Smckusick 	struct file *fp;
104737741Smckusick 	int error;
10487701Ssam 
104938408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
105037741Smckusick 		RETURN (error);
105137741Smckusick 	vattr_null(&vattr);
105237741Smckusick 	vattr.va_uid = uap->uid;
105337741Smckusick 	vattr.va_gid = uap->gid;
105437741Smckusick 	vp = (struct vnode *)fp->f_data;
105537741Smckusick 	VOP_LOCK(vp);
105637741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
105737741Smckusick 		error = EROFS;
105837741Smckusick 		goto out;
105937741Smckusick 	}
106037741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
106137741Smckusick out:
106237741Smckusick 	VOP_UNLOCK(vp);
106337741Smckusick 	RETURN (error);
10647701Ssam }
10657701Ssam 
106638408Smckusick utimes(scp)
106738408Smckusick 	register struct syscontext *scp;
106811811Ssam {
106911811Ssam 	register struct a {
107011811Ssam 		char	*fname;
107111811Ssam 		struct	timeval *tptr;
107238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
107338408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
107437741Smckusick 	register struct vnode *vp;
107511811Ssam 	struct timeval tv[2];
107637741Smckusick 	struct vattr vattr;
107737741Smckusick 	int error;
107811811Ssam 
107937741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
108037741Smckusick 		RETURN (error);
108137741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
108237741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
108337741Smckusick 	ndp->ni_dirp = uap->fname;
108437741Smckusick 	vattr_null(&vattr);
108537741Smckusick 	vattr.va_atime = tv[0];
108637741Smckusick 	vattr.va_mtime = tv[1];
108737741Smckusick 	if (error = namei(ndp))
108837741Smckusick 		RETURN (error);
108937741Smckusick 	vp = ndp->ni_vp;
109037741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
109137741Smckusick 		error = EROFS;
109237741Smckusick 		goto out;
109321015Smckusick 	}
109437741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
109537741Smckusick out:
109637741Smckusick 	vput(vp);
109737741Smckusick 	RETURN (error);
109811811Ssam }
109911811Ssam 
11009167Ssam /*
11019167Ssam  * Truncate a file given its path name.
11029167Ssam  */
110338408Smckusick truncate(scp)
110438408Smckusick 	register struct syscontext *scp;
11057701Ssam {
11067701Ssam 	struct a {
11077701Ssam 		char	*fname;
110826473Skarels 		off_t	length;
110938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
111038408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
111137741Smckusick 	register struct vnode *vp;
111237741Smckusick 	struct vattr vattr;
111337741Smckusick 	int error;
11147701Ssam 
111537741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
111616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
111716694Smckusick 	ndp->ni_dirp = uap->fname;
111837741Smckusick 	vattr_null(&vattr);
111937741Smckusick 	vattr.va_size = uap->length;
112037741Smckusick 	if (error = namei(ndp))
112137741Smckusick 		RETURN (error);
112237741Smckusick 	vp = ndp->ni_vp;
112337741Smckusick 	if (vp->v_type == VDIR) {
112437741Smckusick 		error = EISDIR;
112537741Smckusick 		goto out;
11267701Ssam 	}
112738399Smckusick 	if ((error = vn_writechk(vp)) ||
112838399Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
112937741Smckusick 		goto out;
113037741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
113137741Smckusick out:
113237741Smckusick 	vput(vp);
113337741Smckusick 	RETURN (error);
11347701Ssam }
11357701Ssam 
11369167Ssam /*
11379167Ssam  * Truncate a file given a file descriptor.
11389167Ssam  */
113938408Smckusick ftruncate(scp)
114038408Smckusick 	register struct syscontext *scp;
11417701Ssam {
11427701Ssam 	struct a {
11437701Ssam 		int	fd;
114426473Skarels 		off_t	length;
114538408Smckusick 	} *uap = (struct a *)scp->sc_ap;
114637741Smckusick 	struct vattr vattr;
114737741Smckusick 	struct vnode *vp;
11487701Ssam 	struct file *fp;
114937741Smckusick 	int error;
11507701Ssam 
115138408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
115237741Smckusick 		RETURN (error);
115337741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
115437741Smckusick 		RETURN (EINVAL);
115537741Smckusick 	vattr_null(&vattr);
115637741Smckusick 	vattr.va_size = uap->length;
115737741Smckusick 	vp = (struct vnode *)fp->f_data;
115837741Smckusick 	VOP_LOCK(vp);
115937741Smckusick 	if (vp->v_type == VDIR) {
116037741Smckusick 		error = EISDIR;
116137741Smckusick 		goto out;
11627701Ssam 	}
116338399Smckusick 	if (error = vn_writechk(vp))
116437741Smckusick 		goto out;
116537741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
116637741Smckusick out:
116737741Smckusick 	VOP_UNLOCK(vp);
116837741Smckusick 	RETURN (error);
11697701Ssam }
11707701Ssam 
11719167Ssam /*
11729167Ssam  * Synch an open file.
11739167Ssam  */
117438408Smckusick fsync(scp)
117538408Smckusick 	register struct syscontext *scp;
11769167Ssam {
11779167Ssam 	struct a {
11789167Ssam 		int	fd;
117938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
11809167Ssam 	struct file *fp;
118137741Smckusick 	int error;
11829167Ssam 
118338408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
118437741Smckusick 		RETURN (error);
118537741Smckusick 	error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred);
118637741Smckusick 	RETURN (error);
11879167Ssam }
11889167Ssam 
11899167Ssam /*
11909167Ssam  * Rename system call.
11919167Ssam  *
11929167Ssam  * Source and destination must either both be directories, or both
11939167Ssam  * not be directories.  If target is a directory, it must be empty.
11949167Ssam  */
119538408Smckusick rename(scp)
119638408Smckusick 	register struct syscontext *scp;
11977701Ssam {
11987701Ssam 	struct a {
11997701Ssam 		char	*from;
12007701Ssam 		char	*to;
120138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
120237741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
120338408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
120437741Smckusick 	struct nameidata tond;
120537741Smckusick 	int error;
12067701Ssam 
120737741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
120816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
120916694Smckusick 	ndp->ni_dirp = uap->from;
121037741Smckusick 	if (error = namei(ndp))
121137741Smckusick 		RETURN (error);
121237741Smckusick 	fvp = ndp->ni_vp;
121338266Smckusick 	nddup(ndp, &tond);
121437741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
121537741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
121637741Smckusick 	tond.ni_dirp = uap->to;
121737741Smckusick 	error = namei(&tond);
121837741Smckusick 	tdvp = tond.ni_dvp;
121937741Smckusick 	tvp = tond.ni_vp;
122037741Smckusick 	if (tvp != NULL) {
122137741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
122239242Sbostic 			error = ENOTDIR;
122337741Smckusick 			goto out;
122437741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
122539242Sbostic 			error = EISDIR;
122637741Smckusick 			goto out;
12279167Ssam 		}
12289167Ssam 	}
122937741Smckusick 	if (error) {
123037741Smckusick 		VOP_ABORTOP(ndp);
123137741Smckusick 		goto out1;
123237741Smckusick 	}
123337741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
123437741Smckusick 		error = EXDEV;
12359167Ssam 		goto out;
123610051Ssam 	}
123739286Smckusick 	if (fvp == tdvp)
123837741Smckusick 		error = EINVAL;
123939286Smckusick 	/*
124039286Smckusick 	 * If source is the same as the destination,
124139286Smckusick 	 * then there is nothing to do.
124239286Smckusick 	 */
124339286Smckusick 	if (fvp == tvp)
124439286Smckusick 		error = -1;
124537741Smckusick out:
124637741Smckusick 	if (error) {
124737741Smckusick 		VOP_ABORTOP(&tond);
124837741Smckusick 		VOP_ABORTOP(ndp);
12499167Ssam 	} else {
125037741Smckusick 		error = VOP_RENAME(ndp, &tond);
12519167Ssam 	}
125237741Smckusick out1:
125338266Smckusick 	ndrele(&tond);
125439286Smckusick 	if (error == -1)
125539286Smckusick 		RETURN (0);
125637741Smckusick 	RETURN (error);
12577701Ssam }
12587701Ssam 
12597535Sroot /*
126012756Ssam  * Mkdir system call
126112756Ssam  */
126238408Smckusick mkdir(scp)
126338408Smckusick 	register struct syscontext *scp;
126412756Ssam {
126512756Ssam 	struct a {
126612756Ssam 		char	*name;
126712756Ssam 		int	dmode;
126838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
126938408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
127037741Smckusick 	register struct vnode *vp;
127137741Smckusick 	struct vattr vattr;
127237741Smckusick 	int error;
127312756Ssam 
127437741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
127516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
127616694Smckusick 	ndp->ni_dirp = uap->name;
127737741Smckusick 	if (error = namei(ndp))
127837741Smckusick 		RETURN (error);
127937741Smckusick 	vp = ndp->ni_vp;
128037741Smckusick 	if (vp != NULL) {
128137741Smckusick 		VOP_ABORTOP(ndp);
128237741Smckusick 		RETURN (EEXIST);
128312756Ssam 	}
128437741Smckusick 	vattr_null(&vattr);
128537741Smckusick 	vattr.va_type = VDIR;
128638408Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask;
128737741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
128838145Smckusick 	if (!error)
128938145Smckusick 		vput(ndp->ni_vp);
129037741Smckusick 	RETURN (error);
129112756Ssam }
129212756Ssam 
129312756Ssam /*
129412756Ssam  * Rmdir system call.
129512756Ssam  */
129638408Smckusick rmdir(scp)
129738408Smckusick 	register struct syscontext *scp;
129812756Ssam {
129912756Ssam 	struct a {
130012756Ssam 		char	*name;
130138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
130238408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
130337741Smckusick 	register struct vnode *vp;
130437741Smckusick 	int error;
130512756Ssam 
130637741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
130716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
130816694Smckusick 	ndp->ni_dirp = uap->name;
130937741Smckusick 	if (error = namei(ndp))
131037741Smckusick 		RETURN (error);
131137741Smckusick 	vp = ndp->ni_vp;
131237741Smckusick 	if (vp->v_type != VDIR) {
131337741Smckusick 		error = ENOTDIR;
131412756Ssam 		goto out;
131512756Ssam 	}
131612756Ssam 	/*
131737741Smckusick 	 * No rmdir "." please.
131812756Ssam 	 */
131937741Smckusick 	if (ndp->ni_dvp == vp) {
132037741Smckusick 		error = EINVAL;
132112756Ssam 		goto out;
132212756Ssam 	}
132312756Ssam 	/*
132437741Smckusick 	 * Don't unlink a mounted file.
132512756Ssam 	 */
132637741Smckusick 	if (vp->v_flag & VROOT)
132737741Smckusick 		error = EBUSY;
132812756Ssam out:
132937741Smckusick 	if (error)
133037741Smckusick 		VOP_ABORTOP(ndp);
133137741Smckusick 	else
133237741Smckusick 		error = VOP_RMDIR(ndp);
133337741Smckusick 	RETURN (error);
133412756Ssam }
133512756Ssam 
133637741Smckusick /*
133737741Smckusick  * Read a block of directory entries in a file system independent format
133837741Smckusick  */
133938408Smckusick getdirentries(scp)
134038408Smckusick 	register struct syscontext *scp;
134112756Ssam {
134237741Smckusick 	register struct a {
134337741Smckusick 		int	fd;
134437741Smckusick 		char	*buf;
134537741Smckusick 		unsigned count;
134637741Smckusick 		long	*basep;
134738408Smckusick 	} *uap = (struct a *)scp->sc_ap;
134816540Ssam 	struct file *fp;
134937741Smckusick 	struct uio auio;
135037741Smckusick 	struct iovec aiov;
135138129Smckusick 	off_t off;
135237741Smckusick 	int error;
135312756Ssam 
135438408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
135537741Smckusick 		RETURN (error);
135637741Smckusick 	if ((fp->f_flag & FREAD) == 0)
135737741Smckusick 		RETURN (EBADF);
135837741Smckusick 	aiov.iov_base = uap->buf;
135937741Smckusick 	aiov.iov_len = uap->count;
136037741Smckusick 	auio.uio_iov = &aiov;
136137741Smckusick 	auio.uio_iovcnt = 1;
136237741Smckusick 	auio.uio_rw = UIO_READ;
136337741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
136437741Smckusick 	auio.uio_resid = uap->count;
136538129Smckusick 	off = fp->f_offset;
136637741Smckusick 	if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio,
136737741Smckusick 	    &(fp->f_offset), fp->f_cred))
136837741Smckusick 		RETURN (error);
136938129Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep,
137037741Smckusick 		sizeof(long));
137138408Smckusick 	scp->sc_retval1 = uap->count - auio.uio_resid;
137237741Smckusick 	RETURN (error);
137312756Ssam }
137412756Ssam 
137512756Ssam /*
137612756Ssam  * mode mask for creation of files
137712756Ssam  */
137838408Smckusick umask(scp)
137938408Smckusick 	register struct syscontext *scp;
138012756Ssam {
138112756Ssam 	register struct a {
138212756Ssam 		int	mask;
138338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
138412756Ssam 
138538408Smckusick 	scp->sc_retval1 = scp->sc_cmask;
138638408Smckusick 	scp->sc_cmask = uap->mask & 07777;
138737741Smckusick 	RETURN (0);
138812756Ssam }
138937741Smckusick 
139038408Smckusick getvnode(ofile, fdes, fpp)
139138408Smckusick 	struct file *ofile[];
139237741Smckusick 	struct file **fpp;
139337741Smckusick 	int fdes;
139437741Smckusick {
139537741Smckusick 	struct file *fp;
139637741Smckusick 
139738408Smckusick 	if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
139837741Smckusick 		return (EBADF);
139937741Smckusick 	if (fp->f_type != DTYPE_VNODE)
140037741Smckusick 		return (EINVAL);
140137741Smckusick 	*fpp = fp;
140237741Smckusick 	return (0);
140337741Smckusick }
1404