xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 39665)
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*39665Smckusick  *	@(#)vfs_syscalls.c	7.32 (Berkeley) 11/30/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 	}
87*39665Smckusick 	vinvalbuf(vp, 1);
8837741Smckusick 	if (vp->v_count != 1) {
8937741Smckusick 		vput(vp);
9037741Smckusick 		RETURN (EBUSY);
9137741Smckusick 	}
9237741Smckusick 	if (vp->v_type != VDIR) {
9337741Smckusick 		vput(vp);
9437741Smckusick 		RETURN (ENOTDIR);
9537741Smckusick 	}
9637741Smckusick 	if (uap->type > MOUNT_MAXTYPE ||
9737741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
9837741Smckusick 		vput(vp);
9937741Smckusick 		RETURN (ENODEV);
10037741Smckusick 	}
10137741Smckusick 
10237741Smckusick 	/*
10339335Smckusick 	 * Allocate and initialize the file system.
10437741Smckusick 	 */
10537741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
10637741Smckusick 		M_MOUNT, M_WAITOK);
10737741Smckusick 	mp->m_op = vfssw[uap->type];
10837741Smckusick 	mp->m_flag = 0;
10937741Smckusick 	mp->m_exroot = 0;
11039381Smckusick 	mp->m_mounth = (struct vnode *)0;
11139335Smckusick 	if (error = vfs_lock(mp)) {
11239335Smckusick 		free((caddr_t)mp, M_MOUNT);
11339335Smckusick 		vput(vp);
11439335Smckusick 		RETURN (error);
11539335Smckusick 	}
11639335Smckusick 	if (vp->v_mountedhere != (struct mount *)0) {
11739335Smckusick 		vfs_unlock(mp);
11839335Smckusick 		free((caddr_t)mp, M_MOUNT);
11939335Smckusick 		vput(vp);
12039335Smckusick 		RETURN (EBUSY);
12139335Smckusick 	}
12239335Smckusick 	/*
12339335Smckusick 	 * Put the new filesystem on the mount list after root.
12439335Smckusick 	 */
12539335Smckusick 	mp->m_next = rootfs->m_next;
12639335Smckusick 	mp->m_prev = rootfs;
12739335Smckusick 	rootfs->m_next = mp;
12839335Smckusick 	mp->m_next->m_prev = mp;
12939335Smckusick 	vp->v_mountedhere = mp;
13039335Smckusick 	mp->m_vnodecovered = vp;
13139335Smckusick update:
13239335Smckusick 	/*
13339335Smckusick 	 * Set the mount level flags.
13439335Smckusick 	 */
13539335Smckusick 	if (uap->flags & M_RDONLY)
13639335Smckusick 		mp->m_flag |= M_RDONLY;
13739335Smckusick 	else
13839335Smckusick 		mp->m_flag &= ~M_RDONLY;
13939335Smckusick 	if (uap->flags & M_NOSUID)
14039335Smckusick 		mp->m_flag |= M_NOSUID;
14139335Smckusick 	else
14239335Smckusick 		mp->m_flag &= ~M_NOSUID;
14339335Smckusick 	if (uap->flags & M_NOEXEC)
14439335Smckusick 		mp->m_flag |= M_NOEXEC;
14539335Smckusick 	else
14639335Smckusick 		mp->m_flag &= ~M_NOEXEC;
14739335Smckusick 	if (uap->flags & M_NODEV)
14839335Smckusick 		mp->m_flag |= M_NODEV;
14939335Smckusick 	else
15039335Smckusick 		mp->m_flag &= ~M_NODEV;
15139335Smckusick 	if (uap->flags & M_SYNCHRONOUS)
15239335Smckusick 		mp->m_flag |= M_SYNCHRONOUS;
15339335Smckusick 	else
15439335Smckusick 		mp->m_flag &= ~M_SYNCHRONOUS;
15539335Smckusick 	/*
15639335Smckusick 	 * Mount the filesystem.
15739335Smckusick 	 */
15839335Smckusick 	error = VFS_MOUNT(mp, uap->dir, uap->data, ndp);
15939335Smckusick 	if (mp->m_flag & M_UPDATE) {
16039335Smckusick 		mp->m_flag &= ~M_UPDATE;
16139335Smckusick 		vrele(vp);
16239335Smckusick 		RETURN (error);
16339335Smckusick 	}
16437741Smckusick 	cache_purge(vp);
16537741Smckusick 	if (!error) {
16639335Smckusick 		VOP_UNLOCK(vp);
16737741Smckusick 		vfs_unlock(mp);
16839044Smckusick 		error = VFS_START(mp, 0);
16937741Smckusick 	} else {
17037741Smckusick 		vfs_remove(mp);
17137741Smckusick 		free((caddr_t)mp, M_MOUNT);
17239335Smckusick 		vput(vp);
17337741Smckusick 	}
17437741Smckusick 	RETURN (error);
1756254Sroot }
1766254Sroot 
1779167Ssam /*
17837741Smckusick  * Unmount system call.
17937741Smckusick  *
18037741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
18137741Smckusick  * not special file (as before).
1829167Ssam  */
18338408Smckusick unmount(scp)
18438408Smckusick 	register struct syscontext *scp;
1856254Sroot {
18637741Smckusick 	struct a {
18737741Smckusick 		char	*pathp;
18837741Smckusick 		int	flags;
18938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
19037741Smckusick 	register struct vnode *vp;
19138408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
19239356Smckusick 	struct mount *mp;
19337741Smckusick 	int error;
1946254Sroot 
19537741Smckusick 	/*
19637741Smckusick 	 * Must be super user
19737741Smckusick 	 */
19838408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
19937741Smckusick 		RETURN (error);
20037741Smckusick 
20137741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
20237741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
20337741Smckusick 	ndp->ni_dirp = uap->pathp;
20437741Smckusick 	if (error = namei(ndp))
20537741Smckusick 		RETURN (error);
20637741Smckusick 	vp = ndp->ni_vp;
20737741Smckusick 	/*
20837741Smckusick 	 * Must be the root of the filesystem
20937741Smckusick 	 */
21037741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
21137741Smckusick 		vput(vp);
21237741Smckusick 		RETURN (EINVAL);
21337741Smckusick 	}
21437741Smckusick 	mp = vp->v_mount;
21537741Smckusick 	vput(vp);
21639356Smckusick 	RETURN (dounmount(mp, uap->flags));
21739356Smckusick }
21839356Smckusick 
21939356Smckusick /*
22039356Smckusick  * Do an unmount.
22139356Smckusick  */
22239356Smckusick dounmount(mp, flags)
22339356Smckusick 	register struct mount *mp;
22439356Smckusick 	int flags;
22539356Smckusick {
22639356Smckusick 	struct vnode *coveredvp;
22739356Smckusick 	int error;
22839356Smckusick 
22937741Smckusick 	coveredvp = mp->m_vnodecovered;
23037741Smckusick 	if (error = vfs_lock(mp))
23139356Smckusick 		return (error);
23237741Smckusick 
23337741Smckusick 	xumount(mp);		/* remove unused sticky files from text table */
23437741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
23537741Smckusick 	VFS_SYNC(mp, MNT_WAIT);
23637741Smckusick 
23739356Smckusick 	error = VFS_UNMOUNT(mp, flags);
23837741Smckusick 	if (error) {
23937741Smckusick 		vfs_unlock(mp);
24037741Smckusick 	} else {
24137741Smckusick 		vrele(coveredvp);
24237741Smckusick 		vfs_remove(mp);
24337741Smckusick 		free((caddr_t)mp, M_MOUNT);
24437741Smckusick 	}
24539356Smckusick 	return (error);
2466254Sroot }
2476254Sroot 
2489167Ssam /*
24937741Smckusick  * Sync system call.
25037741Smckusick  * Sync each mounted filesystem.
2519167Ssam  */
25239491Smckusick /* ARGSUSED */
25338408Smckusick sync(scp)
25439491Smckusick 	struct syscontext *scp;
2556254Sroot {
25637741Smckusick 	register struct mount *mp;
25737741Smckusick 
25837741Smckusick 	mp = rootfs;
25937741Smckusick 	do {
26037741Smckusick 		if ((mp->m_flag & M_RDONLY) == 0)
26137741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
26237741Smckusick 		mp = mp->m_next;
26337741Smckusick 	} while (mp != rootfs);
26437741Smckusick }
26537741Smckusick 
26637741Smckusick /*
26737741Smckusick  * get filesystem statistics
26837741Smckusick  */
26938408Smckusick statfs(scp)
27038408Smckusick 	register struct syscontext *scp;
27137741Smckusick {
2726254Sroot 	struct a {
27337741Smckusick 		char *path;
27437741Smckusick 		struct statfs *buf;
27538408Smckusick 	} *uap = (struct a *)scp->sc_ap;
27639464Smckusick 	register struct mount *mp;
27738408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
27837741Smckusick 	struct statfs sb;
27937741Smckusick 	int error;
28037741Smckusick 
28139544Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
28237741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
28337741Smckusick 	ndp->ni_dirp = uap->path;
28437741Smckusick 	if (error = namei(ndp))
28537741Smckusick 		RETURN (error);
28639544Smckusick 	mp = ndp->ni_vp->v_mount;
28739544Smckusick 	vrele(ndp->ni_vp);
28839464Smckusick 	if (error = VFS_STATFS(mp, &sb))
28939544Smckusick 		RETURN (error);
29039464Smckusick 	sb.f_flags = mp->m_flag & M_VISFLAGMASK;
29139464Smckusick 	sb.f_fsid = mp->m_fsid;
29239544Smckusick 	RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)));
29337741Smckusick }
29437741Smckusick 
29538408Smckusick fstatfs(scp)
29638408Smckusick 	register struct syscontext *scp;
29737741Smckusick {
29837741Smckusick 	struct a {
29937741Smckusick 		int fd;
30037741Smckusick 		struct statfs *buf;
30138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
30237741Smckusick 	struct file *fp;
30339464Smckusick 	struct mount *mp;
30437741Smckusick 	struct statfs sb;
30537741Smckusick 	int error;
30637741Smckusick 
30738408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
30837741Smckusick 		RETURN (error);
30939464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
31039464Smckusick 	if (error = VFS_STATFS(mp, &sb))
31137741Smckusick 		RETURN (error);
31239464Smckusick 	sb.f_flags = mp->m_flag & M_VISFLAGMASK;
31339464Smckusick 	sb.f_fsid = mp->m_fsid;
31437741Smckusick 	RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)));
31537741Smckusick }
31637741Smckusick 
31737741Smckusick /*
31838270Smckusick  * get statistics on all filesystems
31938270Smckusick  */
32038408Smckusick getfsstat(scp)
32138408Smckusick 	register struct syscontext *scp;
32238270Smckusick {
32338270Smckusick 	struct a {
32438270Smckusick 		struct statfs *buf;
32538270Smckusick 		long bufsize;
32638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
32738270Smckusick 	register struct mount *mp;
32839606Smckusick 	caddr_t sfsp;
32938270Smckusick 	long count, maxcount, error;
33039606Smckusick 	struct statfs sb;
33138270Smckusick 
33238270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
33339606Smckusick 	sfsp = (caddr_t)uap->buf;
33438270Smckusick 	mp = rootfs;
33538270Smckusick 	count = 0;
33638270Smckusick 	do {
33739606Smckusick 		if (sfsp && count < maxcount && ((mp->m_flag & M_MLOCK) == 0)) {
33839607Smckusick 			if (error = VFS_STATFS(mp, &sb)) {
33939607Smckusick 				mp = mp->m_prev;
34039607Smckusick 				continue;
34139607Smckusick 			}
34239606Smckusick 			sb.f_flags = mp->m_flag & M_VISFLAGMASK;
34339606Smckusick 			sb.f_fsid = mp->m_fsid;
34439606Smckusick 			if (error = copyout((caddr_t)&sb, sfsp, sizeof(sb)))
34539606Smckusick 				RETURN (error);
34639606Smckusick 			sfsp += sizeof(sb);
34738270Smckusick 		}
34839606Smckusick 		count++;
34938270Smckusick 		mp = mp->m_prev;
35038270Smckusick 	} while (mp != rootfs);
35138270Smckusick 	if (sfsp && count > maxcount)
35238408Smckusick 		scp->sc_retval1 = maxcount;
35338270Smckusick 	else
35438408Smckusick 		scp->sc_retval1 = count;
35538270Smckusick 	RETURN (0);
35638270Smckusick }
35738270Smckusick 
35838270Smckusick /*
35938259Smckusick  * Change current working directory to a given file descriptor.
36038259Smckusick  */
36138408Smckusick fchdir(scp)
36238408Smckusick 	register struct syscontext *scp;
36338259Smckusick {
36438259Smckusick 	struct a {
36538259Smckusick 		int	fd;
36638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
36738259Smckusick 	register struct vnode *vp;
36838259Smckusick 	struct file *fp;
36938259Smckusick 	int error;
37038259Smckusick 
37138408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
37238259Smckusick 		RETURN (error);
37338259Smckusick 	vp = (struct vnode *)fp->f_data;
37438259Smckusick 	VOP_LOCK(vp);
37538259Smckusick 	if (vp->v_type != VDIR)
37638259Smckusick 		error = ENOTDIR;
37738259Smckusick 	else
37838408Smckusick 		error = VOP_ACCESS(vp, VEXEC, scp->sc_cred);
37938259Smckusick 	VOP_UNLOCK(vp);
38038408Smckusick 	vrele(scp->sc_cdir);
38138408Smckusick 	scp->sc_cdir = vp;
38238259Smckusick 	RETURN (error);
38338259Smckusick }
38438259Smckusick 
38538259Smckusick /*
38637741Smckusick  * Change current working directory (``.'').
38737741Smckusick  */
38838408Smckusick chdir(scp)
38938408Smckusick 	register struct syscontext *scp;
39037741Smckusick {
39137741Smckusick 	struct a {
3926254Sroot 		char	*fname;
39338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
39438408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
39537741Smckusick 	int error;
3966254Sroot 
39737741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
39816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
39916694Smckusick 	ndp->ni_dirp = uap->fname;
40037741Smckusick 	if (error = chdirec(ndp))
40137741Smckusick 		RETURN (error);
40238408Smckusick 	vrele(scp->sc_cdir);
40338408Smckusick 	scp->sc_cdir = ndp->ni_vp;
40437741Smckusick 	RETURN (0);
40537741Smckusick }
4066254Sroot 
40737741Smckusick /*
40837741Smckusick  * Change notion of root (``/'') directory.
40937741Smckusick  */
41038408Smckusick chroot(scp)
41138408Smckusick 	register struct syscontext *scp;
41237741Smckusick {
41337741Smckusick 	struct a {
41437741Smckusick 		char	*fname;
41538408Smckusick 	} *uap = (struct a *)scp->sc_ap;
41638408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
41737741Smckusick 	int error;
41837741Smckusick 
41938408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
42037741Smckusick 		RETURN (error);
42137741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
42237741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
42337741Smckusick 	ndp->ni_dirp = uap->fname;
42437741Smckusick 	if (error = chdirec(ndp))
42537741Smckusick 		RETURN (error);
42639515Smckusick 	if (scp->sc_rdir != NULL)
42739515Smckusick 		vrele(scp->sc_rdir);
42838408Smckusick 	scp->sc_rdir = ndp->ni_vp;
42937741Smckusick 	RETURN (0);
4306254Sroot }
4316254Sroot 
43237Sbill /*
43337741Smckusick  * Common routine for chroot and chdir.
43437741Smckusick  */
43537741Smckusick chdirec(ndp)
43637741Smckusick 	register struct nameidata *ndp;
43737741Smckusick {
43837741Smckusick 	struct vnode *vp;
43937741Smckusick 	int error;
44037741Smckusick 
44137741Smckusick 	if (error = namei(ndp))
44237741Smckusick 		return (error);
44337741Smckusick 	vp = ndp->ni_vp;
44437741Smckusick 	if (vp->v_type != VDIR)
44537741Smckusick 		error = ENOTDIR;
44637741Smckusick 	else
44738399Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
44837741Smckusick 	VOP_UNLOCK(vp);
44937741Smckusick 	if (error)
45037741Smckusick 		vrele(vp);
45137741Smckusick 	return (error);
45237741Smckusick }
45337741Smckusick 
45437741Smckusick /*
4556254Sroot  * Open system call.
4566254Sroot  */
45738408Smckusick open(scp)
45838408Smckusick 	register struct syscontext *scp;
4596254Sroot {
46012756Ssam 	struct a {
4616254Sroot 		char	*fname;
4627701Ssam 		int	mode;
46312756Ssam 		int	crtmode;
46438408Smckusick 	} *uap = (struct a *) scp->sc_ap;
46538408Smckusick 	struct nameidata *ndp = &scp->sc_nd;
4666254Sroot 
46737741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
46837741Smckusick 	ndp->ni_dirp = uap->fname;
46938408Smckusick 	RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp,
47038408Smckusick 		&scp->sc_retval1));
4716254Sroot }
4726254Sroot 
4736254Sroot /*
4746254Sroot  * Creat system call.
4756254Sroot  */
47638408Smckusick creat(scp)
47738408Smckusick 	register struct syscontext *scp;
4786254Sroot {
47912756Ssam 	struct a {
4806254Sroot 		char	*fname;
4816254Sroot 		int	fmode;
48238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
48338408Smckusick 	struct nameidata *ndp = &scp->sc_nd;
4846254Sroot 
48537741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
48637741Smckusick 	ndp->ni_dirp = uap->fname;
48738408Smckusick 	RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask,
48838408Smckusick 		ndp, &scp->sc_retval1));
4896254Sroot }
4906254Sroot 
4916254Sroot /*
4926254Sroot  * Common code for open and creat.
49312756Ssam  * Check permissions, allocate an open file structure,
49412756Ssam  * and call the device open routine if any.
4956254Sroot  */
49638408Smckusick copen(scp, fmode, cmode, ndp, resultfd)
49738408Smckusick 	register struct syscontext *scp;
49837741Smckusick 	int fmode, cmode;
49937741Smckusick 	struct nameidata *ndp;
50037741Smckusick 	int *resultfd;
50112756Ssam {
5026254Sroot 	register struct file *fp;
50337741Smckusick 	struct file *nfp;
50437741Smckusick 	int indx, error;
50537741Smckusick 	extern struct fileops vnops;
5066254Sroot 
50737741Smckusick 	if (error = falloc(&nfp, &indx))
50837741Smckusick 		return (error);
50937741Smckusick 	fp = nfp;
51038408Smckusick 	scp->sc_retval1 = indx;	/* XXX for fdopen() */
51137741Smckusick 	if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) {
51237741Smckusick 		crfree(fp->f_cred);
51337741Smckusick 		fp->f_count--;
51439499Smckusick 		if (error == -1)	/* XXX from fdopen */
51539499Smckusick 			return (0);	/* XXX from fdopen */
51639499Smckusick 		scp->sc_ofile[indx] = NULL;
51737741Smckusick 		return (error);
51812756Ssam 	}
51937741Smckusick 	fp->f_flag = fmode & FMASK;
52037741Smckusick 	fp->f_type = DTYPE_VNODE;
52137741Smckusick 	fp->f_ops = &vnops;
52237741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
52337741Smckusick 	if (resultfd)
52437741Smckusick 		*resultfd = indx;
52537741Smckusick 	return (0);
5266254Sroot }
5276254Sroot 
5286254Sroot /*
5296254Sroot  * Mknod system call
5306254Sroot  */
53138408Smckusick mknod(scp)
53238408Smckusick 	register struct syscontext *scp;
5336254Sroot {
5346254Sroot 	register struct a {
5356254Sroot 		char	*fname;
5366254Sroot 		int	fmode;
5376254Sroot 		int	dev;
53838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
53938408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
54037741Smckusick 	register struct vnode *vp;
54137741Smckusick 	struct vattr vattr;
54237741Smckusick 	int error;
5436254Sroot 
54438408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
54537741Smckusick 		RETURN (error);
54637741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
54716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
54816694Smckusick 	ndp->ni_dirp = uap->fname;
54937741Smckusick 	if (error = namei(ndp))
55037741Smckusick 		RETURN (error);
55137741Smckusick 	vp = ndp->ni_vp;
55237741Smckusick 	if (vp != NULL) {
55337741Smckusick 		error = EEXIST;
55412756Ssam 		goto out;
5556254Sroot 	}
55637741Smckusick 	vattr_null(&vattr);
55737741Smckusick 	switch (uap->fmode & IFMT) {
55812756Ssam 
55915093Smckusick 	case IFMT:	/* used by badsect to flag bad sectors */
56037741Smckusick 		vattr.va_type = VBAD;
56137741Smckusick 		break;
56212756Ssam 	case IFCHR:
56337741Smckusick 		vattr.va_type = VCHR;
56437741Smckusick 		break;
56512756Ssam 	case IFBLK:
56637741Smckusick 		vattr.va_type = VBLK;
56737741Smckusick 		break;
56837741Smckusick 	default:
56937741Smckusick 		error = EINVAL;
57037741Smckusick 		goto out;
5716254Sroot 	}
57238408Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask;
57337741Smckusick 	vattr.va_rdev = uap->dev;
5746254Sroot out:
57537741Smckusick 	if (error)
57637741Smckusick 		VOP_ABORTOP(ndp);
57737741Smckusick 	else
57837741Smckusick 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
57937741Smckusick 	RETURN (error);
5806254Sroot }
5816254Sroot 
5826254Sroot /*
5836254Sroot  * link system call
5846254Sroot  */
58538408Smckusick link(scp)
58638408Smckusick 	register struct syscontext *scp;
5876254Sroot {
5886254Sroot 	register struct a {
5896254Sroot 		char	*target;
5906254Sroot 		char	*linkname;
59138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
59238408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
59337741Smckusick 	register struct vnode *vp, *xp;
59437741Smckusick 	int error;
5956254Sroot 
59616694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
59716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
59816694Smckusick 	ndp->ni_dirp = uap->target;
59937741Smckusick 	if (error = namei(ndp))
60037741Smckusick 		RETURN (error);
60137741Smckusick 	vp = ndp->ni_vp;
60237741Smckusick 	if (vp->v_type == VDIR &&
60338408Smckusick 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
60437741Smckusick 		goto out1;
60537741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
60616694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
60737741Smckusick 	if (error = namei(ndp))
60837741Smckusick 		goto out1;
60937741Smckusick 	xp = ndp->ni_vp;
6106254Sroot 	if (xp != NULL) {
61137741Smckusick 		error = EEXIST;
6126254Sroot 		goto out;
6136254Sroot 	}
61437741Smckusick 	xp = ndp->ni_dvp;
61537741Smckusick 	if (vp->v_mount != xp->v_mount)
61637741Smckusick 		error = EXDEV;
6176254Sroot out:
61837741Smckusick 	if (error)
61937741Smckusick 		VOP_ABORTOP(ndp);
62037741Smckusick 	else
62137741Smckusick 		error = VOP_LINK(vp, ndp);
62237741Smckusick out1:
62337741Smckusick 	vrele(vp);
62437741Smckusick 	RETURN (error);
6256254Sroot }
6266254Sroot 
6276254Sroot /*
6286254Sroot  * symlink -- make a symbolic link
6296254Sroot  */
63038408Smckusick symlink(scp)
63138408Smckusick 	register struct syscontext *scp;
6326254Sroot {
63337741Smckusick 	struct a {
6346254Sroot 		char	*target;
6356254Sroot 		char	*linkname;
63638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
63738408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
63837741Smckusick 	register struct vnode *vp;
63937741Smckusick 	struct vattr vattr;
64037741Smckusick 	char *target;
64137741Smckusick 	int error;
6426254Sroot 
64316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
64416694Smckusick 	ndp->ni_dirp = uap->linkname;
64537741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
64637741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
64737741Smckusick 		goto out1;
64837741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
64937741Smckusick 	if (error = namei(ndp))
65037741Smckusick 		goto out1;
65137741Smckusick 	vp = ndp->ni_vp;
65237741Smckusick 	if (vp) {
65337741Smckusick 		error = EEXIST;
65437741Smckusick 		goto out;
6556254Sroot 	}
65637741Smckusick 	vp = ndp->ni_dvp;
65737741Smckusick 	vattr_null(&vattr);
65838408Smckusick 	vattr.va_mode = 0777 &~ scp->sc_cmask;
65937741Smckusick out:
66037741Smckusick 	if (error)
66137741Smckusick 		VOP_ABORTOP(ndp);
66237741Smckusick 	else
66337741Smckusick 		error = VOP_SYMLINK(ndp, &vattr, target);
66437741Smckusick out1:
66537741Smckusick 	FREE(target, M_NAMEI);
66637741Smckusick 	RETURN (error);
6676254Sroot }
6686254Sroot 
6696254Sroot /*
6706254Sroot  * Unlink system call.
6716254Sroot  * Hard to avoid races here, especially
6726254Sroot  * in unlinking directories.
6736254Sroot  */
67438408Smckusick unlink(scp)
67538408Smckusick 	register struct syscontext *scp;
6766254Sroot {
6776254Sroot 	struct a {
6786254Sroot 		char	*fname;
67938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
68038408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
68137741Smckusick 	register struct vnode *vp;
68237741Smckusick 	int error;
6836254Sroot 
68437741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
68516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
68616694Smckusick 	ndp->ni_dirp = uap->fname;
68737741Smckusick 	if (error = namei(ndp))
68837741Smckusick 		RETURN (error);
68937741Smckusick 	vp = ndp->ni_vp;
69037741Smckusick 	if (vp->v_type == VDIR &&
69138408Smckusick 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
6926254Sroot 		goto out;
6936254Sroot 	/*
6946254Sroot 	 * Don't unlink a mounted file.
6956254Sroot 	 */
69637741Smckusick 	if (vp->v_flag & VROOT) {
69737741Smckusick 		error = EBUSY;
6986254Sroot 		goto out;
6996254Sroot 	}
70037741Smckusick 	if (vp->v_flag & VTEXT)
70137741Smckusick 		xrele(vp);	/* try once to free text */
7026254Sroot out:
70337741Smckusick 	if (error)
70437741Smckusick 		VOP_ABORTOP(ndp);
7057142Smckusick 	else
70637741Smckusick 		error = VOP_REMOVE(ndp);
70737741Smckusick 	RETURN (error);
7086254Sroot }
7096254Sroot 
7106254Sroot /*
7116254Sroot  * Seek system call
7126254Sroot  */
71338408Smckusick lseek(scp)
71438408Smckusick 	register struct syscontext *scp;
7156254Sroot {
7166254Sroot 	register struct file *fp;
7176254Sroot 	register struct a {
71837741Smckusick 		int	fdes;
7196254Sroot 		off_t	off;
7206254Sroot 		int	sbase;
72138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
72237741Smckusick 	struct vattr vattr;
72337741Smckusick 	int error;
7246254Sroot 
72537741Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
72638408Smckusick 	    (fp = scp->sc_ofile[uap->fdes]) == NULL)
72737741Smckusick 		RETURN (EBADF);
72837741Smckusick 	if (fp->f_type != DTYPE_VNODE)
72937741Smckusick 		RETURN (ESPIPE);
73013878Ssam 	switch (uap->sbase) {
73113878Ssam 
73213878Ssam 	case L_INCR:
73313878Ssam 		fp->f_offset += uap->off;
73413878Ssam 		break;
73513878Ssam 
73613878Ssam 	case L_XTND:
73737741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
73838408Smckusick 		    &vattr, scp->sc_cred))
73937741Smckusick 			RETURN (error);
74037741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
74113878Ssam 		break;
74213878Ssam 
74313878Ssam 	case L_SET:
74413878Ssam 		fp->f_offset = uap->off;
74513878Ssam 		break;
74613878Ssam 
74713878Ssam 	default:
74837741Smckusick 		RETURN (EINVAL);
74913878Ssam 	}
75038408Smckusick 	scp->sc_offset = fp->f_offset;
75137741Smckusick 	RETURN (0);
7526254Sroot }
7536254Sroot 
7546254Sroot /*
7556254Sroot  * Access system call
7566254Sroot  */
75738408Smckusick saccess(scp)
75838408Smckusick 	register struct syscontext *scp;
7596254Sroot {
7606254Sroot 	register struct a {
7616254Sroot 		char	*fname;
7626254Sroot 		int	fmode;
76338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
76438408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
76537741Smckusick 	register struct vnode *vp;
76637741Smckusick 	int error, mode, svuid, svgid;
7676254Sroot 
76838408Smckusick 	svuid = scp->sc_uid;
76938408Smckusick 	svgid = scp->sc_gid;
77038408Smckusick 	scp->sc_uid = scp->sc_ruid;
77138408Smckusick 	scp->sc_gid = scp->sc_rgid;
77237741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
77316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
77416694Smckusick 	ndp->ni_dirp = uap->fname;
77537741Smckusick 	if (error = namei(ndp))
77637741Smckusick 		goto out1;
77737741Smckusick 	vp = ndp->ni_vp;
77837741Smckusick 	/*
77937741Smckusick 	 * fmode == 0 means only check for exist
78037741Smckusick 	 */
78137741Smckusick 	if (uap->fmode) {
78237741Smckusick 		mode = 0;
78337741Smckusick 		if (uap->fmode & R_OK)
78437741Smckusick 			mode |= VREAD;
78537741Smckusick 		if (uap->fmode & W_OK)
78637741Smckusick 			mode |= VWRITE;
78737741Smckusick 		if (uap->fmode & X_OK)
78837741Smckusick 			mode |= VEXEC;
78939543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
79038399Smckusick 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
7916254Sroot 	}
79237741Smckusick 	vput(vp);
79337741Smckusick out1:
79438408Smckusick 	scp->sc_uid = svuid;
79538408Smckusick 	scp->sc_gid = svgid;
79637741Smckusick 	RETURN (error);
7976254Sroot }
7986254Sroot 
7996254Sroot /*
8006574Smckusic  * Stat system call.  This version follows links.
80137Sbill  */
80238408Smckusick stat(scp)
80338408Smckusick 	struct syscontext *scp;
80437Sbill {
80537Sbill 
80638408Smckusick 	stat1(scp, FOLLOW);
80737Sbill }
80837Sbill 
80937Sbill /*
8106574Smckusic  * Lstat system call.  This version does not follow links.
8115992Swnj  */
81238408Smckusick lstat(scp)
81338408Smckusick 	struct syscontext *scp;
8145992Swnj {
81512756Ssam 
81638408Smckusick 	stat1(scp, NOFOLLOW);
81712756Ssam }
81812756Ssam 
81938408Smckusick stat1(scp, follow)
82038408Smckusick 	register struct syscontext *scp;
82112756Ssam 	int follow;
82212756Ssam {
8235992Swnj 	register struct a {
8245992Swnj 		char	*fname;
82512756Ssam 		struct stat *ub;
82638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
82738408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
82812756Ssam 	struct stat sb;
82937741Smckusick 	int error;
8305992Swnj 
83137741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
83216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
83316694Smckusick 	ndp->ni_dirp = uap->fname;
83437741Smckusick 	if (error = namei(ndp))
83537741Smckusick 		RETURN (error);
83637741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
83737741Smckusick 	vput(ndp->ni_vp);
83837741Smckusick 	if (error)
83937741Smckusick 		RETURN (error);
84037741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
84137741Smckusick 	RETURN (error);
8425992Swnj }
8435992Swnj 
8445992Swnj /*
8455992Swnj  * Return target name of a symbolic link
84637Sbill  */
84738408Smckusick readlink(scp)
84838408Smckusick 	register struct syscontext *scp;
8495992Swnj {
8505992Swnj 	register struct a {
8515992Swnj 		char	*name;
8525992Swnj 		char	*buf;
8535992Swnj 		int	count;
85438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
85538408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
85637741Smckusick 	register struct vnode *vp;
85737741Smckusick 	struct iovec aiov;
85837741Smckusick 	struct uio auio;
85937741Smckusick 	int error;
8605992Swnj 
86137741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
86216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
86316694Smckusick 	ndp->ni_dirp = uap->name;
86437741Smckusick 	if (error = namei(ndp))
86537741Smckusick 		RETURN (error);
86637741Smckusick 	vp = ndp->ni_vp;
86737741Smckusick 	if (vp->v_type != VLNK) {
86837741Smckusick 		error = EINVAL;
8695992Swnj 		goto out;
8705992Swnj 	}
87137741Smckusick 	aiov.iov_base = uap->buf;
87237741Smckusick 	aiov.iov_len = uap->count;
87337741Smckusick 	auio.uio_iov = &aiov;
87437741Smckusick 	auio.uio_iovcnt = 1;
87537741Smckusick 	auio.uio_offset = 0;
87637741Smckusick 	auio.uio_rw = UIO_READ;
87737741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
87837741Smckusick 	auio.uio_resid = uap->count;
87937741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
8805992Swnj out:
88137741Smckusick 	vput(vp);
88238408Smckusick 	scp->sc_retval1 = uap->count - auio.uio_resid;
88337741Smckusick 	RETURN (error);
8845992Swnj }
8855992Swnj 
8869167Ssam /*
88738259Smckusick  * Change flags of a file given path name.
88838259Smckusick  */
88938408Smckusick chflags(scp)
89038408Smckusick 	register struct syscontext *scp;
89138259Smckusick {
89238259Smckusick 	struct a {
89338259Smckusick 		char	*fname;
89438259Smckusick 		int	flags;
89538408Smckusick 	} *uap = (struct a *)scp->sc_ap;
89638408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
89738259Smckusick 	register struct vnode *vp;
89838259Smckusick 	struct vattr vattr;
89938259Smckusick 	int error;
90038259Smckusick 
90138259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
90238259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
90338259Smckusick 	ndp->ni_dirp = uap->fname;
90438259Smckusick 	vattr_null(&vattr);
90538259Smckusick 	vattr.va_flags = uap->flags;
90638259Smckusick 	if (error = namei(ndp))
90738259Smckusick 		RETURN (error);
90838259Smckusick 	vp = ndp->ni_vp;
90938259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
91038259Smckusick 		error = EROFS;
91138259Smckusick 		goto out;
91238259Smckusick 	}
91338259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
91438259Smckusick out:
91538259Smckusick 	vput(vp);
91638259Smckusick 	RETURN (error);
91738259Smckusick }
91838259Smckusick 
91938259Smckusick /*
92038259Smckusick  * Change flags of a file given a file descriptor.
92138259Smckusick  */
92238408Smckusick fchflags(scp)
92338408Smckusick 	register struct syscontext *scp;
92438259Smckusick {
92538259Smckusick 	struct a {
92638259Smckusick 		int	fd;
92738259Smckusick 		int	flags;
92838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
92938259Smckusick 	struct vattr vattr;
93038259Smckusick 	struct vnode *vp;
93138259Smckusick 	struct file *fp;
93238259Smckusick 	int error;
93338259Smckusick 
93438408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
93538259Smckusick 		RETURN (error);
93638259Smckusick 	vattr_null(&vattr);
93738259Smckusick 	vattr.va_flags = uap->flags;
93838259Smckusick 	vp = (struct vnode *)fp->f_data;
93938259Smckusick 	VOP_LOCK(vp);
94038259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
94138259Smckusick 		error = EROFS;
94238259Smckusick 		goto out;
94338259Smckusick 	}
94438259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
94538259Smckusick out:
94638259Smckusick 	VOP_UNLOCK(vp);
94738259Smckusick 	RETURN (error);
94838259Smckusick }
94938259Smckusick 
95038259Smckusick /*
9519167Ssam  * Change mode of a file given path name.
9529167Ssam  */
95338408Smckusick chmod(scp)
95438408Smckusick 	register struct syscontext *scp;
9555992Swnj {
9567701Ssam 	struct a {
9576254Sroot 		char	*fname;
9586254Sroot 		int	fmode;
95938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
96038408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
96137741Smckusick 	register struct vnode *vp;
96237741Smckusick 	struct vattr vattr;
96337741Smckusick 	int error;
9645992Swnj 
96537741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
96637741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
96737741Smckusick 	ndp->ni_dirp = uap->fname;
96837741Smckusick 	vattr_null(&vattr);
96937741Smckusick 	vattr.va_mode = uap->fmode & 07777;
97037741Smckusick 	if (error = namei(ndp))
97137741Smckusick 		RETURN (error);
97237741Smckusick 	vp = ndp->ni_vp;
97337741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
97437741Smckusick 		error = EROFS;
97537741Smckusick 		goto out;
97637741Smckusick 	}
97737741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
97837741Smckusick out:
97937741Smckusick 	vput(vp);
98037741Smckusick 	RETURN (error);
9817701Ssam }
9827439Sroot 
9839167Ssam /*
9849167Ssam  * Change mode of a file given a file descriptor.
9859167Ssam  */
98638408Smckusick fchmod(scp)
98738408Smckusick 	register struct syscontext *scp;
9887701Ssam {
9897701Ssam 	struct a {
9907701Ssam 		int	fd;
9917701Ssam 		int	fmode;
99238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
99337741Smckusick 	struct vattr vattr;
99437741Smckusick 	struct vnode *vp;
99537741Smckusick 	struct file *fp;
99637741Smckusick 	int error;
9977701Ssam 
99838408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
99937741Smckusick 		RETURN (error);
100037741Smckusick 	vattr_null(&vattr);
100137741Smckusick 	vattr.va_mode = uap->fmode & 07777;
100237741Smckusick 	vp = (struct vnode *)fp->f_data;
100337741Smckusick 	VOP_LOCK(vp);
100437741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
100537741Smckusick 		error = EROFS;
100637741Smckusick 		goto out;
10077439Sroot 	}
100837741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
100937741Smckusick out:
101037741Smckusick 	VOP_UNLOCK(vp);
101137741Smckusick 	RETURN (error);
10125992Swnj }
10135992Swnj 
10149167Ssam /*
10159167Ssam  * Set ownership given a path name.
10169167Ssam  */
101738408Smckusick chown(scp)
101838408Smckusick 	register struct syscontext *scp;
101937Sbill {
10207701Ssam 	struct a {
10216254Sroot 		char	*fname;
10226254Sroot 		int	uid;
10236254Sroot 		int	gid;
102438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
102538408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
102637741Smckusick 	register struct vnode *vp;
102737741Smckusick 	struct vattr vattr;
102837741Smckusick 	int error;
102937Sbill 
103037741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
103136614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
103236614Sbostic 	ndp->ni_dirp = uap->fname;
103337741Smckusick 	vattr_null(&vattr);
103437741Smckusick 	vattr.va_uid = uap->uid;
103537741Smckusick 	vattr.va_gid = uap->gid;
103637741Smckusick 	if (error = namei(ndp))
103737741Smckusick 		RETURN (error);
103837741Smckusick 	vp = ndp->ni_vp;
103937741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
104037741Smckusick 		error = EROFS;
104137741Smckusick 		goto out;
104237741Smckusick 	}
104337741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
104437741Smckusick out:
104537741Smckusick 	vput(vp);
104637741Smckusick 	RETURN (error);
10477701Ssam }
10487439Sroot 
10499167Ssam /*
10509167Ssam  * Set ownership given a file descriptor.
10519167Ssam  */
105238408Smckusick fchown(scp)
105338408Smckusick 	register struct syscontext *scp;
10547701Ssam {
10557701Ssam 	struct a {
10567701Ssam 		int	fd;
10577701Ssam 		int	uid;
10587701Ssam 		int	gid;
105938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
106037741Smckusick 	struct vattr vattr;
106137741Smckusick 	struct vnode *vp;
106237741Smckusick 	struct file *fp;
106337741Smckusick 	int error;
10647701Ssam 
106538408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
106637741Smckusick 		RETURN (error);
106737741Smckusick 	vattr_null(&vattr);
106837741Smckusick 	vattr.va_uid = uap->uid;
106937741Smckusick 	vattr.va_gid = uap->gid;
107037741Smckusick 	vp = (struct vnode *)fp->f_data;
107137741Smckusick 	VOP_LOCK(vp);
107237741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
107337741Smckusick 		error = EROFS;
107437741Smckusick 		goto out;
107537741Smckusick 	}
107637741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
107737741Smckusick out:
107837741Smckusick 	VOP_UNLOCK(vp);
107937741Smckusick 	RETURN (error);
10807701Ssam }
10817701Ssam 
108238408Smckusick utimes(scp)
108338408Smckusick 	register struct syscontext *scp;
108411811Ssam {
108511811Ssam 	register struct a {
108611811Ssam 		char	*fname;
108711811Ssam 		struct	timeval *tptr;
108838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
108938408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
109037741Smckusick 	register struct vnode *vp;
109111811Ssam 	struct timeval tv[2];
109237741Smckusick 	struct vattr vattr;
109337741Smckusick 	int error;
109411811Ssam 
109537741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
109637741Smckusick 		RETURN (error);
109737741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
109837741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
109937741Smckusick 	ndp->ni_dirp = uap->fname;
110037741Smckusick 	vattr_null(&vattr);
110137741Smckusick 	vattr.va_atime = tv[0];
110237741Smckusick 	vattr.va_mtime = tv[1];
110337741Smckusick 	if (error = namei(ndp))
110437741Smckusick 		RETURN (error);
110537741Smckusick 	vp = ndp->ni_vp;
110637741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
110737741Smckusick 		error = EROFS;
110837741Smckusick 		goto out;
110921015Smckusick 	}
111037741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
111137741Smckusick out:
111237741Smckusick 	vput(vp);
111337741Smckusick 	RETURN (error);
111411811Ssam }
111511811Ssam 
11169167Ssam /*
11179167Ssam  * Truncate a file given its path name.
11189167Ssam  */
111938408Smckusick truncate(scp)
112038408Smckusick 	register struct syscontext *scp;
11217701Ssam {
11227701Ssam 	struct a {
11237701Ssam 		char	*fname;
112426473Skarels 		off_t	length;
112538408Smckusick 	} *uap = (struct a *)scp->sc_ap;
112638408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
112737741Smckusick 	register struct vnode *vp;
112837741Smckusick 	struct vattr vattr;
112937741Smckusick 	int error;
11307701Ssam 
113137741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
113216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
113316694Smckusick 	ndp->ni_dirp = uap->fname;
113437741Smckusick 	vattr_null(&vattr);
113537741Smckusick 	vattr.va_size = uap->length;
113637741Smckusick 	if (error = namei(ndp))
113737741Smckusick 		RETURN (error);
113837741Smckusick 	vp = ndp->ni_vp;
113937741Smckusick 	if (vp->v_type == VDIR) {
114037741Smckusick 		error = EISDIR;
114137741Smckusick 		goto out;
11427701Ssam 	}
114338399Smckusick 	if ((error = vn_writechk(vp)) ||
114438399Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
114537741Smckusick 		goto out;
114637741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
114737741Smckusick out:
114837741Smckusick 	vput(vp);
114937741Smckusick 	RETURN (error);
11507701Ssam }
11517701Ssam 
11529167Ssam /*
11539167Ssam  * Truncate a file given a file descriptor.
11549167Ssam  */
115538408Smckusick ftruncate(scp)
115638408Smckusick 	register struct syscontext *scp;
11577701Ssam {
11587701Ssam 	struct a {
11597701Ssam 		int	fd;
116026473Skarels 		off_t	length;
116138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
116237741Smckusick 	struct vattr vattr;
116337741Smckusick 	struct vnode *vp;
11647701Ssam 	struct file *fp;
116537741Smckusick 	int error;
11667701Ssam 
116738408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
116837741Smckusick 		RETURN (error);
116937741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
117037741Smckusick 		RETURN (EINVAL);
117137741Smckusick 	vattr_null(&vattr);
117237741Smckusick 	vattr.va_size = uap->length;
117337741Smckusick 	vp = (struct vnode *)fp->f_data;
117437741Smckusick 	VOP_LOCK(vp);
117537741Smckusick 	if (vp->v_type == VDIR) {
117637741Smckusick 		error = EISDIR;
117737741Smckusick 		goto out;
11787701Ssam 	}
117938399Smckusick 	if (error = vn_writechk(vp))
118037741Smckusick 		goto out;
118137741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
118237741Smckusick out:
118337741Smckusick 	VOP_UNLOCK(vp);
118437741Smckusick 	RETURN (error);
11857701Ssam }
11867701Ssam 
11879167Ssam /*
11889167Ssam  * Synch an open file.
11899167Ssam  */
119038408Smckusick fsync(scp)
119138408Smckusick 	register struct syscontext *scp;
11929167Ssam {
11939167Ssam 	struct a {
11949167Ssam 		int	fd;
119538408Smckusick 	} *uap = (struct a *)scp->sc_ap;
119639592Smckusick 	register struct vnode *vp;
11979167Ssam 	struct file *fp;
119837741Smckusick 	int error;
11999167Ssam 
120038408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
120137741Smckusick 		RETURN (error);
120239592Smckusick 	vp = (struct vnode *)fp->f_data;
120339592Smckusick 	VOP_LOCK(vp);
120439592Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT);
120539592Smckusick 	VOP_UNLOCK(vp);
120637741Smckusick 	RETURN (error);
12079167Ssam }
12089167Ssam 
12099167Ssam /*
12109167Ssam  * Rename system call.
12119167Ssam  *
12129167Ssam  * Source and destination must either both be directories, or both
12139167Ssam  * not be directories.  If target is a directory, it must be empty.
12149167Ssam  */
121538408Smckusick rename(scp)
121638408Smckusick 	register struct syscontext *scp;
12177701Ssam {
12187701Ssam 	struct a {
12197701Ssam 		char	*from;
12207701Ssam 		char	*to;
122138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
122237741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
122338408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
122437741Smckusick 	struct nameidata tond;
122537741Smckusick 	int error;
12267701Ssam 
122737741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
122816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
122916694Smckusick 	ndp->ni_dirp = uap->from;
123037741Smckusick 	if (error = namei(ndp))
123137741Smckusick 		RETURN (error);
123237741Smckusick 	fvp = ndp->ni_vp;
123338266Smckusick 	nddup(ndp, &tond);
123437741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
123537741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
123637741Smckusick 	tond.ni_dirp = uap->to;
123737741Smckusick 	error = namei(&tond);
123837741Smckusick 	tdvp = tond.ni_dvp;
123937741Smckusick 	tvp = tond.ni_vp;
124037741Smckusick 	if (tvp != NULL) {
124137741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
124239242Sbostic 			error = ENOTDIR;
124337741Smckusick 			goto out;
124437741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
124539242Sbostic 			error = EISDIR;
124637741Smckusick 			goto out;
12479167Ssam 		}
12489167Ssam 	}
124937741Smckusick 	if (error) {
125037741Smckusick 		VOP_ABORTOP(ndp);
125137741Smckusick 		goto out1;
125237741Smckusick 	}
125337741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
125437741Smckusick 		error = EXDEV;
12559167Ssam 		goto out;
125610051Ssam 	}
125739286Smckusick 	if (fvp == tdvp)
125837741Smckusick 		error = EINVAL;
125939286Smckusick 	/*
126039286Smckusick 	 * If source is the same as the destination,
126139286Smckusick 	 * then there is nothing to do.
126239286Smckusick 	 */
126339286Smckusick 	if (fvp == tvp)
126439286Smckusick 		error = -1;
126537741Smckusick out:
126637741Smckusick 	if (error) {
126737741Smckusick 		VOP_ABORTOP(&tond);
126837741Smckusick 		VOP_ABORTOP(ndp);
12699167Ssam 	} else {
127037741Smckusick 		error = VOP_RENAME(ndp, &tond);
12719167Ssam 	}
127237741Smckusick out1:
127338266Smckusick 	ndrele(&tond);
127439286Smckusick 	if (error == -1)
127539286Smckusick 		RETURN (0);
127637741Smckusick 	RETURN (error);
12777701Ssam }
12787701Ssam 
12797535Sroot /*
128012756Ssam  * Mkdir system call
128112756Ssam  */
128238408Smckusick mkdir(scp)
128338408Smckusick 	register struct syscontext *scp;
128412756Ssam {
128512756Ssam 	struct a {
128612756Ssam 		char	*name;
128712756Ssam 		int	dmode;
128838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
128938408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
129037741Smckusick 	register struct vnode *vp;
129137741Smckusick 	struct vattr vattr;
129237741Smckusick 	int error;
129312756Ssam 
129437741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
129516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
129616694Smckusick 	ndp->ni_dirp = uap->name;
129737741Smckusick 	if (error = namei(ndp))
129837741Smckusick 		RETURN (error);
129937741Smckusick 	vp = ndp->ni_vp;
130037741Smckusick 	if (vp != NULL) {
130137741Smckusick 		VOP_ABORTOP(ndp);
130237741Smckusick 		RETURN (EEXIST);
130312756Ssam 	}
130437741Smckusick 	vattr_null(&vattr);
130537741Smckusick 	vattr.va_type = VDIR;
130638408Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask;
130737741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
130838145Smckusick 	if (!error)
130938145Smckusick 		vput(ndp->ni_vp);
131037741Smckusick 	RETURN (error);
131112756Ssam }
131212756Ssam 
131312756Ssam /*
131412756Ssam  * Rmdir system call.
131512756Ssam  */
131638408Smckusick rmdir(scp)
131738408Smckusick 	register struct syscontext *scp;
131812756Ssam {
131912756Ssam 	struct a {
132012756Ssam 		char	*name;
132138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
132238408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
132337741Smckusick 	register struct vnode *vp;
132437741Smckusick 	int error;
132512756Ssam 
132637741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
132716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
132816694Smckusick 	ndp->ni_dirp = uap->name;
132937741Smckusick 	if (error = namei(ndp))
133037741Smckusick 		RETURN (error);
133137741Smckusick 	vp = ndp->ni_vp;
133237741Smckusick 	if (vp->v_type != VDIR) {
133337741Smckusick 		error = ENOTDIR;
133412756Ssam 		goto out;
133512756Ssam 	}
133612756Ssam 	/*
133737741Smckusick 	 * No rmdir "." please.
133812756Ssam 	 */
133937741Smckusick 	if (ndp->ni_dvp == vp) {
134037741Smckusick 		error = EINVAL;
134112756Ssam 		goto out;
134212756Ssam 	}
134312756Ssam 	/*
134437741Smckusick 	 * Don't unlink a mounted file.
134512756Ssam 	 */
134637741Smckusick 	if (vp->v_flag & VROOT)
134737741Smckusick 		error = EBUSY;
134812756Ssam out:
134937741Smckusick 	if (error)
135037741Smckusick 		VOP_ABORTOP(ndp);
135137741Smckusick 	else
135237741Smckusick 		error = VOP_RMDIR(ndp);
135337741Smckusick 	RETURN (error);
135412756Ssam }
135512756Ssam 
135637741Smckusick /*
135737741Smckusick  * Read a block of directory entries in a file system independent format
135837741Smckusick  */
135938408Smckusick getdirentries(scp)
136038408Smckusick 	register struct syscontext *scp;
136112756Ssam {
136237741Smckusick 	register struct a {
136337741Smckusick 		int	fd;
136437741Smckusick 		char	*buf;
136537741Smckusick 		unsigned count;
136637741Smckusick 		long	*basep;
136738408Smckusick 	} *uap = (struct a *)scp->sc_ap;
136839592Smckusick 	register struct vnode *vp;
136916540Ssam 	struct file *fp;
137037741Smckusick 	struct uio auio;
137137741Smckusick 	struct iovec aiov;
137238129Smckusick 	off_t off;
137337741Smckusick 	int error;
137412756Ssam 
137538408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
137637741Smckusick 		RETURN (error);
137737741Smckusick 	if ((fp->f_flag & FREAD) == 0)
137837741Smckusick 		RETURN (EBADF);
137939592Smckusick 	vp = (struct vnode *)fp->f_data;
138039592Smckusick 	if (vp->v_type != VDIR)
138139592Smckusick 		RETURN (EINVAL);
138237741Smckusick 	aiov.iov_base = uap->buf;
138337741Smckusick 	aiov.iov_len = uap->count;
138437741Smckusick 	auio.uio_iov = &aiov;
138537741Smckusick 	auio.uio_iovcnt = 1;
138637741Smckusick 	auio.uio_rw = UIO_READ;
138737741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
138837741Smckusick 	auio.uio_resid = uap->count;
138939592Smckusick 	VOP_LOCK(vp);
139039592Smckusick 	auio.uio_offset = off = fp->f_offset;
139139592Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred);
139239592Smckusick 	fp->f_offset = auio.uio_offset;
139339592Smckusick 	VOP_UNLOCK(vp);
139439592Smckusick 	if (error)
139537741Smckusick 		RETURN (error);
139639592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
139738408Smckusick 	scp->sc_retval1 = uap->count - auio.uio_resid;
139837741Smckusick 	RETURN (error);
139912756Ssam }
140012756Ssam 
140112756Ssam /*
140212756Ssam  * mode mask for creation of files
140312756Ssam  */
140438408Smckusick umask(scp)
140538408Smckusick 	register struct syscontext *scp;
140612756Ssam {
140712756Ssam 	register struct a {
140812756Ssam 		int	mask;
140938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
141012756Ssam 
141138408Smckusick 	scp->sc_retval1 = scp->sc_cmask;
141238408Smckusick 	scp->sc_cmask = uap->mask & 07777;
141337741Smckusick 	RETURN (0);
141412756Ssam }
141537741Smckusick 
141639566Smarc /*
141739566Smarc  * Void all references to file by ripping underlying filesystem
141839566Smarc  * away from vnode.
141939566Smarc  */
142039566Smarc revoke(scp)
142139566Smarc 	register struct syscontext *scp;
142239566Smarc {
142339566Smarc 	struct a {
142439566Smarc 		char	*fname;
142539566Smarc 	} *uap = (struct a *)scp->sc_ap;
142639566Smarc 	register struct nameidata *ndp = &scp->sc_nd;
142739566Smarc 	register struct vnode *vp;
142839566Smarc 	struct vattr vattr;
142939566Smarc 	int error;
143039566Smarc 
143139566Smarc 	ndp->ni_nameiop = LOOKUP | FOLLOW;
143239566Smarc 	ndp->ni_segflg = UIO_USERSPACE;
143339566Smarc 	ndp->ni_dirp = uap->fname;
143439566Smarc 	if (error = namei(ndp))
143539566Smarc 		RETURN (error);
143639566Smarc 	vp = ndp->ni_vp;
143739566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
143839566Smarc 		error = EINVAL;
143939566Smarc 		goto out;
144039566Smarc 	}
144139566Smarc 	if (error = VOP_GETATTR(vp, &vattr, scp->sc_cred))
144239566Smarc 		goto out;
144339566Smarc 	if (scp->sc_uid != vattr.va_uid ||
144439566Smarc 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
144539566Smarc 		goto out;
144639632Smckusick 	if (vp->v_count > 1 || (vp->v_flag & VALIASED))
144739632Smckusick 		vgoneall(vp);
144839566Smarc out:
144939566Smarc 	vrele(vp);
145039566Smarc 	RETURN (error);
145139566Smarc }
145239566Smarc 
145338408Smckusick getvnode(ofile, fdes, fpp)
145438408Smckusick 	struct file *ofile[];
145537741Smckusick 	struct file **fpp;
145637741Smckusick 	int fdes;
145737741Smckusick {
145837741Smckusick 	struct file *fp;
145937741Smckusick 
146038408Smckusick 	if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
146137741Smckusick 		return (EBADF);
146237741Smckusick 	if (fp->f_type != DTYPE_VNODE)
146337741Smckusick 		return (EINVAL);
146437741Smckusick 	*fpp = fp;
146537741Smckusick 	return (0);
146637741Smckusick }
1467