xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 40111)
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*40111Smckusick  *	@(#)vfs_syscalls.c	7.38 (Berkeley) 02/16/90
1823405Smckusick  */
1937Sbill 
2017101Sbloom #include "param.h"
2117101Sbloom #include "systm.h"
2237741Smckusick #include "syscontext.h"
2317101Sbloom #include "kernel.h"
2417101Sbloom #include "file.h"
2517101Sbloom #include "stat.h"
2637741Smckusick #include "vnode.h"
2737741Smckusick #include "../ufs/inode.h"
2837741Smckusick #include "mount.h"
2917101Sbloom #include "proc.h"
3017101Sbloom #include "uio.h"
3137741Smckusick #include "malloc.h"
3237Sbill 
3339797Smckusick #undef RETURN
3439797Smckusick #define RETURN(val)	{ scp->u_error = (val); if (scp->u_spare[0] != 0) panic("lock count"); return; }
3539797Smckusick 
3637741Smckusick /*
3737741Smckusick  * Virtual File System System Calls
3837741Smckusick  */
3912756Ssam 
409167Ssam /*
4137741Smckusick  * mount system call
429167Ssam  */
4338408Smckusick mount(scp)
4438408Smckusick 	register struct syscontext *scp;
456254Sroot {
4637741Smckusick 	register struct a {
4737741Smckusick 		int	type;
4837741Smckusick 		char	*dir;
4937741Smckusick 		int	flags;
5037741Smckusick 		caddr_t	data;
5138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
5238408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
5339335Smckusick 	register struct vnode *vp;
5439335Smckusick 	register struct mount *mp;
55*40111Smckusick 	int error, flag;
566254Sroot 
5737741Smckusick 	/*
5837741Smckusick 	 * Must be super user
5937741Smckusick 	 */
6038408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
6137741Smckusick 		RETURN (error);
6237741Smckusick 	/*
6337741Smckusick 	 * Get vnode to be covered
6437741Smckusick 	 */
6537741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
6637741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
6737741Smckusick 	ndp->ni_dirp = uap->dir;
6837741Smckusick 	if (error = namei(ndp))
6937741Smckusick 		RETURN (error);
7037741Smckusick 	vp = ndp->ni_vp;
7139335Smckusick 	if (uap->flags & M_UPDATE) {
7239335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
7339335Smckusick 			vput(vp);
7439335Smckusick 			RETURN (EINVAL);
7539335Smckusick 		}
7639335Smckusick 		mp = vp->v_mount;
7739335Smckusick 		/*
7839335Smckusick 		 * We allow going from read-only to read-write,
7939335Smckusick 		 * but not from read-write to read-only.
8039335Smckusick 		 */
8139335Smckusick 		if ((mp->m_flag & M_RDONLY) == 0 &&
8239335Smckusick 		    (uap->flags & M_RDONLY) != 0) {
8339335Smckusick 			vput(vp);
8439335Smckusick 			RETURN (EOPNOTSUPP);	/* Needs translation */
8539335Smckusick 		}
86*40111Smckusick 		flag = mp->m_flag;
8739335Smckusick 		mp->m_flag |= M_UPDATE;
8839335Smckusick 		VOP_UNLOCK(vp);
8939335Smckusick 		goto update;
9039335Smckusick 	}
9139665Smckusick 	vinvalbuf(vp, 1);
9239805Smckusick 	if (vp->v_usecount != 1) {
9337741Smckusick 		vput(vp);
9437741Smckusick 		RETURN (EBUSY);
9537741Smckusick 	}
9637741Smckusick 	if (vp->v_type != VDIR) {
9737741Smckusick 		vput(vp);
9837741Smckusick 		RETURN (ENOTDIR);
9937741Smckusick 	}
10039741Smckusick 	if ((unsigned long)uap->type > MOUNT_MAXTYPE ||
10137741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
10237741Smckusick 		vput(vp);
10337741Smckusick 		RETURN (ENODEV);
10437741Smckusick 	}
10537741Smckusick 
10637741Smckusick 	/*
10739335Smckusick 	 * Allocate and initialize the file system.
10837741Smckusick 	 */
10937741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
11037741Smckusick 		M_MOUNT, M_WAITOK);
11137741Smckusick 	mp->m_op = vfssw[uap->type];
11237741Smckusick 	mp->m_flag = 0;
11337741Smckusick 	mp->m_exroot = 0;
11439381Smckusick 	mp->m_mounth = (struct vnode *)0;
11539335Smckusick 	if (error = vfs_lock(mp)) {
11639335Smckusick 		free((caddr_t)mp, M_MOUNT);
11739335Smckusick 		vput(vp);
11839335Smckusick 		RETURN (error);
11939335Smckusick 	}
12039335Smckusick 	if (vp->v_mountedhere != (struct mount *)0) {
12139335Smckusick 		vfs_unlock(mp);
12239335Smckusick 		free((caddr_t)mp, M_MOUNT);
12339335Smckusick 		vput(vp);
12439335Smckusick 		RETURN (EBUSY);
12539335Smckusick 	}
12639335Smckusick 	vp->v_mountedhere = mp;
12739335Smckusick 	mp->m_vnodecovered = vp;
12839335Smckusick update:
12939335Smckusick 	/*
13039335Smckusick 	 * Set the mount level flags.
13139335Smckusick 	 */
13239335Smckusick 	if (uap->flags & M_RDONLY)
13339335Smckusick 		mp->m_flag |= M_RDONLY;
13439335Smckusick 	else
13539335Smckusick 		mp->m_flag &= ~M_RDONLY;
13639335Smckusick 	if (uap->flags & M_NOSUID)
13739335Smckusick 		mp->m_flag |= M_NOSUID;
13839335Smckusick 	else
13939335Smckusick 		mp->m_flag &= ~M_NOSUID;
14039335Smckusick 	if (uap->flags & M_NOEXEC)
14139335Smckusick 		mp->m_flag |= M_NOEXEC;
14239335Smckusick 	else
14339335Smckusick 		mp->m_flag &= ~M_NOEXEC;
14439335Smckusick 	if (uap->flags & M_NODEV)
14539335Smckusick 		mp->m_flag |= M_NODEV;
14639335Smckusick 	else
14739335Smckusick 		mp->m_flag &= ~M_NODEV;
14839335Smckusick 	if (uap->flags & M_SYNCHRONOUS)
14939335Smckusick 		mp->m_flag |= M_SYNCHRONOUS;
15039335Smckusick 	else
15139335Smckusick 		mp->m_flag &= ~M_SYNCHRONOUS;
15239335Smckusick 	/*
15339335Smckusick 	 * Mount the filesystem.
15439335Smckusick 	 */
15539335Smckusick 	error = VFS_MOUNT(mp, uap->dir, uap->data, ndp);
15639335Smckusick 	if (mp->m_flag & M_UPDATE) {
15739335Smckusick 		mp->m_flag &= ~M_UPDATE;
15839335Smckusick 		vrele(vp);
159*40111Smckusick 		if (error)
160*40111Smckusick 			mp->m_flag = flag;
16139335Smckusick 		RETURN (error);
16239335Smckusick 	}
16340110Smckusick 	/*
16440110Smckusick 	 * Put the new filesystem on the mount list after root.
16540110Smckusick 	 */
16640110Smckusick 	mp->m_next = rootfs->m_next;
16740110Smckusick 	mp->m_prev = rootfs;
16840110Smckusick 	rootfs->m_next = mp;
16940110Smckusick 	mp->m_next->m_prev = mp;
17037741Smckusick 	cache_purge(vp);
17137741Smckusick 	if (!error) {
17239335Smckusick 		VOP_UNLOCK(vp);
17337741Smckusick 		vfs_unlock(mp);
17439044Smckusick 		error = VFS_START(mp, 0);
17537741Smckusick 	} else {
17637741Smckusick 		vfs_remove(mp);
17737741Smckusick 		free((caddr_t)mp, M_MOUNT);
17839335Smckusick 		vput(vp);
17937741Smckusick 	}
18037741Smckusick 	RETURN (error);
1816254Sroot }
1826254Sroot 
1839167Ssam /*
18437741Smckusick  * Unmount system call.
18537741Smckusick  *
18637741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
18737741Smckusick  * not special file (as before).
1889167Ssam  */
18938408Smckusick unmount(scp)
19038408Smckusick 	register struct syscontext *scp;
1916254Sroot {
19237741Smckusick 	struct a {
19337741Smckusick 		char	*pathp;
19437741Smckusick 		int	flags;
19538408Smckusick 	} *uap = (struct a *)scp->sc_ap;
19637741Smckusick 	register struct vnode *vp;
19738408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
19839356Smckusick 	struct mount *mp;
19937741Smckusick 	int error;
2006254Sroot 
20137741Smckusick 	/*
20237741Smckusick 	 * Must be super user
20337741Smckusick 	 */
20438408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
20537741Smckusick 		RETURN (error);
20637741Smckusick 
20737741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
20837741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
20937741Smckusick 	ndp->ni_dirp = uap->pathp;
21037741Smckusick 	if (error = namei(ndp))
21137741Smckusick 		RETURN (error);
21237741Smckusick 	vp = ndp->ni_vp;
21337741Smckusick 	/*
21437741Smckusick 	 * Must be the root of the filesystem
21537741Smckusick 	 */
21637741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
21737741Smckusick 		vput(vp);
21837741Smckusick 		RETURN (EINVAL);
21937741Smckusick 	}
22037741Smckusick 	mp = vp->v_mount;
22137741Smckusick 	vput(vp);
22239356Smckusick 	RETURN (dounmount(mp, uap->flags));
22339356Smckusick }
22439356Smckusick 
22539356Smckusick /*
22639356Smckusick  * Do an unmount.
22739356Smckusick  */
22839356Smckusick dounmount(mp, flags)
22939356Smckusick 	register struct mount *mp;
23039356Smckusick 	int flags;
23139356Smckusick {
23239356Smckusick 	struct vnode *coveredvp;
23339356Smckusick 	int error;
23439356Smckusick 
23537741Smckusick 	coveredvp = mp->m_vnodecovered;
23637741Smckusick 	if (error = vfs_lock(mp))
23739356Smckusick 		return (error);
23837741Smckusick 
23937741Smckusick 	xumount(mp);		/* remove unused sticky files from text table */
24037741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
24137741Smckusick 	VFS_SYNC(mp, MNT_WAIT);
24237741Smckusick 
24339356Smckusick 	error = VFS_UNMOUNT(mp, flags);
24437741Smckusick 	if (error) {
24537741Smckusick 		vfs_unlock(mp);
24637741Smckusick 	} else {
24737741Smckusick 		vrele(coveredvp);
24837741Smckusick 		vfs_remove(mp);
24937741Smckusick 		free((caddr_t)mp, M_MOUNT);
25037741Smckusick 	}
25139356Smckusick 	return (error);
2526254Sroot }
2536254Sroot 
2549167Ssam /*
25537741Smckusick  * Sync system call.
25637741Smckusick  * Sync each mounted filesystem.
2579167Ssam  */
25839491Smckusick /* ARGSUSED */
25938408Smckusick sync(scp)
26039491Smckusick 	struct syscontext *scp;
2616254Sroot {
26237741Smckusick 	register struct mount *mp;
26340110Smckusick 	struct mount *nmp;
26437741Smckusick 
26537741Smckusick 	mp = rootfs;
26637741Smckusick 	do {
26740110Smckusick 		nmp = mp->m_next;
26840110Smckusick 		if ((mp->m_flag & (M_MLOCK|M_RDONLY)) == 0)
26937741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
27040110Smckusick 		mp = nmp;
27137741Smckusick 	} while (mp != rootfs);
27237741Smckusick }
27337741Smckusick 
27437741Smckusick /*
27537741Smckusick  * get filesystem statistics
27637741Smckusick  */
27738408Smckusick statfs(scp)
27838408Smckusick 	register struct syscontext *scp;
27937741Smckusick {
2806254Sroot 	struct a {
28137741Smckusick 		char *path;
28237741Smckusick 		struct statfs *buf;
28338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
28439464Smckusick 	register struct mount *mp;
28538408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
28637741Smckusick 	struct statfs sb;
28737741Smckusick 	int error;
28837741Smckusick 
28939544Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
29037741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
29137741Smckusick 	ndp->ni_dirp = uap->path;
29237741Smckusick 	if (error = namei(ndp))
29337741Smckusick 		RETURN (error);
29439544Smckusick 	mp = ndp->ni_vp->v_mount;
29539544Smckusick 	vrele(ndp->ni_vp);
29639464Smckusick 	if (error = VFS_STATFS(mp, &sb))
29739544Smckusick 		RETURN (error);
29839464Smckusick 	sb.f_flags = mp->m_flag & M_VISFLAGMASK;
29939464Smckusick 	sb.f_fsid = mp->m_fsid;
30039544Smckusick 	RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)));
30137741Smckusick }
30237741Smckusick 
30338408Smckusick fstatfs(scp)
30438408Smckusick 	register struct syscontext *scp;
30537741Smckusick {
30637741Smckusick 	struct a {
30737741Smckusick 		int fd;
30837741Smckusick 		struct statfs *buf;
30938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
31037741Smckusick 	struct file *fp;
31139464Smckusick 	struct mount *mp;
31237741Smckusick 	struct statfs sb;
31337741Smckusick 	int error;
31437741Smckusick 
31538408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
31637741Smckusick 		RETURN (error);
31739464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
31839464Smckusick 	if (error = VFS_STATFS(mp, &sb))
31937741Smckusick 		RETURN (error);
32039464Smckusick 	sb.f_flags = mp->m_flag & M_VISFLAGMASK;
32139464Smckusick 	sb.f_fsid = mp->m_fsid;
32237741Smckusick 	RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)));
32337741Smckusick }
32437741Smckusick 
32537741Smckusick /*
32638270Smckusick  * get statistics on all filesystems
32738270Smckusick  */
32838408Smckusick getfsstat(scp)
32938408Smckusick 	register struct syscontext *scp;
33038270Smckusick {
33138270Smckusick 	struct a {
33238270Smckusick 		struct statfs *buf;
33338270Smckusick 		long bufsize;
33438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
33538270Smckusick 	register struct mount *mp;
33639606Smckusick 	caddr_t sfsp;
33738270Smckusick 	long count, maxcount, error;
33839606Smckusick 	struct statfs sb;
33938270Smckusick 
34038270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
34139606Smckusick 	sfsp = (caddr_t)uap->buf;
34238270Smckusick 	mp = rootfs;
34338270Smckusick 	count = 0;
34438270Smckusick 	do {
34539606Smckusick 		if (sfsp && count < maxcount && ((mp->m_flag & M_MLOCK) == 0)) {
34639607Smckusick 			if (error = VFS_STATFS(mp, &sb)) {
34739607Smckusick 				mp = mp->m_prev;
34839607Smckusick 				continue;
34939607Smckusick 			}
35039606Smckusick 			sb.f_flags = mp->m_flag & M_VISFLAGMASK;
35139606Smckusick 			sb.f_fsid = mp->m_fsid;
35239606Smckusick 			if (error = copyout((caddr_t)&sb, sfsp, sizeof(sb)))
35339606Smckusick 				RETURN (error);
35439606Smckusick 			sfsp += sizeof(sb);
35538270Smckusick 		}
35639606Smckusick 		count++;
35738270Smckusick 		mp = mp->m_prev;
35838270Smckusick 	} while (mp != rootfs);
35938270Smckusick 	if (sfsp && count > maxcount)
36038408Smckusick 		scp->sc_retval1 = maxcount;
36138270Smckusick 	else
36238408Smckusick 		scp->sc_retval1 = count;
36338270Smckusick 	RETURN (0);
36438270Smckusick }
36538270Smckusick 
36638270Smckusick /*
36738259Smckusick  * Change current working directory to a given file descriptor.
36838259Smckusick  */
36938408Smckusick fchdir(scp)
37038408Smckusick 	register struct syscontext *scp;
37138259Smckusick {
37238259Smckusick 	struct a {
37338259Smckusick 		int	fd;
37438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
37538259Smckusick 	register struct vnode *vp;
37638259Smckusick 	struct file *fp;
37738259Smckusick 	int error;
37838259Smckusick 
37938408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
38038259Smckusick 		RETURN (error);
38138259Smckusick 	vp = (struct vnode *)fp->f_data;
38238259Smckusick 	VOP_LOCK(vp);
38338259Smckusick 	if (vp->v_type != VDIR)
38438259Smckusick 		error = ENOTDIR;
38538259Smckusick 	else
38638408Smckusick 		error = VOP_ACCESS(vp, VEXEC, scp->sc_cred);
38738259Smckusick 	VOP_UNLOCK(vp);
38839860Smckusick 	if (error)
38939860Smckusick 		RETURN (error);
39039860Smckusick 	VREF(vp);
39138408Smckusick 	vrele(scp->sc_cdir);
39238408Smckusick 	scp->sc_cdir = vp;
39339860Smckusick 	RETURN (0);
39438259Smckusick }
39538259Smckusick 
39638259Smckusick /*
39737741Smckusick  * Change current working directory (``.'').
39837741Smckusick  */
39938408Smckusick chdir(scp)
40038408Smckusick 	register struct syscontext *scp;
40137741Smckusick {
40237741Smckusick 	struct a {
4036254Sroot 		char	*fname;
40438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
40538408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
40637741Smckusick 	int error;
4076254Sroot 
40837741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
40916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
41016694Smckusick 	ndp->ni_dirp = uap->fname;
41137741Smckusick 	if (error = chdirec(ndp))
41237741Smckusick 		RETURN (error);
41338408Smckusick 	vrele(scp->sc_cdir);
41438408Smckusick 	scp->sc_cdir = ndp->ni_vp;
41537741Smckusick 	RETURN (0);
41637741Smckusick }
4176254Sroot 
41837741Smckusick /*
41937741Smckusick  * Change notion of root (``/'') directory.
42037741Smckusick  */
42138408Smckusick chroot(scp)
42238408Smckusick 	register struct syscontext *scp;
42337741Smckusick {
42437741Smckusick 	struct a {
42537741Smckusick 		char	*fname;
42638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
42738408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
42837741Smckusick 	int error;
42937741Smckusick 
43038408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
43137741Smckusick 		RETURN (error);
43237741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
43337741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
43437741Smckusick 	ndp->ni_dirp = uap->fname;
43537741Smckusick 	if (error = chdirec(ndp))
43637741Smckusick 		RETURN (error);
43739515Smckusick 	if (scp->sc_rdir != NULL)
43839515Smckusick 		vrele(scp->sc_rdir);
43938408Smckusick 	scp->sc_rdir = ndp->ni_vp;
44037741Smckusick 	RETURN (0);
4416254Sroot }
4426254Sroot 
44337Sbill /*
44437741Smckusick  * Common routine for chroot and chdir.
44537741Smckusick  */
44637741Smckusick chdirec(ndp)
44737741Smckusick 	register struct nameidata *ndp;
44837741Smckusick {
44937741Smckusick 	struct vnode *vp;
45037741Smckusick 	int error;
45137741Smckusick 
45237741Smckusick 	if (error = namei(ndp))
45337741Smckusick 		return (error);
45437741Smckusick 	vp = ndp->ni_vp;
45537741Smckusick 	if (vp->v_type != VDIR)
45637741Smckusick 		error = ENOTDIR;
45737741Smckusick 	else
45838399Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
45937741Smckusick 	VOP_UNLOCK(vp);
46037741Smckusick 	if (error)
46137741Smckusick 		vrele(vp);
46237741Smckusick 	return (error);
46337741Smckusick }
46437741Smckusick 
46537741Smckusick /*
4666254Sroot  * Open system call.
4676254Sroot  */
46838408Smckusick open(scp)
46938408Smckusick 	register struct syscontext *scp;
4706254Sroot {
47112756Ssam 	struct a {
4726254Sroot 		char	*fname;
4737701Ssam 		int	mode;
47412756Ssam 		int	crtmode;
47538408Smckusick 	} *uap = (struct a *) scp->sc_ap;
47638408Smckusick 	struct nameidata *ndp = &scp->sc_nd;
4776254Sroot 
47837741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
47937741Smckusick 	ndp->ni_dirp = uap->fname;
48038408Smckusick 	RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp,
48138408Smckusick 		&scp->sc_retval1));
4826254Sroot }
4836254Sroot 
4846254Sroot /*
4856254Sroot  * Creat system call.
4866254Sroot  */
48738408Smckusick creat(scp)
48838408Smckusick 	register struct syscontext *scp;
4896254Sroot {
49012756Ssam 	struct a {
4916254Sroot 		char	*fname;
4926254Sroot 		int	fmode;
49338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
49438408Smckusick 	struct nameidata *ndp = &scp->sc_nd;
4956254Sroot 
49637741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
49737741Smckusick 	ndp->ni_dirp = uap->fname;
49838408Smckusick 	RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask,
49938408Smckusick 		ndp, &scp->sc_retval1));
5006254Sroot }
5016254Sroot 
5026254Sroot /*
5036254Sroot  * Common code for open and creat.
50412756Ssam  * Check permissions, allocate an open file structure,
50512756Ssam  * and call the device open routine if any.
5066254Sroot  */
50738408Smckusick copen(scp, fmode, cmode, ndp, resultfd)
50838408Smckusick 	register struct syscontext *scp;
50937741Smckusick 	int fmode, cmode;
51037741Smckusick 	struct nameidata *ndp;
51137741Smckusick 	int *resultfd;
51212756Ssam {
5136254Sroot 	register struct file *fp;
51437741Smckusick 	struct file *nfp;
51537741Smckusick 	int indx, error;
51637741Smckusick 	extern struct fileops vnops;
5176254Sroot 
51837741Smckusick 	if (error = falloc(&nfp, &indx))
51937741Smckusick 		return (error);
52037741Smckusick 	fp = nfp;
52138408Smckusick 	scp->sc_retval1 = indx;	/* XXX for fdopen() */
52237741Smckusick 	if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) {
52337741Smckusick 		crfree(fp->f_cred);
52437741Smckusick 		fp->f_count--;
52539499Smckusick 		if (error == -1)	/* XXX from fdopen */
52639499Smckusick 			return (0);	/* XXX from fdopen */
52739499Smckusick 		scp->sc_ofile[indx] = NULL;
52837741Smckusick 		return (error);
52912756Ssam 	}
53037741Smckusick 	fp->f_flag = fmode & FMASK;
53137741Smckusick 	fp->f_type = DTYPE_VNODE;
53237741Smckusick 	fp->f_ops = &vnops;
53337741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
53437741Smckusick 	if (resultfd)
53537741Smckusick 		*resultfd = indx;
53637741Smckusick 	return (0);
5376254Sroot }
5386254Sroot 
5396254Sroot /*
5406254Sroot  * Mknod system call
5416254Sroot  */
54238408Smckusick mknod(scp)
54338408Smckusick 	register struct syscontext *scp;
5446254Sroot {
5456254Sroot 	register struct a {
5466254Sroot 		char	*fname;
5476254Sroot 		int	fmode;
5486254Sroot 		int	dev;
54938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
55038408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
55137741Smckusick 	register struct vnode *vp;
55237741Smckusick 	struct vattr vattr;
55337741Smckusick 	int error;
5546254Sroot 
55538408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
55637741Smckusick 		RETURN (error);
55737741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
55816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
55916694Smckusick 	ndp->ni_dirp = uap->fname;
56037741Smckusick 	if (error = namei(ndp))
56137741Smckusick 		RETURN (error);
56237741Smckusick 	vp = ndp->ni_vp;
56337741Smckusick 	if (vp != NULL) {
56437741Smckusick 		error = EEXIST;
56512756Ssam 		goto out;
5666254Sroot 	}
56737741Smckusick 	vattr_null(&vattr);
56837741Smckusick 	switch (uap->fmode & IFMT) {
56912756Ssam 
57015093Smckusick 	case IFMT:	/* used by badsect to flag bad sectors */
57137741Smckusick 		vattr.va_type = VBAD;
57237741Smckusick 		break;
57312756Ssam 	case IFCHR:
57437741Smckusick 		vattr.va_type = VCHR;
57537741Smckusick 		break;
57612756Ssam 	case IFBLK:
57737741Smckusick 		vattr.va_type = VBLK;
57837741Smckusick 		break;
57937741Smckusick 	default:
58037741Smckusick 		error = EINVAL;
58137741Smckusick 		goto out;
5826254Sroot 	}
58338408Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask;
58437741Smckusick 	vattr.va_rdev = uap->dev;
5856254Sroot out:
58637741Smckusick 	if (error)
58737741Smckusick 		VOP_ABORTOP(ndp);
58837741Smckusick 	else
58937741Smckusick 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
59037741Smckusick 	RETURN (error);
5916254Sroot }
5926254Sroot 
5936254Sroot /*
5946254Sroot  * link system call
5956254Sroot  */
59638408Smckusick link(scp)
59738408Smckusick 	register struct syscontext *scp;
5986254Sroot {
5996254Sroot 	register struct a {
6006254Sroot 		char	*target;
6016254Sroot 		char	*linkname;
60238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
60338408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
60437741Smckusick 	register struct vnode *vp, *xp;
60537741Smckusick 	int error;
6066254Sroot 
60716694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
60816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
60916694Smckusick 	ndp->ni_dirp = uap->target;
61037741Smckusick 	if (error = namei(ndp))
61137741Smckusick 		RETURN (error);
61237741Smckusick 	vp = ndp->ni_vp;
61337741Smckusick 	if (vp->v_type == VDIR &&
61438408Smckusick 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
61537741Smckusick 		goto out1;
61637741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
61716694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
61837741Smckusick 	if (error = namei(ndp))
61937741Smckusick 		goto out1;
62037741Smckusick 	xp = ndp->ni_vp;
6216254Sroot 	if (xp != NULL) {
62237741Smckusick 		error = EEXIST;
6236254Sroot 		goto out;
6246254Sroot 	}
62537741Smckusick 	xp = ndp->ni_dvp;
62637741Smckusick 	if (vp->v_mount != xp->v_mount)
62737741Smckusick 		error = EXDEV;
6286254Sroot out:
62937741Smckusick 	if (error)
63037741Smckusick 		VOP_ABORTOP(ndp);
63137741Smckusick 	else
63237741Smckusick 		error = VOP_LINK(vp, ndp);
63337741Smckusick out1:
63437741Smckusick 	vrele(vp);
63537741Smckusick 	RETURN (error);
6366254Sroot }
6376254Sroot 
6386254Sroot /*
6396254Sroot  * symlink -- make a symbolic link
6406254Sroot  */
64138408Smckusick symlink(scp)
64238408Smckusick 	register struct syscontext *scp;
6436254Sroot {
64437741Smckusick 	struct a {
6456254Sroot 		char	*target;
6466254Sroot 		char	*linkname;
64738408Smckusick 	} *uap = (struct a *)scp->sc_ap;
64838408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
64937741Smckusick 	register struct vnode *vp;
65037741Smckusick 	struct vattr vattr;
65137741Smckusick 	char *target;
65237741Smckusick 	int error;
6536254Sroot 
65416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
65516694Smckusick 	ndp->ni_dirp = uap->linkname;
65637741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
65737741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
65837741Smckusick 		goto out1;
65937741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
66037741Smckusick 	if (error = namei(ndp))
66137741Smckusick 		goto out1;
66237741Smckusick 	vp = ndp->ni_vp;
66337741Smckusick 	if (vp) {
66437741Smckusick 		error = EEXIST;
66537741Smckusick 		goto out;
6666254Sroot 	}
66737741Smckusick 	vp = ndp->ni_dvp;
66837741Smckusick 	vattr_null(&vattr);
66938408Smckusick 	vattr.va_mode = 0777 &~ scp->sc_cmask;
67037741Smckusick out:
67137741Smckusick 	if (error)
67237741Smckusick 		VOP_ABORTOP(ndp);
67337741Smckusick 	else
67437741Smckusick 		error = VOP_SYMLINK(ndp, &vattr, target);
67537741Smckusick out1:
67637741Smckusick 	FREE(target, M_NAMEI);
67737741Smckusick 	RETURN (error);
6786254Sroot }
6796254Sroot 
6806254Sroot /*
6816254Sroot  * Unlink system call.
6826254Sroot  * Hard to avoid races here, especially
6836254Sroot  * in unlinking directories.
6846254Sroot  */
68538408Smckusick unlink(scp)
68638408Smckusick 	register struct syscontext *scp;
6876254Sroot {
6886254Sroot 	struct a {
6896254Sroot 		char	*fname;
69038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
69138408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
69237741Smckusick 	register struct vnode *vp;
69337741Smckusick 	int error;
6946254Sroot 
69537741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
69616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
69716694Smckusick 	ndp->ni_dirp = uap->fname;
69837741Smckusick 	if (error = namei(ndp))
69937741Smckusick 		RETURN (error);
70037741Smckusick 	vp = ndp->ni_vp;
70137741Smckusick 	if (vp->v_type == VDIR &&
70238408Smckusick 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
7036254Sroot 		goto out;
7046254Sroot 	/*
7056254Sroot 	 * Don't unlink a mounted file.
7066254Sroot 	 */
70737741Smckusick 	if (vp->v_flag & VROOT) {
70837741Smckusick 		error = EBUSY;
7096254Sroot 		goto out;
7106254Sroot 	}
71137741Smckusick 	if (vp->v_flag & VTEXT)
71237741Smckusick 		xrele(vp);	/* try once to free text */
7136254Sroot out:
71437741Smckusick 	if (error)
71537741Smckusick 		VOP_ABORTOP(ndp);
7167142Smckusick 	else
71737741Smckusick 		error = VOP_REMOVE(ndp);
71837741Smckusick 	RETURN (error);
7196254Sroot }
7206254Sroot 
7216254Sroot /*
7226254Sroot  * Seek system call
7236254Sroot  */
72438408Smckusick lseek(scp)
72538408Smckusick 	register struct syscontext *scp;
7266254Sroot {
7276254Sroot 	register struct file *fp;
7286254Sroot 	register struct a {
72937741Smckusick 		int	fdes;
7306254Sroot 		off_t	off;
7316254Sroot 		int	sbase;
73238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
73337741Smckusick 	struct vattr vattr;
73437741Smckusick 	int error;
7356254Sroot 
73637741Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
73738408Smckusick 	    (fp = scp->sc_ofile[uap->fdes]) == NULL)
73837741Smckusick 		RETURN (EBADF);
73937741Smckusick 	if (fp->f_type != DTYPE_VNODE)
74037741Smckusick 		RETURN (ESPIPE);
74113878Ssam 	switch (uap->sbase) {
74213878Ssam 
74313878Ssam 	case L_INCR:
74413878Ssam 		fp->f_offset += uap->off;
74513878Ssam 		break;
74613878Ssam 
74713878Ssam 	case L_XTND:
74837741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
74938408Smckusick 		    &vattr, scp->sc_cred))
75037741Smckusick 			RETURN (error);
75137741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
75213878Ssam 		break;
75313878Ssam 
75413878Ssam 	case L_SET:
75513878Ssam 		fp->f_offset = uap->off;
75613878Ssam 		break;
75713878Ssam 
75813878Ssam 	default:
75937741Smckusick 		RETURN (EINVAL);
76013878Ssam 	}
76138408Smckusick 	scp->sc_offset = fp->f_offset;
76237741Smckusick 	RETURN (0);
7636254Sroot }
7646254Sroot 
7656254Sroot /*
7666254Sroot  * Access system call
7676254Sroot  */
76838408Smckusick saccess(scp)
76938408Smckusick 	register struct syscontext *scp;
7706254Sroot {
7716254Sroot 	register struct a {
7726254Sroot 		char	*fname;
7736254Sroot 		int	fmode;
77438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
77538408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
77637741Smckusick 	register struct vnode *vp;
77737741Smckusick 	int error, mode, svuid, svgid;
7786254Sroot 
77938408Smckusick 	svuid = scp->sc_uid;
78038408Smckusick 	svgid = scp->sc_gid;
78138408Smckusick 	scp->sc_uid = scp->sc_ruid;
78238408Smckusick 	scp->sc_gid = scp->sc_rgid;
78337741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
78416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
78516694Smckusick 	ndp->ni_dirp = uap->fname;
78637741Smckusick 	if (error = namei(ndp))
78737741Smckusick 		goto out1;
78837741Smckusick 	vp = ndp->ni_vp;
78937741Smckusick 	/*
79037741Smckusick 	 * fmode == 0 means only check for exist
79137741Smckusick 	 */
79237741Smckusick 	if (uap->fmode) {
79337741Smckusick 		mode = 0;
79437741Smckusick 		if (uap->fmode & R_OK)
79537741Smckusick 			mode |= VREAD;
79637741Smckusick 		if (uap->fmode & W_OK)
79737741Smckusick 			mode |= VWRITE;
79837741Smckusick 		if (uap->fmode & X_OK)
79937741Smckusick 			mode |= VEXEC;
80039543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
80138399Smckusick 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
8026254Sroot 	}
80337741Smckusick 	vput(vp);
80437741Smckusick out1:
80538408Smckusick 	scp->sc_uid = svuid;
80638408Smckusick 	scp->sc_gid = svgid;
80737741Smckusick 	RETURN (error);
8086254Sroot }
8096254Sroot 
8106254Sroot /*
8116574Smckusic  * Stat system call.  This version follows links.
81237Sbill  */
81338408Smckusick stat(scp)
81438408Smckusick 	struct syscontext *scp;
81537Sbill {
81637Sbill 
81738408Smckusick 	stat1(scp, FOLLOW);
81837Sbill }
81937Sbill 
82037Sbill /*
8216574Smckusic  * Lstat system call.  This version does not follow links.
8225992Swnj  */
82338408Smckusick lstat(scp)
82438408Smckusick 	struct syscontext *scp;
8255992Swnj {
82612756Ssam 
82738408Smckusick 	stat1(scp, NOFOLLOW);
82812756Ssam }
82912756Ssam 
83038408Smckusick stat1(scp, follow)
83138408Smckusick 	register struct syscontext *scp;
83212756Ssam 	int follow;
83312756Ssam {
8345992Swnj 	register struct a {
8355992Swnj 		char	*fname;
83612756Ssam 		struct stat *ub;
83738408Smckusick 	} *uap = (struct a *)scp->sc_ap;
83838408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
83912756Ssam 	struct stat sb;
84037741Smckusick 	int error;
8415992Swnj 
84237741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
84316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
84416694Smckusick 	ndp->ni_dirp = uap->fname;
84537741Smckusick 	if (error = namei(ndp))
84637741Smckusick 		RETURN (error);
84737741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
84837741Smckusick 	vput(ndp->ni_vp);
84937741Smckusick 	if (error)
85037741Smckusick 		RETURN (error);
85137741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
85237741Smckusick 	RETURN (error);
8535992Swnj }
8545992Swnj 
8555992Swnj /*
8565992Swnj  * Return target name of a symbolic link
85737Sbill  */
85838408Smckusick readlink(scp)
85938408Smckusick 	register struct syscontext *scp;
8605992Swnj {
8615992Swnj 	register struct a {
8625992Swnj 		char	*name;
8635992Swnj 		char	*buf;
8645992Swnj 		int	count;
86538408Smckusick 	} *uap = (struct a *)scp->sc_ap;
86638408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
86737741Smckusick 	register struct vnode *vp;
86837741Smckusick 	struct iovec aiov;
86937741Smckusick 	struct uio auio;
87037741Smckusick 	int error;
8715992Swnj 
87237741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
87316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
87416694Smckusick 	ndp->ni_dirp = uap->name;
87537741Smckusick 	if (error = namei(ndp))
87637741Smckusick 		RETURN (error);
87737741Smckusick 	vp = ndp->ni_vp;
87837741Smckusick 	if (vp->v_type != VLNK) {
87937741Smckusick 		error = EINVAL;
8805992Swnj 		goto out;
8815992Swnj 	}
88237741Smckusick 	aiov.iov_base = uap->buf;
88337741Smckusick 	aiov.iov_len = uap->count;
88437741Smckusick 	auio.uio_iov = &aiov;
88537741Smckusick 	auio.uio_iovcnt = 1;
88637741Smckusick 	auio.uio_offset = 0;
88737741Smckusick 	auio.uio_rw = UIO_READ;
88837741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
88937741Smckusick 	auio.uio_resid = uap->count;
89037741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
8915992Swnj out:
89237741Smckusick 	vput(vp);
89338408Smckusick 	scp->sc_retval1 = uap->count - auio.uio_resid;
89437741Smckusick 	RETURN (error);
8955992Swnj }
8965992Swnj 
8979167Ssam /*
89838259Smckusick  * Change flags of a file given path name.
89938259Smckusick  */
90038408Smckusick chflags(scp)
90138408Smckusick 	register struct syscontext *scp;
90238259Smckusick {
90338259Smckusick 	struct a {
90438259Smckusick 		char	*fname;
90538259Smckusick 		int	flags;
90638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
90738408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
90838259Smckusick 	register struct vnode *vp;
90938259Smckusick 	struct vattr vattr;
91038259Smckusick 	int error;
91138259Smckusick 
91238259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
91338259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
91438259Smckusick 	ndp->ni_dirp = uap->fname;
91538259Smckusick 	vattr_null(&vattr);
91638259Smckusick 	vattr.va_flags = uap->flags;
91738259Smckusick 	if (error = namei(ndp))
91838259Smckusick 		RETURN (error);
91938259Smckusick 	vp = ndp->ni_vp;
92038259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
92138259Smckusick 		error = EROFS;
92238259Smckusick 		goto out;
92338259Smckusick 	}
92438259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
92538259Smckusick out:
92638259Smckusick 	vput(vp);
92738259Smckusick 	RETURN (error);
92838259Smckusick }
92938259Smckusick 
93038259Smckusick /*
93138259Smckusick  * Change flags of a file given a file descriptor.
93238259Smckusick  */
93338408Smckusick fchflags(scp)
93438408Smckusick 	register struct syscontext *scp;
93538259Smckusick {
93638259Smckusick 	struct a {
93738259Smckusick 		int	fd;
93838259Smckusick 		int	flags;
93938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
94038259Smckusick 	struct vattr vattr;
94138259Smckusick 	struct vnode *vp;
94238259Smckusick 	struct file *fp;
94338259Smckusick 	int error;
94438259Smckusick 
94538408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
94638259Smckusick 		RETURN (error);
94738259Smckusick 	vattr_null(&vattr);
94838259Smckusick 	vattr.va_flags = uap->flags;
94938259Smckusick 	vp = (struct vnode *)fp->f_data;
95038259Smckusick 	VOP_LOCK(vp);
95138259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
95238259Smckusick 		error = EROFS;
95338259Smckusick 		goto out;
95438259Smckusick 	}
95538259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
95638259Smckusick out:
95738259Smckusick 	VOP_UNLOCK(vp);
95838259Smckusick 	RETURN (error);
95938259Smckusick }
96038259Smckusick 
96138259Smckusick /*
9629167Ssam  * Change mode of a file given path name.
9639167Ssam  */
96438408Smckusick chmod(scp)
96538408Smckusick 	register struct syscontext *scp;
9665992Swnj {
9677701Ssam 	struct a {
9686254Sroot 		char	*fname;
9696254Sroot 		int	fmode;
97038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
97138408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
97237741Smckusick 	register struct vnode *vp;
97337741Smckusick 	struct vattr vattr;
97437741Smckusick 	int error;
9755992Swnj 
97637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
97737741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
97837741Smckusick 	ndp->ni_dirp = uap->fname;
97937741Smckusick 	vattr_null(&vattr);
98037741Smckusick 	vattr.va_mode = uap->fmode & 07777;
98137741Smckusick 	if (error = namei(ndp))
98237741Smckusick 		RETURN (error);
98337741Smckusick 	vp = ndp->ni_vp;
98437741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
98537741Smckusick 		error = EROFS;
98637741Smckusick 		goto out;
98737741Smckusick 	}
98837741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
98937741Smckusick out:
99037741Smckusick 	vput(vp);
99137741Smckusick 	RETURN (error);
9927701Ssam }
9937439Sroot 
9949167Ssam /*
9959167Ssam  * Change mode of a file given a file descriptor.
9969167Ssam  */
99738408Smckusick fchmod(scp)
99838408Smckusick 	register struct syscontext *scp;
9997701Ssam {
10007701Ssam 	struct a {
10017701Ssam 		int	fd;
10027701Ssam 		int	fmode;
100338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
100437741Smckusick 	struct vattr vattr;
100537741Smckusick 	struct vnode *vp;
100637741Smckusick 	struct file *fp;
100737741Smckusick 	int error;
10087701Ssam 
100938408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
101037741Smckusick 		RETURN (error);
101137741Smckusick 	vattr_null(&vattr);
101237741Smckusick 	vattr.va_mode = uap->fmode & 07777;
101337741Smckusick 	vp = (struct vnode *)fp->f_data;
101437741Smckusick 	VOP_LOCK(vp);
101537741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
101637741Smckusick 		error = EROFS;
101737741Smckusick 		goto out;
10187439Sroot 	}
101937741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
102037741Smckusick out:
102137741Smckusick 	VOP_UNLOCK(vp);
102237741Smckusick 	RETURN (error);
10235992Swnj }
10245992Swnj 
10259167Ssam /*
10269167Ssam  * Set ownership given a path name.
10279167Ssam  */
102838408Smckusick chown(scp)
102938408Smckusick 	register struct syscontext *scp;
103037Sbill {
10317701Ssam 	struct a {
10326254Sroot 		char	*fname;
10336254Sroot 		int	uid;
10346254Sroot 		int	gid;
103538408Smckusick 	} *uap = (struct a *)scp->sc_ap;
103638408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
103737741Smckusick 	register struct vnode *vp;
103837741Smckusick 	struct vattr vattr;
103937741Smckusick 	int error;
104037Sbill 
104137741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
104236614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
104336614Sbostic 	ndp->ni_dirp = uap->fname;
104437741Smckusick 	vattr_null(&vattr);
104537741Smckusick 	vattr.va_uid = uap->uid;
104637741Smckusick 	vattr.va_gid = uap->gid;
104737741Smckusick 	if (error = namei(ndp))
104837741Smckusick 		RETURN (error);
104937741Smckusick 	vp = ndp->ni_vp;
105037741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
105137741Smckusick 		error = EROFS;
105237741Smckusick 		goto out;
105337741Smckusick 	}
105437741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
105537741Smckusick out:
105637741Smckusick 	vput(vp);
105737741Smckusick 	RETURN (error);
10587701Ssam }
10597439Sroot 
10609167Ssam /*
10619167Ssam  * Set ownership given a file descriptor.
10629167Ssam  */
106338408Smckusick fchown(scp)
106438408Smckusick 	register struct syscontext *scp;
10657701Ssam {
10667701Ssam 	struct a {
10677701Ssam 		int	fd;
10687701Ssam 		int	uid;
10697701Ssam 		int	gid;
107038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
107137741Smckusick 	struct vattr vattr;
107237741Smckusick 	struct vnode *vp;
107337741Smckusick 	struct file *fp;
107437741Smckusick 	int error;
10757701Ssam 
107638408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
107737741Smckusick 		RETURN (error);
107837741Smckusick 	vattr_null(&vattr);
107937741Smckusick 	vattr.va_uid = uap->uid;
108037741Smckusick 	vattr.va_gid = uap->gid;
108137741Smckusick 	vp = (struct vnode *)fp->f_data;
108237741Smckusick 	VOP_LOCK(vp);
108337741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
108437741Smckusick 		error = EROFS;
108537741Smckusick 		goto out;
108637741Smckusick 	}
108737741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
108837741Smckusick out:
108937741Smckusick 	VOP_UNLOCK(vp);
109037741Smckusick 	RETURN (error);
10917701Ssam }
10927701Ssam 
109338408Smckusick utimes(scp)
109438408Smckusick 	register struct syscontext *scp;
109511811Ssam {
109611811Ssam 	register struct a {
109711811Ssam 		char	*fname;
109811811Ssam 		struct	timeval *tptr;
109938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
110038408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
110137741Smckusick 	register struct vnode *vp;
110211811Ssam 	struct timeval tv[2];
110337741Smckusick 	struct vattr vattr;
110437741Smckusick 	int error;
110511811Ssam 
110637741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
110737741Smckusick 		RETURN (error);
110837741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
110937741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
111037741Smckusick 	ndp->ni_dirp = uap->fname;
111137741Smckusick 	vattr_null(&vattr);
111237741Smckusick 	vattr.va_atime = tv[0];
111337741Smckusick 	vattr.va_mtime = tv[1];
111437741Smckusick 	if (error = namei(ndp))
111537741Smckusick 		RETURN (error);
111637741Smckusick 	vp = ndp->ni_vp;
111737741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
111837741Smckusick 		error = EROFS;
111937741Smckusick 		goto out;
112021015Smckusick 	}
112137741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
112237741Smckusick out:
112337741Smckusick 	vput(vp);
112437741Smckusick 	RETURN (error);
112511811Ssam }
112611811Ssam 
11279167Ssam /*
11289167Ssam  * Truncate a file given its path name.
11299167Ssam  */
113038408Smckusick truncate(scp)
113138408Smckusick 	register struct syscontext *scp;
11327701Ssam {
11337701Ssam 	struct a {
11347701Ssam 		char	*fname;
113526473Skarels 		off_t	length;
113638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
113738408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
113837741Smckusick 	register struct vnode *vp;
113937741Smckusick 	struct vattr vattr;
114037741Smckusick 	int error;
11417701Ssam 
114237741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
114316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
114416694Smckusick 	ndp->ni_dirp = uap->fname;
114537741Smckusick 	vattr_null(&vattr);
114637741Smckusick 	vattr.va_size = uap->length;
114737741Smckusick 	if (error = namei(ndp))
114837741Smckusick 		RETURN (error);
114937741Smckusick 	vp = ndp->ni_vp;
115037741Smckusick 	if (vp->v_type == VDIR) {
115137741Smckusick 		error = EISDIR;
115237741Smckusick 		goto out;
11537701Ssam 	}
115438399Smckusick 	if ((error = vn_writechk(vp)) ||
115538399Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
115637741Smckusick 		goto out;
115737741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
115837741Smckusick out:
115937741Smckusick 	vput(vp);
116037741Smckusick 	RETURN (error);
11617701Ssam }
11627701Ssam 
11639167Ssam /*
11649167Ssam  * Truncate a file given a file descriptor.
11659167Ssam  */
116638408Smckusick ftruncate(scp)
116738408Smckusick 	register struct syscontext *scp;
11687701Ssam {
11697701Ssam 	struct a {
11707701Ssam 		int	fd;
117126473Skarels 		off_t	length;
117238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
117337741Smckusick 	struct vattr vattr;
117437741Smckusick 	struct vnode *vp;
11757701Ssam 	struct file *fp;
117637741Smckusick 	int error;
11777701Ssam 
117838408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
117937741Smckusick 		RETURN (error);
118037741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
118137741Smckusick 		RETURN (EINVAL);
118237741Smckusick 	vattr_null(&vattr);
118337741Smckusick 	vattr.va_size = uap->length;
118437741Smckusick 	vp = (struct vnode *)fp->f_data;
118537741Smckusick 	VOP_LOCK(vp);
118637741Smckusick 	if (vp->v_type == VDIR) {
118737741Smckusick 		error = EISDIR;
118837741Smckusick 		goto out;
11897701Ssam 	}
119038399Smckusick 	if (error = vn_writechk(vp))
119137741Smckusick 		goto out;
119237741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
119337741Smckusick out:
119437741Smckusick 	VOP_UNLOCK(vp);
119537741Smckusick 	RETURN (error);
11967701Ssam }
11977701Ssam 
11989167Ssam /*
11999167Ssam  * Synch an open file.
12009167Ssam  */
120138408Smckusick fsync(scp)
120238408Smckusick 	register struct syscontext *scp;
12039167Ssam {
12049167Ssam 	struct a {
12059167Ssam 		int	fd;
120638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
120739592Smckusick 	register struct vnode *vp;
12089167Ssam 	struct file *fp;
120937741Smckusick 	int error;
12109167Ssam 
121138408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
121237741Smckusick 		RETURN (error);
121339592Smckusick 	vp = (struct vnode *)fp->f_data;
121439592Smckusick 	VOP_LOCK(vp);
121539592Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT);
121639592Smckusick 	VOP_UNLOCK(vp);
121737741Smckusick 	RETURN (error);
12189167Ssam }
12199167Ssam 
12209167Ssam /*
12219167Ssam  * Rename system call.
12229167Ssam  *
12239167Ssam  * Source and destination must either both be directories, or both
12249167Ssam  * not be directories.  If target is a directory, it must be empty.
12259167Ssam  */
122638408Smckusick rename(scp)
122738408Smckusick 	register struct syscontext *scp;
12287701Ssam {
12297701Ssam 	struct a {
12307701Ssam 		char	*from;
12317701Ssam 		char	*to;
123238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
123337741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
123438408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
123537741Smckusick 	struct nameidata tond;
123637741Smckusick 	int error;
12377701Ssam 
123837741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
123916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
124016694Smckusick 	ndp->ni_dirp = uap->from;
124137741Smckusick 	if (error = namei(ndp))
124237741Smckusick 		RETURN (error);
124337741Smckusick 	fvp = ndp->ni_vp;
124438266Smckusick 	nddup(ndp, &tond);
124537741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
124637741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
124737741Smckusick 	tond.ni_dirp = uap->to;
124837741Smckusick 	error = namei(&tond);
124937741Smckusick 	tdvp = tond.ni_dvp;
125037741Smckusick 	tvp = tond.ni_vp;
125137741Smckusick 	if (tvp != NULL) {
125237741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
125339242Sbostic 			error = ENOTDIR;
125437741Smckusick 			goto out;
125537741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
125639242Sbostic 			error = EISDIR;
125737741Smckusick 			goto out;
12589167Ssam 		}
12599167Ssam 	}
126037741Smckusick 	if (error) {
126137741Smckusick 		VOP_ABORTOP(ndp);
126237741Smckusick 		goto out1;
126337741Smckusick 	}
126437741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
126537741Smckusick 		error = EXDEV;
12669167Ssam 		goto out;
126710051Ssam 	}
126839286Smckusick 	if (fvp == tdvp)
126937741Smckusick 		error = EINVAL;
127039286Smckusick 	/*
127139286Smckusick 	 * If source is the same as the destination,
127239286Smckusick 	 * then there is nothing to do.
127339286Smckusick 	 */
127439286Smckusick 	if (fvp == tvp)
127539286Smckusick 		error = -1;
127637741Smckusick out:
127737741Smckusick 	if (error) {
127837741Smckusick 		VOP_ABORTOP(&tond);
127937741Smckusick 		VOP_ABORTOP(ndp);
12809167Ssam 	} else {
128137741Smckusick 		error = VOP_RENAME(ndp, &tond);
12829167Ssam 	}
128337741Smckusick out1:
128438266Smckusick 	ndrele(&tond);
128539286Smckusick 	if (error == -1)
128639286Smckusick 		RETURN (0);
128737741Smckusick 	RETURN (error);
12887701Ssam }
12897701Ssam 
12907535Sroot /*
129112756Ssam  * Mkdir system call
129212756Ssam  */
129338408Smckusick mkdir(scp)
129438408Smckusick 	register struct syscontext *scp;
129512756Ssam {
129612756Ssam 	struct a {
129712756Ssam 		char	*name;
129812756Ssam 		int	dmode;
129938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
130038408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
130137741Smckusick 	register struct vnode *vp;
130237741Smckusick 	struct vattr vattr;
130337741Smckusick 	int error;
130412756Ssam 
130537741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
130616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
130716694Smckusick 	ndp->ni_dirp = uap->name;
130837741Smckusick 	if (error = namei(ndp))
130937741Smckusick 		RETURN (error);
131037741Smckusick 	vp = ndp->ni_vp;
131137741Smckusick 	if (vp != NULL) {
131237741Smckusick 		VOP_ABORTOP(ndp);
131337741Smckusick 		RETURN (EEXIST);
131412756Ssam 	}
131537741Smckusick 	vattr_null(&vattr);
131637741Smckusick 	vattr.va_type = VDIR;
131738408Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask;
131837741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
131938145Smckusick 	if (!error)
132038145Smckusick 		vput(ndp->ni_vp);
132137741Smckusick 	RETURN (error);
132212756Ssam }
132312756Ssam 
132412756Ssam /*
132512756Ssam  * Rmdir system call.
132612756Ssam  */
132738408Smckusick rmdir(scp)
132838408Smckusick 	register struct syscontext *scp;
132912756Ssam {
133012756Ssam 	struct a {
133112756Ssam 		char	*name;
133238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
133338408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
133437741Smckusick 	register struct vnode *vp;
133537741Smckusick 	int error;
133612756Ssam 
133737741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
133816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
133916694Smckusick 	ndp->ni_dirp = uap->name;
134037741Smckusick 	if (error = namei(ndp))
134137741Smckusick 		RETURN (error);
134237741Smckusick 	vp = ndp->ni_vp;
134337741Smckusick 	if (vp->v_type != VDIR) {
134437741Smckusick 		error = ENOTDIR;
134512756Ssam 		goto out;
134612756Ssam 	}
134712756Ssam 	/*
134837741Smckusick 	 * No rmdir "." please.
134912756Ssam 	 */
135037741Smckusick 	if (ndp->ni_dvp == vp) {
135137741Smckusick 		error = EINVAL;
135212756Ssam 		goto out;
135312756Ssam 	}
135412756Ssam 	/*
135537741Smckusick 	 * Don't unlink a mounted file.
135612756Ssam 	 */
135737741Smckusick 	if (vp->v_flag & VROOT)
135837741Smckusick 		error = EBUSY;
135912756Ssam out:
136037741Smckusick 	if (error)
136137741Smckusick 		VOP_ABORTOP(ndp);
136237741Smckusick 	else
136337741Smckusick 		error = VOP_RMDIR(ndp);
136437741Smckusick 	RETURN (error);
136512756Ssam }
136612756Ssam 
136737741Smckusick /*
136837741Smckusick  * Read a block of directory entries in a file system independent format
136937741Smckusick  */
137038408Smckusick getdirentries(scp)
137138408Smckusick 	register struct syscontext *scp;
137212756Ssam {
137337741Smckusick 	register struct a {
137437741Smckusick 		int	fd;
137537741Smckusick 		char	*buf;
137637741Smckusick 		unsigned count;
137737741Smckusick 		long	*basep;
137838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
137939592Smckusick 	register struct vnode *vp;
138016540Ssam 	struct file *fp;
138137741Smckusick 	struct uio auio;
138237741Smckusick 	struct iovec aiov;
138338129Smckusick 	off_t off;
138437741Smckusick 	int error;
138512756Ssam 
138638408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
138737741Smckusick 		RETURN (error);
138837741Smckusick 	if ((fp->f_flag & FREAD) == 0)
138937741Smckusick 		RETURN (EBADF);
139039592Smckusick 	vp = (struct vnode *)fp->f_data;
139139592Smckusick 	if (vp->v_type != VDIR)
139239592Smckusick 		RETURN (EINVAL);
139337741Smckusick 	aiov.iov_base = uap->buf;
139437741Smckusick 	aiov.iov_len = uap->count;
139537741Smckusick 	auio.uio_iov = &aiov;
139637741Smckusick 	auio.uio_iovcnt = 1;
139737741Smckusick 	auio.uio_rw = UIO_READ;
139837741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
139937741Smckusick 	auio.uio_resid = uap->count;
140039592Smckusick 	VOP_LOCK(vp);
140139592Smckusick 	auio.uio_offset = off = fp->f_offset;
140239592Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred);
140339592Smckusick 	fp->f_offset = auio.uio_offset;
140439592Smckusick 	VOP_UNLOCK(vp);
140539592Smckusick 	if (error)
140637741Smckusick 		RETURN (error);
140739592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
140838408Smckusick 	scp->sc_retval1 = uap->count - auio.uio_resid;
140937741Smckusick 	RETURN (error);
141012756Ssam }
141112756Ssam 
141212756Ssam /*
141312756Ssam  * mode mask for creation of files
141412756Ssam  */
141538408Smckusick umask(scp)
141638408Smckusick 	register struct syscontext *scp;
141712756Ssam {
141812756Ssam 	register struct a {
141912756Ssam 		int	mask;
142038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
142112756Ssam 
142238408Smckusick 	scp->sc_retval1 = scp->sc_cmask;
142338408Smckusick 	scp->sc_cmask = uap->mask & 07777;
142437741Smckusick 	RETURN (0);
142512756Ssam }
142637741Smckusick 
142739566Smarc /*
142839566Smarc  * Void all references to file by ripping underlying filesystem
142939566Smarc  * away from vnode.
143039566Smarc  */
143139566Smarc revoke(scp)
143239566Smarc 	register struct syscontext *scp;
143339566Smarc {
143439566Smarc 	struct a {
143539566Smarc 		char	*fname;
143639566Smarc 	} *uap = (struct a *)scp->sc_ap;
143739566Smarc 	register struct nameidata *ndp = &scp->sc_nd;
143839566Smarc 	register struct vnode *vp;
143939566Smarc 	struct vattr vattr;
144039566Smarc 	int error;
144139566Smarc 
144239566Smarc 	ndp->ni_nameiop = LOOKUP | FOLLOW;
144339566Smarc 	ndp->ni_segflg = UIO_USERSPACE;
144439566Smarc 	ndp->ni_dirp = uap->fname;
144539566Smarc 	if (error = namei(ndp))
144639566Smarc 		RETURN (error);
144739566Smarc 	vp = ndp->ni_vp;
144839566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
144939566Smarc 		error = EINVAL;
145039566Smarc 		goto out;
145139566Smarc 	}
145239566Smarc 	if (error = VOP_GETATTR(vp, &vattr, scp->sc_cred))
145339566Smarc 		goto out;
145439566Smarc 	if (scp->sc_uid != vattr.va_uid ||
145539566Smarc 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
145639566Smarc 		goto out;
145739805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
145839632Smckusick 		vgoneall(vp);
145939566Smarc out:
146039566Smarc 	vrele(vp);
146139566Smarc 	RETURN (error);
146239566Smarc }
146339566Smarc 
146438408Smckusick getvnode(ofile, fdes, fpp)
146538408Smckusick 	struct file *ofile[];
146637741Smckusick 	struct file **fpp;
146737741Smckusick 	int fdes;
146837741Smckusick {
146937741Smckusick 	struct file *fp;
147037741Smckusick 
147138408Smckusick 	if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
147237741Smckusick 		return (EBADF);
147337741Smckusick 	if (fp->f_type != DTYPE_VNODE)
147437741Smckusick 		return (EINVAL);
147537741Smckusick 	*fpp = fp;
147637741Smckusick 	return (0);
147737741Smckusick }
1478