xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 39797)
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*39797Smckusick  *	@(#)vfs_syscalls.c	7.34 (Berkeley) 12/29/89
1823405Smckusick  */
1937Sbill 
2017101Sbloom #include "param.h"
2117101Sbloom #include "systm.h"
2237741Smckusick #include "syscontext.h"
2317101Sbloom #include "kernel.h"
2417101Sbloom #include "file.h"
2517101Sbloom #include "stat.h"
2637741Smckusick #include "vnode.h"
2737741Smckusick #include "../ufs/inode.h"
2837741Smckusick #include "mount.h"
2917101Sbloom #include "proc.h"
3017101Sbloom #include "uio.h"
3137741Smckusick #include "malloc.h"
3237Sbill 
33*39797Smckusick #undef RETURN
34*39797Smckusick #define RETURN(val)	{ scp->u_error = (val); if (scp->u_spare[0] != 0) panic("lock count"); return; }
35*39797Smckusick 
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);
9137741Smckusick 	if (vp->v_count != 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 	/*
12639335Smckusick 	 * Put the new filesystem on the mount list after root.
12739335Smckusick 	 */
12839335Smckusick 	mp->m_next = rootfs->m_next;
12939335Smckusick 	mp->m_prev = rootfs;
13039335Smckusick 	rootfs->m_next = mp;
13139335Smckusick 	mp->m_next->m_prev = mp;
13239335Smckusick 	vp->v_mountedhere = mp;
13339335Smckusick 	mp->m_vnodecovered = vp;
13439335Smckusick update:
13539335Smckusick 	/*
13639335Smckusick 	 * Set the mount level flags.
13739335Smckusick 	 */
13839335Smckusick 	if (uap->flags & M_RDONLY)
13939335Smckusick 		mp->m_flag |= M_RDONLY;
14039335Smckusick 	else
14139335Smckusick 		mp->m_flag &= ~M_RDONLY;
14239335Smckusick 	if (uap->flags & M_NOSUID)
14339335Smckusick 		mp->m_flag |= M_NOSUID;
14439335Smckusick 	else
14539335Smckusick 		mp->m_flag &= ~M_NOSUID;
14639335Smckusick 	if (uap->flags & M_NOEXEC)
14739335Smckusick 		mp->m_flag |= M_NOEXEC;
14839335Smckusick 	else
14939335Smckusick 		mp->m_flag &= ~M_NOEXEC;
15039335Smckusick 	if (uap->flags & M_NODEV)
15139335Smckusick 		mp->m_flag |= M_NODEV;
15239335Smckusick 	else
15339335Smckusick 		mp->m_flag &= ~M_NODEV;
15439335Smckusick 	if (uap->flags & M_SYNCHRONOUS)
15539335Smckusick 		mp->m_flag |= M_SYNCHRONOUS;
15639335Smckusick 	else
15739335Smckusick 		mp->m_flag &= ~M_SYNCHRONOUS;
15839335Smckusick 	/*
15939335Smckusick 	 * Mount the filesystem.
16039335Smckusick 	 */
16139335Smckusick 	error = VFS_MOUNT(mp, uap->dir, uap->data, ndp);
16239335Smckusick 	if (mp->m_flag & M_UPDATE) {
16339335Smckusick 		mp->m_flag &= ~M_UPDATE;
16439335Smckusick 		vrele(vp);
16539335Smckusick 		RETURN (error);
16639335Smckusick 	}
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;
26037741Smckusick 
26137741Smckusick 	mp = rootfs;
26237741Smckusick 	do {
26337741Smckusick 		if ((mp->m_flag & M_RDONLY) == 0)
26437741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
26537741Smckusick 		mp = mp->m_next;
26637741Smckusick 	} while (mp != rootfs);
26737741Smckusick }
26837741Smckusick 
26937741Smckusick /*
27037741Smckusick  * get filesystem statistics
27137741Smckusick  */
27238408Smckusick statfs(scp)
27338408Smckusick 	register struct syscontext *scp;
27437741Smckusick {
2756254Sroot 	struct a {
27637741Smckusick 		char *path;
27737741Smckusick 		struct statfs *buf;
27838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
27939464Smckusick 	register struct mount *mp;
28038408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
28137741Smckusick 	struct statfs sb;
28237741Smckusick 	int error;
28337741Smckusick 
28439544Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
28537741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
28637741Smckusick 	ndp->ni_dirp = uap->path;
28737741Smckusick 	if (error = namei(ndp))
28837741Smckusick 		RETURN (error);
28939544Smckusick 	mp = ndp->ni_vp->v_mount;
29039544Smckusick 	vrele(ndp->ni_vp);
29139464Smckusick 	if (error = VFS_STATFS(mp, &sb))
29239544Smckusick 		RETURN (error);
29339464Smckusick 	sb.f_flags = mp->m_flag & M_VISFLAGMASK;
29439464Smckusick 	sb.f_fsid = mp->m_fsid;
29539544Smckusick 	RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)));
29637741Smckusick }
29737741Smckusick 
29838408Smckusick fstatfs(scp)
29938408Smckusick 	register struct syscontext *scp;
30037741Smckusick {
30137741Smckusick 	struct a {
30237741Smckusick 		int fd;
30337741Smckusick 		struct statfs *buf;
30438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
30537741Smckusick 	struct file *fp;
30639464Smckusick 	struct mount *mp;
30737741Smckusick 	struct statfs sb;
30837741Smckusick 	int error;
30937741Smckusick 
31038408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
31137741Smckusick 		RETURN (error);
31239464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
31339464Smckusick 	if (error = VFS_STATFS(mp, &sb))
31437741Smckusick 		RETURN (error);
31539464Smckusick 	sb.f_flags = mp->m_flag & M_VISFLAGMASK;
31639464Smckusick 	sb.f_fsid = mp->m_fsid;
31737741Smckusick 	RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)));
31837741Smckusick }
31937741Smckusick 
32037741Smckusick /*
32138270Smckusick  * get statistics on all filesystems
32238270Smckusick  */
32338408Smckusick getfsstat(scp)
32438408Smckusick 	register struct syscontext *scp;
32538270Smckusick {
32638270Smckusick 	struct a {
32738270Smckusick 		struct statfs *buf;
32838270Smckusick 		long bufsize;
32938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
33038270Smckusick 	register struct mount *mp;
33139606Smckusick 	caddr_t sfsp;
33238270Smckusick 	long count, maxcount, error;
33339606Smckusick 	struct statfs sb;
33438270Smckusick 
33538270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
33639606Smckusick 	sfsp = (caddr_t)uap->buf;
33738270Smckusick 	mp = rootfs;
33838270Smckusick 	count = 0;
33938270Smckusick 	do {
34039606Smckusick 		if (sfsp && count < maxcount && ((mp->m_flag & M_MLOCK) == 0)) {
34139607Smckusick 			if (error = VFS_STATFS(mp, &sb)) {
34239607Smckusick 				mp = mp->m_prev;
34339607Smckusick 				continue;
34439607Smckusick 			}
34539606Smckusick 			sb.f_flags = mp->m_flag & M_VISFLAGMASK;
34639606Smckusick 			sb.f_fsid = mp->m_fsid;
34739606Smckusick 			if (error = copyout((caddr_t)&sb, sfsp, sizeof(sb)))
34839606Smckusick 				RETURN (error);
34939606Smckusick 			sfsp += sizeof(sb);
35038270Smckusick 		}
35139606Smckusick 		count++;
35238270Smckusick 		mp = mp->m_prev;
35338270Smckusick 	} while (mp != rootfs);
35438270Smckusick 	if (sfsp && count > maxcount)
35538408Smckusick 		scp->sc_retval1 = maxcount;
35638270Smckusick 	else
35738408Smckusick 		scp->sc_retval1 = count;
35838270Smckusick 	RETURN (0);
35938270Smckusick }
36038270Smckusick 
36138270Smckusick /*
36238259Smckusick  * Change current working directory to a given file descriptor.
36338259Smckusick  */
36438408Smckusick fchdir(scp)
36538408Smckusick 	register struct syscontext *scp;
36638259Smckusick {
36738259Smckusick 	struct a {
36838259Smckusick 		int	fd;
36938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
37038259Smckusick 	register struct vnode *vp;
37138259Smckusick 	struct file *fp;
37238259Smckusick 	int error;
37338259Smckusick 
37438408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
37538259Smckusick 		RETURN (error);
37638259Smckusick 	vp = (struct vnode *)fp->f_data;
37738259Smckusick 	VOP_LOCK(vp);
37838259Smckusick 	if (vp->v_type != VDIR)
37938259Smckusick 		error = ENOTDIR;
38038259Smckusick 	else
38138408Smckusick 		error = VOP_ACCESS(vp, VEXEC, scp->sc_cred);
38238259Smckusick 	VOP_UNLOCK(vp);
38338408Smckusick 	vrele(scp->sc_cdir);
38438408Smckusick 	scp->sc_cdir = vp;
38538259Smckusick 	RETURN (error);
38638259Smckusick }
38738259Smckusick 
38838259Smckusick /*
38937741Smckusick  * Change current working directory (``.'').
39037741Smckusick  */
39138408Smckusick chdir(scp)
39238408Smckusick 	register struct syscontext *scp;
39337741Smckusick {
39437741Smckusick 	struct a {
3956254Sroot 		char	*fname;
39638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
39738408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
39837741Smckusick 	int error;
3996254Sroot 
40037741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
40116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
40216694Smckusick 	ndp->ni_dirp = uap->fname;
40337741Smckusick 	if (error = chdirec(ndp))
40437741Smckusick 		RETURN (error);
40538408Smckusick 	vrele(scp->sc_cdir);
40638408Smckusick 	scp->sc_cdir = ndp->ni_vp;
40737741Smckusick 	RETURN (0);
40837741Smckusick }
4096254Sroot 
41037741Smckusick /*
41137741Smckusick  * Change notion of root (``/'') directory.
41237741Smckusick  */
41338408Smckusick chroot(scp)
41438408Smckusick 	register struct syscontext *scp;
41537741Smckusick {
41637741Smckusick 	struct a {
41737741Smckusick 		char	*fname;
41838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
41938408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
42037741Smckusick 	int error;
42137741Smckusick 
42238408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
42337741Smckusick 		RETURN (error);
42437741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
42537741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
42637741Smckusick 	ndp->ni_dirp = uap->fname;
42737741Smckusick 	if (error = chdirec(ndp))
42837741Smckusick 		RETURN (error);
42939515Smckusick 	if (scp->sc_rdir != NULL)
43039515Smckusick 		vrele(scp->sc_rdir);
43138408Smckusick 	scp->sc_rdir = ndp->ni_vp;
43237741Smckusick 	RETURN (0);
4336254Sroot }
4346254Sroot 
43537Sbill /*
43637741Smckusick  * Common routine for chroot and chdir.
43737741Smckusick  */
43837741Smckusick chdirec(ndp)
43937741Smckusick 	register struct nameidata *ndp;
44037741Smckusick {
44137741Smckusick 	struct vnode *vp;
44237741Smckusick 	int error;
44337741Smckusick 
44437741Smckusick 	if (error = namei(ndp))
44537741Smckusick 		return (error);
44637741Smckusick 	vp = ndp->ni_vp;
44737741Smckusick 	if (vp->v_type != VDIR)
44837741Smckusick 		error = ENOTDIR;
44937741Smckusick 	else
45038399Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
45137741Smckusick 	VOP_UNLOCK(vp);
45237741Smckusick 	if (error)
45337741Smckusick 		vrele(vp);
45437741Smckusick 	return (error);
45537741Smckusick }
45637741Smckusick 
45737741Smckusick /*
4586254Sroot  * Open system call.
4596254Sroot  */
46038408Smckusick open(scp)
46138408Smckusick 	register struct syscontext *scp;
4626254Sroot {
46312756Ssam 	struct a {
4646254Sroot 		char	*fname;
4657701Ssam 		int	mode;
46612756Ssam 		int	crtmode;
46738408Smckusick 	} *uap = (struct a *) scp->sc_ap;
46838408Smckusick 	struct nameidata *ndp = &scp->sc_nd;
4696254Sroot 
47037741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
47137741Smckusick 	ndp->ni_dirp = uap->fname;
47238408Smckusick 	RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp,
47338408Smckusick 		&scp->sc_retval1));
4746254Sroot }
4756254Sroot 
4766254Sroot /*
4776254Sroot  * Creat system call.
4786254Sroot  */
47938408Smckusick creat(scp)
48038408Smckusick 	register struct syscontext *scp;
4816254Sroot {
48212756Ssam 	struct a {
4836254Sroot 		char	*fname;
4846254Sroot 		int	fmode;
48538408Smckusick 	} *uap = (struct a *)scp->sc_ap;
48638408Smckusick 	struct nameidata *ndp = &scp->sc_nd;
4876254Sroot 
48837741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
48937741Smckusick 	ndp->ni_dirp = uap->fname;
49038408Smckusick 	RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask,
49138408Smckusick 		ndp, &scp->sc_retval1));
4926254Sroot }
4936254Sroot 
4946254Sroot /*
4956254Sroot  * Common code for open and creat.
49612756Ssam  * Check permissions, allocate an open file structure,
49712756Ssam  * and call the device open routine if any.
4986254Sroot  */
49938408Smckusick copen(scp, fmode, cmode, ndp, resultfd)
50038408Smckusick 	register struct syscontext *scp;
50137741Smckusick 	int fmode, cmode;
50237741Smckusick 	struct nameidata *ndp;
50337741Smckusick 	int *resultfd;
50412756Ssam {
5056254Sroot 	register struct file *fp;
50637741Smckusick 	struct file *nfp;
50737741Smckusick 	int indx, error;
50837741Smckusick 	extern struct fileops vnops;
5096254Sroot 
51037741Smckusick 	if (error = falloc(&nfp, &indx))
51137741Smckusick 		return (error);
51237741Smckusick 	fp = nfp;
51338408Smckusick 	scp->sc_retval1 = indx;	/* XXX for fdopen() */
51437741Smckusick 	if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) {
51537741Smckusick 		crfree(fp->f_cred);
51637741Smckusick 		fp->f_count--;
51739499Smckusick 		if (error == -1)	/* XXX from fdopen */
51839499Smckusick 			return (0);	/* XXX from fdopen */
51939499Smckusick 		scp->sc_ofile[indx] = NULL;
52037741Smckusick 		return (error);
52112756Ssam 	}
52237741Smckusick 	fp->f_flag = fmode & FMASK;
52337741Smckusick 	fp->f_type = DTYPE_VNODE;
52437741Smckusick 	fp->f_ops = &vnops;
52537741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
52637741Smckusick 	if (resultfd)
52737741Smckusick 		*resultfd = indx;
52837741Smckusick 	return (0);
5296254Sroot }
5306254Sroot 
5316254Sroot /*
5326254Sroot  * Mknod system call
5336254Sroot  */
53438408Smckusick mknod(scp)
53538408Smckusick 	register struct syscontext *scp;
5366254Sroot {
5376254Sroot 	register struct a {
5386254Sroot 		char	*fname;
5396254Sroot 		int	fmode;
5406254Sroot 		int	dev;
54138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
54238408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
54337741Smckusick 	register struct vnode *vp;
54437741Smckusick 	struct vattr vattr;
54537741Smckusick 	int error;
5466254Sroot 
54738408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
54837741Smckusick 		RETURN (error);
54937741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
55016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
55116694Smckusick 	ndp->ni_dirp = uap->fname;
55237741Smckusick 	if (error = namei(ndp))
55337741Smckusick 		RETURN (error);
55437741Smckusick 	vp = ndp->ni_vp;
55537741Smckusick 	if (vp != NULL) {
55637741Smckusick 		error = EEXIST;
55712756Ssam 		goto out;
5586254Sroot 	}
55937741Smckusick 	vattr_null(&vattr);
56037741Smckusick 	switch (uap->fmode & IFMT) {
56112756Ssam 
56215093Smckusick 	case IFMT:	/* used by badsect to flag bad sectors */
56337741Smckusick 		vattr.va_type = VBAD;
56437741Smckusick 		break;
56512756Ssam 	case IFCHR:
56637741Smckusick 		vattr.va_type = VCHR;
56737741Smckusick 		break;
56812756Ssam 	case IFBLK:
56937741Smckusick 		vattr.va_type = VBLK;
57037741Smckusick 		break;
57137741Smckusick 	default:
57237741Smckusick 		error = EINVAL;
57337741Smckusick 		goto out;
5746254Sroot 	}
57538408Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask;
57637741Smckusick 	vattr.va_rdev = uap->dev;
5776254Sroot out:
57837741Smckusick 	if (error)
57937741Smckusick 		VOP_ABORTOP(ndp);
58037741Smckusick 	else
58137741Smckusick 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
58237741Smckusick 	RETURN (error);
5836254Sroot }
5846254Sroot 
5856254Sroot /*
5866254Sroot  * link system call
5876254Sroot  */
58838408Smckusick link(scp)
58938408Smckusick 	register struct syscontext *scp;
5906254Sroot {
5916254Sroot 	register struct a {
5926254Sroot 		char	*target;
5936254Sroot 		char	*linkname;
59438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
59538408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
59637741Smckusick 	register struct vnode *vp, *xp;
59737741Smckusick 	int error;
5986254Sroot 
59916694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
60016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
60116694Smckusick 	ndp->ni_dirp = uap->target;
60237741Smckusick 	if (error = namei(ndp))
60337741Smckusick 		RETURN (error);
60437741Smckusick 	vp = ndp->ni_vp;
60537741Smckusick 	if (vp->v_type == VDIR &&
60638408Smckusick 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
60737741Smckusick 		goto out1;
60837741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
60916694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
61037741Smckusick 	if (error = namei(ndp))
61137741Smckusick 		goto out1;
61237741Smckusick 	xp = ndp->ni_vp;
6136254Sroot 	if (xp != NULL) {
61437741Smckusick 		error = EEXIST;
6156254Sroot 		goto out;
6166254Sroot 	}
61737741Smckusick 	xp = ndp->ni_dvp;
61837741Smckusick 	if (vp->v_mount != xp->v_mount)
61937741Smckusick 		error = EXDEV;
6206254Sroot out:
62137741Smckusick 	if (error)
62237741Smckusick 		VOP_ABORTOP(ndp);
62337741Smckusick 	else
62437741Smckusick 		error = VOP_LINK(vp, ndp);
62537741Smckusick out1:
62637741Smckusick 	vrele(vp);
62737741Smckusick 	RETURN (error);
6286254Sroot }
6296254Sroot 
6306254Sroot /*
6316254Sroot  * symlink -- make a symbolic link
6326254Sroot  */
63338408Smckusick symlink(scp)
63438408Smckusick 	register struct syscontext *scp;
6356254Sroot {
63637741Smckusick 	struct a {
6376254Sroot 		char	*target;
6386254Sroot 		char	*linkname;
63938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
64038408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
64137741Smckusick 	register struct vnode *vp;
64237741Smckusick 	struct vattr vattr;
64337741Smckusick 	char *target;
64437741Smckusick 	int error;
6456254Sroot 
64616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
64716694Smckusick 	ndp->ni_dirp = uap->linkname;
64837741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
64937741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
65037741Smckusick 		goto out1;
65137741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
65237741Smckusick 	if (error = namei(ndp))
65337741Smckusick 		goto out1;
65437741Smckusick 	vp = ndp->ni_vp;
65537741Smckusick 	if (vp) {
65637741Smckusick 		error = EEXIST;
65737741Smckusick 		goto out;
6586254Sroot 	}
65937741Smckusick 	vp = ndp->ni_dvp;
66037741Smckusick 	vattr_null(&vattr);
66138408Smckusick 	vattr.va_mode = 0777 &~ scp->sc_cmask;
66237741Smckusick out:
66337741Smckusick 	if (error)
66437741Smckusick 		VOP_ABORTOP(ndp);
66537741Smckusick 	else
66637741Smckusick 		error = VOP_SYMLINK(ndp, &vattr, target);
66737741Smckusick out1:
66837741Smckusick 	FREE(target, M_NAMEI);
66937741Smckusick 	RETURN (error);
6706254Sroot }
6716254Sroot 
6726254Sroot /*
6736254Sroot  * Unlink system call.
6746254Sroot  * Hard to avoid races here, especially
6756254Sroot  * in unlinking directories.
6766254Sroot  */
67738408Smckusick unlink(scp)
67838408Smckusick 	register struct syscontext *scp;
6796254Sroot {
6806254Sroot 	struct a {
6816254Sroot 		char	*fname;
68238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
68338408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
68437741Smckusick 	register struct vnode *vp;
68537741Smckusick 	int error;
6866254Sroot 
68737741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
68816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
68916694Smckusick 	ndp->ni_dirp = uap->fname;
69037741Smckusick 	if (error = namei(ndp))
69137741Smckusick 		RETURN (error);
69237741Smckusick 	vp = ndp->ni_vp;
69337741Smckusick 	if (vp->v_type == VDIR &&
69438408Smckusick 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
6956254Sroot 		goto out;
6966254Sroot 	/*
6976254Sroot 	 * Don't unlink a mounted file.
6986254Sroot 	 */
69937741Smckusick 	if (vp->v_flag & VROOT) {
70037741Smckusick 		error = EBUSY;
7016254Sroot 		goto out;
7026254Sroot 	}
70337741Smckusick 	if (vp->v_flag & VTEXT)
70437741Smckusick 		xrele(vp);	/* try once to free text */
7056254Sroot out:
70637741Smckusick 	if (error)
70737741Smckusick 		VOP_ABORTOP(ndp);
7087142Smckusick 	else
70937741Smckusick 		error = VOP_REMOVE(ndp);
71037741Smckusick 	RETURN (error);
7116254Sroot }
7126254Sroot 
7136254Sroot /*
7146254Sroot  * Seek system call
7156254Sroot  */
71638408Smckusick lseek(scp)
71738408Smckusick 	register struct syscontext *scp;
7186254Sroot {
7196254Sroot 	register struct file *fp;
7206254Sroot 	register struct a {
72137741Smckusick 		int	fdes;
7226254Sroot 		off_t	off;
7236254Sroot 		int	sbase;
72438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
72537741Smckusick 	struct vattr vattr;
72637741Smckusick 	int error;
7276254Sroot 
72837741Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
72938408Smckusick 	    (fp = scp->sc_ofile[uap->fdes]) == NULL)
73037741Smckusick 		RETURN (EBADF);
73137741Smckusick 	if (fp->f_type != DTYPE_VNODE)
73237741Smckusick 		RETURN (ESPIPE);
73313878Ssam 	switch (uap->sbase) {
73413878Ssam 
73513878Ssam 	case L_INCR:
73613878Ssam 		fp->f_offset += uap->off;
73713878Ssam 		break;
73813878Ssam 
73913878Ssam 	case L_XTND:
74037741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
74138408Smckusick 		    &vattr, scp->sc_cred))
74237741Smckusick 			RETURN (error);
74337741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
74413878Ssam 		break;
74513878Ssam 
74613878Ssam 	case L_SET:
74713878Ssam 		fp->f_offset = uap->off;
74813878Ssam 		break;
74913878Ssam 
75013878Ssam 	default:
75137741Smckusick 		RETURN (EINVAL);
75213878Ssam 	}
75338408Smckusick 	scp->sc_offset = fp->f_offset;
75437741Smckusick 	RETURN (0);
7556254Sroot }
7566254Sroot 
7576254Sroot /*
7586254Sroot  * Access system call
7596254Sroot  */
76038408Smckusick saccess(scp)
76138408Smckusick 	register struct syscontext *scp;
7626254Sroot {
7636254Sroot 	register struct a {
7646254Sroot 		char	*fname;
7656254Sroot 		int	fmode;
76638408Smckusick 	} *uap = (struct a *)scp->sc_ap;
76738408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
76837741Smckusick 	register struct vnode *vp;
76937741Smckusick 	int error, mode, svuid, svgid;
7706254Sroot 
77138408Smckusick 	svuid = scp->sc_uid;
77238408Smckusick 	svgid = scp->sc_gid;
77338408Smckusick 	scp->sc_uid = scp->sc_ruid;
77438408Smckusick 	scp->sc_gid = scp->sc_rgid;
77537741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
77616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
77716694Smckusick 	ndp->ni_dirp = uap->fname;
77837741Smckusick 	if (error = namei(ndp))
77937741Smckusick 		goto out1;
78037741Smckusick 	vp = ndp->ni_vp;
78137741Smckusick 	/*
78237741Smckusick 	 * fmode == 0 means only check for exist
78337741Smckusick 	 */
78437741Smckusick 	if (uap->fmode) {
78537741Smckusick 		mode = 0;
78637741Smckusick 		if (uap->fmode & R_OK)
78737741Smckusick 			mode |= VREAD;
78837741Smckusick 		if (uap->fmode & W_OK)
78937741Smckusick 			mode |= VWRITE;
79037741Smckusick 		if (uap->fmode & X_OK)
79137741Smckusick 			mode |= VEXEC;
79239543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
79338399Smckusick 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
7946254Sroot 	}
79537741Smckusick 	vput(vp);
79637741Smckusick out1:
79738408Smckusick 	scp->sc_uid = svuid;
79838408Smckusick 	scp->sc_gid = svgid;
79937741Smckusick 	RETURN (error);
8006254Sroot }
8016254Sroot 
8026254Sroot /*
8036574Smckusic  * Stat system call.  This version follows links.
80437Sbill  */
80538408Smckusick stat(scp)
80638408Smckusick 	struct syscontext *scp;
80737Sbill {
80837Sbill 
80938408Smckusick 	stat1(scp, FOLLOW);
81037Sbill }
81137Sbill 
81237Sbill /*
8136574Smckusic  * Lstat system call.  This version does not follow links.
8145992Swnj  */
81538408Smckusick lstat(scp)
81638408Smckusick 	struct syscontext *scp;
8175992Swnj {
81812756Ssam 
81938408Smckusick 	stat1(scp, NOFOLLOW);
82012756Ssam }
82112756Ssam 
82238408Smckusick stat1(scp, follow)
82338408Smckusick 	register struct syscontext *scp;
82412756Ssam 	int follow;
82512756Ssam {
8265992Swnj 	register struct a {
8275992Swnj 		char	*fname;
82812756Ssam 		struct stat *ub;
82938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
83038408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
83112756Ssam 	struct stat sb;
83237741Smckusick 	int error;
8335992Swnj 
83437741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
83516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
83616694Smckusick 	ndp->ni_dirp = uap->fname;
83737741Smckusick 	if (error = namei(ndp))
83837741Smckusick 		RETURN (error);
83937741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
84037741Smckusick 	vput(ndp->ni_vp);
84137741Smckusick 	if (error)
84237741Smckusick 		RETURN (error);
84337741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
84437741Smckusick 	RETURN (error);
8455992Swnj }
8465992Swnj 
8475992Swnj /*
8485992Swnj  * Return target name of a symbolic link
84937Sbill  */
85038408Smckusick readlink(scp)
85138408Smckusick 	register struct syscontext *scp;
8525992Swnj {
8535992Swnj 	register struct a {
8545992Swnj 		char	*name;
8555992Swnj 		char	*buf;
8565992Swnj 		int	count;
85738408Smckusick 	} *uap = (struct a *)scp->sc_ap;
85838408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
85937741Smckusick 	register struct vnode *vp;
86037741Smckusick 	struct iovec aiov;
86137741Smckusick 	struct uio auio;
86237741Smckusick 	int error;
8635992Swnj 
86437741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
86516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
86616694Smckusick 	ndp->ni_dirp = uap->name;
86737741Smckusick 	if (error = namei(ndp))
86837741Smckusick 		RETURN (error);
86937741Smckusick 	vp = ndp->ni_vp;
87037741Smckusick 	if (vp->v_type != VLNK) {
87137741Smckusick 		error = EINVAL;
8725992Swnj 		goto out;
8735992Swnj 	}
87437741Smckusick 	aiov.iov_base = uap->buf;
87537741Smckusick 	aiov.iov_len = uap->count;
87637741Smckusick 	auio.uio_iov = &aiov;
87737741Smckusick 	auio.uio_iovcnt = 1;
87837741Smckusick 	auio.uio_offset = 0;
87937741Smckusick 	auio.uio_rw = UIO_READ;
88037741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
88137741Smckusick 	auio.uio_resid = uap->count;
88237741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
8835992Swnj out:
88437741Smckusick 	vput(vp);
88538408Smckusick 	scp->sc_retval1 = uap->count - auio.uio_resid;
88637741Smckusick 	RETURN (error);
8875992Swnj }
8885992Swnj 
8899167Ssam /*
89038259Smckusick  * Change flags of a file given path name.
89138259Smckusick  */
89238408Smckusick chflags(scp)
89338408Smckusick 	register struct syscontext *scp;
89438259Smckusick {
89538259Smckusick 	struct a {
89638259Smckusick 		char	*fname;
89738259Smckusick 		int	flags;
89838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
89938408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
90038259Smckusick 	register struct vnode *vp;
90138259Smckusick 	struct vattr vattr;
90238259Smckusick 	int error;
90338259Smckusick 
90438259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
90538259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
90638259Smckusick 	ndp->ni_dirp = uap->fname;
90738259Smckusick 	vattr_null(&vattr);
90838259Smckusick 	vattr.va_flags = uap->flags;
90938259Smckusick 	if (error = namei(ndp))
91038259Smckusick 		RETURN (error);
91138259Smckusick 	vp = ndp->ni_vp;
91238259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
91338259Smckusick 		error = EROFS;
91438259Smckusick 		goto out;
91538259Smckusick 	}
91638259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
91738259Smckusick out:
91838259Smckusick 	vput(vp);
91938259Smckusick 	RETURN (error);
92038259Smckusick }
92138259Smckusick 
92238259Smckusick /*
92338259Smckusick  * Change flags of a file given a file descriptor.
92438259Smckusick  */
92538408Smckusick fchflags(scp)
92638408Smckusick 	register struct syscontext *scp;
92738259Smckusick {
92838259Smckusick 	struct a {
92938259Smckusick 		int	fd;
93038259Smckusick 		int	flags;
93138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
93238259Smckusick 	struct vattr vattr;
93338259Smckusick 	struct vnode *vp;
93438259Smckusick 	struct file *fp;
93538259Smckusick 	int error;
93638259Smckusick 
93738408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
93838259Smckusick 		RETURN (error);
93938259Smckusick 	vattr_null(&vattr);
94038259Smckusick 	vattr.va_flags = uap->flags;
94138259Smckusick 	vp = (struct vnode *)fp->f_data;
94238259Smckusick 	VOP_LOCK(vp);
94338259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
94438259Smckusick 		error = EROFS;
94538259Smckusick 		goto out;
94638259Smckusick 	}
94738259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
94838259Smckusick out:
94938259Smckusick 	VOP_UNLOCK(vp);
95038259Smckusick 	RETURN (error);
95138259Smckusick }
95238259Smckusick 
95338259Smckusick /*
9549167Ssam  * Change mode of a file given path name.
9559167Ssam  */
95638408Smckusick chmod(scp)
95738408Smckusick 	register struct syscontext *scp;
9585992Swnj {
9597701Ssam 	struct a {
9606254Sroot 		char	*fname;
9616254Sroot 		int	fmode;
96238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
96338408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
96437741Smckusick 	register struct vnode *vp;
96537741Smckusick 	struct vattr vattr;
96637741Smckusick 	int error;
9675992Swnj 
96837741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
96937741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
97037741Smckusick 	ndp->ni_dirp = uap->fname;
97137741Smckusick 	vattr_null(&vattr);
97237741Smckusick 	vattr.va_mode = uap->fmode & 07777;
97337741Smckusick 	if (error = namei(ndp))
97437741Smckusick 		RETURN (error);
97537741Smckusick 	vp = ndp->ni_vp;
97637741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
97737741Smckusick 		error = EROFS;
97837741Smckusick 		goto out;
97937741Smckusick 	}
98037741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
98137741Smckusick out:
98237741Smckusick 	vput(vp);
98337741Smckusick 	RETURN (error);
9847701Ssam }
9857439Sroot 
9869167Ssam /*
9879167Ssam  * Change mode of a file given a file descriptor.
9889167Ssam  */
98938408Smckusick fchmod(scp)
99038408Smckusick 	register struct syscontext *scp;
9917701Ssam {
9927701Ssam 	struct a {
9937701Ssam 		int	fd;
9947701Ssam 		int	fmode;
99538408Smckusick 	} *uap = (struct a *)scp->sc_ap;
99637741Smckusick 	struct vattr vattr;
99737741Smckusick 	struct vnode *vp;
99837741Smckusick 	struct file *fp;
99937741Smckusick 	int error;
10007701Ssam 
100138408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
100237741Smckusick 		RETURN (error);
100337741Smckusick 	vattr_null(&vattr);
100437741Smckusick 	vattr.va_mode = uap->fmode & 07777;
100537741Smckusick 	vp = (struct vnode *)fp->f_data;
100637741Smckusick 	VOP_LOCK(vp);
100737741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
100837741Smckusick 		error = EROFS;
100937741Smckusick 		goto out;
10107439Sroot 	}
101137741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
101237741Smckusick out:
101337741Smckusick 	VOP_UNLOCK(vp);
101437741Smckusick 	RETURN (error);
10155992Swnj }
10165992Swnj 
10179167Ssam /*
10189167Ssam  * Set ownership given a path name.
10199167Ssam  */
102038408Smckusick chown(scp)
102138408Smckusick 	register struct syscontext *scp;
102237Sbill {
10237701Ssam 	struct a {
10246254Sroot 		char	*fname;
10256254Sroot 		int	uid;
10266254Sroot 		int	gid;
102738408Smckusick 	} *uap = (struct a *)scp->sc_ap;
102838408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
102937741Smckusick 	register struct vnode *vp;
103037741Smckusick 	struct vattr vattr;
103137741Smckusick 	int error;
103237Sbill 
103337741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
103436614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
103536614Sbostic 	ndp->ni_dirp = uap->fname;
103637741Smckusick 	vattr_null(&vattr);
103737741Smckusick 	vattr.va_uid = uap->uid;
103837741Smckusick 	vattr.va_gid = uap->gid;
103937741Smckusick 	if (error = namei(ndp))
104037741Smckusick 		RETURN (error);
104137741Smckusick 	vp = ndp->ni_vp;
104237741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
104337741Smckusick 		error = EROFS;
104437741Smckusick 		goto out;
104537741Smckusick 	}
104637741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
104737741Smckusick out:
104837741Smckusick 	vput(vp);
104937741Smckusick 	RETURN (error);
10507701Ssam }
10517439Sroot 
10529167Ssam /*
10539167Ssam  * Set ownership given a file descriptor.
10549167Ssam  */
105538408Smckusick fchown(scp)
105638408Smckusick 	register struct syscontext *scp;
10577701Ssam {
10587701Ssam 	struct a {
10597701Ssam 		int	fd;
10607701Ssam 		int	uid;
10617701Ssam 		int	gid;
106238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
106337741Smckusick 	struct vattr vattr;
106437741Smckusick 	struct vnode *vp;
106537741Smckusick 	struct file *fp;
106637741Smckusick 	int error;
10677701Ssam 
106838408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
106937741Smckusick 		RETURN (error);
107037741Smckusick 	vattr_null(&vattr);
107137741Smckusick 	vattr.va_uid = uap->uid;
107237741Smckusick 	vattr.va_gid = uap->gid;
107337741Smckusick 	vp = (struct vnode *)fp->f_data;
107437741Smckusick 	VOP_LOCK(vp);
107537741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
107637741Smckusick 		error = EROFS;
107737741Smckusick 		goto out;
107837741Smckusick 	}
107937741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
108037741Smckusick out:
108137741Smckusick 	VOP_UNLOCK(vp);
108237741Smckusick 	RETURN (error);
10837701Ssam }
10847701Ssam 
108538408Smckusick utimes(scp)
108638408Smckusick 	register struct syscontext *scp;
108711811Ssam {
108811811Ssam 	register struct a {
108911811Ssam 		char	*fname;
109011811Ssam 		struct	timeval *tptr;
109138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
109238408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
109337741Smckusick 	register struct vnode *vp;
109411811Ssam 	struct timeval tv[2];
109537741Smckusick 	struct vattr vattr;
109637741Smckusick 	int error;
109711811Ssam 
109837741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
109937741Smckusick 		RETURN (error);
110037741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
110137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
110237741Smckusick 	ndp->ni_dirp = uap->fname;
110337741Smckusick 	vattr_null(&vattr);
110437741Smckusick 	vattr.va_atime = tv[0];
110537741Smckusick 	vattr.va_mtime = tv[1];
110637741Smckusick 	if (error = namei(ndp))
110737741Smckusick 		RETURN (error);
110837741Smckusick 	vp = ndp->ni_vp;
110937741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
111037741Smckusick 		error = EROFS;
111137741Smckusick 		goto out;
111221015Smckusick 	}
111337741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
111437741Smckusick out:
111537741Smckusick 	vput(vp);
111637741Smckusick 	RETURN (error);
111711811Ssam }
111811811Ssam 
11199167Ssam /*
11209167Ssam  * Truncate a file given its path name.
11219167Ssam  */
112238408Smckusick truncate(scp)
112338408Smckusick 	register struct syscontext *scp;
11247701Ssam {
11257701Ssam 	struct a {
11267701Ssam 		char	*fname;
112726473Skarels 		off_t	length;
112838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
112938408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
113037741Smckusick 	register struct vnode *vp;
113137741Smckusick 	struct vattr vattr;
113237741Smckusick 	int error;
11337701Ssam 
113437741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
113516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
113616694Smckusick 	ndp->ni_dirp = uap->fname;
113737741Smckusick 	vattr_null(&vattr);
113837741Smckusick 	vattr.va_size = uap->length;
113937741Smckusick 	if (error = namei(ndp))
114037741Smckusick 		RETURN (error);
114137741Smckusick 	vp = ndp->ni_vp;
114237741Smckusick 	if (vp->v_type == VDIR) {
114337741Smckusick 		error = EISDIR;
114437741Smckusick 		goto out;
11457701Ssam 	}
114638399Smckusick 	if ((error = vn_writechk(vp)) ||
114738399Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
114837741Smckusick 		goto out;
114937741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
115037741Smckusick out:
115137741Smckusick 	vput(vp);
115237741Smckusick 	RETURN (error);
11537701Ssam }
11547701Ssam 
11559167Ssam /*
11569167Ssam  * Truncate a file given a file descriptor.
11579167Ssam  */
115838408Smckusick ftruncate(scp)
115938408Smckusick 	register struct syscontext *scp;
11607701Ssam {
11617701Ssam 	struct a {
11627701Ssam 		int	fd;
116326473Skarels 		off_t	length;
116438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
116537741Smckusick 	struct vattr vattr;
116637741Smckusick 	struct vnode *vp;
11677701Ssam 	struct file *fp;
116837741Smckusick 	int error;
11697701Ssam 
117038408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
117137741Smckusick 		RETURN (error);
117237741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
117337741Smckusick 		RETURN (EINVAL);
117437741Smckusick 	vattr_null(&vattr);
117537741Smckusick 	vattr.va_size = uap->length;
117637741Smckusick 	vp = (struct vnode *)fp->f_data;
117737741Smckusick 	VOP_LOCK(vp);
117837741Smckusick 	if (vp->v_type == VDIR) {
117937741Smckusick 		error = EISDIR;
118037741Smckusick 		goto out;
11817701Ssam 	}
118238399Smckusick 	if (error = vn_writechk(vp))
118337741Smckusick 		goto out;
118437741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
118537741Smckusick out:
118637741Smckusick 	VOP_UNLOCK(vp);
118737741Smckusick 	RETURN (error);
11887701Ssam }
11897701Ssam 
11909167Ssam /*
11919167Ssam  * Synch an open file.
11929167Ssam  */
119338408Smckusick fsync(scp)
119438408Smckusick 	register struct syscontext *scp;
11959167Ssam {
11969167Ssam 	struct a {
11979167Ssam 		int	fd;
119838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
119939592Smckusick 	register struct vnode *vp;
12009167Ssam 	struct file *fp;
120137741Smckusick 	int error;
12029167Ssam 
120338408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
120437741Smckusick 		RETURN (error);
120539592Smckusick 	vp = (struct vnode *)fp->f_data;
120639592Smckusick 	VOP_LOCK(vp);
120739592Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT);
120839592Smckusick 	VOP_UNLOCK(vp);
120937741Smckusick 	RETURN (error);
12109167Ssam }
12119167Ssam 
12129167Ssam /*
12139167Ssam  * Rename system call.
12149167Ssam  *
12159167Ssam  * Source and destination must either both be directories, or both
12169167Ssam  * not be directories.  If target is a directory, it must be empty.
12179167Ssam  */
121838408Smckusick rename(scp)
121938408Smckusick 	register struct syscontext *scp;
12207701Ssam {
12217701Ssam 	struct a {
12227701Ssam 		char	*from;
12237701Ssam 		char	*to;
122438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
122537741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
122638408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
122737741Smckusick 	struct nameidata tond;
122837741Smckusick 	int error;
12297701Ssam 
123037741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
123116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
123216694Smckusick 	ndp->ni_dirp = uap->from;
123337741Smckusick 	if (error = namei(ndp))
123437741Smckusick 		RETURN (error);
123537741Smckusick 	fvp = ndp->ni_vp;
123638266Smckusick 	nddup(ndp, &tond);
123737741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
123837741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
123937741Smckusick 	tond.ni_dirp = uap->to;
124037741Smckusick 	error = namei(&tond);
124137741Smckusick 	tdvp = tond.ni_dvp;
124237741Smckusick 	tvp = tond.ni_vp;
124337741Smckusick 	if (tvp != NULL) {
124437741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
124539242Sbostic 			error = ENOTDIR;
124637741Smckusick 			goto out;
124737741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
124839242Sbostic 			error = EISDIR;
124937741Smckusick 			goto out;
12509167Ssam 		}
12519167Ssam 	}
125237741Smckusick 	if (error) {
125337741Smckusick 		VOP_ABORTOP(ndp);
125437741Smckusick 		goto out1;
125537741Smckusick 	}
125637741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
125737741Smckusick 		error = EXDEV;
12589167Ssam 		goto out;
125910051Ssam 	}
126039286Smckusick 	if (fvp == tdvp)
126137741Smckusick 		error = EINVAL;
126239286Smckusick 	/*
126339286Smckusick 	 * If source is the same as the destination,
126439286Smckusick 	 * then there is nothing to do.
126539286Smckusick 	 */
126639286Smckusick 	if (fvp == tvp)
126739286Smckusick 		error = -1;
126837741Smckusick out:
126937741Smckusick 	if (error) {
127037741Smckusick 		VOP_ABORTOP(&tond);
127137741Smckusick 		VOP_ABORTOP(ndp);
12729167Ssam 	} else {
127337741Smckusick 		error = VOP_RENAME(ndp, &tond);
12749167Ssam 	}
127537741Smckusick out1:
127638266Smckusick 	ndrele(&tond);
127739286Smckusick 	if (error == -1)
127839286Smckusick 		RETURN (0);
127937741Smckusick 	RETURN (error);
12807701Ssam }
12817701Ssam 
12827535Sroot /*
128312756Ssam  * Mkdir system call
128412756Ssam  */
128538408Smckusick mkdir(scp)
128638408Smckusick 	register struct syscontext *scp;
128712756Ssam {
128812756Ssam 	struct a {
128912756Ssam 		char	*name;
129012756Ssam 		int	dmode;
129138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
129238408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
129337741Smckusick 	register struct vnode *vp;
129437741Smckusick 	struct vattr vattr;
129537741Smckusick 	int error;
129612756Ssam 
129737741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
129816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
129916694Smckusick 	ndp->ni_dirp = uap->name;
130037741Smckusick 	if (error = namei(ndp))
130137741Smckusick 		RETURN (error);
130237741Smckusick 	vp = ndp->ni_vp;
130337741Smckusick 	if (vp != NULL) {
130437741Smckusick 		VOP_ABORTOP(ndp);
130537741Smckusick 		RETURN (EEXIST);
130612756Ssam 	}
130737741Smckusick 	vattr_null(&vattr);
130837741Smckusick 	vattr.va_type = VDIR;
130938408Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask;
131037741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
131138145Smckusick 	if (!error)
131238145Smckusick 		vput(ndp->ni_vp);
131337741Smckusick 	RETURN (error);
131412756Ssam }
131512756Ssam 
131612756Ssam /*
131712756Ssam  * Rmdir system call.
131812756Ssam  */
131938408Smckusick rmdir(scp)
132038408Smckusick 	register struct syscontext *scp;
132112756Ssam {
132212756Ssam 	struct a {
132312756Ssam 		char	*name;
132438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
132538408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
132637741Smckusick 	register struct vnode *vp;
132737741Smckusick 	int error;
132812756Ssam 
132937741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
133016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
133116694Smckusick 	ndp->ni_dirp = uap->name;
133237741Smckusick 	if (error = namei(ndp))
133337741Smckusick 		RETURN (error);
133437741Smckusick 	vp = ndp->ni_vp;
133537741Smckusick 	if (vp->v_type != VDIR) {
133637741Smckusick 		error = ENOTDIR;
133712756Ssam 		goto out;
133812756Ssam 	}
133912756Ssam 	/*
134037741Smckusick 	 * No rmdir "." please.
134112756Ssam 	 */
134237741Smckusick 	if (ndp->ni_dvp == vp) {
134337741Smckusick 		error = EINVAL;
134412756Ssam 		goto out;
134512756Ssam 	}
134612756Ssam 	/*
134737741Smckusick 	 * Don't unlink a mounted file.
134812756Ssam 	 */
134937741Smckusick 	if (vp->v_flag & VROOT)
135037741Smckusick 		error = EBUSY;
135112756Ssam out:
135237741Smckusick 	if (error)
135337741Smckusick 		VOP_ABORTOP(ndp);
135437741Smckusick 	else
135537741Smckusick 		error = VOP_RMDIR(ndp);
135637741Smckusick 	RETURN (error);
135712756Ssam }
135812756Ssam 
135937741Smckusick /*
136037741Smckusick  * Read a block of directory entries in a file system independent format
136137741Smckusick  */
136238408Smckusick getdirentries(scp)
136338408Smckusick 	register struct syscontext *scp;
136412756Ssam {
136537741Smckusick 	register struct a {
136637741Smckusick 		int	fd;
136737741Smckusick 		char	*buf;
136837741Smckusick 		unsigned count;
136937741Smckusick 		long	*basep;
137038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
137139592Smckusick 	register struct vnode *vp;
137216540Ssam 	struct file *fp;
137337741Smckusick 	struct uio auio;
137437741Smckusick 	struct iovec aiov;
137538129Smckusick 	off_t off;
137637741Smckusick 	int error;
137712756Ssam 
137838408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
137937741Smckusick 		RETURN (error);
138037741Smckusick 	if ((fp->f_flag & FREAD) == 0)
138137741Smckusick 		RETURN (EBADF);
138239592Smckusick 	vp = (struct vnode *)fp->f_data;
138339592Smckusick 	if (vp->v_type != VDIR)
138439592Smckusick 		RETURN (EINVAL);
138537741Smckusick 	aiov.iov_base = uap->buf;
138637741Smckusick 	aiov.iov_len = uap->count;
138737741Smckusick 	auio.uio_iov = &aiov;
138837741Smckusick 	auio.uio_iovcnt = 1;
138937741Smckusick 	auio.uio_rw = UIO_READ;
139037741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
139137741Smckusick 	auio.uio_resid = uap->count;
139239592Smckusick 	VOP_LOCK(vp);
139339592Smckusick 	auio.uio_offset = off = fp->f_offset;
139439592Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred);
139539592Smckusick 	fp->f_offset = auio.uio_offset;
139639592Smckusick 	VOP_UNLOCK(vp);
139739592Smckusick 	if (error)
139837741Smckusick 		RETURN (error);
139939592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
140038408Smckusick 	scp->sc_retval1 = uap->count - auio.uio_resid;
140137741Smckusick 	RETURN (error);
140212756Ssam }
140312756Ssam 
140412756Ssam /*
140512756Ssam  * mode mask for creation of files
140612756Ssam  */
140738408Smckusick umask(scp)
140838408Smckusick 	register struct syscontext *scp;
140912756Ssam {
141012756Ssam 	register struct a {
141112756Ssam 		int	mask;
141238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
141312756Ssam 
141438408Smckusick 	scp->sc_retval1 = scp->sc_cmask;
141538408Smckusick 	scp->sc_cmask = uap->mask & 07777;
141637741Smckusick 	RETURN (0);
141712756Ssam }
141837741Smckusick 
141939566Smarc /*
142039566Smarc  * Void all references to file by ripping underlying filesystem
142139566Smarc  * away from vnode.
142239566Smarc  */
142339566Smarc revoke(scp)
142439566Smarc 	register struct syscontext *scp;
142539566Smarc {
142639566Smarc 	struct a {
142739566Smarc 		char	*fname;
142839566Smarc 	} *uap = (struct a *)scp->sc_ap;
142939566Smarc 	register struct nameidata *ndp = &scp->sc_nd;
143039566Smarc 	register struct vnode *vp;
143139566Smarc 	struct vattr vattr;
143239566Smarc 	int error;
143339566Smarc 
143439566Smarc 	ndp->ni_nameiop = LOOKUP | FOLLOW;
143539566Smarc 	ndp->ni_segflg = UIO_USERSPACE;
143639566Smarc 	ndp->ni_dirp = uap->fname;
143739566Smarc 	if (error = namei(ndp))
143839566Smarc 		RETURN (error);
143939566Smarc 	vp = ndp->ni_vp;
144039566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
144139566Smarc 		error = EINVAL;
144239566Smarc 		goto out;
144339566Smarc 	}
144439566Smarc 	if (error = VOP_GETATTR(vp, &vattr, scp->sc_cred))
144539566Smarc 		goto out;
144639566Smarc 	if (scp->sc_uid != vattr.va_uid ||
144739566Smarc 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
144839566Smarc 		goto out;
144939632Smckusick 	if (vp->v_count > 1 || (vp->v_flag & VALIASED))
145039632Smckusick 		vgoneall(vp);
145139566Smarc out:
145239566Smarc 	vrele(vp);
145339566Smarc 	RETURN (error);
145439566Smarc }
145539566Smarc 
145638408Smckusick getvnode(ofile, fdes, fpp)
145738408Smckusick 	struct file *ofile[];
145837741Smckusick 	struct file **fpp;
145937741Smckusick 	int fdes;
146037741Smckusick {
146137741Smckusick 	struct file *fp;
146237741Smckusick 
146338408Smckusick 	if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
146437741Smckusick 		return (EBADF);
146537741Smckusick 	if (fp->f_type != DTYPE_VNODE)
146637741Smckusick 		return (EINVAL);
146737741Smckusick 	*fpp = fp;
146837741Smckusick 	return (0);
146937741Smckusick }
1470