xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 39044)
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*39044Smckusick  *	@(#)vfs_syscalls.c	7.15 (Berkeley) 09/05/89
1823405Smckusick  */
1937Sbill 
2017101Sbloom #include "param.h"
2117101Sbloom #include "systm.h"
2237741Smckusick #include "syscontext.h"
2317101Sbloom #include "kernel.h"
2417101Sbloom #include "file.h"
2517101Sbloom #include "stat.h"
2637741Smckusick #include "vnode.h"
2737741Smckusick #include "../ufs/inode.h"
2837741Smckusick #include "mount.h"
2917101Sbloom #include "proc.h"
3017101Sbloom #include "uio.h"
3137741Smckusick #include "malloc.h"
3237Sbill 
3337741Smckusick /*
3437741Smckusick  * Virtual File System System Calls
3537741Smckusick  */
3612756Ssam 
379167Ssam /*
3837741Smckusick  * mount system call
399167Ssam  */
4038408Smckusick mount(scp)
4138408Smckusick 	register struct syscontext *scp;
426254Sroot {
4337741Smckusick 	register struct a {
4437741Smckusick 		int	type;
4537741Smckusick 		char	*dir;
4637741Smckusick 		int	flags;
4737741Smckusick 		caddr_t	data;
4838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
4938408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
5037741Smckusick 	struct vnode *vp;
5137741Smckusick 	struct mount *mp;
5237741Smckusick 	int error;
536254Sroot 
5437741Smckusick 	/*
5537741Smckusick 	 * Must be super user
5637741Smckusick 	 */
5738408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
5837741Smckusick 		RETURN (error);
5937741Smckusick 	/*
6037741Smckusick 	 * Get vnode to be covered
6137741Smckusick 	 */
6237741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
6337741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
6437741Smckusick 	ndp->ni_dirp = uap->dir;
6537741Smckusick 	if (error = namei(ndp))
6637741Smckusick 		RETURN (error);
6737741Smckusick 	vp = ndp->ni_vp;
6837741Smckusick 	if (vp->v_count != 1) {
6937741Smckusick 		vput(vp);
7037741Smckusick 		RETURN (EBUSY);
7137741Smckusick 	}
7237741Smckusick 	if (vp->v_type != VDIR) {
7337741Smckusick 		vput(vp);
7437741Smckusick 		RETURN (ENOTDIR);
7537741Smckusick 	}
7637741Smckusick 	if (uap->type > MOUNT_MAXTYPE ||
7737741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
7837741Smckusick 		vput(vp);
7937741Smckusick 		RETURN (ENODEV);
8037741Smckusick 	}
8137741Smckusick 
8237741Smckusick 	/*
8337741Smckusick 	 * Mount the filesystem.
8437741Smckusick 	 */
8537741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
8637741Smckusick 		M_MOUNT, M_WAITOK);
8737741Smckusick 	mp->m_op = vfssw[uap->type];
8837741Smckusick 	mp->m_flag = 0;
8937741Smckusick 	mp->m_exroot = 0;
9037741Smckusick 	error = vfs_add(vp, mp, uap->flags);
9137741Smckusick 	if (!error)
9237741Smckusick 		error = VFS_MOUNT(mp, uap->dir, uap->data, ndp);
9337741Smckusick 	cache_purge(vp);
9437741Smckusick 	VOP_UNLOCK(vp);
9537741Smckusick 	if (!error) {
9637741Smckusick 		vfs_unlock(mp);
97*39044Smckusick 		error = VFS_START(mp, 0);
9837741Smckusick 	} else {
9937741Smckusick 		vfs_remove(mp);
10037741Smckusick 		free((caddr_t)mp, M_MOUNT);
10137741Smckusick 		vrele(vp);
10237741Smckusick 	}
10337741Smckusick 	RETURN (error);
1046254Sroot }
1056254Sroot 
1069167Ssam /*
10737741Smckusick  * Unmount system call.
10837741Smckusick  *
10937741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
11037741Smckusick  * not special file (as before).
1119167Ssam  */
11238408Smckusick unmount(scp)
11338408Smckusick 	register struct syscontext *scp;
1146254Sroot {
11537741Smckusick 	struct a {
11637741Smckusick 		char	*pathp;
11737741Smckusick 		int	flags;
11838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
11937741Smckusick 	register struct vnode *vp;
12037741Smckusick 	register struct mount *mp;
12138408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
12237741Smckusick 	struct vnode *coveredvp;
12337741Smckusick 	int error;
1246254Sroot 
12537741Smckusick 	/*
12637741Smckusick 	 * Must be super user
12737741Smckusick 	 */
12838408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
12937741Smckusick 		RETURN (error);
13037741Smckusick 
13137741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
13237741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
13337741Smckusick 	ndp->ni_dirp = uap->pathp;
13437741Smckusick 	if (error = namei(ndp))
13537741Smckusick 		RETURN (error);
13637741Smckusick 	vp = ndp->ni_vp;
13737741Smckusick 	/*
13837741Smckusick 	 * Must be the root of the filesystem
13937741Smckusick 	 */
14037741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
14137741Smckusick 		vput(vp);
14237741Smckusick 		RETURN (EINVAL);
14337741Smckusick 	}
14437741Smckusick 	mp = vp->v_mount;
14537741Smckusick 	vput(vp);
14637741Smckusick 	/*
14737741Smckusick 	 * Do the unmount.
14837741Smckusick 	 */
14937741Smckusick 	coveredvp = mp->m_vnodecovered;
15037741Smckusick 	if (error = vfs_lock(mp))
15137741Smckusick 		RETURN (error);
15237741Smckusick 
15337741Smckusick 	xumount(mp);		/* remove unused sticky files from text table */
15437741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
15537741Smckusick 	VFS_SYNC(mp, MNT_WAIT);
15637741Smckusick 
15737741Smckusick 	error = VFS_UNMOUNT(mp, uap->flags);
15837741Smckusick 	if (error) {
15937741Smckusick 		vfs_unlock(mp);
16037741Smckusick 	} else {
16137741Smckusick 		vrele(coveredvp);
16237741Smckusick 		vfs_remove(mp);
16337741Smckusick 		free((caddr_t)mp, M_MOUNT);
16437741Smckusick 	}
16537741Smckusick 	RETURN (error);
1666254Sroot }
1676254Sroot 
1689167Ssam /*
16937741Smckusick  * Sync system call.
17037741Smckusick  * Sync each mounted filesystem.
1719167Ssam  */
17238408Smckusick sync(scp)
17338408Smckusick 	register struct syscontext *scp;
1746254Sroot {
17537741Smckusick 	register struct mount *mp;
17637741Smckusick 
17737741Smckusick 	mp = rootfs;
17837741Smckusick 	do {
17937741Smckusick 		if ((mp->m_flag & M_RDONLY) == 0)
18037741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
18137741Smckusick 		mp = mp->m_next;
18237741Smckusick 	} while (mp != rootfs);
18337741Smckusick }
18437741Smckusick 
18537741Smckusick /*
18637741Smckusick  * get filesystem statistics
18737741Smckusick  */
18838408Smckusick statfs(scp)
18938408Smckusick 	register struct syscontext *scp;
19037741Smckusick {
1916254Sroot 	struct a {
19237741Smckusick 		char *path;
19337741Smckusick 		struct statfs *buf;
19438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
19537741Smckusick 	register struct vnode *vp;
19638408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
19737741Smckusick 	struct statfs sb;
19837741Smckusick 	int error;
19937741Smckusick 
20037741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
20137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
20237741Smckusick 	ndp->ni_dirp = uap->path;
20337741Smckusick 	if (error = namei(ndp))
20437741Smckusick 		RETURN (error);
20537741Smckusick 	vp = ndp->ni_vp;
20637741Smckusick 	if (error = VFS_STATFS(vp->v_mount, &sb))
20737741Smckusick 		goto out;
20837741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb));
20937741Smckusick out:
21037741Smckusick 	vput(vp);
21137741Smckusick 	RETURN (error);
21237741Smckusick }
21337741Smckusick 
21438408Smckusick fstatfs(scp)
21538408Smckusick 	register struct syscontext *scp;
21637741Smckusick {
21737741Smckusick 	struct a {
21837741Smckusick 		int fd;
21937741Smckusick 		struct statfs *buf;
22038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
22137741Smckusick 	struct file *fp;
22237741Smckusick 	struct statfs sb;
22337741Smckusick 	int error;
22437741Smckusick 
22538408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
22637741Smckusick 		RETURN (error);
22737741Smckusick 	if (error = VFS_STATFS(((struct vnode *)fp->f_data)->v_mount, &sb))
22837741Smckusick 		RETURN (error);
22937741Smckusick 	RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)));
23037741Smckusick }
23137741Smckusick 
23237741Smckusick /*
23338270Smckusick  * get statistics on all filesystems
23438270Smckusick  */
23538408Smckusick getfsstat(scp)
23638408Smckusick 	register struct syscontext *scp;
23738270Smckusick {
23838270Smckusick 	struct a {
23938270Smckusick 		struct statfs *buf;
24038270Smckusick 		long bufsize;
24138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
24238270Smckusick 	register struct mount *mp;
24338270Smckusick 	register struct statfs *sfsp;
24438270Smckusick 	long count, maxcount, error;
24538270Smckusick 
24638270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
24738270Smckusick 	sfsp = uap->buf;
24838270Smckusick 	mp = rootfs;
24938270Smckusick 	count = 0;
25038270Smckusick 	do {
25138270Smckusick 		count++;
252*39044Smckusick 		if (sfsp && count <= maxcount &&
253*39044Smckusick 		    ((mp->m_flag & M_MLOCK) == 0)) {
25438270Smckusick 			if (error = VFS_STATFS(mp, sfsp))
25538270Smckusick 				RETURN (error);
25638270Smckusick 			sfsp++;
25738270Smckusick 		}
25838270Smckusick 		mp = mp->m_prev;
25938270Smckusick 	} while (mp != rootfs);
26038270Smckusick 	if (sfsp && count > maxcount)
26138408Smckusick 		scp->sc_retval1 = maxcount;
26238270Smckusick 	else
26338408Smckusick 		scp->sc_retval1 = count;
26438270Smckusick 	RETURN (0);
26538270Smckusick }
26638270Smckusick 
26738270Smckusick /*
26838259Smckusick  * Change current working directory to a given file descriptor.
26938259Smckusick  */
27038408Smckusick fchdir(scp)
27138408Smckusick 	register struct syscontext *scp;
27238259Smckusick {
27338259Smckusick 	struct a {
27438259Smckusick 		int	fd;
27538408Smckusick 	} *uap = (struct a *)scp->sc_ap;
27638259Smckusick 	register struct vnode *vp;
27738259Smckusick 	struct file *fp;
27838259Smckusick 	int error;
27938259Smckusick 
28038408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
28138259Smckusick 		RETURN (error);
28238259Smckusick 	vp = (struct vnode *)fp->f_data;
28338259Smckusick 	VOP_LOCK(vp);
28438259Smckusick 	if (vp->v_type != VDIR)
28538259Smckusick 		error = ENOTDIR;
28638259Smckusick 	else
28738408Smckusick 		error = VOP_ACCESS(vp, VEXEC, scp->sc_cred);
28838259Smckusick 	VOP_UNLOCK(vp);
28938408Smckusick 	vrele(scp->sc_cdir);
29038408Smckusick 	scp->sc_cdir = vp;
29138259Smckusick 	RETURN (error);
29238259Smckusick }
29338259Smckusick 
29438259Smckusick /*
29537741Smckusick  * Change current working directory (``.'').
29637741Smckusick  */
29738408Smckusick chdir(scp)
29838408Smckusick 	register struct syscontext *scp;
29937741Smckusick {
30037741Smckusick 	struct a {
3016254Sroot 		char	*fname;
30238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
30338408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
30437741Smckusick 	int error;
3056254Sroot 
30637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
30716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
30816694Smckusick 	ndp->ni_dirp = uap->fname;
30937741Smckusick 	if (error = chdirec(ndp))
31037741Smckusick 		RETURN (error);
31138408Smckusick 	vrele(scp->sc_cdir);
31238408Smckusick 	scp->sc_cdir = ndp->ni_vp;
31337741Smckusick 	RETURN (0);
31437741Smckusick }
3156254Sroot 
31637741Smckusick /*
31737741Smckusick  * Change notion of root (``/'') directory.
31837741Smckusick  */
31938408Smckusick chroot(scp)
32038408Smckusick 	register struct syscontext *scp;
32137741Smckusick {
32237741Smckusick 	struct a {
32337741Smckusick 		char	*fname;
32438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
32538408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
32637741Smckusick 	int error;
32737741Smckusick 
32838408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
32937741Smckusick 		RETURN (error);
33037741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
33137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
33237741Smckusick 	ndp->ni_dirp = uap->fname;
33337741Smckusick 	if (error = chdirec(ndp))
33437741Smckusick 		RETURN (error);
33538408Smckusick 	vrele(scp->sc_rdir);
33638408Smckusick 	scp->sc_rdir = ndp->ni_vp;
33737741Smckusick 	RETURN (0);
3386254Sroot }
3396254Sroot 
34037Sbill /*
34137741Smckusick  * Common routine for chroot and chdir.
34237741Smckusick  */
34337741Smckusick chdirec(ndp)
34437741Smckusick 	register struct nameidata *ndp;
34537741Smckusick {
34637741Smckusick 	struct vnode *vp;
34737741Smckusick 	int error;
34837741Smckusick 
34937741Smckusick 	if (error = namei(ndp))
35037741Smckusick 		return (error);
35137741Smckusick 	vp = ndp->ni_vp;
35237741Smckusick 	if (vp->v_type != VDIR)
35337741Smckusick 		error = ENOTDIR;
35437741Smckusick 	else
35538399Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
35637741Smckusick 	VOP_UNLOCK(vp);
35737741Smckusick 	if (error)
35837741Smckusick 		vrele(vp);
35937741Smckusick 	return (error);
36037741Smckusick }
36137741Smckusick 
36237741Smckusick /*
3636254Sroot  * Open system call.
3646254Sroot  */
36538408Smckusick open(scp)
36638408Smckusick 	register struct syscontext *scp;
3676254Sroot {
36812756Ssam 	struct a {
3696254Sroot 		char	*fname;
3707701Ssam 		int	mode;
37112756Ssam 		int	crtmode;
37238408Smckusick 	} *uap = (struct a *) scp->sc_ap;
37338408Smckusick 	struct nameidata *ndp = &scp->sc_nd;
3746254Sroot 
37537741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
37637741Smckusick 	ndp->ni_dirp = uap->fname;
37738408Smckusick 	RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp,
37838408Smckusick 		&scp->sc_retval1));
3796254Sroot }
3806254Sroot 
3816254Sroot /*
3826254Sroot  * Creat system call.
3836254Sroot  */
38438408Smckusick creat(scp)
38538408Smckusick 	register struct syscontext *scp;
3866254Sroot {
38712756Ssam 	struct a {
3886254Sroot 		char	*fname;
3896254Sroot 		int	fmode;
39038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
39138408Smckusick 	struct nameidata *ndp = &scp->sc_nd;
3926254Sroot 
39337741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
39437741Smckusick 	ndp->ni_dirp = uap->fname;
39538408Smckusick 	RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask,
39638408Smckusick 		ndp, &scp->sc_retval1));
3976254Sroot }
3986254Sroot 
3996254Sroot /*
4006254Sroot  * Common code for open and creat.
40112756Ssam  * Check permissions, allocate an open file structure,
40212756Ssam  * and call the device open routine if any.
4036254Sroot  */
40438408Smckusick copen(scp, fmode, cmode, ndp, resultfd)
40538408Smckusick 	register struct syscontext *scp;
40637741Smckusick 	int fmode, cmode;
40737741Smckusick 	struct nameidata *ndp;
40837741Smckusick 	int *resultfd;
40912756Ssam {
4106254Sroot 	register struct file *fp;
41137741Smckusick 	struct file *nfp;
41237741Smckusick 	int indx, error;
41337741Smckusick 	extern struct fileops vnops;
4146254Sroot 
41537741Smckusick 	if (error = falloc(&nfp, &indx))
41637741Smckusick 		return (error);
41737741Smckusick 	fp = nfp;
41838408Smckusick 	scp->sc_retval1 = indx;	/* XXX for fdopen() */
41937741Smckusick 	if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) {
42038408Smckusick 		scp->sc_ofile[indx] = NULL;
42137741Smckusick 		crfree(fp->f_cred);
42237741Smckusick 		fp->f_count--;
42337741Smckusick 		return (error);
42412756Ssam 	}
42537741Smckusick 	fp->f_flag = fmode & FMASK;
42637741Smckusick 	fp->f_type = DTYPE_VNODE;
42737741Smckusick 	fp->f_ops = &vnops;
42837741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
42937741Smckusick 	if (resultfd)
43037741Smckusick 		*resultfd = indx;
43137741Smckusick 	return (0);
4326254Sroot }
4336254Sroot 
4346254Sroot /*
4356254Sroot  * Mknod system call
4366254Sroot  */
43738408Smckusick mknod(scp)
43838408Smckusick 	register struct syscontext *scp;
4396254Sroot {
4406254Sroot 	register struct a {
4416254Sroot 		char	*fname;
4426254Sroot 		int	fmode;
4436254Sroot 		int	dev;
44438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
44538408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
44637741Smckusick 	register struct vnode *vp;
44737741Smckusick 	struct vattr vattr;
44837741Smckusick 	int error;
4496254Sroot 
45038408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
45137741Smckusick 		RETURN (error);
45237741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
45316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
45416694Smckusick 	ndp->ni_dirp = uap->fname;
45537741Smckusick 	if (error = namei(ndp))
45637741Smckusick 		RETURN (error);
45737741Smckusick 	vp = ndp->ni_vp;
45837741Smckusick 	if (vp != NULL) {
45937741Smckusick 		error = EEXIST;
46012756Ssam 		goto out;
4616254Sroot 	}
46237741Smckusick 	vattr_null(&vattr);
46337741Smckusick 	switch (uap->fmode & IFMT) {
46412756Ssam 
46515093Smckusick 	case IFMT:	/* used by badsect to flag bad sectors */
46637741Smckusick 		vattr.va_type = VBAD;
46737741Smckusick 		break;
46812756Ssam 	case IFCHR:
46937741Smckusick 		vattr.va_type = VCHR;
47037741Smckusick 		break;
47112756Ssam 	case IFBLK:
47237741Smckusick 		vattr.va_type = VBLK;
47337741Smckusick 		break;
47437741Smckusick 	default:
47537741Smckusick 		error = EINVAL;
47637741Smckusick 		goto out;
4776254Sroot 	}
47838408Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask;
47937741Smckusick 	vattr.va_rdev = uap->dev;
4806254Sroot out:
48137741Smckusick 	if (error)
48237741Smckusick 		VOP_ABORTOP(ndp);
48337741Smckusick 	else
48437741Smckusick 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
48537741Smckusick 	RETURN (error);
4866254Sroot }
4876254Sroot 
4886254Sroot /*
4896254Sroot  * link system call
4906254Sroot  */
49138408Smckusick link(scp)
49238408Smckusick 	register struct syscontext *scp;
4936254Sroot {
4946254Sroot 	register struct a {
4956254Sroot 		char	*target;
4966254Sroot 		char	*linkname;
49738408Smckusick 	} *uap = (struct a *)scp->sc_ap;
49838408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
49937741Smckusick 	register struct vnode *vp, *xp;
50037741Smckusick 	int error;
5016254Sroot 
50216694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
50316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
50416694Smckusick 	ndp->ni_dirp = uap->target;
50537741Smckusick 	if (error = namei(ndp))
50637741Smckusick 		RETURN (error);
50737741Smckusick 	vp = ndp->ni_vp;
50837741Smckusick 	if (vp->v_type == VDIR &&
50938408Smckusick 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
51037741Smckusick 		goto out1;
51137741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
51216694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
51337741Smckusick 	if (error = namei(ndp))
51437741Smckusick 		goto out1;
51537741Smckusick 	xp = ndp->ni_vp;
5166254Sroot 	if (xp != NULL) {
51737741Smckusick 		error = EEXIST;
5186254Sroot 		goto out;
5196254Sroot 	}
52037741Smckusick 	xp = ndp->ni_dvp;
52137741Smckusick 	if (vp->v_mount != xp->v_mount)
52237741Smckusick 		error = EXDEV;
5236254Sroot out:
52437741Smckusick 	if (error)
52537741Smckusick 		VOP_ABORTOP(ndp);
52637741Smckusick 	else
52737741Smckusick 		error = VOP_LINK(vp, ndp);
52837741Smckusick out1:
52937741Smckusick 	vrele(vp);
53037741Smckusick 	RETURN (error);
5316254Sroot }
5326254Sroot 
5336254Sroot /*
5346254Sroot  * symlink -- make a symbolic link
5356254Sroot  */
53638408Smckusick symlink(scp)
53738408Smckusick 	register struct syscontext *scp;
5386254Sroot {
53937741Smckusick 	struct a {
5406254Sroot 		char	*target;
5416254Sroot 		char	*linkname;
54238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
54338408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
54437741Smckusick 	register struct vnode *vp;
54537741Smckusick 	struct vattr vattr;
54637741Smckusick 	char *target;
54737741Smckusick 	int error;
5486254Sroot 
54916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
55016694Smckusick 	ndp->ni_dirp = uap->linkname;
55137741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
55237741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
55337741Smckusick 		goto out1;
55437741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
55537741Smckusick 	if (error = namei(ndp))
55637741Smckusick 		goto out1;
55737741Smckusick 	vp = ndp->ni_vp;
55837741Smckusick 	if (vp) {
55937741Smckusick 		error = EEXIST;
56037741Smckusick 		goto out;
5616254Sroot 	}
56237741Smckusick 	vp = ndp->ni_dvp;
56337741Smckusick 	vattr_null(&vattr);
56438408Smckusick 	vattr.va_mode = 0777 &~ scp->sc_cmask;
56537741Smckusick out:
56637741Smckusick 	if (error)
56737741Smckusick 		VOP_ABORTOP(ndp);
56837741Smckusick 	else
56937741Smckusick 		error = VOP_SYMLINK(ndp, &vattr, target);
57037741Smckusick out1:
57137741Smckusick 	FREE(target, M_NAMEI);
57237741Smckusick 	RETURN (error);
5736254Sroot }
5746254Sroot 
5756254Sroot /*
5766254Sroot  * Unlink system call.
5776254Sroot  * Hard to avoid races here, especially
5786254Sroot  * in unlinking directories.
5796254Sroot  */
58038408Smckusick unlink(scp)
58138408Smckusick 	register struct syscontext *scp;
5826254Sroot {
5836254Sroot 	struct a {
5846254Sroot 		char	*fname;
58538408Smckusick 	} *uap = (struct a *)scp->sc_ap;
58638408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
58737741Smckusick 	register struct vnode *vp;
58837741Smckusick 	int error;
5896254Sroot 
59037741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
59116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
59216694Smckusick 	ndp->ni_dirp = uap->fname;
59337741Smckusick 	if (error = namei(ndp))
59437741Smckusick 		RETURN (error);
59537741Smckusick 	vp = ndp->ni_vp;
59637741Smckusick 	if (vp->v_type == VDIR &&
59738408Smckusick 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
5986254Sroot 		goto out;
5996254Sroot 	/*
6006254Sroot 	 * Don't unlink a mounted file.
6016254Sroot 	 */
60237741Smckusick 	if (vp->v_flag & VROOT) {
60337741Smckusick 		error = EBUSY;
6046254Sroot 		goto out;
6056254Sroot 	}
60637741Smckusick 	if (vp->v_flag & VTEXT)
60737741Smckusick 		xrele(vp);	/* try once to free text */
6086254Sroot out:
60937741Smckusick 	if (error)
61037741Smckusick 		VOP_ABORTOP(ndp);
6117142Smckusick 	else
61237741Smckusick 		error = VOP_REMOVE(ndp);
61337741Smckusick 	RETURN (error);
6146254Sroot }
6156254Sroot 
6166254Sroot /*
6176254Sroot  * Seek system call
6186254Sroot  */
61938408Smckusick lseek(scp)
62038408Smckusick 	register struct syscontext *scp;
6216254Sroot {
6226254Sroot 	register struct file *fp;
6236254Sroot 	register struct a {
62437741Smckusick 		int	fdes;
6256254Sroot 		off_t	off;
6266254Sroot 		int	sbase;
62738408Smckusick 	} *uap = (struct a *)scp->sc_ap;
62837741Smckusick 	struct vattr vattr;
62937741Smckusick 	int error;
6306254Sroot 
63137741Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
63238408Smckusick 	    (fp = scp->sc_ofile[uap->fdes]) == NULL)
63337741Smckusick 		RETURN (EBADF);
63437741Smckusick 	if (fp->f_type != DTYPE_VNODE)
63537741Smckusick 		RETURN (ESPIPE);
63613878Ssam 	switch (uap->sbase) {
63713878Ssam 
63813878Ssam 	case L_INCR:
63913878Ssam 		fp->f_offset += uap->off;
64013878Ssam 		break;
64113878Ssam 
64213878Ssam 	case L_XTND:
64337741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
64438408Smckusick 		    &vattr, scp->sc_cred))
64537741Smckusick 			RETURN (error);
64637741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
64713878Ssam 		break;
64813878Ssam 
64913878Ssam 	case L_SET:
65013878Ssam 		fp->f_offset = uap->off;
65113878Ssam 		break;
65213878Ssam 
65313878Ssam 	default:
65437741Smckusick 		RETURN (EINVAL);
65513878Ssam 	}
65638408Smckusick 	scp->sc_offset = fp->f_offset;
65737741Smckusick 	RETURN (0);
6586254Sroot }
6596254Sroot 
6606254Sroot /*
6616254Sroot  * Access system call
6626254Sroot  */
66338408Smckusick saccess(scp)
66438408Smckusick 	register struct syscontext *scp;
6656254Sroot {
6666254Sroot 	register struct a {
6676254Sroot 		char	*fname;
6686254Sroot 		int	fmode;
66938408Smckusick 	} *uap = (struct a *)scp->sc_ap;
67038408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
67137741Smckusick 	register struct vnode *vp;
67237741Smckusick 	int error, mode, svuid, svgid;
6736254Sroot 
67438408Smckusick 	svuid = scp->sc_uid;
67538408Smckusick 	svgid = scp->sc_gid;
67638408Smckusick 	scp->sc_uid = scp->sc_ruid;
67738408Smckusick 	scp->sc_gid = scp->sc_rgid;
67837741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
67916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
68016694Smckusick 	ndp->ni_dirp = uap->fname;
68137741Smckusick 	if (error = namei(ndp))
68237741Smckusick 		goto out1;
68337741Smckusick 	vp = ndp->ni_vp;
68437741Smckusick 	/*
68537741Smckusick 	 * fmode == 0 means only check for exist
68637741Smckusick 	 */
68737741Smckusick 	if (uap->fmode) {
68837741Smckusick 		mode = 0;
68937741Smckusick 		if (uap->fmode & R_OK)
69037741Smckusick 			mode |= VREAD;
69137741Smckusick 		if (uap->fmode & W_OK)
69237741Smckusick 			mode |= VWRITE;
69337741Smckusick 		if (uap->fmode & X_OK)
69437741Smckusick 			mode |= VEXEC;
69538399Smckusick 		if ((error = vn_writechk(vp)) == 0)
69638399Smckusick 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
6976254Sroot 	}
69837741Smckusick 	vput(vp);
69937741Smckusick out1:
70038408Smckusick 	scp->sc_uid = svuid;
70138408Smckusick 	scp->sc_gid = svgid;
70237741Smckusick 	RETURN (error);
7036254Sroot }
7046254Sroot 
7056254Sroot /*
7066574Smckusic  * Stat system call.  This version follows links.
70737Sbill  */
70838408Smckusick stat(scp)
70938408Smckusick 	struct syscontext *scp;
71037Sbill {
71137Sbill 
71238408Smckusick 	stat1(scp, FOLLOW);
71337Sbill }
71437Sbill 
71537Sbill /*
7166574Smckusic  * Lstat system call.  This version does not follow links.
7175992Swnj  */
71838408Smckusick lstat(scp)
71938408Smckusick 	struct syscontext *scp;
7205992Swnj {
72112756Ssam 
72238408Smckusick 	stat1(scp, NOFOLLOW);
72312756Ssam }
72412756Ssam 
72538408Smckusick stat1(scp, follow)
72638408Smckusick 	register struct syscontext *scp;
72712756Ssam 	int follow;
72812756Ssam {
7295992Swnj 	register struct a {
7305992Swnj 		char	*fname;
73112756Ssam 		struct stat *ub;
73238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
73338408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
73412756Ssam 	struct stat sb;
73537741Smckusick 	int error;
7365992Swnj 
73737741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
73816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
73916694Smckusick 	ndp->ni_dirp = uap->fname;
74037741Smckusick 	if (error = namei(ndp))
74137741Smckusick 		RETURN (error);
74237741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
74337741Smckusick 	vput(ndp->ni_vp);
74437741Smckusick 	if (error)
74537741Smckusick 		RETURN (error);
74637741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
74737741Smckusick 	RETURN (error);
7485992Swnj }
7495992Swnj 
7505992Swnj /*
7515992Swnj  * Return target name of a symbolic link
75237Sbill  */
75338408Smckusick readlink(scp)
75438408Smckusick 	register struct syscontext *scp;
7555992Swnj {
7565992Swnj 	register struct a {
7575992Swnj 		char	*name;
7585992Swnj 		char	*buf;
7595992Swnj 		int	count;
76038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
76138408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
76237741Smckusick 	register struct vnode *vp;
76337741Smckusick 	struct iovec aiov;
76437741Smckusick 	struct uio auio;
76537741Smckusick 	int error;
7665992Swnj 
76737741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
76816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
76916694Smckusick 	ndp->ni_dirp = uap->name;
77037741Smckusick 	if (error = namei(ndp))
77137741Smckusick 		RETURN (error);
77237741Smckusick 	vp = ndp->ni_vp;
77337741Smckusick 	if (vp->v_type != VLNK) {
77437741Smckusick 		error = EINVAL;
7755992Swnj 		goto out;
7765992Swnj 	}
77737741Smckusick 	aiov.iov_base = uap->buf;
77837741Smckusick 	aiov.iov_len = uap->count;
77937741Smckusick 	auio.uio_iov = &aiov;
78037741Smckusick 	auio.uio_iovcnt = 1;
78137741Smckusick 	auio.uio_offset = 0;
78237741Smckusick 	auio.uio_rw = UIO_READ;
78337741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
78437741Smckusick 	auio.uio_resid = uap->count;
78537741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
7865992Swnj out:
78737741Smckusick 	vput(vp);
78838408Smckusick 	scp->sc_retval1 = uap->count - auio.uio_resid;
78937741Smckusick 	RETURN (error);
7905992Swnj }
7915992Swnj 
7929167Ssam /*
79338259Smckusick  * Change flags of a file given path name.
79438259Smckusick  */
79538408Smckusick chflags(scp)
79638408Smckusick 	register struct syscontext *scp;
79738259Smckusick {
79838259Smckusick 	struct a {
79938259Smckusick 		char	*fname;
80038259Smckusick 		int	flags;
80138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
80238408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
80338259Smckusick 	register struct vnode *vp;
80438259Smckusick 	struct vattr vattr;
80538259Smckusick 	int error;
80638259Smckusick 
80738259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
80838259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
80938259Smckusick 	ndp->ni_dirp = uap->fname;
81038259Smckusick 	vattr_null(&vattr);
81138259Smckusick 	vattr.va_flags = uap->flags;
81238259Smckusick 	if (error = namei(ndp))
81338259Smckusick 		RETURN (error);
81438259Smckusick 	vp = ndp->ni_vp;
81538259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
81638259Smckusick 		error = EROFS;
81738259Smckusick 		goto out;
81838259Smckusick 	}
81938259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
82038259Smckusick out:
82138259Smckusick 	vput(vp);
82238259Smckusick 	RETURN (error);
82338259Smckusick }
82438259Smckusick 
82538259Smckusick /*
82638259Smckusick  * Change flags of a file given a file descriptor.
82738259Smckusick  */
82838408Smckusick fchflags(scp)
82938408Smckusick 	register struct syscontext *scp;
83038259Smckusick {
83138259Smckusick 	struct a {
83238259Smckusick 		int	fd;
83338259Smckusick 		int	flags;
83438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
83538259Smckusick 	struct vattr vattr;
83638259Smckusick 	struct vnode *vp;
83738259Smckusick 	struct file *fp;
83838259Smckusick 	int error;
83938259Smckusick 
84038408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
84138259Smckusick 		RETURN (error);
84238259Smckusick 	vattr_null(&vattr);
84338259Smckusick 	vattr.va_flags = uap->flags;
84438259Smckusick 	vp = (struct vnode *)fp->f_data;
84538259Smckusick 	VOP_LOCK(vp);
84638259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
84738259Smckusick 		error = EROFS;
84838259Smckusick 		goto out;
84938259Smckusick 	}
85038259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
85138259Smckusick out:
85238259Smckusick 	VOP_UNLOCK(vp);
85338259Smckusick 	RETURN (error);
85438259Smckusick }
85538259Smckusick 
85638259Smckusick /*
8579167Ssam  * Change mode of a file given path name.
8589167Ssam  */
85938408Smckusick chmod(scp)
86038408Smckusick 	register struct syscontext *scp;
8615992Swnj {
8627701Ssam 	struct a {
8636254Sroot 		char	*fname;
8646254Sroot 		int	fmode;
86538408Smckusick 	} *uap = (struct a *)scp->sc_ap;
86638408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
86737741Smckusick 	register struct vnode *vp;
86837741Smckusick 	struct vattr vattr;
86937741Smckusick 	int error;
8705992Swnj 
87137741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
87237741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
87337741Smckusick 	ndp->ni_dirp = uap->fname;
87437741Smckusick 	vattr_null(&vattr);
87537741Smckusick 	vattr.va_mode = uap->fmode & 07777;
87637741Smckusick 	if (error = namei(ndp))
87737741Smckusick 		RETURN (error);
87837741Smckusick 	vp = ndp->ni_vp;
87937741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
88037741Smckusick 		error = EROFS;
88137741Smckusick 		goto out;
88237741Smckusick 	}
88337741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
88437741Smckusick out:
88537741Smckusick 	vput(vp);
88637741Smckusick 	RETURN (error);
8877701Ssam }
8887439Sroot 
8899167Ssam /*
8909167Ssam  * Change mode of a file given a file descriptor.
8919167Ssam  */
89238408Smckusick fchmod(scp)
89338408Smckusick 	register struct syscontext *scp;
8947701Ssam {
8957701Ssam 	struct a {
8967701Ssam 		int	fd;
8977701Ssam 		int	fmode;
89838408Smckusick 	} *uap = (struct a *)scp->sc_ap;
89937741Smckusick 	struct vattr vattr;
90037741Smckusick 	struct vnode *vp;
90137741Smckusick 	struct file *fp;
90237741Smckusick 	int error;
9037701Ssam 
90438408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
90537741Smckusick 		RETURN (error);
90637741Smckusick 	vattr_null(&vattr);
90737741Smckusick 	vattr.va_mode = uap->fmode & 07777;
90837741Smckusick 	vp = (struct vnode *)fp->f_data;
90937741Smckusick 	VOP_LOCK(vp);
91037741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
91137741Smckusick 		error = EROFS;
91237741Smckusick 		goto out;
9137439Sroot 	}
91437741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
91537741Smckusick out:
91637741Smckusick 	VOP_UNLOCK(vp);
91737741Smckusick 	RETURN (error);
9185992Swnj }
9195992Swnj 
9209167Ssam /*
9219167Ssam  * Set ownership given a path name.
9229167Ssam  */
92338408Smckusick chown(scp)
92438408Smckusick 	register struct syscontext *scp;
92537Sbill {
9267701Ssam 	struct a {
9276254Sroot 		char	*fname;
9286254Sroot 		int	uid;
9296254Sroot 		int	gid;
93038408Smckusick 	} *uap = (struct a *)scp->sc_ap;
93138408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
93237741Smckusick 	register struct vnode *vp;
93337741Smckusick 	struct vattr vattr;
93437741Smckusick 	int error;
93537Sbill 
93637741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
93736614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
93836614Sbostic 	ndp->ni_dirp = uap->fname;
93937741Smckusick 	vattr_null(&vattr);
94037741Smckusick 	vattr.va_uid = uap->uid;
94137741Smckusick 	vattr.va_gid = uap->gid;
94237741Smckusick 	if (error = namei(ndp))
94337741Smckusick 		RETURN (error);
94437741Smckusick 	vp = ndp->ni_vp;
94537741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
94637741Smckusick 		error = EROFS;
94737741Smckusick 		goto out;
94837741Smckusick 	}
94937741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
95037741Smckusick out:
95137741Smckusick 	vput(vp);
95237741Smckusick 	RETURN (error);
9537701Ssam }
9547439Sroot 
9559167Ssam /*
9569167Ssam  * Set ownership given a file descriptor.
9579167Ssam  */
95838408Smckusick fchown(scp)
95938408Smckusick 	register struct syscontext *scp;
9607701Ssam {
9617701Ssam 	struct a {
9627701Ssam 		int	fd;
9637701Ssam 		int	uid;
9647701Ssam 		int	gid;
96538408Smckusick 	} *uap = (struct a *)scp->sc_ap;
96637741Smckusick 	struct vattr vattr;
96737741Smckusick 	struct vnode *vp;
96837741Smckusick 	struct file *fp;
96937741Smckusick 	int error;
9707701Ssam 
97138408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
97237741Smckusick 		RETURN (error);
97337741Smckusick 	vattr_null(&vattr);
97437741Smckusick 	vattr.va_uid = uap->uid;
97537741Smckusick 	vattr.va_gid = uap->gid;
97637741Smckusick 	vp = (struct vnode *)fp->f_data;
97737741Smckusick 	VOP_LOCK(vp);
97837741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
97937741Smckusick 		error = EROFS;
98037741Smckusick 		goto out;
98137741Smckusick 	}
98237741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
98337741Smckusick out:
98437741Smckusick 	VOP_UNLOCK(vp);
98537741Smckusick 	RETURN (error);
9867701Ssam }
9877701Ssam 
98838408Smckusick utimes(scp)
98938408Smckusick 	register struct syscontext *scp;
99011811Ssam {
99111811Ssam 	register struct a {
99211811Ssam 		char	*fname;
99311811Ssam 		struct	timeval *tptr;
99438408Smckusick 	} *uap = (struct a *)scp->sc_ap;
99538408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
99637741Smckusick 	register struct vnode *vp;
99711811Ssam 	struct timeval tv[2];
99837741Smckusick 	struct vattr vattr;
99937741Smckusick 	int error;
100011811Ssam 
100137741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
100237741Smckusick 		RETURN (error);
100337741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
100437741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
100537741Smckusick 	ndp->ni_dirp = uap->fname;
100637741Smckusick 	vattr_null(&vattr);
100737741Smckusick 	vattr.va_atime = tv[0];
100837741Smckusick 	vattr.va_mtime = tv[1];
100937741Smckusick 	if (error = namei(ndp))
101037741Smckusick 		RETURN (error);
101137741Smckusick 	vp = ndp->ni_vp;
101237741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
101337741Smckusick 		error = EROFS;
101437741Smckusick 		goto out;
101521015Smckusick 	}
101637741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
101737741Smckusick out:
101837741Smckusick 	vput(vp);
101937741Smckusick 	RETURN (error);
102011811Ssam }
102111811Ssam 
10229167Ssam /*
10239167Ssam  * Truncate a file given its path name.
10249167Ssam  */
102538408Smckusick truncate(scp)
102638408Smckusick 	register struct syscontext *scp;
10277701Ssam {
10287701Ssam 	struct a {
10297701Ssam 		char	*fname;
103026473Skarels 		off_t	length;
103138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
103238408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
103337741Smckusick 	register struct vnode *vp;
103437741Smckusick 	struct vattr vattr;
103537741Smckusick 	int error;
10367701Ssam 
103737741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
103816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
103916694Smckusick 	ndp->ni_dirp = uap->fname;
104037741Smckusick 	vattr_null(&vattr);
104137741Smckusick 	vattr.va_size = uap->length;
104237741Smckusick 	if (error = namei(ndp))
104337741Smckusick 		RETURN (error);
104437741Smckusick 	vp = ndp->ni_vp;
104537741Smckusick 	if (vp->v_type == VDIR) {
104637741Smckusick 		error = EISDIR;
104737741Smckusick 		goto out;
10487701Ssam 	}
104938399Smckusick 	if ((error = vn_writechk(vp)) ||
105038399Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
105137741Smckusick 		goto out;
105237741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
105337741Smckusick out:
105437741Smckusick 	vput(vp);
105537741Smckusick 	RETURN (error);
10567701Ssam }
10577701Ssam 
10589167Ssam /*
10599167Ssam  * Truncate a file given a file descriptor.
10609167Ssam  */
106138408Smckusick ftruncate(scp)
106238408Smckusick 	register struct syscontext *scp;
10637701Ssam {
10647701Ssam 	struct a {
10657701Ssam 		int	fd;
106626473Skarels 		off_t	length;
106738408Smckusick 	} *uap = (struct a *)scp->sc_ap;
106837741Smckusick 	struct vattr vattr;
106937741Smckusick 	struct vnode *vp;
10707701Ssam 	struct file *fp;
107137741Smckusick 	int error;
10727701Ssam 
107338408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
107437741Smckusick 		RETURN (error);
107537741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
107637741Smckusick 		RETURN (EINVAL);
107737741Smckusick 	vattr_null(&vattr);
107837741Smckusick 	vattr.va_size = uap->length;
107937741Smckusick 	vp = (struct vnode *)fp->f_data;
108037741Smckusick 	VOP_LOCK(vp);
108137741Smckusick 	if (vp->v_type == VDIR) {
108237741Smckusick 		error = EISDIR;
108337741Smckusick 		goto out;
10847701Ssam 	}
108538399Smckusick 	if (error = vn_writechk(vp))
108637741Smckusick 		goto out;
108737741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
108837741Smckusick out:
108937741Smckusick 	VOP_UNLOCK(vp);
109037741Smckusick 	RETURN (error);
10917701Ssam }
10927701Ssam 
10939167Ssam /*
10949167Ssam  * Synch an open file.
10959167Ssam  */
109638408Smckusick fsync(scp)
109738408Smckusick 	register struct syscontext *scp;
10989167Ssam {
10999167Ssam 	struct a {
11009167Ssam 		int	fd;
110138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
11029167Ssam 	struct file *fp;
110337741Smckusick 	int error;
11049167Ssam 
110538408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
110637741Smckusick 		RETURN (error);
110737741Smckusick 	error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred);
110837741Smckusick 	RETURN (error);
11099167Ssam }
11109167Ssam 
11119167Ssam /*
11129167Ssam  * Rename system call.
11139167Ssam  *
11149167Ssam  * Source and destination must either both be directories, or both
11159167Ssam  * not be directories.  If target is a directory, it must be empty.
11169167Ssam  */
111738408Smckusick rename(scp)
111838408Smckusick 	register struct syscontext *scp;
11197701Ssam {
11207701Ssam 	struct a {
11217701Ssam 		char	*from;
11227701Ssam 		char	*to;
112338408Smckusick 	} *uap = (struct a *)scp->sc_ap;
112437741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
112538408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
112637741Smckusick 	struct nameidata tond;
112737741Smckusick 	int error;
11287701Ssam 
112937741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
113016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
113116694Smckusick 	ndp->ni_dirp = uap->from;
113237741Smckusick 	if (error = namei(ndp))
113337741Smckusick 		RETURN (error);
113437741Smckusick 	fvp = ndp->ni_vp;
113538266Smckusick 	nddup(ndp, &tond);
113637741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
113737741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
113837741Smckusick 	tond.ni_dirp = uap->to;
113937741Smckusick 	error = namei(&tond);
114037741Smckusick 	tdvp = tond.ni_dvp;
114137741Smckusick 	tvp = tond.ni_vp;
114237741Smckusick 	if (tvp != NULL) {
114337741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
114437741Smckusick 			error = EISDIR;
114537741Smckusick 			goto out;
114637741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
114737741Smckusick 			error = ENOTDIR;
114837741Smckusick 			goto out;
11499167Ssam 		}
11509167Ssam 	}
115137741Smckusick 	if (error) {
115237741Smckusick 		VOP_ABORTOP(ndp);
115337741Smckusick 		goto out1;
115437741Smckusick 	}
115537741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
115637741Smckusick 		error = EXDEV;
11579167Ssam 		goto out;
115810051Ssam 	}
115937741Smckusick 	if (fvp == tdvp || fvp == tvp)
116037741Smckusick 		error = EINVAL;
116137741Smckusick out:
116237741Smckusick 	if (error) {
116337741Smckusick 		VOP_ABORTOP(&tond);
116437741Smckusick 		VOP_ABORTOP(ndp);
11659167Ssam 	} else {
116637741Smckusick 		error = VOP_RENAME(ndp, &tond);
11679167Ssam 	}
116837741Smckusick out1:
116938266Smckusick 	ndrele(&tond);
117037741Smckusick 	RETURN (error);
11717701Ssam }
11727701Ssam 
11737535Sroot /*
117412756Ssam  * Mkdir system call
117512756Ssam  */
117638408Smckusick mkdir(scp)
117738408Smckusick 	register struct syscontext *scp;
117812756Ssam {
117912756Ssam 	struct a {
118012756Ssam 		char	*name;
118112756Ssam 		int	dmode;
118238408Smckusick 	} *uap = (struct a *)scp->sc_ap;
118338408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
118437741Smckusick 	register struct vnode *vp;
118537741Smckusick 	struct vattr vattr;
118637741Smckusick 	int error;
118712756Ssam 
118837741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
118916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
119016694Smckusick 	ndp->ni_dirp = uap->name;
119137741Smckusick 	if (error = namei(ndp))
119237741Smckusick 		RETURN (error);
119337741Smckusick 	vp = ndp->ni_vp;
119437741Smckusick 	if (vp != NULL) {
119537741Smckusick 		VOP_ABORTOP(ndp);
119637741Smckusick 		RETURN (EEXIST);
119712756Ssam 	}
119837741Smckusick 	vattr_null(&vattr);
119937741Smckusick 	vattr.va_type = VDIR;
120038408Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask;
120137741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
120238145Smckusick 	if (!error)
120338145Smckusick 		vput(ndp->ni_vp);
120437741Smckusick 	RETURN (error);
120512756Ssam }
120612756Ssam 
120712756Ssam /*
120812756Ssam  * Rmdir system call.
120912756Ssam  */
121038408Smckusick rmdir(scp)
121138408Smckusick 	register struct syscontext *scp;
121212756Ssam {
121312756Ssam 	struct a {
121412756Ssam 		char	*name;
121538408Smckusick 	} *uap = (struct a *)scp->sc_ap;
121638408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
121737741Smckusick 	register struct vnode *vp;
121837741Smckusick 	int error;
121912756Ssam 
122037741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
122116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
122216694Smckusick 	ndp->ni_dirp = uap->name;
122337741Smckusick 	if (error = namei(ndp))
122437741Smckusick 		RETURN (error);
122537741Smckusick 	vp = ndp->ni_vp;
122637741Smckusick 	if (vp->v_type != VDIR) {
122737741Smckusick 		error = ENOTDIR;
122812756Ssam 		goto out;
122912756Ssam 	}
123012756Ssam 	/*
123137741Smckusick 	 * No rmdir "." please.
123212756Ssam 	 */
123337741Smckusick 	if (ndp->ni_dvp == vp) {
123437741Smckusick 		error = EINVAL;
123512756Ssam 		goto out;
123612756Ssam 	}
123712756Ssam 	/*
123837741Smckusick 	 * Don't unlink a mounted file.
123912756Ssam 	 */
124037741Smckusick 	if (vp->v_flag & VROOT)
124137741Smckusick 		error = EBUSY;
124212756Ssam out:
124337741Smckusick 	if (error)
124437741Smckusick 		VOP_ABORTOP(ndp);
124537741Smckusick 	else
124637741Smckusick 		error = VOP_RMDIR(ndp);
124737741Smckusick 	RETURN (error);
124812756Ssam }
124912756Ssam 
125037741Smckusick /*
125137741Smckusick  * Read a block of directory entries in a file system independent format
125237741Smckusick  */
125338408Smckusick getdirentries(scp)
125438408Smckusick 	register struct syscontext *scp;
125512756Ssam {
125637741Smckusick 	register struct a {
125737741Smckusick 		int	fd;
125837741Smckusick 		char	*buf;
125937741Smckusick 		unsigned count;
126037741Smckusick 		long	*basep;
126138408Smckusick 	} *uap = (struct a *)scp->sc_ap;
126216540Ssam 	struct file *fp;
126337741Smckusick 	struct uio auio;
126437741Smckusick 	struct iovec aiov;
126538129Smckusick 	off_t off;
126637741Smckusick 	int error;
126712756Ssam 
126838408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
126937741Smckusick 		RETURN (error);
127037741Smckusick 	if ((fp->f_flag & FREAD) == 0)
127137741Smckusick 		RETURN (EBADF);
127237741Smckusick 	aiov.iov_base = uap->buf;
127337741Smckusick 	aiov.iov_len = uap->count;
127437741Smckusick 	auio.uio_iov = &aiov;
127537741Smckusick 	auio.uio_iovcnt = 1;
127637741Smckusick 	auio.uio_rw = UIO_READ;
127737741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
127837741Smckusick 	auio.uio_resid = uap->count;
127938129Smckusick 	off = fp->f_offset;
128037741Smckusick 	if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio,
128137741Smckusick 	    &(fp->f_offset), fp->f_cred))
128237741Smckusick 		RETURN (error);
128338129Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep,
128437741Smckusick 		sizeof(long));
128538408Smckusick 	scp->sc_retval1 = uap->count - auio.uio_resid;
128637741Smckusick 	RETURN (error);
128712756Ssam }
128812756Ssam 
128912756Ssam /*
129012756Ssam  * mode mask for creation of files
129112756Ssam  */
129238408Smckusick umask(scp)
129338408Smckusick 	register struct syscontext *scp;
129412756Ssam {
129512756Ssam 	register struct a {
129612756Ssam 		int	mask;
129738408Smckusick 	} *uap = (struct a *)scp->sc_ap;
129812756Ssam 
129938408Smckusick 	scp->sc_retval1 = scp->sc_cmask;
130038408Smckusick 	scp->sc_cmask = uap->mask & 07777;
130137741Smckusick 	RETURN (0);
130212756Ssam }
130337741Smckusick 
130438408Smckusick getvnode(ofile, fdes, fpp)
130538408Smckusick 	struct file *ofile[];
130637741Smckusick 	struct file **fpp;
130737741Smckusick 	int fdes;
130837741Smckusick {
130937741Smckusick 	struct file *fp;
131037741Smckusick 
131138408Smckusick 	if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
131237741Smckusick 		return (EBADF);
131337741Smckusick 	if (fp->f_type != DTYPE_VNODE)
131437741Smckusick 		return (EINVAL);
131537741Smckusick 	*fpp = fp;
131637741Smckusick 	return (0);
131737741Smckusick }
1318