xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 40110)
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*40110Smckusick  *	@(#)vfs_syscalls.c	7.37 (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;
5537741Smckusick 	int error;
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 		}
8639335Smckusick 		mp->m_flag |= M_UPDATE;
8739335Smckusick 		VOP_UNLOCK(vp);
8839335Smckusick 		goto update;
8939335Smckusick 	}
9039665Smckusick 	vinvalbuf(vp, 1);
9139805Smckusick 	if (vp->v_usecount != 1) {
9237741Smckusick 		vput(vp);
9337741Smckusick 		RETURN (EBUSY);
9437741Smckusick 	}
9537741Smckusick 	if (vp->v_type != VDIR) {
9637741Smckusick 		vput(vp);
9737741Smckusick 		RETURN (ENOTDIR);
9837741Smckusick 	}
9939741Smckusick 	if ((unsigned long)uap->type > MOUNT_MAXTYPE ||
10037741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
10137741Smckusick 		vput(vp);
10237741Smckusick 		RETURN (ENODEV);
10337741Smckusick 	}
10437741Smckusick 
10537741Smckusick 	/*
10639335Smckusick 	 * Allocate and initialize the file system.
10737741Smckusick 	 */
10837741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
10937741Smckusick 		M_MOUNT, M_WAITOK);
11037741Smckusick 	mp->m_op = vfssw[uap->type];
11137741Smckusick 	mp->m_flag = 0;
11237741Smckusick 	mp->m_exroot = 0;
11339381Smckusick 	mp->m_mounth = (struct vnode *)0;
11439335Smckusick 	if (error = vfs_lock(mp)) {
11539335Smckusick 		free((caddr_t)mp, M_MOUNT);
11639335Smckusick 		vput(vp);
11739335Smckusick 		RETURN (error);
11839335Smckusick 	}
11939335Smckusick 	if (vp->v_mountedhere != (struct mount *)0) {
12039335Smckusick 		vfs_unlock(mp);
12139335Smckusick 		free((caddr_t)mp, M_MOUNT);
12239335Smckusick 		vput(vp);
12339335Smckusick 		RETURN (EBUSY);
12439335Smckusick 	}
12539335Smckusick 	vp->v_mountedhere = mp;
12639335Smckusick 	mp->m_vnodecovered = vp;
12739335Smckusick update:
12839335Smckusick 	/*
12939335Smckusick 	 * Set the mount level flags.
13039335Smckusick 	 */
13139335Smckusick 	if (uap->flags & M_RDONLY)
13239335Smckusick 		mp->m_flag |= M_RDONLY;
13339335Smckusick 	else
13439335Smckusick 		mp->m_flag &= ~M_RDONLY;
13539335Smckusick 	if (uap->flags & M_NOSUID)
13639335Smckusick 		mp->m_flag |= M_NOSUID;
13739335Smckusick 	else
13839335Smckusick 		mp->m_flag &= ~M_NOSUID;
13939335Smckusick 	if (uap->flags & M_NOEXEC)
14039335Smckusick 		mp->m_flag |= M_NOEXEC;
14139335Smckusick 	else
14239335Smckusick 		mp->m_flag &= ~M_NOEXEC;
14339335Smckusick 	if (uap->flags & M_NODEV)
14439335Smckusick 		mp->m_flag |= M_NODEV;
14539335Smckusick 	else
14639335Smckusick 		mp->m_flag &= ~M_NODEV;
14739335Smckusick 	if (uap->flags & M_SYNCHRONOUS)
14839335Smckusick 		mp->m_flag |= M_SYNCHRONOUS;
14939335Smckusick 	else
15039335Smckusick 		mp->m_flag &= ~M_SYNCHRONOUS;
15139335Smckusick 	/*
15239335Smckusick 	 * Mount the filesystem.
15339335Smckusick 	 */
15439335Smckusick 	error = VFS_MOUNT(mp, uap->dir, uap->data, ndp);
15539335Smckusick 	if (mp->m_flag & M_UPDATE) {
15639335Smckusick 		mp->m_flag &= ~M_UPDATE;
15739335Smckusick 		vrele(vp);
15839335Smckusick 		RETURN (error);
15939335Smckusick 	}
160*40110Smckusick 	/*
161*40110Smckusick 	 * Put the new filesystem on the mount list after root.
162*40110Smckusick 	 */
163*40110Smckusick 	mp->m_next = rootfs->m_next;
164*40110Smckusick 	mp->m_prev = rootfs;
165*40110Smckusick 	rootfs->m_next = mp;
166*40110Smckusick 	mp->m_next->m_prev = mp;
16737741Smckusick 	cache_purge(vp);
16837741Smckusick 	if (!error) {
16939335Smckusick 		VOP_UNLOCK(vp);
17037741Smckusick 		vfs_unlock(mp);
17139044Smckusick 		error = VFS_START(mp, 0);
17237741Smckusick 	} else {
17337741Smckusick 		vfs_remove(mp);
17437741Smckusick 		free((caddr_t)mp, M_MOUNT);
17539335Smckusick 		vput(vp);
17637741Smckusick 	}
17737741Smckusick 	RETURN (error);
1786254Sroot }
1796254Sroot 
1809167Ssam /*
18137741Smckusick  * Unmount system call.
18237741Smckusick  *
18337741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
18437741Smckusick  * not special file (as before).
1859167Ssam  */
18638408Smckusick unmount(scp)
18738408Smckusick 	register struct syscontext *scp;
1886254Sroot {
18937741Smckusick 	struct a {
19037741Smckusick 		char	*pathp;
19137741Smckusick 		int	flags;
19238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
19337741Smckusick 	register struct vnode *vp;
19438408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
19539356Smckusick 	struct mount *mp;
19637741Smckusick 	int error;
1976254Sroot 
19837741Smckusick 	/*
19937741Smckusick 	 * Must be super user
20037741Smckusick 	 */
20138408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
20237741Smckusick 		RETURN (error);
20337741Smckusick 
20437741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
20537741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
20637741Smckusick 	ndp->ni_dirp = uap->pathp;
20737741Smckusick 	if (error = namei(ndp))
20837741Smckusick 		RETURN (error);
20937741Smckusick 	vp = ndp->ni_vp;
21037741Smckusick 	/*
21137741Smckusick 	 * Must be the root of the filesystem
21237741Smckusick 	 */
21337741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
21437741Smckusick 		vput(vp);
21537741Smckusick 		RETURN (EINVAL);
21637741Smckusick 	}
21737741Smckusick 	mp = vp->v_mount;
21837741Smckusick 	vput(vp);
21939356Smckusick 	RETURN (dounmount(mp, uap->flags));
22039356Smckusick }
22139356Smckusick 
22239356Smckusick /*
22339356Smckusick  * Do an unmount.
22439356Smckusick  */
22539356Smckusick dounmount(mp, flags)
22639356Smckusick 	register struct mount *mp;
22739356Smckusick 	int flags;
22839356Smckusick {
22939356Smckusick 	struct vnode *coveredvp;
23039356Smckusick 	int error;
23139356Smckusick 
23237741Smckusick 	coveredvp = mp->m_vnodecovered;
23337741Smckusick 	if (error = vfs_lock(mp))
23439356Smckusick 		return (error);
23537741Smckusick 
23637741Smckusick 	xumount(mp);		/* remove unused sticky files from text table */
23737741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
23837741Smckusick 	VFS_SYNC(mp, MNT_WAIT);
23937741Smckusick 
24039356Smckusick 	error = VFS_UNMOUNT(mp, flags);
24137741Smckusick 	if (error) {
24237741Smckusick 		vfs_unlock(mp);
24337741Smckusick 	} else {
24437741Smckusick 		vrele(coveredvp);
24537741Smckusick 		vfs_remove(mp);
24637741Smckusick 		free((caddr_t)mp, M_MOUNT);
24737741Smckusick 	}
24839356Smckusick 	return (error);
2496254Sroot }
2506254Sroot 
2519167Ssam /*
25237741Smckusick  * Sync system call.
25337741Smckusick  * Sync each mounted filesystem.
2549167Ssam  */
25539491Smckusick /* ARGSUSED */
25638408Smckusick sync(scp)
25739491Smckusick 	struct syscontext *scp;
2586254Sroot {
25937741Smckusick 	register struct mount *mp;
260*40110Smckusick 	struct mount *nmp;
26137741Smckusick 
26237741Smckusick 	mp = rootfs;
26337741Smckusick 	do {
264*40110Smckusick 		nmp = mp->m_next;
265*40110Smckusick 		if ((mp->m_flag & (M_MLOCK|M_RDONLY)) == 0)
26637741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
267*40110Smckusick 		mp = nmp;
26837741Smckusick 	} while (mp != rootfs);
26937741Smckusick }
27037741Smckusick 
27137741Smckusick /*
27237741Smckusick  * get filesystem statistics
27337741Smckusick  */
27438408Smckusick statfs(scp)
27538408Smckusick 	register struct syscontext *scp;
27637741Smckusick {
2776254Sroot 	struct a {
27837741Smckusick 		char *path;
27937741Smckusick 		struct statfs *buf;
28038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
28139464Smckusick 	register struct mount *mp;
28238408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
28337741Smckusick 	struct statfs sb;
28437741Smckusick 	int error;
28537741Smckusick 
28639544Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
28737741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
28837741Smckusick 	ndp->ni_dirp = uap->path;
28937741Smckusick 	if (error = namei(ndp))
29037741Smckusick 		RETURN (error);
29139544Smckusick 	mp = ndp->ni_vp->v_mount;
29239544Smckusick 	vrele(ndp->ni_vp);
29339464Smckusick 	if (error = VFS_STATFS(mp, &sb))
29439544Smckusick 		RETURN (error);
29539464Smckusick 	sb.f_flags = mp->m_flag & M_VISFLAGMASK;
29639464Smckusick 	sb.f_fsid = mp->m_fsid;
29739544Smckusick 	RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)));
29837741Smckusick }
29937741Smckusick 
30038408Smckusick fstatfs(scp)
30138408Smckusick 	register struct syscontext *scp;
30237741Smckusick {
30337741Smckusick 	struct a {
30437741Smckusick 		int fd;
30537741Smckusick 		struct statfs *buf;
30638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
30737741Smckusick 	struct file *fp;
30839464Smckusick 	struct mount *mp;
30937741Smckusick 	struct statfs sb;
31037741Smckusick 	int error;
31137741Smckusick 
31238408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
31337741Smckusick 		RETURN (error);
31439464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
31539464Smckusick 	if (error = VFS_STATFS(mp, &sb))
31637741Smckusick 		RETURN (error);
31739464Smckusick 	sb.f_flags = mp->m_flag & M_VISFLAGMASK;
31839464Smckusick 	sb.f_fsid = mp->m_fsid;
31937741Smckusick 	RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)));
32037741Smckusick }
32137741Smckusick 
32237741Smckusick /*
32338270Smckusick  * get statistics on all filesystems
32438270Smckusick  */
32538408Smckusick getfsstat(scp)
32638408Smckusick 	register struct syscontext *scp;
32738270Smckusick {
32838270Smckusick 	struct a {
32938270Smckusick 		struct statfs *buf;
33038270Smckusick 		long bufsize;
33138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
33238270Smckusick 	register struct mount *mp;
33339606Smckusick 	caddr_t sfsp;
33438270Smckusick 	long count, maxcount, error;
33539606Smckusick 	struct statfs sb;
33638270Smckusick 
33738270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
33839606Smckusick 	sfsp = (caddr_t)uap->buf;
33938270Smckusick 	mp = rootfs;
34038270Smckusick 	count = 0;
34138270Smckusick 	do {
34239606Smckusick 		if (sfsp && count < maxcount && ((mp->m_flag & M_MLOCK) == 0)) {
34339607Smckusick 			if (error = VFS_STATFS(mp, &sb)) {
34439607Smckusick 				mp = mp->m_prev;
34539607Smckusick 				continue;
34639607Smckusick 			}
34739606Smckusick 			sb.f_flags = mp->m_flag & M_VISFLAGMASK;
34839606Smckusick 			sb.f_fsid = mp->m_fsid;
34939606Smckusick 			if (error = copyout((caddr_t)&sb, sfsp, sizeof(sb)))
35039606Smckusick 				RETURN (error);
35139606Smckusick 			sfsp += sizeof(sb);
35238270Smckusick 		}
35339606Smckusick 		count++;
35438270Smckusick 		mp = mp->m_prev;
35538270Smckusick 	} while (mp != rootfs);
35638270Smckusick 	if (sfsp && count > maxcount)
35738408Smckusick 		scp->sc_retval1 = maxcount;
35838270Smckusick 	else
35938408Smckusick 		scp->sc_retval1 = count;
36038270Smckusick 	RETURN (0);
36138270Smckusick }
36238270Smckusick 
36338270Smckusick /*
36438259Smckusick  * Change current working directory to a given file descriptor.
36538259Smckusick  */
36638408Smckusick fchdir(scp)
36738408Smckusick 	register struct syscontext *scp;
36838259Smckusick {
36938259Smckusick 	struct a {
37038259Smckusick 		int	fd;
37138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
37238259Smckusick 	register struct vnode *vp;
37338259Smckusick 	struct file *fp;
37438259Smckusick 	int error;
37538259Smckusick 
37638408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
37738259Smckusick 		RETURN (error);
37838259Smckusick 	vp = (struct vnode *)fp->f_data;
37938259Smckusick 	VOP_LOCK(vp);
38038259Smckusick 	if (vp->v_type != VDIR)
38138259Smckusick 		error = ENOTDIR;
38238259Smckusick 	else
38338408Smckusick 		error = VOP_ACCESS(vp, VEXEC, scp->sc_cred);
38438259Smckusick 	VOP_UNLOCK(vp);
38539860Smckusick 	if (error)
38639860Smckusick 		RETURN (error);
38739860Smckusick 	VREF(vp);
38838408Smckusick 	vrele(scp->sc_cdir);
38938408Smckusick 	scp->sc_cdir = vp;
39039860Smckusick 	RETURN (0);
39138259Smckusick }
39238259Smckusick 
39338259Smckusick /*
39437741Smckusick  * Change current working directory (``.'').
39537741Smckusick  */
39638408Smckusick chdir(scp)
39738408Smckusick 	register struct syscontext *scp;
39837741Smckusick {
39937741Smckusick 	struct a {
4006254Sroot 		char	*fname;
40138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
40238408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
40337741Smckusick 	int error;
4046254Sroot 
40537741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
40616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
40716694Smckusick 	ndp->ni_dirp = uap->fname;
40837741Smckusick 	if (error = chdirec(ndp))
40937741Smckusick 		RETURN (error);
41038408Smckusick 	vrele(scp->sc_cdir);
41138408Smckusick 	scp->sc_cdir = ndp->ni_vp;
41237741Smckusick 	RETURN (0);
41337741Smckusick }
4146254Sroot 
41537741Smckusick /*
41637741Smckusick  * Change notion of root (``/'') directory.
41737741Smckusick  */
41838408Smckusick chroot(scp)
41938408Smckusick 	register struct syscontext *scp;
42037741Smckusick {
42137741Smckusick 	struct a {
42237741Smckusick 		char	*fname;
42338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
42438408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
42537741Smckusick 	int error;
42637741Smckusick 
42738408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
42837741Smckusick 		RETURN (error);
42937741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
43037741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
43137741Smckusick 	ndp->ni_dirp = uap->fname;
43237741Smckusick 	if (error = chdirec(ndp))
43337741Smckusick 		RETURN (error);
43439515Smckusick 	if (scp->sc_rdir != NULL)
43539515Smckusick 		vrele(scp->sc_rdir);
43638408Smckusick 	scp->sc_rdir = ndp->ni_vp;
43737741Smckusick 	RETURN (0);
4386254Sroot }
4396254Sroot 
44037Sbill /*
44137741Smckusick  * Common routine for chroot and chdir.
44237741Smckusick  */
44337741Smckusick chdirec(ndp)
44437741Smckusick 	register struct nameidata *ndp;
44537741Smckusick {
44637741Smckusick 	struct vnode *vp;
44737741Smckusick 	int error;
44837741Smckusick 
44937741Smckusick 	if (error = namei(ndp))
45037741Smckusick 		return (error);
45137741Smckusick 	vp = ndp->ni_vp;
45237741Smckusick 	if (vp->v_type != VDIR)
45337741Smckusick 		error = ENOTDIR;
45437741Smckusick 	else
45538399Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
45637741Smckusick 	VOP_UNLOCK(vp);
45737741Smckusick 	if (error)
45837741Smckusick 		vrele(vp);
45937741Smckusick 	return (error);
46037741Smckusick }
46137741Smckusick 
46237741Smckusick /*
4636254Sroot  * Open system call.
4646254Sroot  */
46538408Smckusick open(scp)
46638408Smckusick 	register struct syscontext *scp;
4676254Sroot {
46812756Ssam 	struct a {
4696254Sroot 		char	*fname;
4707701Ssam 		int	mode;
47112756Ssam 		int	crtmode;
47238408Smckusick 	} *uap = (struct a *) scp->sc_ap;
47338408Smckusick 	struct nameidata *ndp = &scp->sc_nd;
4746254Sroot 
47537741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
47637741Smckusick 	ndp->ni_dirp = uap->fname;
47738408Smckusick 	RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp,
47838408Smckusick 		&scp->sc_retval1));
4796254Sroot }
4806254Sroot 
4816254Sroot /*
4826254Sroot  * Creat system call.
4836254Sroot  */
48438408Smckusick creat(scp)
48538408Smckusick 	register struct syscontext *scp;
4866254Sroot {
48712756Ssam 	struct a {
4886254Sroot 		char	*fname;
4896254Sroot 		int	fmode;
49038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
49138408Smckusick 	struct nameidata *ndp = &scp->sc_nd;
4926254Sroot 
49337741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
49437741Smckusick 	ndp->ni_dirp = uap->fname;
49538408Smckusick 	RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask,
49638408Smckusick 		ndp, &scp->sc_retval1));
4976254Sroot }
4986254Sroot 
4996254Sroot /*
5006254Sroot  * Common code for open and creat.
50112756Ssam  * Check permissions, allocate an open file structure,
50212756Ssam  * and call the device open routine if any.
5036254Sroot  */
50438408Smckusick copen(scp, fmode, cmode, ndp, resultfd)
50538408Smckusick 	register struct syscontext *scp;
50637741Smckusick 	int fmode, cmode;
50737741Smckusick 	struct nameidata *ndp;
50837741Smckusick 	int *resultfd;
50912756Ssam {
5106254Sroot 	register struct file *fp;
51137741Smckusick 	struct file *nfp;
51237741Smckusick 	int indx, error;
51337741Smckusick 	extern struct fileops vnops;
5146254Sroot 
51537741Smckusick 	if (error = falloc(&nfp, &indx))
51637741Smckusick 		return (error);
51737741Smckusick 	fp = nfp;
51838408Smckusick 	scp->sc_retval1 = indx;	/* XXX for fdopen() */
51937741Smckusick 	if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) {
52037741Smckusick 		crfree(fp->f_cred);
52137741Smckusick 		fp->f_count--;
52239499Smckusick 		if (error == -1)	/* XXX from fdopen */
52339499Smckusick 			return (0);	/* XXX from fdopen */
52439499Smckusick 		scp->sc_ofile[indx] = NULL;
52537741Smckusick 		return (error);
52612756Ssam 	}
52737741Smckusick 	fp->f_flag = fmode & FMASK;
52837741Smckusick 	fp->f_type = DTYPE_VNODE;
52937741Smckusick 	fp->f_ops = &vnops;
53037741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
53137741Smckusick 	if (resultfd)
53237741Smckusick 		*resultfd = indx;
53337741Smckusick 	return (0);
5346254Sroot }
5356254Sroot 
5366254Sroot /*
5376254Sroot  * Mknod system call
5386254Sroot  */
53938408Smckusick mknod(scp)
54038408Smckusick 	register struct syscontext *scp;
5416254Sroot {
5426254Sroot 	register struct a {
5436254Sroot 		char	*fname;
5446254Sroot 		int	fmode;
5456254Sroot 		int	dev;
54638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
54738408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
54837741Smckusick 	register struct vnode *vp;
54937741Smckusick 	struct vattr vattr;
55037741Smckusick 	int error;
5516254Sroot 
55238408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
55337741Smckusick 		RETURN (error);
55437741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
55516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
55616694Smckusick 	ndp->ni_dirp = uap->fname;
55737741Smckusick 	if (error = namei(ndp))
55837741Smckusick 		RETURN (error);
55937741Smckusick 	vp = ndp->ni_vp;
56037741Smckusick 	if (vp != NULL) {
56137741Smckusick 		error = EEXIST;
56212756Ssam 		goto out;
5636254Sroot 	}
56437741Smckusick 	vattr_null(&vattr);
56537741Smckusick 	switch (uap->fmode & IFMT) {
56612756Ssam 
56715093Smckusick 	case IFMT:	/* used by badsect to flag bad sectors */
56837741Smckusick 		vattr.va_type = VBAD;
56937741Smckusick 		break;
57012756Ssam 	case IFCHR:
57137741Smckusick 		vattr.va_type = VCHR;
57237741Smckusick 		break;
57312756Ssam 	case IFBLK:
57437741Smckusick 		vattr.va_type = VBLK;
57537741Smckusick 		break;
57637741Smckusick 	default:
57737741Smckusick 		error = EINVAL;
57837741Smckusick 		goto out;
5796254Sroot 	}
58038408Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask;
58137741Smckusick 	vattr.va_rdev = uap->dev;
5826254Sroot out:
58337741Smckusick 	if (error)
58437741Smckusick 		VOP_ABORTOP(ndp);
58537741Smckusick 	else
58637741Smckusick 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
58737741Smckusick 	RETURN (error);
5886254Sroot }
5896254Sroot 
5906254Sroot /*
5916254Sroot  * link system call
5926254Sroot  */
59338408Smckusick link(scp)
59438408Smckusick 	register struct syscontext *scp;
5956254Sroot {
5966254Sroot 	register struct a {
5976254Sroot 		char	*target;
5986254Sroot 		char	*linkname;
59938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
60038408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
60137741Smckusick 	register struct vnode *vp, *xp;
60237741Smckusick 	int error;
6036254Sroot 
60416694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
60516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
60616694Smckusick 	ndp->ni_dirp = uap->target;
60737741Smckusick 	if (error = namei(ndp))
60837741Smckusick 		RETURN (error);
60937741Smckusick 	vp = ndp->ni_vp;
61037741Smckusick 	if (vp->v_type == VDIR &&
61138408Smckusick 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
61237741Smckusick 		goto out1;
61337741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
61416694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
61537741Smckusick 	if (error = namei(ndp))
61637741Smckusick 		goto out1;
61737741Smckusick 	xp = ndp->ni_vp;
6186254Sroot 	if (xp != NULL) {
61937741Smckusick 		error = EEXIST;
6206254Sroot 		goto out;
6216254Sroot 	}
62237741Smckusick 	xp = ndp->ni_dvp;
62337741Smckusick 	if (vp->v_mount != xp->v_mount)
62437741Smckusick 		error = EXDEV;
6256254Sroot out:
62637741Smckusick 	if (error)
62737741Smckusick 		VOP_ABORTOP(ndp);
62837741Smckusick 	else
62937741Smckusick 		error = VOP_LINK(vp, ndp);
63037741Smckusick out1:
63137741Smckusick 	vrele(vp);
63237741Smckusick 	RETURN (error);
6336254Sroot }
6346254Sroot 
6356254Sroot /*
6366254Sroot  * symlink -- make a symbolic link
6376254Sroot  */
63838408Smckusick symlink(scp)
63938408Smckusick 	register struct syscontext *scp;
6406254Sroot {
64137741Smckusick 	struct a {
6426254Sroot 		char	*target;
6436254Sroot 		char	*linkname;
64438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
64538408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
64637741Smckusick 	register struct vnode *vp;
64737741Smckusick 	struct vattr vattr;
64837741Smckusick 	char *target;
64937741Smckusick 	int error;
6506254Sroot 
65116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
65216694Smckusick 	ndp->ni_dirp = uap->linkname;
65337741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
65437741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
65537741Smckusick 		goto out1;
65637741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
65737741Smckusick 	if (error = namei(ndp))
65837741Smckusick 		goto out1;
65937741Smckusick 	vp = ndp->ni_vp;
66037741Smckusick 	if (vp) {
66137741Smckusick 		error = EEXIST;
66237741Smckusick 		goto out;
6636254Sroot 	}
66437741Smckusick 	vp = ndp->ni_dvp;
66537741Smckusick 	vattr_null(&vattr);
66638408Smckusick 	vattr.va_mode = 0777 &~ scp->sc_cmask;
66737741Smckusick out:
66837741Smckusick 	if (error)
66937741Smckusick 		VOP_ABORTOP(ndp);
67037741Smckusick 	else
67137741Smckusick 		error = VOP_SYMLINK(ndp, &vattr, target);
67237741Smckusick out1:
67337741Smckusick 	FREE(target, M_NAMEI);
67437741Smckusick 	RETURN (error);
6756254Sroot }
6766254Sroot 
6776254Sroot /*
6786254Sroot  * Unlink system call.
6796254Sroot  * Hard to avoid races here, especially
6806254Sroot  * in unlinking directories.
6816254Sroot  */
68238408Smckusick unlink(scp)
68338408Smckusick 	register struct syscontext *scp;
6846254Sroot {
6856254Sroot 	struct a {
6866254Sroot 		char	*fname;
68738408Smckusick 	} *uap = (struct a *)scp->sc_ap;
68838408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
68937741Smckusick 	register struct vnode *vp;
69037741Smckusick 	int error;
6916254Sroot 
69237741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
69316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
69416694Smckusick 	ndp->ni_dirp = uap->fname;
69537741Smckusick 	if (error = namei(ndp))
69637741Smckusick 		RETURN (error);
69737741Smckusick 	vp = ndp->ni_vp;
69837741Smckusick 	if (vp->v_type == VDIR &&
69938408Smckusick 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
7006254Sroot 		goto out;
7016254Sroot 	/*
7026254Sroot 	 * Don't unlink a mounted file.
7036254Sroot 	 */
70437741Smckusick 	if (vp->v_flag & VROOT) {
70537741Smckusick 		error = EBUSY;
7066254Sroot 		goto out;
7076254Sroot 	}
70837741Smckusick 	if (vp->v_flag & VTEXT)
70937741Smckusick 		xrele(vp);	/* try once to free text */
7106254Sroot out:
71137741Smckusick 	if (error)
71237741Smckusick 		VOP_ABORTOP(ndp);
7137142Smckusick 	else
71437741Smckusick 		error = VOP_REMOVE(ndp);
71537741Smckusick 	RETURN (error);
7166254Sroot }
7176254Sroot 
7186254Sroot /*
7196254Sroot  * Seek system call
7206254Sroot  */
72138408Smckusick lseek(scp)
72238408Smckusick 	register struct syscontext *scp;
7236254Sroot {
7246254Sroot 	register struct file *fp;
7256254Sroot 	register struct a {
72637741Smckusick 		int	fdes;
7276254Sroot 		off_t	off;
7286254Sroot 		int	sbase;
72938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
73037741Smckusick 	struct vattr vattr;
73137741Smckusick 	int error;
7326254Sroot 
73337741Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
73438408Smckusick 	    (fp = scp->sc_ofile[uap->fdes]) == NULL)
73537741Smckusick 		RETURN (EBADF);
73637741Smckusick 	if (fp->f_type != DTYPE_VNODE)
73737741Smckusick 		RETURN (ESPIPE);
73813878Ssam 	switch (uap->sbase) {
73913878Ssam 
74013878Ssam 	case L_INCR:
74113878Ssam 		fp->f_offset += uap->off;
74213878Ssam 		break;
74313878Ssam 
74413878Ssam 	case L_XTND:
74537741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
74638408Smckusick 		    &vattr, scp->sc_cred))
74737741Smckusick 			RETURN (error);
74837741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
74913878Ssam 		break;
75013878Ssam 
75113878Ssam 	case L_SET:
75213878Ssam 		fp->f_offset = uap->off;
75313878Ssam 		break;
75413878Ssam 
75513878Ssam 	default:
75637741Smckusick 		RETURN (EINVAL);
75713878Ssam 	}
75838408Smckusick 	scp->sc_offset = fp->f_offset;
75937741Smckusick 	RETURN (0);
7606254Sroot }
7616254Sroot 
7626254Sroot /*
7636254Sroot  * Access system call
7646254Sroot  */
76538408Smckusick saccess(scp)
76638408Smckusick 	register struct syscontext *scp;
7676254Sroot {
7686254Sroot 	register struct a {
7696254Sroot 		char	*fname;
7706254Sroot 		int	fmode;
77138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
77238408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
77337741Smckusick 	register struct vnode *vp;
77437741Smckusick 	int error, mode, svuid, svgid;
7756254Sroot 
77638408Smckusick 	svuid = scp->sc_uid;
77738408Smckusick 	svgid = scp->sc_gid;
77838408Smckusick 	scp->sc_uid = scp->sc_ruid;
77938408Smckusick 	scp->sc_gid = scp->sc_rgid;
78037741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
78116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
78216694Smckusick 	ndp->ni_dirp = uap->fname;
78337741Smckusick 	if (error = namei(ndp))
78437741Smckusick 		goto out1;
78537741Smckusick 	vp = ndp->ni_vp;
78637741Smckusick 	/*
78737741Smckusick 	 * fmode == 0 means only check for exist
78837741Smckusick 	 */
78937741Smckusick 	if (uap->fmode) {
79037741Smckusick 		mode = 0;
79137741Smckusick 		if (uap->fmode & R_OK)
79237741Smckusick 			mode |= VREAD;
79337741Smckusick 		if (uap->fmode & W_OK)
79437741Smckusick 			mode |= VWRITE;
79537741Smckusick 		if (uap->fmode & X_OK)
79637741Smckusick 			mode |= VEXEC;
79739543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
79838399Smckusick 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
7996254Sroot 	}
80037741Smckusick 	vput(vp);
80137741Smckusick out1:
80238408Smckusick 	scp->sc_uid = svuid;
80338408Smckusick 	scp->sc_gid = svgid;
80437741Smckusick 	RETURN (error);
8056254Sroot }
8066254Sroot 
8076254Sroot /*
8086574Smckusic  * Stat system call.  This version follows links.
80937Sbill  */
81038408Smckusick stat(scp)
81138408Smckusick 	struct syscontext *scp;
81237Sbill {
81337Sbill 
81438408Smckusick 	stat1(scp, FOLLOW);
81537Sbill }
81637Sbill 
81737Sbill /*
8186574Smckusic  * Lstat system call.  This version does not follow links.
8195992Swnj  */
82038408Smckusick lstat(scp)
82138408Smckusick 	struct syscontext *scp;
8225992Swnj {
82312756Ssam 
82438408Smckusick 	stat1(scp, NOFOLLOW);
82512756Ssam }
82612756Ssam 
82738408Smckusick stat1(scp, follow)
82838408Smckusick 	register struct syscontext *scp;
82912756Ssam 	int follow;
83012756Ssam {
8315992Swnj 	register struct a {
8325992Swnj 		char	*fname;
83312756Ssam 		struct stat *ub;
83438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
83538408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
83612756Ssam 	struct stat sb;
83737741Smckusick 	int error;
8385992Swnj 
83937741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
84016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
84116694Smckusick 	ndp->ni_dirp = uap->fname;
84237741Smckusick 	if (error = namei(ndp))
84337741Smckusick 		RETURN (error);
84437741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
84537741Smckusick 	vput(ndp->ni_vp);
84637741Smckusick 	if (error)
84737741Smckusick 		RETURN (error);
84837741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
84937741Smckusick 	RETURN (error);
8505992Swnj }
8515992Swnj 
8525992Swnj /*
8535992Swnj  * Return target name of a symbolic link
85437Sbill  */
85538408Smckusick readlink(scp)
85638408Smckusick 	register struct syscontext *scp;
8575992Swnj {
8585992Swnj 	register struct a {
8595992Swnj 		char	*name;
8605992Swnj 		char	*buf;
8615992Swnj 		int	count;
86238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
86338408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
86437741Smckusick 	register struct vnode *vp;
86537741Smckusick 	struct iovec aiov;
86637741Smckusick 	struct uio auio;
86737741Smckusick 	int error;
8685992Swnj 
86937741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
87016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
87116694Smckusick 	ndp->ni_dirp = uap->name;
87237741Smckusick 	if (error = namei(ndp))
87337741Smckusick 		RETURN (error);
87437741Smckusick 	vp = ndp->ni_vp;
87537741Smckusick 	if (vp->v_type != VLNK) {
87637741Smckusick 		error = EINVAL;
8775992Swnj 		goto out;
8785992Swnj 	}
87937741Smckusick 	aiov.iov_base = uap->buf;
88037741Smckusick 	aiov.iov_len = uap->count;
88137741Smckusick 	auio.uio_iov = &aiov;
88237741Smckusick 	auio.uio_iovcnt = 1;
88337741Smckusick 	auio.uio_offset = 0;
88437741Smckusick 	auio.uio_rw = UIO_READ;
88537741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
88637741Smckusick 	auio.uio_resid = uap->count;
88737741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
8885992Swnj out:
88937741Smckusick 	vput(vp);
89038408Smckusick 	scp->sc_retval1 = uap->count - auio.uio_resid;
89137741Smckusick 	RETURN (error);
8925992Swnj }
8935992Swnj 
8949167Ssam /*
89538259Smckusick  * Change flags of a file given path name.
89638259Smckusick  */
89738408Smckusick chflags(scp)
89838408Smckusick 	register struct syscontext *scp;
89938259Smckusick {
90038259Smckusick 	struct a {
90138259Smckusick 		char	*fname;
90238259Smckusick 		int	flags;
90338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
90438408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
90538259Smckusick 	register struct vnode *vp;
90638259Smckusick 	struct vattr vattr;
90738259Smckusick 	int error;
90838259Smckusick 
90938259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
91038259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
91138259Smckusick 	ndp->ni_dirp = uap->fname;
91238259Smckusick 	vattr_null(&vattr);
91338259Smckusick 	vattr.va_flags = uap->flags;
91438259Smckusick 	if (error = namei(ndp))
91538259Smckusick 		RETURN (error);
91638259Smckusick 	vp = ndp->ni_vp;
91738259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
91838259Smckusick 		error = EROFS;
91938259Smckusick 		goto out;
92038259Smckusick 	}
92138259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
92238259Smckusick out:
92338259Smckusick 	vput(vp);
92438259Smckusick 	RETURN (error);
92538259Smckusick }
92638259Smckusick 
92738259Smckusick /*
92838259Smckusick  * Change flags of a file given a file descriptor.
92938259Smckusick  */
93038408Smckusick fchflags(scp)
93138408Smckusick 	register struct syscontext *scp;
93238259Smckusick {
93338259Smckusick 	struct a {
93438259Smckusick 		int	fd;
93538259Smckusick 		int	flags;
93638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
93738259Smckusick 	struct vattr vattr;
93838259Smckusick 	struct vnode *vp;
93938259Smckusick 	struct file *fp;
94038259Smckusick 	int error;
94138259Smckusick 
94238408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
94338259Smckusick 		RETURN (error);
94438259Smckusick 	vattr_null(&vattr);
94538259Smckusick 	vattr.va_flags = uap->flags;
94638259Smckusick 	vp = (struct vnode *)fp->f_data;
94738259Smckusick 	VOP_LOCK(vp);
94838259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
94938259Smckusick 		error = EROFS;
95038259Smckusick 		goto out;
95138259Smckusick 	}
95238259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
95338259Smckusick out:
95438259Smckusick 	VOP_UNLOCK(vp);
95538259Smckusick 	RETURN (error);
95638259Smckusick }
95738259Smckusick 
95838259Smckusick /*
9599167Ssam  * Change mode of a file given path name.
9609167Ssam  */
96138408Smckusick chmod(scp)
96238408Smckusick 	register struct syscontext *scp;
9635992Swnj {
9647701Ssam 	struct a {
9656254Sroot 		char	*fname;
9666254Sroot 		int	fmode;
96738408Smckusick 	} *uap = (struct a *)scp->sc_ap;
96838408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
96937741Smckusick 	register struct vnode *vp;
97037741Smckusick 	struct vattr vattr;
97137741Smckusick 	int error;
9725992Swnj 
97337741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
97437741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
97537741Smckusick 	ndp->ni_dirp = uap->fname;
97637741Smckusick 	vattr_null(&vattr);
97737741Smckusick 	vattr.va_mode = uap->fmode & 07777;
97837741Smckusick 	if (error = namei(ndp))
97937741Smckusick 		RETURN (error);
98037741Smckusick 	vp = ndp->ni_vp;
98137741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
98237741Smckusick 		error = EROFS;
98337741Smckusick 		goto out;
98437741Smckusick 	}
98537741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
98637741Smckusick out:
98737741Smckusick 	vput(vp);
98837741Smckusick 	RETURN (error);
9897701Ssam }
9907439Sroot 
9919167Ssam /*
9929167Ssam  * Change mode of a file given a file descriptor.
9939167Ssam  */
99438408Smckusick fchmod(scp)
99538408Smckusick 	register struct syscontext *scp;
9967701Ssam {
9977701Ssam 	struct a {
9987701Ssam 		int	fd;
9997701Ssam 		int	fmode;
100038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
100137741Smckusick 	struct vattr vattr;
100237741Smckusick 	struct vnode *vp;
100337741Smckusick 	struct file *fp;
100437741Smckusick 	int error;
10057701Ssam 
100638408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
100737741Smckusick 		RETURN (error);
100837741Smckusick 	vattr_null(&vattr);
100937741Smckusick 	vattr.va_mode = uap->fmode & 07777;
101037741Smckusick 	vp = (struct vnode *)fp->f_data;
101137741Smckusick 	VOP_LOCK(vp);
101237741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
101337741Smckusick 		error = EROFS;
101437741Smckusick 		goto out;
10157439Sroot 	}
101637741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
101737741Smckusick out:
101837741Smckusick 	VOP_UNLOCK(vp);
101937741Smckusick 	RETURN (error);
10205992Swnj }
10215992Swnj 
10229167Ssam /*
10239167Ssam  * Set ownership given a path name.
10249167Ssam  */
102538408Smckusick chown(scp)
102638408Smckusick 	register struct syscontext *scp;
102737Sbill {
10287701Ssam 	struct a {
10296254Sroot 		char	*fname;
10306254Sroot 		int	uid;
10316254Sroot 		int	gid;
103238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
103338408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
103437741Smckusick 	register struct vnode *vp;
103537741Smckusick 	struct vattr vattr;
103637741Smckusick 	int error;
103737Sbill 
103837741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
103936614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
104036614Sbostic 	ndp->ni_dirp = uap->fname;
104137741Smckusick 	vattr_null(&vattr);
104237741Smckusick 	vattr.va_uid = uap->uid;
104337741Smckusick 	vattr.va_gid = uap->gid;
104437741Smckusick 	if (error = namei(ndp))
104537741Smckusick 		RETURN (error);
104637741Smckusick 	vp = ndp->ni_vp;
104737741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
104837741Smckusick 		error = EROFS;
104937741Smckusick 		goto out;
105037741Smckusick 	}
105137741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
105237741Smckusick out:
105337741Smckusick 	vput(vp);
105437741Smckusick 	RETURN (error);
10557701Ssam }
10567439Sroot 
10579167Ssam /*
10589167Ssam  * Set ownership given a file descriptor.
10599167Ssam  */
106038408Smckusick fchown(scp)
106138408Smckusick 	register struct syscontext *scp;
10627701Ssam {
10637701Ssam 	struct a {
10647701Ssam 		int	fd;
10657701Ssam 		int	uid;
10667701Ssam 		int	gid;
106738408Smckusick 	} *uap = (struct a *)scp->sc_ap;
106837741Smckusick 	struct vattr vattr;
106937741Smckusick 	struct vnode *vp;
107037741Smckusick 	struct file *fp;
107137741Smckusick 	int error;
10727701Ssam 
107338408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
107437741Smckusick 		RETURN (error);
107537741Smckusick 	vattr_null(&vattr);
107637741Smckusick 	vattr.va_uid = uap->uid;
107737741Smckusick 	vattr.va_gid = uap->gid;
107837741Smckusick 	vp = (struct vnode *)fp->f_data;
107937741Smckusick 	VOP_LOCK(vp);
108037741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
108137741Smckusick 		error = EROFS;
108237741Smckusick 		goto out;
108337741Smckusick 	}
108437741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
108537741Smckusick out:
108637741Smckusick 	VOP_UNLOCK(vp);
108737741Smckusick 	RETURN (error);
10887701Ssam }
10897701Ssam 
109038408Smckusick utimes(scp)
109138408Smckusick 	register struct syscontext *scp;
109211811Ssam {
109311811Ssam 	register struct a {
109411811Ssam 		char	*fname;
109511811Ssam 		struct	timeval *tptr;
109638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
109738408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
109837741Smckusick 	register struct vnode *vp;
109911811Ssam 	struct timeval tv[2];
110037741Smckusick 	struct vattr vattr;
110137741Smckusick 	int error;
110211811Ssam 
110337741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
110437741Smckusick 		RETURN (error);
110537741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
110637741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
110737741Smckusick 	ndp->ni_dirp = uap->fname;
110837741Smckusick 	vattr_null(&vattr);
110937741Smckusick 	vattr.va_atime = tv[0];
111037741Smckusick 	vattr.va_mtime = tv[1];
111137741Smckusick 	if (error = namei(ndp))
111237741Smckusick 		RETURN (error);
111337741Smckusick 	vp = ndp->ni_vp;
111437741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
111537741Smckusick 		error = EROFS;
111637741Smckusick 		goto out;
111721015Smckusick 	}
111837741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
111937741Smckusick out:
112037741Smckusick 	vput(vp);
112137741Smckusick 	RETURN (error);
112211811Ssam }
112311811Ssam 
11249167Ssam /*
11259167Ssam  * Truncate a file given its path name.
11269167Ssam  */
112738408Smckusick truncate(scp)
112838408Smckusick 	register struct syscontext *scp;
11297701Ssam {
11307701Ssam 	struct a {
11317701Ssam 		char	*fname;
113226473Skarels 		off_t	length;
113338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
113438408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
113537741Smckusick 	register struct vnode *vp;
113637741Smckusick 	struct vattr vattr;
113737741Smckusick 	int error;
11387701Ssam 
113937741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
114016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
114116694Smckusick 	ndp->ni_dirp = uap->fname;
114237741Smckusick 	vattr_null(&vattr);
114337741Smckusick 	vattr.va_size = uap->length;
114437741Smckusick 	if (error = namei(ndp))
114537741Smckusick 		RETURN (error);
114637741Smckusick 	vp = ndp->ni_vp;
114737741Smckusick 	if (vp->v_type == VDIR) {
114837741Smckusick 		error = EISDIR;
114937741Smckusick 		goto out;
11507701Ssam 	}
115138399Smckusick 	if ((error = vn_writechk(vp)) ||
115238399Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
115337741Smckusick 		goto out;
115437741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
115537741Smckusick out:
115637741Smckusick 	vput(vp);
115737741Smckusick 	RETURN (error);
11587701Ssam }
11597701Ssam 
11609167Ssam /*
11619167Ssam  * Truncate a file given a file descriptor.
11629167Ssam  */
116338408Smckusick ftruncate(scp)
116438408Smckusick 	register struct syscontext *scp;
11657701Ssam {
11667701Ssam 	struct a {
11677701Ssam 		int	fd;
116826473Skarels 		off_t	length;
116938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
117037741Smckusick 	struct vattr vattr;
117137741Smckusick 	struct vnode *vp;
11727701Ssam 	struct file *fp;
117337741Smckusick 	int error;
11747701Ssam 
117538408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
117637741Smckusick 		RETURN (error);
117737741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
117837741Smckusick 		RETURN (EINVAL);
117937741Smckusick 	vattr_null(&vattr);
118037741Smckusick 	vattr.va_size = uap->length;
118137741Smckusick 	vp = (struct vnode *)fp->f_data;
118237741Smckusick 	VOP_LOCK(vp);
118337741Smckusick 	if (vp->v_type == VDIR) {
118437741Smckusick 		error = EISDIR;
118537741Smckusick 		goto out;
11867701Ssam 	}
118738399Smckusick 	if (error = vn_writechk(vp))
118837741Smckusick 		goto out;
118937741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
119037741Smckusick out:
119137741Smckusick 	VOP_UNLOCK(vp);
119237741Smckusick 	RETURN (error);
11937701Ssam }
11947701Ssam 
11959167Ssam /*
11969167Ssam  * Synch an open file.
11979167Ssam  */
119838408Smckusick fsync(scp)
119938408Smckusick 	register struct syscontext *scp;
12009167Ssam {
12019167Ssam 	struct a {
12029167Ssam 		int	fd;
120338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
120439592Smckusick 	register struct vnode *vp;
12059167Ssam 	struct file *fp;
120637741Smckusick 	int error;
12079167Ssam 
120838408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
120937741Smckusick 		RETURN (error);
121039592Smckusick 	vp = (struct vnode *)fp->f_data;
121139592Smckusick 	VOP_LOCK(vp);
121239592Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT);
121339592Smckusick 	VOP_UNLOCK(vp);
121437741Smckusick 	RETURN (error);
12159167Ssam }
12169167Ssam 
12179167Ssam /*
12189167Ssam  * Rename system call.
12199167Ssam  *
12209167Ssam  * Source and destination must either both be directories, or both
12219167Ssam  * not be directories.  If target is a directory, it must be empty.
12229167Ssam  */
122338408Smckusick rename(scp)
122438408Smckusick 	register struct syscontext *scp;
12257701Ssam {
12267701Ssam 	struct a {
12277701Ssam 		char	*from;
12287701Ssam 		char	*to;
122938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
123037741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
123138408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
123237741Smckusick 	struct nameidata tond;
123337741Smckusick 	int error;
12347701Ssam 
123537741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
123616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
123716694Smckusick 	ndp->ni_dirp = uap->from;
123837741Smckusick 	if (error = namei(ndp))
123937741Smckusick 		RETURN (error);
124037741Smckusick 	fvp = ndp->ni_vp;
124138266Smckusick 	nddup(ndp, &tond);
124237741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
124337741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
124437741Smckusick 	tond.ni_dirp = uap->to;
124537741Smckusick 	error = namei(&tond);
124637741Smckusick 	tdvp = tond.ni_dvp;
124737741Smckusick 	tvp = tond.ni_vp;
124837741Smckusick 	if (tvp != NULL) {
124937741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
125039242Sbostic 			error = ENOTDIR;
125137741Smckusick 			goto out;
125237741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
125339242Sbostic 			error = EISDIR;
125437741Smckusick 			goto out;
12559167Ssam 		}
12569167Ssam 	}
125737741Smckusick 	if (error) {
125837741Smckusick 		VOP_ABORTOP(ndp);
125937741Smckusick 		goto out1;
126037741Smckusick 	}
126137741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
126237741Smckusick 		error = EXDEV;
12639167Ssam 		goto out;
126410051Ssam 	}
126539286Smckusick 	if (fvp == tdvp)
126637741Smckusick 		error = EINVAL;
126739286Smckusick 	/*
126839286Smckusick 	 * If source is the same as the destination,
126939286Smckusick 	 * then there is nothing to do.
127039286Smckusick 	 */
127139286Smckusick 	if (fvp == tvp)
127239286Smckusick 		error = -1;
127337741Smckusick out:
127437741Smckusick 	if (error) {
127537741Smckusick 		VOP_ABORTOP(&tond);
127637741Smckusick 		VOP_ABORTOP(ndp);
12779167Ssam 	} else {
127837741Smckusick 		error = VOP_RENAME(ndp, &tond);
12799167Ssam 	}
128037741Smckusick out1:
128138266Smckusick 	ndrele(&tond);
128239286Smckusick 	if (error == -1)
128339286Smckusick 		RETURN (0);
128437741Smckusick 	RETURN (error);
12857701Ssam }
12867701Ssam 
12877535Sroot /*
128812756Ssam  * Mkdir system call
128912756Ssam  */
129038408Smckusick mkdir(scp)
129138408Smckusick 	register struct syscontext *scp;
129212756Ssam {
129312756Ssam 	struct a {
129412756Ssam 		char	*name;
129512756Ssam 		int	dmode;
129638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
129738408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
129837741Smckusick 	register struct vnode *vp;
129937741Smckusick 	struct vattr vattr;
130037741Smckusick 	int error;
130112756Ssam 
130237741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
130316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
130416694Smckusick 	ndp->ni_dirp = uap->name;
130537741Smckusick 	if (error = namei(ndp))
130637741Smckusick 		RETURN (error);
130737741Smckusick 	vp = ndp->ni_vp;
130837741Smckusick 	if (vp != NULL) {
130937741Smckusick 		VOP_ABORTOP(ndp);
131037741Smckusick 		RETURN (EEXIST);
131112756Ssam 	}
131237741Smckusick 	vattr_null(&vattr);
131337741Smckusick 	vattr.va_type = VDIR;
131438408Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask;
131537741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
131638145Smckusick 	if (!error)
131738145Smckusick 		vput(ndp->ni_vp);
131837741Smckusick 	RETURN (error);
131912756Ssam }
132012756Ssam 
132112756Ssam /*
132212756Ssam  * Rmdir system call.
132312756Ssam  */
132438408Smckusick rmdir(scp)
132538408Smckusick 	register struct syscontext *scp;
132612756Ssam {
132712756Ssam 	struct a {
132812756Ssam 		char	*name;
132938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
133038408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
133137741Smckusick 	register struct vnode *vp;
133237741Smckusick 	int error;
133312756Ssam 
133437741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
133516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
133616694Smckusick 	ndp->ni_dirp = uap->name;
133737741Smckusick 	if (error = namei(ndp))
133837741Smckusick 		RETURN (error);
133937741Smckusick 	vp = ndp->ni_vp;
134037741Smckusick 	if (vp->v_type != VDIR) {
134137741Smckusick 		error = ENOTDIR;
134212756Ssam 		goto out;
134312756Ssam 	}
134412756Ssam 	/*
134537741Smckusick 	 * No rmdir "." please.
134612756Ssam 	 */
134737741Smckusick 	if (ndp->ni_dvp == vp) {
134837741Smckusick 		error = EINVAL;
134912756Ssam 		goto out;
135012756Ssam 	}
135112756Ssam 	/*
135237741Smckusick 	 * Don't unlink a mounted file.
135312756Ssam 	 */
135437741Smckusick 	if (vp->v_flag & VROOT)
135537741Smckusick 		error = EBUSY;
135612756Ssam out:
135737741Smckusick 	if (error)
135837741Smckusick 		VOP_ABORTOP(ndp);
135937741Smckusick 	else
136037741Smckusick 		error = VOP_RMDIR(ndp);
136137741Smckusick 	RETURN (error);
136212756Ssam }
136312756Ssam 
136437741Smckusick /*
136537741Smckusick  * Read a block of directory entries in a file system independent format
136637741Smckusick  */
136738408Smckusick getdirentries(scp)
136838408Smckusick 	register struct syscontext *scp;
136912756Ssam {
137037741Smckusick 	register struct a {
137137741Smckusick 		int	fd;
137237741Smckusick 		char	*buf;
137337741Smckusick 		unsigned count;
137437741Smckusick 		long	*basep;
137538408Smckusick 	} *uap = (struct a *)scp->sc_ap;
137639592Smckusick 	register struct vnode *vp;
137716540Ssam 	struct file *fp;
137837741Smckusick 	struct uio auio;
137937741Smckusick 	struct iovec aiov;
138038129Smckusick 	off_t off;
138137741Smckusick 	int error;
138212756Ssam 
138338408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
138437741Smckusick 		RETURN (error);
138537741Smckusick 	if ((fp->f_flag & FREAD) == 0)
138637741Smckusick 		RETURN (EBADF);
138739592Smckusick 	vp = (struct vnode *)fp->f_data;
138839592Smckusick 	if (vp->v_type != VDIR)
138939592Smckusick 		RETURN (EINVAL);
139037741Smckusick 	aiov.iov_base = uap->buf;
139137741Smckusick 	aiov.iov_len = uap->count;
139237741Smckusick 	auio.uio_iov = &aiov;
139337741Smckusick 	auio.uio_iovcnt = 1;
139437741Smckusick 	auio.uio_rw = UIO_READ;
139537741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
139637741Smckusick 	auio.uio_resid = uap->count;
139739592Smckusick 	VOP_LOCK(vp);
139839592Smckusick 	auio.uio_offset = off = fp->f_offset;
139939592Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred);
140039592Smckusick 	fp->f_offset = auio.uio_offset;
140139592Smckusick 	VOP_UNLOCK(vp);
140239592Smckusick 	if (error)
140337741Smckusick 		RETURN (error);
140439592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
140538408Smckusick 	scp->sc_retval1 = uap->count - auio.uio_resid;
140637741Smckusick 	RETURN (error);
140712756Ssam }
140812756Ssam 
140912756Ssam /*
141012756Ssam  * mode mask for creation of files
141112756Ssam  */
141238408Smckusick umask(scp)
141338408Smckusick 	register struct syscontext *scp;
141412756Ssam {
141512756Ssam 	register struct a {
141612756Ssam 		int	mask;
141738408Smckusick 	} *uap = (struct a *)scp->sc_ap;
141812756Ssam 
141938408Smckusick 	scp->sc_retval1 = scp->sc_cmask;
142038408Smckusick 	scp->sc_cmask = uap->mask & 07777;
142137741Smckusick 	RETURN (0);
142212756Ssam }
142337741Smckusick 
142439566Smarc /*
142539566Smarc  * Void all references to file by ripping underlying filesystem
142639566Smarc  * away from vnode.
142739566Smarc  */
142839566Smarc revoke(scp)
142939566Smarc 	register struct syscontext *scp;
143039566Smarc {
143139566Smarc 	struct a {
143239566Smarc 		char	*fname;
143339566Smarc 	} *uap = (struct a *)scp->sc_ap;
143439566Smarc 	register struct nameidata *ndp = &scp->sc_nd;
143539566Smarc 	register struct vnode *vp;
143639566Smarc 	struct vattr vattr;
143739566Smarc 	int error;
143839566Smarc 
143939566Smarc 	ndp->ni_nameiop = LOOKUP | FOLLOW;
144039566Smarc 	ndp->ni_segflg = UIO_USERSPACE;
144139566Smarc 	ndp->ni_dirp = uap->fname;
144239566Smarc 	if (error = namei(ndp))
144339566Smarc 		RETURN (error);
144439566Smarc 	vp = ndp->ni_vp;
144539566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
144639566Smarc 		error = EINVAL;
144739566Smarc 		goto out;
144839566Smarc 	}
144939566Smarc 	if (error = VOP_GETATTR(vp, &vattr, scp->sc_cred))
145039566Smarc 		goto out;
145139566Smarc 	if (scp->sc_uid != vattr.va_uid ||
145239566Smarc 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
145339566Smarc 		goto out;
145439805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
145539632Smckusick 		vgoneall(vp);
145639566Smarc out:
145739566Smarc 	vrele(vp);
145839566Smarc 	RETURN (error);
145939566Smarc }
146039566Smarc 
146138408Smckusick getvnode(ofile, fdes, fpp)
146238408Smckusick 	struct file *ofile[];
146337741Smckusick 	struct file **fpp;
146437741Smckusick 	int fdes;
146537741Smckusick {
146637741Smckusick 	struct file *fp;
146737741Smckusick 
146838408Smckusick 	if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
146937741Smckusick 		return (EBADF);
147037741Smckusick 	if (fp->f_type != DTYPE_VNODE)
147137741Smckusick 		return (EINVAL);
147237741Smckusick 	*fpp = fp;
147337741Smckusick 	return (0);
147437741Smckusick }
1475