xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 39381)
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*39381Smckusick  *	@(#)vfs_syscalls.c	7.20 (Berkeley) 10/24/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;
109*39381Smckusick 	mp->m_mounth = (struct vnode *)0;
11039335Smckusick 	if (error = vfs_lock(mp)) {
11139335Smckusick 		free((caddr_t)mp, M_MOUNT);
11239335Smckusick 		vput(vp);
11339335Smckusick 		RETURN (error);
11439335Smckusick 	}
11539335Smckusick 	if (vp->v_mountedhere != (struct mount *)0) {
11639335Smckusick 		vfs_unlock(mp);
11739335Smckusick 		free((caddr_t)mp, M_MOUNT);
11839335Smckusick 		vput(vp);
11939335Smckusick 		RETURN (EBUSY);
12039335Smckusick 	}
12139335Smckusick 	/*
12239335Smckusick 	 * Put the new filesystem on the mount list after root.
12339335Smckusick 	 */
12439335Smckusick 	mp->m_next = rootfs->m_next;
12539335Smckusick 	mp->m_prev = rootfs;
12639335Smckusick 	rootfs->m_next = mp;
12739335Smckusick 	mp->m_next->m_prev = mp;
12839335Smckusick 	vp->v_mountedhere = mp;
12939335Smckusick 	mp->m_vnodecovered = vp;
13039335Smckusick update:
13139335Smckusick 	/*
13239335Smckusick 	 * Set the mount level flags.
13339335Smckusick 	 */
13439335Smckusick 	if (uap->flags & M_RDONLY)
13539335Smckusick 		mp->m_flag |= M_RDONLY;
13639335Smckusick 	else
13739335Smckusick 		mp->m_flag &= ~M_RDONLY;
13839335Smckusick 	if (uap->flags & M_NOSUID)
13939335Smckusick 		mp->m_flag |= M_NOSUID;
14039335Smckusick 	else
14139335Smckusick 		mp->m_flag &= ~M_NOSUID;
14239335Smckusick 	if (uap->flags & M_NOEXEC)
14339335Smckusick 		mp->m_flag |= M_NOEXEC;
14439335Smckusick 	else
14539335Smckusick 		mp->m_flag &= ~M_NOEXEC;
14639335Smckusick 	if (uap->flags & M_NODEV)
14739335Smckusick 		mp->m_flag |= M_NODEV;
14839335Smckusick 	else
14939335Smckusick 		mp->m_flag &= ~M_NODEV;
15039335Smckusick 	if (uap->flags & M_SYNCHRONOUS)
15139335Smckusick 		mp->m_flag |= M_SYNCHRONOUS;
15239335Smckusick 	else
15339335Smckusick 		mp->m_flag &= ~M_SYNCHRONOUS;
15439335Smckusick 	/*
15539335Smckusick 	 * Mount the filesystem.
15639335Smckusick 	 */
15739335Smckusick 	error = VFS_MOUNT(mp, uap->dir, uap->data, ndp);
15839335Smckusick 	if (mp->m_flag & M_UPDATE) {
15939335Smckusick 		mp->m_flag &= ~M_UPDATE;
16039335Smckusick 		vrele(vp);
16139335Smckusick 		RETURN (error);
16239335Smckusick 	}
16337741Smckusick 	cache_purge(vp);
16437741Smckusick 	if (!error) {
16539335Smckusick 		VOP_UNLOCK(vp);
16637741Smckusick 		vfs_unlock(mp);
16739044Smckusick 		error = VFS_START(mp, 0);
16837741Smckusick 	} else {
16937741Smckusick 		vfs_remove(mp);
17037741Smckusick 		free((caddr_t)mp, M_MOUNT);
17139335Smckusick 		vput(vp);
17237741Smckusick 	}
17337741Smckusick 	RETURN (error);
1746254Sroot }
1756254Sroot 
1769167Ssam /*
17737741Smckusick  * Unmount system call.
17837741Smckusick  *
17937741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
18037741Smckusick  * not special file (as before).
1819167Ssam  */
18238408Smckusick unmount(scp)
18338408Smckusick 	register struct syscontext *scp;
1846254Sroot {
18537741Smckusick 	struct a {
18637741Smckusick 		char	*pathp;
18737741Smckusick 		int	flags;
18838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
18937741Smckusick 	register struct vnode *vp;
19038408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
19139356Smckusick 	struct mount *mp;
19237741Smckusick 	int error;
1936254Sroot 
19437741Smckusick 	/*
19537741Smckusick 	 * Must be super user
19637741Smckusick 	 */
19738408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
19837741Smckusick 		RETURN (error);
19937741Smckusick 
20037741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
20137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
20237741Smckusick 	ndp->ni_dirp = uap->pathp;
20337741Smckusick 	if (error = namei(ndp))
20437741Smckusick 		RETURN (error);
20537741Smckusick 	vp = ndp->ni_vp;
20637741Smckusick 	/*
20737741Smckusick 	 * Must be the root of the filesystem
20837741Smckusick 	 */
20937741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
21037741Smckusick 		vput(vp);
21137741Smckusick 		RETURN (EINVAL);
21237741Smckusick 	}
21337741Smckusick 	mp = vp->v_mount;
21437741Smckusick 	vput(vp);
21539356Smckusick 	RETURN (dounmount(mp, uap->flags));
21639356Smckusick }
21739356Smckusick 
21839356Smckusick /*
21939356Smckusick  * Do an unmount.
22039356Smckusick  */
22139356Smckusick dounmount(mp, flags)
22239356Smckusick 	register struct mount *mp;
22339356Smckusick 	int flags;
22439356Smckusick {
22539356Smckusick 	struct vnode *coveredvp;
22639356Smckusick 	int error;
22739356Smckusick 
22837741Smckusick 	coveredvp = mp->m_vnodecovered;
22937741Smckusick 	if (error = vfs_lock(mp))
23039356Smckusick 		return (error);
23137741Smckusick 
23237741Smckusick 	xumount(mp);		/* remove unused sticky files from text table */
23337741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
23437741Smckusick 	VFS_SYNC(mp, MNT_WAIT);
23537741Smckusick 
23639356Smckusick 	error = VFS_UNMOUNT(mp, flags);
23737741Smckusick 	if (error) {
23837741Smckusick 		vfs_unlock(mp);
23937741Smckusick 	} else {
24037741Smckusick 		vrele(coveredvp);
24137741Smckusick 		vfs_remove(mp);
24237741Smckusick 		free((caddr_t)mp, M_MOUNT);
24337741Smckusick 	}
24439356Smckusick 	return (error);
2456254Sroot }
2466254Sroot 
2479167Ssam /*
24837741Smckusick  * Sync system call.
24937741Smckusick  * Sync each mounted filesystem.
2509167Ssam  */
25138408Smckusick sync(scp)
25238408Smckusick 	register struct syscontext *scp;
2536254Sroot {
25437741Smckusick 	register struct mount *mp;
25537741Smckusick 
25637741Smckusick 	mp = rootfs;
25737741Smckusick 	do {
25837741Smckusick 		if ((mp->m_flag & M_RDONLY) == 0)
25937741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
26037741Smckusick 		mp = mp->m_next;
26137741Smckusick 	} while (mp != rootfs);
26237741Smckusick }
26337741Smckusick 
26437741Smckusick /*
26537741Smckusick  * get filesystem statistics
26637741Smckusick  */
26738408Smckusick statfs(scp)
26838408Smckusick 	register struct syscontext *scp;
26937741Smckusick {
2706254Sroot 	struct a {
27137741Smckusick 		char *path;
27237741Smckusick 		struct statfs *buf;
27338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
27437741Smckusick 	register struct vnode *vp;
27538408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
27637741Smckusick 	struct statfs sb;
27737741Smckusick 	int error;
27837741Smckusick 
27937741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
28037741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
28137741Smckusick 	ndp->ni_dirp = uap->path;
28237741Smckusick 	if (error = namei(ndp))
28337741Smckusick 		RETURN (error);
28437741Smckusick 	vp = ndp->ni_vp;
28537741Smckusick 	if (error = VFS_STATFS(vp->v_mount, &sb))
28637741Smckusick 		goto out;
28737741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb));
28837741Smckusick out:
28937741Smckusick 	vput(vp);
29037741Smckusick 	RETURN (error);
29137741Smckusick }
29237741Smckusick 
29338408Smckusick fstatfs(scp)
29438408Smckusick 	register struct syscontext *scp;
29537741Smckusick {
29637741Smckusick 	struct a {
29737741Smckusick 		int fd;
29837741Smckusick 		struct statfs *buf;
29938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
30037741Smckusick 	struct file *fp;
30137741Smckusick 	struct statfs sb;
30237741Smckusick 	int error;
30337741Smckusick 
30438408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
30537741Smckusick 		RETURN (error);
30637741Smckusick 	if (error = VFS_STATFS(((struct vnode *)fp->f_data)->v_mount, &sb))
30737741Smckusick 		RETURN (error);
30837741Smckusick 	RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)));
30937741Smckusick }
31037741Smckusick 
31137741Smckusick /*
31238270Smckusick  * get statistics on all filesystems
31338270Smckusick  */
31438408Smckusick getfsstat(scp)
31538408Smckusick 	register struct syscontext *scp;
31638270Smckusick {
31738270Smckusick 	struct a {
31838270Smckusick 		struct statfs *buf;
31938270Smckusick 		long bufsize;
32038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
32138270Smckusick 	register struct mount *mp;
32238270Smckusick 	register struct statfs *sfsp;
32338270Smckusick 	long count, maxcount, error;
32438270Smckusick 
32538270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
32638270Smckusick 	sfsp = uap->buf;
32738270Smckusick 	mp = rootfs;
32838270Smckusick 	count = 0;
32938270Smckusick 	do {
33038270Smckusick 		count++;
33139044Smckusick 		if (sfsp && count <= maxcount &&
33239044Smckusick 		    ((mp->m_flag & M_MLOCK) == 0)) {
33338270Smckusick 			if (error = VFS_STATFS(mp, sfsp))
33438270Smckusick 				RETURN (error);
33538270Smckusick 			sfsp++;
33638270Smckusick 		}
33738270Smckusick 		mp = mp->m_prev;
33838270Smckusick 	} while (mp != rootfs);
33938270Smckusick 	if (sfsp && count > maxcount)
34038408Smckusick 		scp->sc_retval1 = maxcount;
34138270Smckusick 	else
34238408Smckusick 		scp->sc_retval1 = count;
34338270Smckusick 	RETURN (0);
34438270Smckusick }
34538270Smckusick 
34638270Smckusick /*
34738259Smckusick  * Change current working directory to a given file descriptor.
34838259Smckusick  */
34938408Smckusick fchdir(scp)
35038408Smckusick 	register struct syscontext *scp;
35138259Smckusick {
35238259Smckusick 	struct a {
35338259Smckusick 		int	fd;
35438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
35538259Smckusick 	register struct vnode *vp;
35638259Smckusick 	struct file *fp;
35738259Smckusick 	int error;
35838259Smckusick 
35938408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
36038259Smckusick 		RETURN (error);
36138259Smckusick 	vp = (struct vnode *)fp->f_data;
36238259Smckusick 	VOP_LOCK(vp);
36338259Smckusick 	if (vp->v_type != VDIR)
36438259Smckusick 		error = ENOTDIR;
36538259Smckusick 	else
36638408Smckusick 		error = VOP_ACCESS(vp, VEXEC, scp->sc_cred);
36738259Smckusick 	VOP_UNLOCK(vp);
36838408Smckusick 	vrele(scp->sc_cdir);
36938408Smckusick 	scp->sc_cdir = vp;
37038259Smckusick 	RETURN (error);
37138259Smckusick }
37238259Smckusick 
37338259Smckusick /*
37437741Smckusick  * Change current working directory (``.'').
37537741Smckusick  */
37638408Smckusick chdir(scp)
37738408Smckusick 	register struct syscontext *scp;
37837741Smckusick {
37937741Smckusick 	struct a {
3806254Sroot 		char	*fname;
38138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
38238408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
38337741Smckusick 	int error;
3846254Sroot 
38537741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
38616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
38716694Smckusick 	ndp->ni_dirp = uap->fname;
38837741Smckusick 	if (error = chdirec(ndp))
38937741Smckusick 		RETURN (error);
39038408Smckusick 	vrele(scp->sc_cdir);
39138408Smckusick 	scp->sc_cdir = ndp->ni_vp;
39237741Smckusick 	RETURN (0);
39337741Smckusick }
3946254Sroot 
39537741Smckusick /*
39637741Smckusick  * Change notion of root (``/'') directory.
39737741Smckusick  */
39838408Smckusick chroot(scp)
39938408Smckusick 	register struct syscontext *scp;
40037741Smckusick {
40137741Smckusick 	struct a {
40237741Smckusick 		char	*fname;
40338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
40438408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
40537741Smckusick 	int error;
40637741Smckusick 
40738408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
40837741Smckusick 		RETURN (error);
40937741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
41037741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
41137741Smckusick 	ndp->ni_dirp = uap->fname;
41237741Smckusick 	if (error = chdirec(ndp))
41337741Smckusick 		RETURN (error);
41438408Smckusick 	vrele(scp->sc_rdir);
41538408Smckusick 	scp->sc_rdir = ndp->ni_vp;
41637741Smckusick 	RETURN (0);
4176254Sroot }
4186254Sroot 
41937Sbill /*
42037741Smckusick  * Common routine for chroot and chdir.
42137741Smckusick  */
42237741Smckusick chdirec(ndp)
42337741Smckusick 	register struct nameidata *ndp;
42437741Smckusick {
42537741Smckusick 	struct vnode *vp;
42637741Smckusick 	int error;
42737741Smckusick 
42837741Smckusick 	if (error = namei(ndp))
42937741Smckusick 		return (error);
43037741Smckusick 	vp = ndp->ni_vp;
43137741Smckusick 	if (vp->v_type != VDIR)
43237741Smckusick 		error = ENOTDIR;
43337741Smckusick 	else
43438399Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
43537741Smckusick 	VOP_UNLOCK(vp);
43637741Smckusick 	if (error)
43737741Smckusick 		vrele(vp);
43837741Smckusick 	return (error);
43937741Smckusick }
44037741Smckusick 
44137741Smckusick /*
4426254Sroot  * Open system call.
4436254Sroot  */
44438408Smckusick open(scp)
44538408Smckusick 	register struct syscontext *scp;
4466254Sroot {
44712756Ssam 	struct a {
4486254Sroot 		char	*fname;
4497701Ssam 		int	mode;
45012756Ssam 		int	crtmode;
45138408Smckusick 	} *uap = (struct a *) scp->sc_ap;
45238408Smckusick 	struct nameidata *ndp = &scp->sc_nd;
4536254Sroot 
45437741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
45537741Smckusick 	ndp->ni_dirp = uap->fname;
45638408Smckusick 	RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp,
45738408Smckusick 		&scp->sc_retval1));
4586254Sroot }
4596254Sroot 
4606254Sroot /*
4616254Sroot  * Creat system call.
4626254Sroot  */
46338408Smckusick creat(scp)
46438408Smckusick 	register struct syscontext *scp;
4656254Sroot {
46612756Ssam 	struct a {
4676254Sroot 		char	*fname;
4686254Sroot 		int	fmode;
46938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
47038408Smckusick 	struct nameidata *ndp = &scp->sc_nd;
4716254Sroot 
47237741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
47337741Smckusick 	ndp->ni_dirp = uap->fname;
47438408Smckusick 	RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask,
47538408Smckusick 		ndp, &scp->sc_retval1));
4766254Sroot }
4776254Sroot 
4786254Sroot /*
4796254Sroot  * Common code for open and creat.
48012756Ssam  * Check permissions, allocate an open file structure,
48112756Ssam  * and call the device open routine if any.
4826254Sroot  */
48338408Smckusick copen(scp, fmode, cmode, ndp, resultfd)
48438408Smckusick 	register struct syscontext *scp;
48537741Smckusick 	int fmode, cmode;
48637741Smckusick 	struct nameidata *ndp;
48737741Smckusick 	int *resultfd;
48812756Ssam {
4896254Sroot 	register struct file *fp;
49037741Smckusick 	struct file *nfp;
49137741Smckusick 	int indx, error;
49237741Smckusick 	extern struct fileops vnops;
4936254Sroot 
49437741Smckusick 	if (error = falloc(&nfp, &indx))
49537741Smckusick 		return (error);
49637741Smckusick 	fp = nfp;
49738408Smckusick 	scp->sc_retval1 = indx;	/* XXX for fdopen() */
49837741Smckusick 	if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) {
49938408Smckusick 		scp->sc_ofile[indx] = NULL;
50037741Smckusick 		crfree(fp->f_cred);
50137741Smckusick 		fp->f_count--;
50237741Smckusick 		return (error);
50312756Ssam 	}
50437741Smckusick 	fp->f_flag = fmode & FMASK;
50537741Smckusick 	fp->f_type = DTYPE_VNODE;
50637741Smckusick 	fp->f_ops = &vnops;
50737741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
50837741Smckusick 	if (resultfd)
50937741Smckusick 		*resultfd = indx;
51037741Smckusick 	return (0);
5116254Sroot }
5126254Sroot 
5136254Sroot /*
5146254Sroot  * Mknod system call
5156254Sroot  */
51638408Smckusick mknod(scp)
51738408Smckusick 	register struct syscontext *scp;
5186254Sroot {
5196254Sroot 	register struct a {
5206254Sroot 		char	*fname;
5216254Sroot 		int	fmode;
5226254Sroot 		int	dev;
52338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
52438408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
52537741Smckusick 	register struct vnode *vp;
52637741Smckusick 	struct vattr vattr;
52737741Smckusick 	int error;
5286254Sroot 
52938408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
53037741Smckusick 		RETURN (error);
53137741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
53216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
53316694Smckusick 	ndp->ni_dirp = uap->fname;
53437741Smckusick 	if (error = namei(ndp))
53537741Smckusick 		RETURN (error);
53637741Smckusick 	vp = ndp->ni_vp;
53737741Smckusick 	if (vp != NULL) {
53837741Smckusick 		error = EEXIST;
53912756Ssam 		goto out;
5406254Sroot 	}
54137741Smckusick 	vattr_null(&vattr);
54237741Smckusick 	switch (uap->fmode & IFMT) {
54312756Ssam 
54415093Smckusick 	case IFMT:	/* used by badsect to flag bad sectors */
54537741Smckusick 		vattr.va_type = VBAD;
54637741Smckusick 		break;
54712756Ssam 	case IFCHR:
54837741Smckusick 		vattr.va_type = VCHR;
54937741Smckusick 		break;
55012756Ssam 	case IFBLK:
55137741Smckusick 		vattr.va_type = VBLK;
55237741Smckusick 		break;
55337741Smckusick 	default:
55437741Smckusick 		error = EINVAL;
55537741Smckusick 		goto out;
5566254Sroot 	}
55738408Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask;
55837741Smckusick 	vattr.va_rdev = uap->dev;
5596254Sroot out:
56037741Smckusick 	if (error)
56137741Smckusick 		VOP_ABORTOP(ndp);
56237741Smckusick 	else
56337741Smckusick 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
56437741Smckusick 	RETURN (error);
5656254Sroot }
5666254Sroot 
5676254Sroot /*
5686254Sroot  * link system call
5696254Sroot  */
57038408Smckusick link(scp)
57138408Smckusick 	register struct syscontext *scp;
5726254Sroot {
5736254Sroot 	register struct a {
5746254Sroot 		char	*target;
5756254Sroot 		char	*linkname;
57638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
57738408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
57837741Smckusick 	register struct vnode *vp, *xp;
57937741Smckusick 	int error;
5806254Sroot 
58116694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
58216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
58316694Smckusick 	ndp->ni_dirp = uap->target;
58437741Smckusick 	if (error = namei(ndp))
58537741Smckusick 		RETURN (error);
58637741Smckusick 	vp = ndp->ni_vp;
58737741Smckusick 	if (vp->v_type == VDIR &&
58838408Smckusick 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
58937741Smckusick 		goto out1;
59037741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
59116694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
59237741Smckusick 	if (error = namei(ndp))
59337741Smckusick 		goto out1;
59437741Smckusick 	xp = ndp->ni_vp;
5956254Sroot 	if (xp != NULL) {
59637741Smckusick 		error = EEXIST;
5976254Sroot 		goto out;
5986254Sroot 	}
59937741Smckusick 	xp = ndp->ni_dvp;
60037741Smckusick 	if (vp->v_mount != xp->v_mount)
60137741Smckusick 		error = EXDEV;
6026254Sroot out:
60337741Smckusick 	if (error)
60437741Smckusick 		VOP_ABORTOP(ndp);
60537741Smckusick 	else
60637741Smckusick 		error = VOP_LINK(vp, ndp);
60737741Smckusick out1:
60837741Smckusick 	vrele(vp);
60937741Smckusick 	RETURN (error);
6106254Sroot }
6116254Sroot 
6126254Sroot /*
6136254Sroot  * symlink -- make a symbolic link
6146254Sroot  */
61538408Smckusick symlink(scp)
61638408Smckusick 	register struct syscontext *scp;
6176254Sroot {
61837741Smckusick 	struct a {
6196254Sroot 		char	*target;
6206254Sroot 		char	*linkname;
62138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
62238408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
62337741Smckusick 	register struct vnode *vp;
62437741Smckusick 	struct vattr vattr;
62537741Smckusick 	char *target;
62637741Smckusick 	int error;
6276254Sroot 
62816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
62916694Smckusick 	ndp->ni_dirp = uap->linkname;
63037741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
63137741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
63237741Smckusick 		goto out1;
63337741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
63437741Smckusick 	if (error = namei(ndp))
63537741Smckusick 		goto out1;
63637741Smckusick 	vp = ndp->ni_vp;
63737741Smckusick 	if (vp) {
63837741Smckusick 		error = EEXIST;
63937741Smckusick 		goto out;
6406254Sroot 	}
64137741Smckusick 	vp = ndp->ni_dvp;
64237741Smckusick 	vattr_null(&vattr);
64338408Smckusick 	vattr.va_mode = 0777 &~ scp->sc_cmask;
64437741Smckusick out:
64537741Smckusick 	if (error)
64637741Smckusick 		VOP_ABORTOP(ndp);
64737741Smckusick 	else
64837741Smckusick 		error = VOP_SYMLINK(ndp, &vattr, target);
64937741Smckusick out1:
65037741Smckusick 	FREE(target, M_NAMEI);
65137741Smckusick 	RETURN (error);
6526254Sroot }
6536254Sroot 
6546254Sroot /*
6556254Sroot  * Unlink system call.
6566254Sroot  * Hard to avoid races here, especially
6576254Sroot  * in unlinking directories.
6586254Sroot  */
65938408Smckusick unlink(scp)
66038408Smckusick 	register struct syscontext *scp;
6616254Sroot {
6626254Sroot 	struct a {
6636254Sroot 		char	*fname;
66438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
66538408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
66637741Smckusick 	register struct vnode *vp;
66737741Smckusick 	int error;
6686254Sroot 
66937741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
67016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
67116694Smckusick 	ndp->ni_dirp = uap->fname;
67237741Smckusick 	if (error = namei(ndp))
67337741Smckusick 		RETURN (error);
67437741Smckusick 	vp = ndp->ni_vp;
67537741Smckusick 	if (vp->v_type == VDIR &&
67638408Smckusick 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
6776254Sroot 		goto out;
6786254Sroot 	/*
6796254Sroot 	 * Don't unlink a mounted file.
6806254Sroot 	 */
68137741Smckusick 	if (vp->v_flag & VROOT) {
68237741Smckusick 		error = EBUSY;
6836254Sroot 		goto out;
6846254Sroot 	}
68537741Smckusick 	if (vp->v_flag & VTEXT)
68637741Smckusick 		xrele(vp);	/* try once to free text */
6876254Sroot out:
68837741Smckusick 	if (error)
68937741Smckusick 		VOP_ABORTOP(ndp);
6907142Smckusick 	else
69137741Smckusick 		error = VOP_REMOVE(ndp);
69237741Smckusick 	RETURN (error);
6936254Sroot }
6946254Sroot 
6956254Sroot /*
6966254Sroot  * Seek system call
6976254Sroot  */
69838408Smckusick lseek(scp)
69938408Smckusick 	register struct syscontext *scp;
7006254Sroot {
7016254Sroot 	register struct file *fp;
7026254Sroot 	register struct a {
70337741Smckusick 		int	fdes;
7046254Sroot 		off_t	off;
7056254Sroot 		int	sbase;
70638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
70737741Smckusick 	struct vattr vattr;
70837741Smckusick 	int error;
7096254Sroot 
71037741Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
71138408Smckusick 	    (fp = scp->sc_ofile[uap->fdes]) == NULL)
71237741Smckusick 		RETURN (EBADF);
71337741Smckusick 	if (fp->f_type != DTYPE_VNODE)
71437741Smckusick 		RETURN (ESPIPE);
71513878Ssam 	switch (uap->sbase) {
71613878Ssam 
71713878Ssam 	case L_INCR:
71813878Ssam 		fp->f_offset += uap->off;
71913878Ssam 		break;
72013878Ssam 
72113878Ssam 	case L_XTND:
72237741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
72338408Smckusick 		    &vattr, scp->sc_cred))
72437741Smckusick 			RETURN (error);
72537741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
72613878Ssam 		break;
72713878Ssam 
72813878Ssam 	case L_SET:
72913878Ssam 		fp->f_offset = uap->off;
73013878Ssam 		break;
73113878Ssam 
73213878Ssam 	default:
73337741Smckusick 		RETURN (EINVAL);
73413878Ssam 	}
73538408Smckusick 	scp->sc_offset = fp->f_offset;
73637741Smckusick 	RETURN (0);
7376254Sroot }
7386254Sroot 
7396254Sroot /*
7406254Sroot  * Access system call
7416254Sroot  */
74238408Smckusick saccess(scp)
74338408Smckusick 	register struct syscontext *scp;
7446254Sroot {
7456254Sroot 	register struct a {
7466254Sroot 		char	*fname;
7476254Sroot 		int	fmode;
74838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
74938408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
75037741Smckusick 	register struct vnode *vp;
75137741Smckusick 	int error, mode, svuid, svgid;
7526254Sroot 
75338408Smckusick 	svuid = scp->sc_uid;
75438408Smckusick 	svgid = scp->sc_gid;
75538408Smckusick 	scp->sc_uid = scp->sc_ruid;
75638408Smckusick 	scp->sc_gid = scp->sc_rgid;
75737741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
75816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
75916694Smckusick 	ndp->ni_dirp = uap->fname;
76037741Smckusick 	if (error = namei(ndp))
76137741Smckusick 		goto out1;
76237741Smckusick 	vp = ndp->ni_vp;
76337741Smckusick 	/*
76437741Smckusick 	 * fmode == 0 means only check for exist
76537741Smckusick 	 */
76637741Smckusick 	if (uap->fmode) {
76737741Smckusick 		mode = 0;
76837741Smckusick 		if (uap->fmode & R_OK)
76937741Smckusick 			mode |= VREAD;
77037741Smckusick 		if (uap->fmode & W_OK)
77137741Smckusick 			mode |= VWRITE;
77237741Smckusick 		if (uap->fmode & X_OK)
77337741Smckusick 			mode |= VEXEC;
77438399Smckusick 		if ((error = vn_writechk(vp)) == 0)
77538399Smckusick 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
7766254Sroot 	}
77737741Smckusick 	vput(vp);
77837741Smckusick out1:
77938408Smckusick 	scp->sc_uid = svuid;
78038408Smckusick 	scp->sc_gid = svgid;
78137741Smckusick 	RETURN (error);
7826254Sroot }
7836254Sroot 
7846254Sroot /*
7856574Smckusic  * Stat system call.  This version follows links.
78637Sbill  */
78738408Smckusick stat(scp)
78838408Smckusick 	struct syscontext *scp;
78937Sbill {
79037Sbill 
79138408Smckusick 	stat1(scp, FOLLOW);
79237Sbill }
79337Sbill 
79437Sbill /*
7956574Smckusic  * Lstat system call.  This version does not follow links.
7965992Swnj  */
79738408Smckusick lstat(scp)
79838408Smckusick 	struct syscontext *scp;
7995992Swnj {
80012756Ssam 
80138408Smckusick 	stat1(scp, NOFOLLOW);
80212756Ssam }
80312756Ssam 
80438408Smckusick stat1(scp, follow)
80538408Smckusick 	register struct syscontext *scp;
80612756Ssam 	int follow;
80712756Ssam {
8085992Swnj 	register struct a {
8095992Swnj 		char	*fname;
81012756Ssam 		struct stat *ub;
81138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
81238408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
81312756Ssam 	struct stat sb;
81437741Smckusick 	int error;
8155992Swnj 
81637741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
81716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
81816694Smckusick 	ndp->ni_dirp = uap->fname;
81937741Smckusick 	if (error = namei(ndp))
82037741Smckusick 		RETURN (error);
82137741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
82237741Smckusick 	vput(ndp->ni_vp);
82337741Smckusick 	if (error)
82437741Smckusick 		RETURN (error);
82537741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
82637741Smckusick 	RETURN (error);
8275992Swnj }
8285992Swnj 
8295992Swnj /*
8305992Swnj  * Return target name of a symbolic link
83137Sbill  */
83238408Smckusick readlink(scp)
83338408Smckusick 	register struct syscontext *scp;
8345992Swnj {
8355992Swnj 	register struct a {
8365992Swnj 		char	*name;
8375992Swnj 		char	*buf;
8385992Swnj 		int	count;
83938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
84038408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
84137741Smckusick 	register struct vnode *vp;
84237741Smckusick 	struct iovec aiov;
84337741Smckusick 	struct uio auio;
84437741Smckusick 	int error;
8455992Swnj 
84637741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
84716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
84816694Smckusick 	ndp->ni_dirp = uap->name;
84937741Smckusick 	if (error = namei(ndp))
85037741Smckusick 		RETURN (error);
85137741Smckusick 	vp = ndp->ni_vp;
85237741Smckusick 	if (vp->v_type != VLNK) {
85337741Smckusick 		error = EINVAL;
8545992Swnj 		goto out;
8555992Swnj 	}
85637741Smckusick 	aiov.iov_base = uap->buf;
85737741Smckusick 	aiov.iov_len = uap->count;
85837741Smckusick 	auio.uio_iov = &aiov;
85937741Smckusick 	auio.uio_iovcnt = 1;
86037741Smckusick 	auio.uio_offset = 0;
86137741Smckusick 	auio.uio_rw = UIO_READ;
86237741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
86337741Smckusick 	auio.uio_resid = uap->count;
86437741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
8655992Swnj out:
86637741Smckusick 	vput(vp);
86738408Smckusick 	scp->sc_retval1 = uap->count - auio.uio_resid;
86837741Smckusick 	RETURN (error);
8695992Swnj }
8705992Swnj 
8719167Ssam /*
87238259Smckusick  * Change flags of a file given path name.
87338259Smckusick  */
87438408Smckusick chflags(scp)
87538408Smckusick 	register struct syscontext *scp;
87638259Smckusick {
87738259Smckusick 	struct a {
87838259Smckusick 		char	*fname;
87938259Smckusick 		int	flags;
88038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
88138408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
88238259Smckusick 	register struct vnode *vp;
88338259Smckusick 	struct vattr vattr;
88438259Smckusick 	int error;
88538259Smckusick 
88638259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
88738259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
88838259Smckusick 	ndp->ni_dirp = uap->fname;
88938259Smckusick 	vattr_null(&vattr);
89038259Smckusick 	vattr.va_flags = uap->flags;
89138259Smckusick 	if (error = namei(ndp))
89238259Smckusick 		RETURN (error);
89338259Smckusick 	vp = ndp->ni_vp;
89438259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
89538259Smckusick 		error = EROFS;
89638259Smckusick 		goto out;
89738259Smckusick 	}
89838259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
89938259Smckusick out:
90038259Smckusick 	vput(vp);
90138259Smckusick 	RETURN (error);
90238259Smckusick }
90338259Smckusick 
90438259Smckusick /*
90538259Smckusick  * Change flags of a file given a file descriptor.
90638259Smckusick  */
90738408Smckusick fchflags(scp)
90838408Smckusick 	register struct syscontext *scp;
90938259Smckusick {
91038259Smckusick 	struct a {
91138259Smckusick 		int	fd;
91238259Smckusick 		int	flags;
91338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
91438259Smckusick 	struct vattr vattr;
91538259Smckusick 	struct vnode *vp;
91638259Smckusick 	struct file *fp;
91738259Smckusick 	int error;
91838259Smckusick 
91938408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
92038259Smckusick 		RETURN (error);
92138259Smckusick 	vattr_null(&vattr);
92238259Smckusick 	vattr.va_flags = uap->flags;
92338259Smckusick 	vp = (struct vnode *)fp->f_data;
92438259Smckusick 	VOP_LOCK(vp);
92538259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
92638259Smckusick 		error = EROFS;
92738259Smckusick 		goto out;
92838259Smckusick 	}
92938259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
93038259Smckusick out:
93138259Smckusick 	VOP_UNLOCK(vp);
93238259Smckusick 	RETURN (error);
93338259Smckusick }
93438259Smckusick 
93538259Smckusick /*
9369167Ssam  * Change mode of a file given path name.
9379167Ssam  */
93838408Smckusick chmod(scp)
93938408Smckusick 	register struct syscontext *scp;
9405992Swnj {
9417701Ssam 	struct a {
9426254Sroot 		char	*fname;
9436254Sroot 		int	fmode;
94438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
94538408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
94637741Smckusick 	register struct vnode *vp;
94737741Smckusick 	struct vattr vattr;
94837741Smckusick 	int error;
9495992Swnj 
95037741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
95137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
95237741Smckusick 	ndp->ni_dirp = uap->fname;
95337741Smckusick 	vattr_null(&vattr);
95437741Smckusick 	vattr.va_mode = uap->fmode & 07777;
95537741Smckusick 	if (error = namei(ndp))
95637741Smckusick 		RETURN (error);
95737741Smckusick 	vp = ndp->ni_vp;
95837741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
95937741Smckusick 		error = EROFS;
96037741Smckusick 		goto out;
96137741Smckusick 	}
96237741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
96337741Smckusick out:
96437741Smckusick 	vput(vp);
96537741Smckusick 	RETURN (error);
9667701Ssam }
9677439Sroot 
9689167Ssam /*
9699167Ssam  * Change mode of a file given a file descriptor.
9709167Ssam  */
97138408Smckusick fchmod(scp)
97238408Smckusick 	register struct syscontext *scp;
9737701Ssam {
9747701Ssam 	struct a {
9757701Ssam 		int	fd;
9767701Ssam 		int	fmode;
97738408Smckusick 	} *uap = (struct a *)scp->sc_ap;
97837741Smckusick 	struct vattr vattr;
97937741Smckusick 	struct vnode *vp;
98037741Smckusick 	struct file *fp;
98137741Smckusick 	int error;
9827701Ssam 
98338408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
98437741Smckusick 		RETURN (error);
98537741Smckusick 	vattr_null(&vattr);
98637741Smckusick 	vattr.va_mode = uap->fmode & 07777;
98737741Smckusick 	vp = (struct vnode *)fp->f_data;
98837741Smckusick 	VOP_LOCK(vp);
98937741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
99037741Smckusick 		error = EROFS;
99137741Smckusick 		goto out;
9927439Sroot 	}
99337741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
99437741Smckusick out:
99537741Smckusick 	VOP_UNLOCK(vp);
99637741Smckusick 	RETURN (error);
9975992Swnj }
9985992Swnj 
9999167Ssam /*
10009167Ssam  * Set ownership given a path name.
10019167Ssam  */
100238408Smckusick chown(scp)
100338408Smckusick 	register struct syscontext *scp;
100437Sbill {
10057701Ssam 	struct a {
10066254Sroot 		char	*fname;
10076254Sroot 		int	uid;
10086254Sroot 		int	gid;
100938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
101038408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
101137741Smckusick 	register struct vnode *vp;
101237741Smckusick 	struct vattr vattr;
101337741Smckusick 	int error;
101437Sbill 
101537741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
101636614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
101736614Sbostic 	ndp->ni_dirp = uap->fname;
101837741Smckusick 	vattr_null(&vattr);
101937741Smckusick 	vattr.va_uid = uap->uid;
102037741Smckusick 	vattr.va_gid = uap->gid;
102137741Smckusick 	if (error = namei(ndp))
102237741Smckusick 		RETURN (error);
102337741Smckusick 	vp = ndp->ni_vp;
102437741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
102537741Smckusick 		error = EROFS;
102637741Smckusick 		goto out;
102737741Smckusick 	}
102837741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
102937741Smckusick out:
103037741Smckusick 	vput(vp);
103137741Smckusick 	RETURN (error);
10327701Ssam }
10337439Sroot 
10349167Ssam /*
10359167Ssam  * Set ownership given a file descriptor.
10369167Ssam  */
103738408Smckusick fchown(scp)
103838408Smckusick 	register struct syscontext *scp;
10397701Ssam {
10407701Ssam 	struct a {
10417701Ssam 		int	fd;
10427701Ssam 		int	uid;
10437701Ssam 		int	gid;
104438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
104537741Smckusick 	struct vattr vattr;
104637741Smckusick 	struct vnode *vp;
104737741Smckusick 	struct file *fp;
104837741Smckusick 	int error;
10497701Ssam 
105038408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
105137741Smckusick 		RETURN (error);
105237741Smckusick 	vattr_null(&vattr);
105337741Smckusick 	vattr.va_uid = uap->uid;
105437741Smckusick 	vattr.va_gid = uap->gid;
105537741Smckusick 	vp = (struct vnode *)fp->f_data;
105637741Smckusick 	VOP_LOCK(vp);
105737741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
105837741Smckusick 		error = EROFS;
105937741Smckusick 		goto out;
106037741Smckusick 	}
106137741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
106237741Smckusick out:
106337741Smckusick 	VOP_UNLOCK(vp);
106437741Smckusick 	RETURN (error);
10657701Ssam }
10667701Ssam 
106738408Smckusick utimes(scp)
106838408Smckusick 	register struct syscontext *scp;
106911811Ssam {
107011811Ssam 	register struct a {
107111811Ssam 		char	*fname;
107211811Ssam 		struct	timeval *tptr;
107338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
107438408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
107537741Smckusick 	register struct vnode *vp;
107611811Ssam 	struct timeval tv[2];
107737741Smckusick 	struct vattr vattr;
107837741Smckusick 	int error;
107911811Ssam 
108037741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
108137741Smckusick 		RETURN (error);
108237741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
108337741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
108437741Smckusick 	ndp->ni_dirp = uap->fname;
108537741Smckusick 	vattr_null(&vattr);
108637741Smckusick 	vattr.va_atime = tv[0];
108737741Smckusick 	vattr.va_mtime = tv[1];
108837741Smckusick 	if (error = namei(ndp))
108937741Smckusick 		RETURN (error);
109037741Smckusick 	vp = ndp->ni_vp;
109137741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
109237741Smckusick 		error = EROFS;
109337741Smckusick 		goto out;
109421015Smckusick 	}
109537741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
109637741Smckusick out:
109737741Smckusick 	vput(vp);
109837741Smckusick 	RETURN (error);
109911811Ssam }
110011811Ssam 
11019167Ssam /*
11029167Ssam  * Truncate a file given its path name.
11039167Ssam  */
110438408Smckusick truncate(scp)
110538408Smckusick 	register struct syscontext *scp;
11067701Ssam {
11077701Ssam 	struct a {
11087701Ssam 		char	*fname;
110926473Skarels 		off_t	length;
111038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
111138408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
111237741Smckusick 	register struct vnode *vp;
111337741Smckusick 	struct vattr vattr;
111437741Smckusick 	int error;
11157701Ssam 
111637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
111716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
111816694Smckusick 	ndp->ni_dirp = uap->fname;
111937741Smckusick 	vattr_null(&vattr);
112037741Smckusick 	vattr.va_size = uap->length;
112137741Smckusick 	if (error = namei(ndp))
112237741Smckusick 		RETURN (error);
112337741Smckusick 	vp = ndp->ni_vp;
112437741Smckusick 	if (vp->v_type == VDIR) {
112537741Smckusick 		error = EISDIR;
112637741Smckusick 		goto out;
11277701Ssam 	}
112838399Smckusick 	if ((error = vn_writechk(vp)) ||
112938399Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
113037741Smckusick 		goto out;
113137741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
113237741Smckusick out:
113337741Smckusick 	vput(vp);
113437741Smckusick 	RETURN (error);
11357701Ssam }
11367701Ssam 
11379167Ssam /*
11389167Ssam  * Truncate a file given a file descriptor.
11399167Ssam  */
114038408Smckusick ftruncate(scp)
114138408Smckusick 	register struct syscontext *scp;
11427701Ssam {
11437701Ssam 	struct a {
11447701Ssam 		int	fd;
114526473Skarels 		off_t	length;
114638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
114737741Smckusick 	struct vattr vattr;
114837741Smckusick 	struct vnode *vp;
11497701Ssam 	struct file *fp;
115037741Smckusick 	int error;
11517701Ssam 
115238408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
115337741Smckusick 		RETURN (error);
115437741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
115537741Smckusick 		RETURN (EINVAL);
115637741Smckusick 	vattr_null(&vattr);
115737741Smckusick 	vattr.va_size = uap->length;
115837741Smckusick 	vp = (struct vnode *)fp->f_data;
115937741Smckusick 	VOP_LOCK(vp);
116037741Smckusick 	if (vp->v_type == VDIR) {
116137741Smckusick 		error = EISDIR;
116237741Smckusick 		goto out;
11637701Ssam 	}
116438399Smckusick 	if (error = vn_writechk(vp))
116537741Smckusick 		goto out;
116637741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
116737741Smckusick out:
116837741Smckusick 	VOP_UNLOCK(vp);
116937741Smckusick 	RETURN (error);
11707701Ssam }
11717701Ssam 
11729167Ssam /*
11739167Ssam  * Synch an open file.
11749167Ssam  */
117538408Smckusick fsync(scp)
117638408Smckusick 	register struct syscontext *scp;
11779167Ssam {
11789167Ssam 	struct a {
11799167Ssam 		int	fd;
118038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
11819167Ssam 	struct file *fp;
118237741Smckusick 	int error;
11839167Ssam 
118438408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
118537741Smckusick 		RETURN (error);
118637741Smckusick 	error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred);
118737741Smckusick 	RETURN (error);
11889167Ssam }
11899167Ssam 
11909167Ssam /*
11919167Ssam  * Rename system call.
11929167Ssam  *
11939167Ssam  * Source and destination must either both be directories, or both
11949167Ssam  * not be directories.  If target is a directory, it must be empty.
11959167Ssam  */
119638408Smckusick rename(scp)
119738408Smckusick 	register struct syscontext *scp;
11987701Ssam {
11997701Ssam 	struct a {
12007701Ssam 		char	*from;
12017701Ssam 		char	*to;
120238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
120337741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
120438408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
120537741Smckusick 	struct nameidata tond;
120637741Smckusick 	int error;
12077701Ssam 
120837741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
120916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
121016694Smckusick 	ndp->ni_dirp = uap->from;
121137741Smckusick 	if (error = namei(ndp))
121237741Smckusick 		RETURN (error);
121337741Smckusick 	fvp = ndp->ni_vp;
121438266Smckusick 	nddup(ndp, &tond);
121537741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
121637741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
121737741Smckusick 	tond.ni_dirp = uap->to;
121837741Smckusick 	error = namei(&tond);
121937741Smckusick 	tdvp = tond.ni_dvp;
122037741Smckusick 	tvp = tond.ni_vp;
122137741Smckusick 	if (tvp != NULL) {
122237741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
122339242Sbostic 			error = ENOTDIR;
122437741Smckusick 			goto out;
122537741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
122639242Sbostic 			error = EISDIR;
122737741Smckusick 			goto out;
12289167Ssam 		}
12299167Ssam 	}
123037741Smckusick 	if (error) {
123137741Smckusick 		VOP_ABORTOP(ndp);
123237741Smckusick 		goto out1;
123337741Smckusick 	}
123437741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
123537741Smckusick 		error = EXDEV;
12369167Ssam 		goto out;
123710051Ssam 	}
123839286Smckusick 	if (fvp == tdvp)
123937741Smckusick 		error = EINVAL;
124039286Smckusick 	/*
124139286Smckusick 	 * If source is the same as the destination,
124239286Smckusick 	 * then there is nothing to do.
124339286Smckusick 	 */
124439286Smckusick 	if (fvp == tvp)
124539286Smckusick 		error = -1;
124637741Smckusick out:
124737741Smckusick 	if (error) {
124837741Smckusick 		VOP_ABORTOP(&tond);
124937741Smckusick 		VOP_ABORTOP(ndp);
12509167Ssam 	} else {
125137741Smckusick 		error = VOP_RENAME(ndp, &tond);
12529167Ssam 	}
125337741Smckusick out1:
125438266Smckusick 	ndrele(&tond);
125539286Smckusick 	if (error == -1)
125639286Smckusick 		RETURN (0);
125737741Smckusick 	RETURN (error);
12587701Ssam }
12597701Ssam 
12607535Sroot /*
126112756Ssam  * Mkdir system call
126212756Ssam  */
126338408Smckusick mkdir(scp)
126438408Smckusick 	register struct syscontext *scp;
126512756Ssam {
126612756Ssam 	struct a {
126712756Ssam 		char	*name;
126812756Ssam 		int	dmode;
126938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
127038408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
127137741Smckusick 	register struct vnode *vp;
127237741Smckusick 	struct vattr vattr;
127337741Smckusick 	int error;
127412756Ssam 
127537741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
127616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
127716694Smckusick 	ndp->ni_dirp = uap->name;
127837741Smckusick 	if (error = namei(ndp))
127937741Smckusick 		RETURN (error);
128037741Smckusick 	vp = ndp->ni_vp;
128137741Smckusick 	if (vp != NULL) {
128237741Smckusick 		VOP_ABORTOP(ndp);
128337741Smckusick 		RETURN (EEXIST);
128412756Ssam 	}
128537741Smckusick 	vattr_null(&vattr);
128637741Smckusick 	vattr.va_type = VDIR;
128738408Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask;
128837741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
128938145Smckusick 	if (!error)
129038145Smckusick 		vput(ndp->ni_vp);
129137741Smckusick 	RETURN (error);
129212756Ssam }
129312756Ssam 
129412756Ssam /*
129512756Ssam  * Rmdir system call.
129612756Ssam  */
129738408Smckusick rmdir(scp)
129838408Smckusick 	register struct syscontext *scp;
129912756Ssam {
130012756Ssam 	struct a {
130112756Ssam 		char	*name;
130238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
130338408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
130437741Smckusick 	register struct vnode *vp;
130537741Smckusick 	int error;
130612756Ssam 
130737741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
130816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
130916694Smckusick 	ndp->ni_dirp = uap->name;
131037741Smckusick 	if (error = namei(ndp))
131137741Smckusick 		RETURN (error);
131237741Smckusick 	vp = ndp->ni_vp;
131337741Smckusick 	if (vp->v_type != VDIR) {
131437741Smckusick 		error = ENOTDIR;
131512756Ssam 		goto out;
131612756Ssam 	}
131712756Ssam 	/*
131837741Smckusick 	 * No rmdir "." please.
131912756Ssam 	 */
132037741Smckusick 	if (ndp->ni_dvp == vp) {
132137741Smckusick 		error = EINVAL;
132212756Ssam 		goto out;
132312756Ssam 	}
132412756Ssam 	/*
132537741Smckusick 	 * Don't unlink a mounted file.
132612756Ssam 	 */
132737741Smckusick 	if (vp->v_flag & VROOT)
132837741Smckusick 		error = EBUSY;
132912756Ssam out:
133037741Smckusick 	if (error)
133137741Smckusick 		VOP_ABORTOP(ndp);
133237741Smckusick 	else
133337741Smckusick 		error = VOP_RMDIR(ndp);
133437741Smckusick 	RETURN (error);
133512756Ssam }
133612756Ssam 
133737741Smckusick /*
133837741Smckusick  * Read a block of directory entries in a file system independent format
133937741Smckusick  */
134038408Smckusick getdirentries(scp)
134138408Smckusick 	register struct syscontext *scp;
134212756Ssam {
134337741Smckusick 	register struct a {
134437741Smckusick 		int	fd;
134537741Smckusick 		char	*buf;
134637741Smckusick 		unsigned count;
134737741Smckusick 		long	*basep;
134838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
134916540Ssam 	struct file *fp;
135037741Smckusick 	struct uio auio;
135137741Smckusick 	struct iovec aiov;
135238129Smckusick 	off_t off;
135337741Smckusick 	int error;
135412756Ssam 
135538408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
135637741Smckusick 		RETURN (error);
135737741Smckusick 	if ((fp->f_flag & FREAD) == 0)
135837741Smckusick 		RETURN (EBADF);
135937741Smckusick 	aiov.iov_base = uap->buf;
136037741Smckusick 	aiov.iov_len = uap->count;
136137741Smckusick 	auio.uio_iov = &aiov;
136237741Smckusick 	auio.uio_iovcnt = 1;
136337741Smckusick 	auio.uio_rw = UIO_READ;
136437741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
136537741Smckusick 	auio.uio_resid = uap->count;
136638129Smckusick 	off = fp->f_offset;
136737741Smckusick 	if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio,
136837741Smckusick 	    &(fp->f_offset), fp->f_cred))
136937741Smckusick 		RETURN (error);
137038129Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep,
137137741Smckusick 		sizeof(long));
137238408Smckusick 	scp->sc_retval1 = uap->count - auio.uio_resid;
137337741Smckusick 	RETURN (error);
137412756Ssam }
137512756Ssam 
137612756Ssam /*
137712756Ssam  * mode mask for creation of files
137812756Ssam  */
137938408Smckusick umask(scp)
138038408Smckusick 	register struct syscontext *scp;
138112756Ssam {
138212756Ssam 	register struct a {
138312756Ssam 		int	mask;
138438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
138512756Ssam 
138638408Smckusick 	scp->sc_retval1 = scp->sc_cmask;
138738408Smckusick 	scp->sc_cmask = uap->mask & 07777;
138837741Smckusick 	RETURN (0);
138912756Ssam }
139037741Smckusick 
139138408Smckusick getvnode(ofile, fdes, fpp)
139238408Smckusick 	struct file *ofile[];
139337741Smckusick 	struct file **fpp;
139437741Smckusick 	int fdes;
139537741Smckusick {
139637741Smckusick 	struct file *fp;
139737741Smckusick 
139838408Smckusick 	if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
139937741Smckusick 		return (EBADF);
140037741Smckusick 	if (fp->f_type != DTYPE_VNODE)
140137741Smckusick 		return (EINVAL);
140237741Smckusick 	*fpp = fp;
140337741Smckusick 	return (0);
140437741Smckusick }
1405