xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 39499)
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*39499Smckusick  *	@(#)vfs_syscalls.c	7.23 (Berkeley) 11/09/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;
10939381Smckusick 	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  */
25139491Smckusick /* ARGSUSED */
25238408Smckusick sync(scp)
25339491Smckusick 	struct syscontext *scp;
2546254Sroot {
25537741Smckusick 	register struct mount *mp;
25637741Smckusick 
25737741Smckusick 	mp = rootfs;
25837741Smckusick 	do {
25937741Smckusick 		if ((mp->m_flag & M_RDONLY) == 0)
26037741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
26137741Smckusick 		mp = mp->m_next;
26237741Smckusick 	} while (mp != rootfs);
26337741Smckusick }
26437741Smckusick 
26537741Smckusick /*
26637741Smckusick  * get filesystem statistics
26737741Smckusick  */
26838408Smckusick statfs(scp)
26938408Smckusick 	register struct syscontext *scp;
27037741Smckusick {
2716254Sroot 	struct a {
27237741Smckusick 		char *path;
27337741Smckusick 		struct statfs *buf;
27438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
27537741Smckusick 	register struct vnode *vp;
27639464Smckusick 	register struct mount *mp;
27738408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
27837741Smckusick 	struct statfs sb;
27937741Smckusick 	int error;
28037741Smckusick 
28137741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
28237741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
28337741Smckusick 	ndp->ni_dirp = uap->path;
28437741Smckusick 	if (error = namei(ndp))
28537741Smckusick 		RETURN (error);
28637741Smckusick 	vp = ndp->ni_vp;
28739464Smckusick 	mp = vp->v_mount;
28839464Smckusick 	if (error = VFS_STATFS(mp, &sb))
28937741Smckusick 		goto out;
29039464Smckusick 	sb.f_flags = mp->m_flag & M_VISFLAGMASK;
29139464Smckusick 	sb.f_fsid = mp->m_fsid;
29237741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb));
29337741Smckusick out:
29437741Smckusick 	vput(vp);
29537741Smckusick 	RETURN (error);
29637741Smckusick }
29737741Smckusick 
29838408Smckusick fstatfs(scp)
29938408Smckusick 	register struct syscontext *scp;
30037741Smckusick {
30137741Smckusick 	struct a {
30237741Smckusick 		int fd;
30337741Smckusick 		struct statfs *buf;
30438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
30537741Smckusick 	struct file *fp;
30639464Smckusick 	struct mount *mp;
30737741Smckusick 	struct statfs sb;
30837741Smckusick 	int error;
30937741Smckusick 
31038408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
31137741Smckusick 		RETURN (error);
31239464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
31339464Smckusick 	if (error = VFS_STATFS(mp, &sb))
31437741Smckusick 		RETURN (error);
31539464Smckusick 	sb.f_flags = mp->m_flag & M_VISFLAGMASK;
31639464Smckusick 	sb.f_fsid = mp->m_fsid;
31737741Smckusick 	RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)));
31837741Smckusick }
31937741Smckusick 
32037741Smckusick /*
32138270Smckusick  * get statistics on all filesystems
32238270Smckusick  */
32338408Smckusick getfsstat(scp)
32438408Smckusick 	register struct syscontext *scp;
32538270Smckusick {
32638270Smckusick 	struct a {
32738270Smckusick 		struct statfs *buf;
32838270Smckusick 		long bufsize;
32938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
33038270Smckusick 	register struct mount *mp;
33138270Smckusick 	register struct statfs *sfsp;
33238270Smckusick 	long count, maxcount, error;
33338270Smckusick 
33438270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
33538270Smckusick 	sfsp = uap->buf;
33638270Smckusick 	mp = rootfs;
33738270Smckusick 	count = 0;
33838270Smckusick 	do {
33938270Smckusick 		count++;
34039044Smckusick 		if (sfsp && count <= maxcount &&
34139044Smckusick 		    ((mp->m_flag & M_MLOCK) == 0)) {
34238270Smckusick 			if (error = VFS_STATFS(mp, sfsp))
34338270Smckusick 				RETURN (error);
34439464Smckusick 			sfsp->f_flags = mp->m_flag & M_VISFLAGMASK;
34539464Smckusick 			sfsp->f_fsid = mp->m_fsid;
34638270Smckusick 			sfsp++;
34738270Smckusick 		}
34838270Smckusick 		mp = mp->m_prev;
34938270Smckusick 	} while (mp != rootfs);
35038270Smckusick 	if (sfsp && count > maxcount)
35138408Smckusick 		scp->sc_retval1 = maxcount;
35238270Smckusick 	else
35338408Smckusick 		scp->sc_retval1 = count;
35438270Smckusick 	RETURN (0);
35538270Smckusick }
35638270Smckusick 
35738270Smckusick /*
35838259Smckusick  * Change current working directory to a given file descriptor.
35938259Smckusick  */
36038408Smckusick fchdir(scp)
36138408Smckusick 	register struct syscontext *scp;
36238259Smckusick {
36338259Smckusick 	struct a {
36438259Smckusick 		int	fd;
36538408Smckusick 	} *uap = (struct a *)scp->sc_ap;
36638259Smckusick 	register struct vnode *vp;
36738259Smckusick 	struct file *fp;
36838259Smckusick 	int error;
36938259Smckusick 
37038408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
37138259Smckusick 		RETURN (error);
37238259Smckusick 	vp = (struct vnode *)fp->f_data;
37338259Smckusick 	VOP_LOCK(vp);
37438259Smckusick 	if (vp->v_type != VDIR)
37538259Smckusick 		error = ENOTDIR;
37638259Smckusick 	else
37738408Smckusick 		error = VOP_ACCESS(vp, VEXEC, scp->sc_cred);
37838259Smckusick 	VOP_UNLOCK(vp);
37938408Smckusick 	vrele(scp->sc_cdir);
38038408Smckusick 	scp->sc_cdir = vp;
38138259Smckusick 	RETURN (error);
38238259Smckusick }
38338259Smckusick 
38438259Smckusick /*
38537741Smckusick  * Change current working directory (``.'').
38637741Smckusick  */
38738408Smckusick chdir(scp)
38838408Smckusick 	register struct syscontext *scp;
38937741Smckusick {
39037741Smckusick 	struct a {
3916254Sroot 		char	*fname;
39238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
39338408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
39437741Smckusick 	int error;
3956254Sroot 
39637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
39716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
39816694Smckusick 	ndp->ni_dirp = uap->fname;
39937741Smckusick 	if (error = chdirec(ndp))
40037741Smckusick 		RETURN (error);
40138408Smckusick 	vrele(scp->sc_cdir);
40238408Smckusick 	scp->sc_cdir = ndp->ni_vp;
40337741Smckusick 	RETURN (0);
40437741Smckusick }
4056254Sroot 
40637741Smckusick /*
40737741Smckusick  * Change notion of root (``/'') directory.
40837741Smckusick  */
40938408Smckusick chroot(scp)
41038408Smckusick 	register struct syscontext *scp;
41137741Smckusick {
41237741Smckusick 	struct a {
41337741Smckusick 		char	*fname;
41438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
41538408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
41637741Smckusick 	int error;
41737741Smckusick 
41838408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
41937741Smckusick 		RETURN (error);
42037741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
42137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
42237741Smckusick 	ndp->ni_dirp = uap->fname;
42337741Smckusick 	if (error = chdirec(ndp))
42437741Smckusick 		RETURN (error);
42538408Smckusick 	vrele(scp->sc_rdir);
42638408Smckusick 	scp->sc_rdir = ndp->ni_vp;
42737741Smckusick 	RETURN (0);
4286254Sroot }
4296254Sroot 
43037Sbill /*
43137741Smckusick  * Common routine for chroot and chdir.
43237741Smckusick  */
43337741Smckusick chdirec(ndp)
43437741Smckusick 	register struct nameidata *ndp;
43537741Smckusick {
43637741Smckusick 	struct vnode *vp;
43737741Smckusick 	int error;
43837741Smckusick 
43937741Smckusick 	if (error = namei(ndp))
44037741Smckusick 		return (error);
44137741Smckusick 	vp = ndp->ni_vp;
44237741Smckusick 	if (vp->v_type != VDIR)
44337741Smckusick 		error = ENOTDIR;
44437741Smckusick 	else
44538399Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
44637741Smckusick 	VOP_UNLOCK(vp);
44737741Smckusick 	if (error)
44837741Smckusick 		vrele(vp);
44937741Smckusick 	return (error);
45037741Smckusick }
45137741Smckusick 
45237741Smckusick /*
4536254Sroot  * Open system call.
4546254Sroot  */
45538408Smckusick open(scp)
45638408Smckusick 	register struct syscontext *scp;
4576254Sroot {
45812756Ssam 	struct a {
4596254Sroot 		char	*fname;
4607701Ssam 		int	mode;
46112756Ssam 		int	crtmode;
46238408Smckusick 	} *uap = (struct a *) scp->sc_ap;
46338408Smckusick 	struct nameidata *ndp = &scp->sc_nd;
4646254Sroot 
46537741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
46637741Smckusick 	ndp->ni_dirp = uap->fname;
46738408Smckusick 	RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp,
46838408Smckusick 		&scp->sc_retval1));
4696254Sroot }
4706254Sroot 
4716254Sroot /*
4726254Sroot  * Creat system call.
4736254Sroot  */
47438408Smckusick creat(scp)
47538408Smckusick 	register struct syscontext *scp;
4766254Sroot {
47712756Ssam 	struct a {
4786254Sroot 		char	*fname;
4796254Sroot 		int	fmode;
48038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
48138408Smckusick 	struct nameidata *ndp = &scp->sc_nd;
4826254Sroot 
48337741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
48437741Smckusick 	ndp->ni_dirp = uap->fname;
48538408Smckusick 	RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask,
48638408Smckusick 		ndp, &scp->sc_retval1));
4876254Sroot }
4886254Sroot 
4896254Sroot /*
4906254Sroot  * Common code for open and creat.
49112756Ssam  * Check permissions, allocate an open file structure,
49212756Ssam  * and call the device open routine if any.
4936254Sroot  */
49438408Smckusick copen(scp, fmode, cmode, ndp, resultfd)
49538408Smckusick 	register struct syscontext *scp;
49637741Smckusick 	int fmode, cmode;
49737741Smckusick 	struct nameidata *ndp;
49837741Smckusick 	int *resultfd;
49912756Ssam {
5006254Sroot 	register struct file *fp;
50137741Smckusick 	struct file *nfp;
50237741Smckusick 	int indx, error;
50337741Smckusick 	extern struct fileops vnops;
5046254Sroot 
50537741Smckusick 	if (error = falloc(&nfp, &indx))
50637741Smckusick 		return (error);
50737741Smckusick 	fp = nfp;
50838408Smckusick 	scp->sc_retval1 = indx;	/* XXX for fdopen() */
50937741Smckusick 	if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) {
51037741Smckusick 		crfree(fp->f_cred);
51137741Smckusick 		fp->f_count--;
512*39499Smckusick 		if (error == -1)	/* XXX from fdopen */
513*39499Smckusick 			return (0);	/* XXX from fdopen */
514*39499Smckusick 		scp->sc_ofile[indx] = NULL;
51537741Smckusick 		return (error);
51612756Ssam 	}
51737741Smckusick 	fp->f_flag = fmode & FMASK;
51837741Smckusick 	fp->f_type = DTYPE_VNODE;
51937741Smckusick 	fp->f_ops = &vnops;
52037741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
52137741Smckusick 	if (resultfd)
52237741Smckusick 		*resultfd = indx;
52337741Smckusick 	return (0);
5246254Sroot }
5256254Sroot 
5266254Sroot /*
5276254Sroot  * Mknod system call
5286254Sroot  */
52938408Smckusick mknod(scp)
53038408Smckusick 	register struct syscontext *scp;
5316254Sroot {
5326254Sroot 	register struct a {
5336254Sroot 		char	*fname;
5346254Sroot 		int	fmode;
5356254Sroot 		int	dev;
53638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
53738408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
53837741Smckusick 	register struct vnode *vp;
53937741Smckusick 	struct vattr vattr;
54037741Smckusick 	int error;
5416254Sroot 
54238408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
54337741Smckusick 		RETURN (error);
54437741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
54516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
54616694Smckusick 	ndp->ni_dirp = uap->fname;
54737741Smckusick 	if (error = namei(ndp))
54837741Smckusick 		RETURN (error);
54937741Smckusick 	vp = ndp->ni_vp;
55037741Smckusick 	if (vp != NULL) {
55137741Smckusick 		error = EEXIST;
55212756Ssam 		goto out;
5536254Sroot 	}
55437741Smckusick 	vattr_null(&vattr);
55537741Smckusick 	switch (uap->fmode & IFMT) {
55612756Ssam 
55715093Smckusick 	case IFMT:	/* used by badsect to flag bad sectors */
55837741Smckusick 		vattr.va_type = VBAD;
55937741Smckusick 		break;
56012756Ssam 	case IFCHR:
56137741Smckusick 		vattr.va_type = VCHR;
56237741Smckusick 		break;
56312756Ssam 	case IFBLK:
56437741Smckusick 		vattr.va_type = VBLK;
56537741Smckusick 		break;
56637741Smckusick 	default:
56737741Smckusick 		error = EINVAL;
56837741Smckusick 		goto out;
5696254Sroot 	}
57038408Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask;
57137741Smckusick 	vattr.va_rdev = uap->dev;
5726254Sroot out:
57337741Smckusick 	if (error)
57437741Smckusick 		VOP_ABORTOP(ndp);
57537741Smckusick 	else
57637741Smckusick 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
57737741Smckusick 	RETURN (error);
5786254Sroot }
5796254Sroot 
5806254Sroot /*
5816254Sroot  * link system call
5826254Sroot  */
58338408Smckusick link(scp)
58438408Smckusick 	register struct syscontext *scp;
5856254Sroot {
5866254Sroot 	register struct a {
5876254Sroot 		char	*target;
5886254Sroot 		char	*linkname;
58938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
59038408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
59137741Smckusick 	register struct vnode *vp, *xp;
59237741Smckusick 	int error;
5936254Sroot 
59416694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
59516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
59616694Smckusick 	ndp->ni_dirp = uap->target;
59737741Smckusick 	if (error = namei(ndp))
59837741Smckusick 		RETURN (error);
59937741Smckusick 	vp = ndp->ni_vp;
60037741Smckusick 	if (vp->v_type == VDIR &&
60138408Smckusick 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
60237741Smckusick 		goto out1;
60337741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
60416694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
60537741Smckusick 	if (error = namei(ndp))
60637741Smckusick 		goto out1;
60737741Smckusick 	xp = ndp->ni_vp;
6086254Sroot 	if (xp != NULL) {
60937741Smckusick 		error = EEXIST;
6106254Sroot 		goto out;
6116254Sroot 	}
61237741Smckusick 	xp = ndp->ni_dvp;
61337741Smckusick 	if (vp->v_mount != xp->v_mount)
61437741Smckusick 		error = EXDEV;
6156254Sroot out:
61637741Smckusick 	if (error)
61737741Smckusick 		VOP_ABORTOP(ndp);
61837741Smckusick 	else
61937741Smckusick 		error = VOP_LINK(vp, ndp);
62037741Smckusick out1:
62137741Smckusick 	vrele(vp);
62237741Smckusick 	RETURN (error);
6236254Sroot }
6246254Sroot 
6256254Sroot /*
6266254Sroot  * symlink -- make a symbolic link
6276254Sroot  */
62838408Smckusick symlink(scp)
62938408Smckusick 	register struct syscontext *scp;
6306254Sroot {
63137741Smckusick 	struct a {
6326254Sroot 		char	*target;
6336254Sroot 		char	*linkname;
63438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
63538408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
63637741Smckusick 	register struct vnode *vp;
63737741Smckusick 	struct vattr vattr;
63837741Smckusick 	char *target;
63937741Smckusick 	int error;
6406254Sroot 
64116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
64216694Smckusick 	ndp->ni_dirp = uap->linkname;
64337741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
64437741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
64537741Smckusick 		goto out1;
64637741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
64737741Smckusick 	if (error = namei(ndp))
64837741Smckusick 		goto out1;
64937741Smckusick 	vp = ndp->ni_vp;
65037741Smckusick 	if (vp) {
65137741Smckusick 		error = EEXIST;
65237741Smckusick 		goto out;
6536254Sroot 	}
65437741Smckusick 	vp = ndp->ni_dvp;
65537741Smckusick 	vattr_null(&vattr);
65638408Smckusick 	vattr.va_mode = 0777 &~ scp->sc_cmask;
65737741Smckusick out:
65837741Smckusick 	if (error)
65937741Smckusick 		VOP_ABORTOP(ndp);
66037741Smckusick 	else
66137741Smckusick 		error = VOP_SYMLINK(ndp, &vattr, target);
66237741Smckusick out1:
66337741Smckusick 	FREE(target, M_NAMEI);
66437741Smckusick 	RETURN (error);
6656254Sroot }
6666254Sroot 
6676254Sroot /*
6686254Sroot  * Unlink system call.
6696254Sroot  * Hard to avoid races here, especially
6706254Sroot  * in unlinking directories.
6716254Sroot  */
67238408Smckusick unlink(scp)
67338408Smckusick 	register struct syscontext *scp;
6746254Sroot {
6756254Sroot 	struct a {
6766254Sroot 		char	*fname;
67738408Smckusick 	} *uap = (struct a *)scp->sc_ap;
67838408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
67937741Smckusick 	register struct vnode *vp;
68037741Smckusick 	int error;
6816254Sroot 
68237741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
68316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
68416694Smckusick 	ndp->ni_dirp = uap->fname;
68537741Smckusick 	if (error = namei(ndp))
68637741Smckusick 		RETURN (error);
68737741Smckusick 	vp = ndp->ni_vp;
68837741Smckusick 	if (vp->v_type == VDIR &&
68938408Smckusick 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
6906254Sroot 		goto out;
6916254Sroot 	/*
6926254Sroot 	 * Don't unlink a mounted file.
6936254Sroot 	 */
69437741Smckusick 	if (vp->v_flag & VROOT) {
69537741Smckusick 		error = EBUSY;
6966254Sroot 		goto out;
6976254Sroot 	}
69837741Smckusick 	if (vp->v_flag & VTEXT)
69937741Smckusick 		xrele(vp);	/* try once to free text */
7006254Sroot out:
70137741Smckusick 	if (error)
70237741Smckusick 		VOP_ABORTOP(ndp);
7037142Smckusick 	else
70437741Smckusick 		error = VOP_REMOVE(ndp);
70537741Smckusick 	RETURN (error);
7066254Sroot }
7076254Sroot 
7086254Sroot /*
7096254Sroot  * Seek system call
7106254Sroot  */
71138408Smckusick lseek(scp)
71238408Smckusick 	register struct syscontext *scp;
7136254Sroot {
7146254Sroot 	register struct file *fp;
7156254Sroot 	register struct a {
71637741Smckusick 		int	fdes;
7176254Sroot 		off_t	off;
7186254Sroot 		int	sbase;
71938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
72037741Smckusick 	struct vattr vattr;
72137741Smckusick 	int error;
7226254Sroot 
72337741Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
72438408Smckusick 	    (fp = scp->sc_ofile[uap->fdes]) == NULL)
72537741Smckusick 		RETURN (EBADF);
72637741Smckusick 	if (fp->f_type != DTYPE_VNODE)
72737741Smckusick 		RETURN (ESPIPE);
72813878Ssam 	switch (uap->sbase) {
72913878Ssam 
73013878Ssam 	case L_INCR:
73113878Ssam 		fp->f_offset += uap->off;
73213878Ssam 		break;
73313878Ssam 
73413878Ssam 	case L_XTND:
73537741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
73638408Smckusick 		    &vattr, scp->sc_cred))
73737741Smckusick 			RETURN (error);
73837741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
73913878Ssam 		break;
74013878Ssam 
74113878Ssam 	case L_SET:
74213878Ssam 		fp->f_offset = uap->off;
74313878Ssam 		break;
74413878Ssam 
74513878Ssam 	default:
74637741Smckusick 		RETURN (EINVAL);
74713878Ssam 	}
74838408Smckusick 	scp->sc_offset = fp->f_offset;
74937741Smckusick 	RETURN (0);
7506254Sroot }
7516254Sroot 
7526254Sroot /*
7536254Sroot  * Access system call
7546254Sroot  */
75538408Smckusick saccess(scp)
75638408Smckusick 	register struct syscontext *scp;
7576254Sroot {
7586254Sroot 	register struct a {
7596254Sroot 		char	*fname;
7606254Sroot 		int	fmode;
76138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
76238408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
76337741Smckusick 	register struct vnode *vp;
76437741Smckusick 	int error, mode, svuid, svgid;
7656254Sroot 
76638408Smckusick 	svuid = scp->sc_uid;
76738408Smckusick 	svgid = scp->sc_gid;
76838408Smckusick 	scp->sc_uid = scp->sc_ruid;
76938408Smckusick 	scp->sc_gid = scp->sc_rgid;
77037741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
77116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
77216694Smckusick 	ndp->ni_dirp = uap->fname;
77337741Smckusick 	if (error = namei(ndp))
77437741Smckusick 		goto out1;
77537741Smckusick 	vp = ndp->ni_vp;
77637741Smckusick 	/*
77737741Smckusick 	 * fmode == 0 means only check for exist
77837741Smckusick 	 */
77937741Smckusick 	if (uap->fmode) {
78037741Smckusick 		mode = 0;
78137741Smckusick 		if (uap->fmode & R_OK)
78237741Smckusick 			mode |= VREAD;
78337741Smckusick 		if (uap->fmode & W_OK)
78437741Smckusick 			mode |= VWRITE;
78537741Smckusick 		if (uap->fmode & X_OK)
78637741Smckusick 			mode |= VEXEC;
78738399Smckusick 		if ((error = vn_writechk(vp)) == 0)
78838399Smckusick 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
7896254Sroot 	}
79037741Smckusick 	vput(vp);
79137741Smckusick out1:
79238408Smckusick 	scp->sc_uid = svuid;
79338408Smckusick 	scp->sc_gid = svgid;
79437741Smckusick 	RETURN (error);
7956254Sroot }
7966254Sroot 
7976254Sroot /*
7986574Smckusic  * Stat system call.  This version follows links.
79937Sbill  */
80038408Smckusick stat(scp)
80138408Smckusick 	struct syscontext *scp;
80237Sbill {
80337Sbill 
80438408Smckusick 	stat1(scp, FOLLOW);
80537Sbill }
80637Sbill 
80737Sbill /*
8086574Smckusic  * Lstat system call.  This version does not follow links.
8095992Swnj  */
81038408Smckusick lstat(scp)
81138408Smckusick 	struct syscontext *scp;
8125992Swnj {
81312756Ssam 
81438408Smckusick 	stat1(scp, NOFOLLOW);
81512756Ssam }
81612756Ssam 
81738408Smckusick stat1(scp, follow)
81838408Smckusick 	register struct syscontext *scp;
81912756Ssam 	int follow;
82012756Ssam {
8215992Swnj 	register struct a {
8225992Swnj 		char	*fname;
82312756Ssam 		struct stat *ub;
82438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
82538408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
82612756Ssam 	struct stat sb;
82737741Smckusick 	int error;
8285992Swnj 
82937741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
83016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
83116694Smckusick 	ndp->ni_dirp = uap->fname;
83237741Smckusick 	if (error = namei(ndp))
83337741Smckusick 		RETURN (error);
83437741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
83537741Smckusick 	vput(ndp->ni_vp);
83637741Smckusick 	if (error)
83737741Smckusick 		RETURN (error);
83837741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
83937741Smckusick 	RETURN (error);
8405992Swnj }
8415992Swnj 
8425992Swnj /*
8435992Swnj  * Return target name of a symbolic link
84437Sbill  */
84538408Smckusick readlink(scp)
84638408Smckusick 	register struct syscontext *scp;
8475992Swnj {
8485992Swnj 	register struct a {
8495992Swnj 		char	*name;
8505992Swnj 		char	*buf;
8515992Swnj 		int	count;
85238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
85338408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
85437741Smckusick 	register struct vnode *vp;
85537741Smckusick 	struct iovec aiov;
85637741Smckusick 	struct uio auio;
85737741Smckusick 	int error;
8585992Swnj 
85937741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
86016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
86116694Smckusick 	ndp->ni_dirp = uap->name;
86237741Smckusick 	if (error = namei(ndp))
86337741Smckusick 		RETURN (error);
86437741Smckusick 	vp = ndp->ni_vp;
86537741Smckusick 	if (vp->v_type != VLNK) {
86637741Smckusick 		error = EINVAL;
8675992Swnj 		goto out;
8685992Swnj 	}
86937741Smckusick 	aiov.iov_base = uap->buf;
87037741Smckusick 	aiov.iov_len = uap->count;
87137741Smckusick 	auio.uio_iov = &aiov;
87237741Smckusick 	auio.uio_iovcnt = 1;
87337741Smckusick 	auio.uio_offset = 0;
87437741Smckusick 	auio.uio_rw = UIO_READ;
87537741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
87637741Smckusick 	auio.uio_resid = uap->count;
87737741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
8785992Swnj out:
87937741Smckusick 	vput(vp);
88038408Smckusick 	scp->sc_retval1 = uap->count - auio.uio_resid;
88137741Smckusick 	RETURN (error);
8825992Swnj }
8835992Swnj 
8849167Ssam /*
88538259Smckusick  * Change flags of a file given path name.
88638259Smckusick  */
88738408Smckusick chflags(scp)
88838408Smckusick 	register struct syscontext *scp;
88938259Smckusick {
89038259Smckusick 	struct a {
89138259Smckusick 		char	*fname;
89238259Smckusick 		int	flags;
89338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
89438408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
89538259Smckusick 	register struct vnode *vp;
89638259Smckusick 	struct vattr vattr;
89738259Smckusick 	int error;
89838259Smckusick 
89938259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
90038259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
90138259Smckusick 	ndp->ni_dirp = uap->fname;
90238259Smckusick 	vattr_null(&vattr);
90338259Smckusick 	vattr.va_flags = uap->flags;
90438259Smckusick 	if (error = namei(ndp))
90538259Smckusick 		RETURN (error);
90638259Smckusick 	vp = ndp->ni_vp;
90738259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
90838259Smckusick 		error = EROFS;
90938259Smckusick 		goto out;
91038259Smckusick 	}
91138259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
91238259Smckusick out:
91338259Smckusick 	vput(vp);
91438259Smckusick 	RETURN (error);
91538259Smckusick }
91638259Smckusick 
91738259Smckusick /*
91838259Smckusick  * Change flags of a file given a file descriptor.
91938259Smckusick  */
92038408Smckusick fchflags(scp)
92138408Smckusick 	register struct syscontext *scp;
92238259Smckusick {
92338259Smckusick 	struct a {
92438259Smckusick 		int	fd;
92538259Smckusick 		int	flags;
92638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
92738259Smckusick 	struct vattr vattr;
92838259Smckusick 	struct vnode *vp;
92938259Smckusick 	struct file *fp;
93038259Smckusick 	int error;
93138259Smckusick 
93238408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
93338259Smckusick 		RETURN (error);
93438259Smckusick 	vattr_null(&vattr);
93538259Smckusick 	vattr.va_flags = uap->flags;
93638259Smckusick 	vp = (struct vnode *)fp->f_data;
93738259Smckusick 	VOP_LOCK(vp);
93838259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
93938259Smckusick 		error = EROFS;
94038259Smckusick 		goto out;
94138259Smckusick 	}
94238259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
94338259Smckusick out:
94438259Smckusick 	VOP_UNLOCK(vp);
94538259Smckusick 	RETURN (error);
94638259Smckusick }
94738259Smckusick 
94838259Smckusick /*
9499167Ssam  * Change mode of a file given path name.
9509167Ssam  */
95138408Smckusick chmod(scp)
95238408Smckusick 	register struct syscontext *scp;
9535992Swnj {
9547701Ssam 	struct a {
9556254Sroot 		char	*fname;
9566254Sroot 		int	fmode;
95738408Smckusick 	} *uap = (struct a *)scp->sc_ap;
95838408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
95937741Smckusick 	register struct vnode *vp;
96037741Smckusick 	struct vattr vattr;
96137741Smckusick 	int error;
9625992Swnj 
96337741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
96437741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
96537741Smckusick 	ndp->ni_dirp = uap->fname;
96637741Smckusick 	vattr_null(&vattr);
96737741Smckusick 	vattr.va_mode = uap->fmode & 07777;
96837741Smckusick 	if (error = namei(ndp))
96937741Smckusick 		RETURN (error);
97037741Smckusick 	vp = ndp->ni_vp;
97137741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
97237741Smckusick 		error = EROFS;
97337741Smckusick 		goto out;
97437741Smckusick 	}
97537741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
97637741Smckusick out:
97737741Smckusick 	vput(vp);
97837741Smckusick 	RETURN (error);
9797701Ssam }
9807439Sroot 
9819167Ssam /*
9829167Ssam  * Change mode of a file given a file descriptor.
9839167Ssam  */
98438408Smckusick fchmod(scp)
98538408Smckusick 	register struct syscontext *scp;
9867701Ssam {
9877701Ssam 	struct a {
9887701Ssam 		int	fd;
9897701Ssam 		int	fmode;
99038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
99137741Smckusick 	struct vattr vattr;
99237741Smckusick 	struct vnode *vp;
99337741Smckusick 	struct file *fp;
99437741Smckusick 	int error;
9957701Ssam 
99638408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
99737741Smckusick 		RETURN (error);
99837741Smckusick 	vattr_null(&vattr);
99937741Smckusick 	vattr.va_mode = uap->fmode & 07777;
100037741Smckusick 	vp = (struct vnode *)fp->f_data;
100137741Smckusick 	VOP_LOCK(vp);
100237741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
100337741Smckusick 		error = EROFS;
100437741Smckusick 		goto out;
10057439Sroot 	}
100637741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
100737741Smckusick out:
100837741Smckusick 	VOP_UNLOCK(vp);
100937741Smckusick 	RETURN (error);
10105992Swnj }
10115992Swnj 
10129167Ssam /*
10139167Ssam  * Set ownership given a path name.
10149167Ssam  */
101538408Smckusick chown(scp)
101638408Smckusick 	register struct syscontext *scp;
101737Sbill {
10187701Ssam 	struct a {
10196254Sroot 		char	*fname;
10206254Sroot 		int	uid;
10216254Sroot 		int	gid;
102238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
102338408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
102437741Smckusick 	register struct vnode *vp;
102537741Smckusick 	struct vattr vattr;
102637741Smckusick 	int error;
102737Sbill 
102837741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
102936614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
103036614Sbostic 	ndp->ni_dirp = uap->fname;
103137741Smckusick 	vattr_null(&vattr);
103237741Smckusick 	vattr.va_uid = uap->uid;
103337741Smckusick 	vattr.va_gid = uap->gid;
103437741Smckusick 	if (error = namei(ndp))
103537741Smckusick 		RETURN (error);
103637741Smckusick 	vp = ndp->ni_vp;
103737741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
103837741Smckusick 		error = EROFS;
103937741Smckusick 		goto out;
104037741Smckusick 	}
104137741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
104237741Smckusick out:
104337741Smckusick 	vput(vp);
104437741Smckusick 	RETURN (error);
10457701Ssam }
10467439Sroot 
10479167Ssam /*
10489167Ssam  * Set ownership given a file descriptor.
10499167Ssam  */
105038408Smckusick fchown(scp)
105138408Smckusick 	register struct syscontext *scp;
10527701Ssam {
10537701Ssam 	struct a {
10547701Ssam 		int	fd;
10557701Ssam 		int	uid;
10567701Ssam 		int	gid;
105738408Smckusick 	} *uap = (struct a *)scp->sc_ap;
105837741Smckusick 	struct vattr vattr;
105937741Smckusick 	struct vnode *vp;
106037741Smckusick 	struct file *fp;
106137741Smckusick 	int error;
10627701Ssam 
106338408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
106437741Smckusick 		RETURN (error);
106537741Smckusick 	vattr_null(&vattr);
106637741Smckusick 	vattr.va_uid = uap->uid;
106737741Smckusick 	vattr.va_gid = uap->gid;
106837741Smckusick 	vp = (struct vnode *)fp->f_data;
106937741Smckusick 	VOP_LOCK(vp);
107037741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
107137741Smckusick 		error = EROFS;
107237741Smckusick 		goto out;
107337741Smckusick 	}
107437741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
107537741Smckusick out:
107637741Smckusick 	VOP_UNLOCK(vp);
107737741Smckusick 	RETURN (error);
10787701Ssam }
10797701Ssam 
108038408Smckusick utimes(scp)
108138408Smckusick 	register struct syscontext *scp;
108211811Ssam {
108311811Ssam 	register struct a {
108411811Ssam 		char	*fname;
108511811Ssam 		struct	timeval *tptr;
108638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
108738408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
108837741Smckusick 	register struct vnode *vp;
108911811Ssam 	struct timeval tv[2];
109037741Smckusick 	struct vattr vattr;
109137741Smckusick 	int error;
109211811Ssam 
109337741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
109437741Smckusick 		RETURN (error);
109537741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
109637741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
109737741Smckusick 	ndp->ni_dirp = uap->fname;
109837741Smckusick 	vattr_null(&vattr);
109937741Smckusick 	vattr.va_atime = tv[0];
110037741Smckusick 	vattr.va_mtime = tv[1];
110137741Smckusick 	if (error = namei(ndp))
110237741Smckusick 		RETURN (error);
110337741Smckusick 	vp = ndp->ni_vp;
110437741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
110537741Smckusick 		error = EROFS;
110637741Smckusick 		goto out;
110721015Smckusick 	}
110837741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
110937741Smckusick out:
111037741Smckusick 	vput(vp);
111137741Smckusick 	RETURN (error);
111211811Ssam }
111311811Ssam 
11149167Ssam /*
11159167Ssam  * Truncate a file given its path name.
11169167Ssam  */
111738408Smckusick truncate(scp)
111838408Smckusick 	register struct syscontext *scp;
11197701Ssam {
11207701Ssam 	struct a {
11217701Ssam 		char	*fname;
112226473Skarels 		off_t	length;
112338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
112438408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
112537741Smckusick 	register struct vnode *vp;
112637741Smckusick 	struct vattr vattr;
112737741Smckusick 	int error;
11287701Ssam 
112937741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
113016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
113116694Smckusick 	ndp->ni_dirp = uap->fname;
113237741Smckusick 	vattr_null(&vattr);
113337741Smckusick 	vattr.va_size = uap->length;
113437741Smckusick 	if (error = namei(ndp))
113537741Smckusick 		RETURN (error);
113637741Smckusick 	vp = ndp->ni_vp;
113737741Smckusick 	if (vp->v_type == VDIR) {
113837741Smckusick 		error = EISDIR;
113937741Smckusick 		goto out;
11407701Ssam 	}
114138399Smckusick 	if ((error = vn_writechk(vp)) ||
114238399Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
114337741Smckusick 		goto out;
114437741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
114537741Smckusick out:
114637741Smckusick 	vput(vp);
114737741Smckusick 	RETURN (error);
11487701Ssam }
11497701Ssam 
11509167Ssam /*
11519167Ssam  * Truncate a file given a file descriptor.
11529167Ssam  */
115338408Smckusick ftruncate(scp)
115438408Smckusick 	register struct syscontext *scp;
11557701Ssam {
11567701Ssam 	struct a {
11577701Ssam 		int	fd;
115826473Skarels 		off_t	length;
115938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
116037741Smckusick 	struct vattr vattr;
116137741Smckusick 	struct vnode *vp;
11627701Ssam 	struct file *fp;
116337741Smckusick 	int error;
11647701Ssam 
116538408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
116637741Smckusick 		RETURN (error);
116737741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
116837741Smckusick 		RETURN (EINVAL);
116937741Smckusick 	vattr_null(&vattr);
117037741Smckusick 	vattr.va_size = uap->length;
117137741Smckusick 	vp = (struct vnode *)fp->f_data;
117237741Smckusick 	VOP_LOCK(vp);
117337741Smckusick 	if (vp->v_type == VDIR) {
117437741Smckusick 		error = EISDIR;
117537741Smckusick 		goto out;
11767701Ssam 	}
117738399Smckusick 	if (error = vn_writechk(vp))
117837741Smckusick 		goto out;
117937741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
118037741Smckusick out:
118137741Smckusick 	VOP_UNLOCK(vp);
118237741Smckusick 	RETURN (error);
11837701Ssam }
11847701Ssam 
11859167Ssam /*
11869167Ssam  * Synch an open file.
11879167Ssam  */
118838408Smckusick fsync(scp)
118938408Smckusick 	register struct syscontext *scp;
11909167Ssam {
11919167Ssam 	struct a {
11929167Ssam 		int	fd;
119338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
11949167Ssam 	struct file *fp;
119537741Smckusick 	int error;
11969167Ssam 
119738408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
119837741Smckusick 		RETURN (error);
119937741Smckusick 	error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred);
120037741Smckusick 	RETURN (error);
12019167Ssam }
12029167Ssam 
12039167Ssam /*
12049167Ssam  * Rename system call.
12059167Ssam  *
12069167Ssam  * Source and destination must either both be directories, or both
12079167Ssam  * not be directories.  If target is a directory, it must be empty.
12089167Ssam  */
120938408Smckusick rename(scp)
121038408Smckusick 	register struct syscontext *scp;
12117701Ssam {
12127701Ssam 	struct a {
12137701Ssam 		char	*from;
12147701Ssam 		char	*to;
121538408Smckusick 	} *uap = (struct a *)scp->sc_ap;
121637741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
121738408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
121837741Smckusick 	struct nameidata tond;
121937741Smckusick 	int error;
12207701Ssam 
122137741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
122216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
122316694Smckusick 	ndp->ni_dirp = uap->from;
122437741Smckusick 	if (error = namei(ndp))
122537741Smckusick 		RETURN (error);
122637741Smckusick 	fvp = ndp->ni_vp;
122738266Smckusick 	nddup(ndp, &tond);
122837741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
122937741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
123037741Smckusick 	tond.ni_dirp = uap->to;
123137741Smckusick 	error = namei(&tond);
123237741Smckusick 	tdvp = tond.ni_dvp;
123337741Smckusick 	tvp = tond.ni_vp;
123437741Smckusick 	if (tvp != NULL) {
123537741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
123639242Sbostic 			error = ENOTDIR;
123737741Smckusick 			goto out;
123837741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
123939242Sbostic 			error = EISDIR;
124037741Smckusick 			goto out;
12419167Ssam 		}
12429167Ssam 	}
124337741Smckusick 	if (error) {
124437741Smckusick 		VOP_ABORTOP(ndp);
124537741Smckusick 		goto out1;
124637741Smckusick 	}
124737741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
124837741Smckusick 		error = EXDEV;
12499167Ssam 		goto out;
125010051Ssam 	}
125139286Smckusick 	if (fvp == tdvp)
125237741Smckusick 		error = EINVAL;
125339286Smckusick 	/*
125439286Smckusick 	 * If source is the same as the destination,
125539286Smckusick 	 * then there is nothing to do.
125639286Smckusick 	 */
125739286Smckusick 	if (fvp == tvp)
125839286Smckusick 		error = -1;
125937741Smckusick out:
126037741Smckusick 	if (error) {
126137741Smckusick 		VOP_ABORTOP(&tond);
126237741Smckusick 		VOP_ABORTOP(ndp);
12639167Ssam 	} else {
126437741Smckusick 		error = VOP_RENAME(ndp, &tond);
12659167Ssam 	}
126637741Smckusick out1:
126738266Smckusick 	ndrele(&tond);
126839286Smckusick 	if (error == -1)
126939286Smckusick 		RETURN (0);
127037741Smckusick 	RETURN (error);
12717701Ssam }
12727701Ssam 
12737535Sroot /*
127412756Ssam  * Mkdir system call
127512756Ssam  */
127638408Smckusick mkdir(scp)
127738408Smckusick 	register struct syscontext *scp;
127812756Ssam {
127912756Ssam 	struct a {
128012756Ssam 		char	*name;
128112756Ssam 		int	dmode;
128238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
128338408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
128437741Smckusick 	register struct vnode *vp;
128537741Smckusick 	struct vattr vattr;
128637741Smckusick 	int error;
128712756Ssam 
128837741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
128916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
129016694Smckusick 	ndp->ni_dirp = uap->name;
129137741Smckusick 	if (error = namei(ndp))
129237741Smckusick 		RETURN (error);
129337741Smckusick 	vp = ndp->ni_vp;
129437741Smckusick 	if (vp != NULL) {
129537741Smckusick 		VOP_ABORTOP(ndp);
129637741Smckusick 		RETURN (EEXIST);
129712756Ssam 	}
129837741Smckusick 	vattr_null(&vattr);
129937741Smckusick 	vattr.va_type = VDIR;
130038408Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask;
130137741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
130238145Smckusick 	if (!error)
130338145Smckusick 		vput(ndp->ni_vp);
130437741Smckusick 	RETURN (error);
130512756Ssam }
130612756Ssam 
130712756Ssam /*
130812756Ssam  * Rmdir system call.
130912756Ssam  */
131038408Smckusick rmdir(scp)
131138408Smckusick 	register struct syscontext *scp;
131212756Ssam {
131312756Ssam 	struct a {
131412756Ssam 		char	*name;
131538408Smckusick 	} *uap = (struct a *)scp->sc_ap;
131638408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
131737741Smckusick 	register struct vnode *vp;
131837741Smckusick 	int error;
131912756Ssam 
132037741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
132116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
132216694Smckusick 	ndp->ni_dirp = uap->name;
132337741Smckusick 	if (error = namei(ndp))
132437741Smckusick 		RETURN (error);
132537741Smckusick 	vp = ndp->ni_vp;
132637741Smckusick 	if (vp->v_type != VDIR) {
132737741Smckusick 		error = ENOTDIR;
132812756Ssam 		goto out;
132912756Ssam 	}
133012756Ssam 	/*
133137741Smckusick 	 * No rmdir "." please.
133212756Ssam 	 */
133337741Smckusick 	if (ndp->ni_dvp == vp) {
133437741Smckusick 		error = EINVAL;
133512756Ssam 		goto out;
133612756Ssam 	}
133712756Ssam 	/*
133837741Smckusick 	 * Don't unlink a mounted file.
133912756Ssam 	 */
134037741Smckusick 	if (vp->v_flag & VROOT)
134137741Smckusick 		error = EBUSY;
134212756Ssam out:
134337741Smckusick 	if (error)
134437741Smckusick 		VOP_ABORTOP(ndp);
134537741Smckusick 	else
134637741Smckusick 		error = VOP_RMDIR(ndp);
134737741Smckusick 	RETURN (error);
134812756Ssam }
134912756Ssam 
135037741Smckusick /*
135137741Smckusick  * Read a block of directory entries in a file system independent format
135237741Smckusick  */
135338408Smckusick getdirentries(scp)
135438408Smckusick 	register struct syscontext *scp;
135512756Ssam {
135637741Smckusick 	register struct a {
135737741Smckusick 		int	fd;
135837741Smckusick 		char	*buf;
135937741Smckusick 		unsigned count;
136037741Smckusick 		long	*basep;
136138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
136216540Ssam 	struct file *fp;
136337741Smckusick 	struct uio auio;
136437741Smckusick 	struct iovec aiov;
136538129Smckusick 	off_t off;
136637741Smckusick 	int error;
136712756Ssam 
136838408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
136937741Smckusick 		RETURN (error);
137037741Smckusick 	if ((fp->f_flag & FREAD) == 0)
137137741Smckusick 		RETURN (EBADF);
137237741Smckusick 	aiov.iov_base = uap->buf;
137337741Smckusick 	aiov.iov_len = uap->count;
137437741Smckusick 	auio.uio_iov = &aiov;
137537741Smckusick 	auio.uio_iovcnt = 1;
137637741Smckusick 	auio.uio_rw = UIO_READ;
137737741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
137837741Smckusick 	auio.uio_resid = uap->count;
137938129Smckusick 	off = fp->f_offset;
138037741Smckusick 	if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio,
138137741Smckusick 	    &(fp->f_offset), fp->f_cred))
138237741Smckusick 		RETURN (error);
138338129Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep,
138437741Smckusick 		sizeof(long));
138538408Smckusick 	scp->sc_retval1 = uap->count - auio.uio_resid;
138637741Smckusick 	RETURN (error);
138712756Ssam }
138812756Ssam 
138912756Ssam /*
139012756Ssam  * mode mask for creation of files
139112756Ssam  */
139238408Smckusick umask(scp)
139338408Smckusick 	register struct syscontext *scp;
139412756Ssam {
139512756Ssam 	register struct a {
139612756Ssam 		int	mask;
139738408Smckusick 	} *uap = (struct a *)scp->sc_ap;
139812756Ssam 
139938408Smckusick 	scp->sc_retval1 = scp->sc_cmask;
140038408Smckusick 	scp->sc_cmask = uap->mask & 07777;
140137741Smckusick 	RETURN (0);
140212756Ssam }
140337741Smckusick 
140438408Smckusick getvnode(ofile, fdes, fpp)
140538408Smckusick 	struct file *ofile[];
140637741Smckusick 	struct file **fpp;
140737741Smckusick 	int fdes;
140837741Smckusick {
140937741Smckusick 	struct file *fp;
141037741Smckusick 
141138408Smckusick 	if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
141237741Smckusick 		return (EBADF);
141337741Smckusick 	if (fp->f_type != DTYPE_VNODE)
141437741Smckusick 		return (EINVAL);
141537741Smckusick 	*fpp = fp;
141637741Smckusick 	return (0);
141737741Smckusick }
1418