xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 38408)
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*38408Smckusick  *	@(#)vfs_syscalls.c	7.14 (Berkeley) 07/04/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  */
40*38408Smckusick mount(scp)
41*38408Smckusick 	register struct syscontext *scp;
426254Sroot {
4337741Smckusick 	register struct a {
4437741Smckusick 		int	type;
4537741Smckusick 		char	*dir;
4637741Smckusick 		int	flags;
4737741Smckusick 		caddr_t	data;
48*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
49*38408Smckusick 	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 	 */
57*38408Smckusick 	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);
9737741Smckusick 	} else {
9837741Smckusick 		vfs_remove(mp);
9937741Smckusick 		free((caddr_t)mp, M_MOUNT);
10037741Smckusick 		vrele(vp);
10137741Smckusick 	}
10237741Smckusick 	RETURN (error);
1036254Sroot }
1046254Sroot 
1059167Ssam /*
10637741Smckusick  * Unmount system call.
10737741Smckusick  *
10837741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
10937741Smckusick  * not special file (as before).
1109167Ssam  */
111*38408Smckusick unmount(scp)
112*38408Smckusick 	register struct syscontext *scp;
1136254Sroot {
11437741Smckusick 	struct a {
11537741Smckusick 		char	*pathp;
11637741Smckusick 		int	flags;
117*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
11837741Smckusick 	register struct vnode *vp;
11937741Smckusick 	register struct mount *mp;
120*38408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
12137741Smckusick 	struct vnode *coveredvp;
12237741Smckusick 	int error;
1236254Sroot 
12437741Smckusick 	/*
12537741Smckusick 	 * Must be super user
12637741Smckusick 	 */
127*38408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
12837741Smckusick 		RETURN (error);
12937741Smckusick 
13037741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
13137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
13237741Smckusick 	ndp->ni_dirp = uap->pathp;
13337741Smckusick 	if (error = namei(ndp))
13437741Smckusick 		RETURN (error);
13537741Smckusick 	vp = ndp->ni_vp;
13637741Smckusick 	/*
13737741Smckusick 	 * Must be the root of the filesystem
13837741Smckusick 	 */
13937741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
14037741Smckusick 		vput(vp);
14137741Smckusick 		RETURN (EINVAL);
14237741Smckusick 	}
14337741Smckusick 	mp = vp->v_mount;
14437741Smckusick 	vput(vp);
14537741Smckusick 	/*
14637741Smckusick 	 * Do the unmount.
14737741Smckusick 	 */
14837741Smckusick 	coveredvp = mp->m_vnodecovered;
14937741Smckusick 	if (error = vfs_lock(mp))
15037741Smckusick 		RETURN (error);
15137741Smckusick 
15237741Smckusick 	xumount(mp);		/* remove unused sticky files from text table */
15337741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
15437741Smckusick 	VFS_SYNC(mp, MNT_WAIT);
15537741Smckusick 
15637741Smckusick 	error = VFS_UNMOUNT(mp, uap->flags);
15737741Smckusick 	if (error) {
15837741Smckusick 		vfs_unlock(mp);
15937741Smckusick 	} else {
16037741Smckusick 		vrele(coveredvp);
16137741Smckusick 		vfs_remove(mp);
16237741Smckusick 		free((caddr_t)mp, M_MOUNT);
16337741Smckusick 	}
16437741Smckusick 	RETURN (error);
1656254Sroot }
1666254Sroot 
1679167Ssam /*
16837741Smckusick  * Sync system call.
16937741Smckusick  * Sync each mounted filesystem.
1709167Ssam  */
171*38408Smckusick sync(scp)
172*38408Smckusick 	register struct syscontext *scp;
1736254Sroot {
17437741Smckusick 	register struct mount *mp;
17537741Smckusick 
17637741Smckusick 	mp = rootfs;
17737741Smckusick 	do {
17837741Smckusick 		if ((mp->m_flag & M_RDONLY) == 0)
17937741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
18037741Smckusick 		mp = mp->m_next;
18137741Smckusick 	} while (mp != rootfs);
18237741Smckusick }
18337741Smckusick 
18437741Smckusick /*
18537741Smckusick  * get filesystem statistics
18637741Smckusick  */
187*38408Smckusick statfs(scp)
188*38408Smckusick 	register struct syscontext *scp;
18937741Smckusick {
1906254Sroot 	struct a {
19137741Smckusick 		char *path;
19237741Smckusick 		struct statfs *buf;
193*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
19437741Smckusick 	register struct vnode *vp;
195*38408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
19637741Smckusick 	struct statfs sb;
19737741Smckusick 	int error;
19837741Smckusick 
19937741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
20037741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
20137741Smckusick 	ndp->ni_dirp = uap->path;
20237741Smckusick 	if (error = namei(ndp))
20337741Smckusick 		RETURN (error);
20437741Smckusick 	vp = ndp->ni_vp;
20537741Smckusick 	if (error = VFS_STATFS(vp->v_mount, &sb))
20637741Smckusick 		goto out;
20737741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb));
20837741Smckusick out:
20937741Smckusick 	vput(vp);
21037741Smckusick 	RETURN (error);
21137741Smckusick }
21237741Smckusick 
213*38408Smckusick fstatfs(scp)
214*38408Smckusick 	register struct syscontext *scp;
21537741Smckusick {
21637741Smckusick 	struct a {
21737741Smckusick 		int fd;
21837741Smckusick 		struct statfs *buf;
219*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
22037741Smckusick 	struct file *fp;
22137741Smckusick 	struct statfs sb;
22237741Smckusick 	int error;
22337741Smckusick 
224*38408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
22537741Smckusick 		RETURN (error);
22637741Smckusick 	if (error = VFS_STATFS(((struct vnode *)fp->f_data)->v_mount, &sb))
22737741Smckusick 		RETURN (error);
22837741Smckusick 	RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)));
22937741Smckusick }
23037741Smckusick 
23137741Smckusick /*
23238270Smckusick  * get statistics on all filesystems
23338270Smckusick  */
234*38408Smckusick getfsstat(scp)
235*38408Smckusick 	register struct syscontext *scp;
23638270Smckusick {
23738270Smckusick 	struct a {
23838270Smckusick 		struct statfs *buf;
23938270Smckusick 		long bufsize;
240*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
24138270Smckusick 	register struct mount *mp;
24238270Smckusick 	register struct statfs *sfsp;
24338270Smckusick 	long count, maxcount, error;
24438270Smckusick 
24538270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
24638270Smckusick 	sfsp = uap->buf;
24738270Smckusick 	mp = rootfs;
24838270Smckusick 	count = 0;
24938270Smckusick 	do {
25038270Smckusick 		count++;
25138270Smckusick 		if (sfsp && count <= maxcount) {
25238270Smckusick 			if (error = VFS_STATFS(mp, sfsp))
25338270Smckusick 				RETURN (error);
25438270Smckusick 			sfsp++;
25538270Smckusick 		}
25638270Smckusick 		mp = mp->m_prev;
25738270Smckusick 	} while (mp != rootfs);
25838270Smckusick 	if (sfsp && count > maxcount)
259*38408Smckusick 		scp->sc_retval1 = maxcount;
26038270Smckusick 	else
261*38408Smckusick 		scp->sc_retval1 = count;
26238270Smckusick 	RETURN (0);
26338270Smckusick }
26438270Smckusick 
26538270Smckusick /*
26638259Smckusick  * Change current working directory to a given file descriptor.
26738259Smckusick  */
268*38408Smckusick fchdir(scp)
269*38408Smckusick 	register struct syscontext *scp;
27038259Smckusick {
27138259Smckusick 	struct a {
27238259Smckusick 		int	fd;
273*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
27438259Smckusick 	register struct vnode *vp;
27538259Smckusick 	struct file *fp;
27638259Smckusick 	int error;
27738259Smckusick 
278*38408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
27938259Smckusick 		RETURN (error);
28038259Smckusick 	vp = (struct vnode *)fp->f_data;
28138259Smckusick 	VOP_LOCK(vp);
28238259Smckusick 	if (vp->v_type != VDIR)
28338259Smckusick 		error = ENOTDIR;
28438259Smckusick 	else
285*38408Smckusick 		error = VOP_ACCESS(vp, VEXEC, scp->sc_cred);
28638259Smckusick 	VOP_UNLOCK(vp);
287*38408Smckusick 	vrele(scp->sc_cdir);
288*38408Smckusick 	scp->sc_cdir = vp;
28938259Smckusick 	RETURN (error);
29038259Smckusick }
29138259Smckusick 
29238259Smckusick /*
29337741Smckusick  * Change current working directory (``.'').
29437741Smckusick  */
295*38408Smckusick chdir(scp)
296*38408Smckusick 	register struct syscontext *scp;
29737741Smckusick {
29837741Smckusick 	struct a {
2996254Sroot 		char	*fname;
300*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
301*38408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
30237741Smckusick 	int error;
3036254Sroot 
30437741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
30516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
30616694Smckusick 	ndp->ni_dirp = uap->fname;
30737741Smckusick 	if (error = chdirec(ndp))
30837741Smckusick 		RETURN (error);
309*38408Smckusick 	vrele(scp->sc_cdir);
310*38408Smckusick 	scp->sc_cdir = ndp->ni_vp;
31137741Smckusick 	RETURN (0);
31237741Smckusick }
3136254Sroot 
31437741Smckusick /*
31537741Smckusick  * Change notion of root (``/'') directory.
31637741Smckusick  */
317*38408Smckusick chroot(scp)
318*38408Smckusick 	register struct syscontext *scp;
31937741Smckusick {
32037741Smckusick 	struct a {
32137741Smckusick 		char	*fname;
322*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
323*38408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
32437741Smckusick 	int error;
32537741Smckusick 
326*38408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
32737741Smckusick 		RETURN (error);
32837741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
32937741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
33037741Smckusick 	ndp->ni_dirp = uap->fname;
33137741Smckusick 	if (error = chdirec(ndp))
33237741Smckusick 		RETURN (error);
333*38408Smckusick 	vrele(scp->sc_rdir);
334*38408Smckusick 	scp->sc_rdir = ndp->ni_vp;
33537741Smckusick 	RETURN (0);
3366254Sroot }
3376254Sroot 
33837Sbill /*
33937741Smckusick  * Common routine for chroot and chdir.
34037741Smckusick  */
34137741Smckusick chdirec(ndp)
34237741Smckusick 	register struct nameidata *ndp;
34337741Smckusick {
34437741Smckusick 	struct vnode *vp;
34537741Smckusick 	int error;
34637741Smckusick 
34737741Smckusick 	if (error = namei(ndp))
34837741Smckusick 		return (error);
34937741Smckusick 	vp = ndp->ni_vp;
35037741Smckusick 	if (vp->v_type != VDIR)
35137741Smckusick 		error = ENOTDIR;
35237741Smckusick 	else
35338399Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
35437741Smckusick 	VOP_UNLOCK(vp);
35537741Smckusick 	if (error)
35637741Smckusick 		vrele(vp);
35737741Smckusick 	return (error);
35837741Smckusick }
35937741Smckusick 
36037741Smckusick /*
3616254Sroot  * Open system call.
3626254Sroot  */
363*38408Smckusick open(scp)
364*38408Smckusick 	register struct syscontext *scp;
3656254Sroot {
36612756Ssam 	struct a {
3676254Sroot 		char	*fname;
3687701Ssam 		int	mode;
36912756Ssam 		int	crtmode;
370*38408Smckusick 	} *uap = (struct a *) scp->sc_ap;
371*38408Smckusick 	struct nameidata *ndp = &scp->sc_nd;
3726254Sroot 
37337741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
37437741Smckusick 	ndp->ni_dirp = uap->fname;
375*38408Smckusick 	RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp,
376*38408Smckusick 		&scp->sc_retval1));
3776254Sroot }
3786254Sroot 
3796254Sroot /*
3806254Sroot  * Creat system call.
3816254Sroot  */
382*38408Smckusick creat(scp)
383*38408Smckusick 	register struct syscontext *scp;
3846254Sroot {
38512756Ssam 	struct a {
3866254Sroot 		char	*fname;
3876254Sroot 		int	fmode;
388*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
389*38408Smckusick 	struct nameidata *ndp = &scp->sc_nd;
3906254Sroot 
39137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
39237741Smckusick 	ndp->ni_dirp = uap->fname;
393*38408Smckusick 	RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask,
394*38408Smckusick 		ndp, &scp->sc_retval1));
3956254Sroot }
3966254Sroot 
3976254Sroot /*
3986254Sroot  * Common code for open and creat.
39912756Ssam  * Check permissions, allocate an open file structure,
40012756Ssam  * and call the device open routine if any.
4016254Sroot  */
402*38408Smckusick copen(scp, fmode, cmode, ndp, resultfd)
403*38408Smckusick 	register struct syscontext *scp;
40437741Smckusick 	int fmode, cmode;
40537741Smckusick 	struct nameidata *ndp;
40637741Smckusick 	int *resultfd;
40712756Ssam {
4086254Sroot 	register struct file *fp;
40937741Smckusick 	struct file *nfp;
41037741Smckusick 	int indx, error;
41137741Smckusick 	extern struct fileops vnops;
4126254Sroot 
41337741Smckusick 	if (error = falloc(&nfp, &indx))
41437741Smckusick 		return (error);
41537741Smckusick 	fp = nfp;
416*38408Smckusick 	scp->sc_retval1 = indx;	/* XXX for fdopen() */
41737741Smckusick 	if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) {
418*38408Smckusick 		scp->sc_ofile[indx] = NULL;
41937741Smckusick 		crfree(fp->f_cred);
42037741Smckusick 		fp->f_count--;
42137741Smckusick 		return (error);
42212756Ssam 	}
42337741Smckusick 	fp->f_flag = fmode & FMASK;
42437741Smckusick 	fp->f_type = DTYPE_VNODE;
42537741Smckusick 	fp->f_ops = &vnops;
42637741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
42737741Smckusick 	if (resultfd)
42837741Smckusick 		*resultfd = indx;
42937741Smckusick 	return (0);
4306254Sroot }
4316254Sroot 
4326254Sroot /*
4336254Sroot  * Mknod system call
4346254Sroot  */
435*38408Smckusick mknod(scp)
436*38408Smckusick 	register struct syscontext *scp;
4376254Sroot {
4386254Sroot 	register struct a {
4396254Sroot 		char	*fname;
4406254Sroot 		int	fmode;
4416254Sroot 		int	dev;
442*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
443*38408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
44437741Smckusick 	register struct vnode *vp;
44537741Smckusick 	struct vattr vattr;
44637741Smckusick 	int error;
4476254Sroot 
448*38408Smckusick 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
44937741Smckusick 		RETURN (error);
45037741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
45116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
45216694Smckusick 	ndp->ni_dirp = uap->fname;
45337741Smckusick 	if (error = namei(ndp))
45437741Smckusick 		RETURN (error);
45537741Smckusick 	vp = ndp->ni_vp;
45637741Smckusick 	if (vp != NULL) {
45737741Smckusick 		error = EEXIST;
45812756Ssam 		goto out;
4596254Sroot 	}
46037741Smckusick 	vattr_null(&vattr);
46137741Smckusick 	switch (uap->fmode & IFMT) {
46212756Ssam 
46315093Smckusick 	case IFMT:	/* used by badsect to flag bad sectors */
46437741Smckusick 		vattr.va_type = VBAD;
46537741Smckusick 		break;
46612756Ssam 	case IFCHR:
46737741Smckusick 		vattr.va_type = VCHR;
46837741Smckusick 		break;
46912756Ssam 	case IFBLK:
47037741Smckusick 		vattr.va_type = VBLK;
47137741Smckusick 		break;
47237741Smckusick 	default:
47337741Smckusick 		error = EINVAL;
47437741Smckusick 		goto out;
4756254Sroot 	}
476*38408Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask;
47737741Smckusick 	vattr.va_rdev = uap->dev;
4786254Sroot out:
47937741Smckusick 	if (error)
48037741Smckusick 		VOP_ABORTOP(ndp);
48137741Smckusick 	else
48237741Smckusick 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
48337741Smckusick 	RETURN (error);
4846254Sroot }
4856254Sroot 
4866254Sroot /*
4876254Sroot  * link system call
4886254Sroot  */
489*38408Smckusick link(scp)
490*38408Smckusick 	register struct syscontext *scp;
4916254Sroot {
4926254Sroot 	register struct a {
4936254Sroot 		char	*target;
4946254Sroot 		char	*linkname;
495*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
496*38408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
49737741Smckusick 	register struct vnode *vp, *xp;
49837741Smckusick 	int error;
4996254Sroot 
50016694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
50116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
50216694Smckusick 	ndp->ni_dirp = uap->target;
50337741Smckusick 	if (error = namei(ndp))
50437741Smckusick 		RETURN (error);
50537741Smckusick 	vp = ndp->ni_vp;
50637741Smckusick 	if (vp->v_type == VDIR &&
507*38408Smckusick 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
50837741Smckusick 		goto out1;
50937741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
51016694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
51137741Smckusick 	if (error = namei(ndp))
51237741Smckusick 		goto out1;
51337741Smckusick 	xp = ndp->ni_vp;
5146254Sroot 	if (xp != NULL) {
51537741Smckusick 		error = EEXIST;
5166254Sroot 		goto out;
5176254Sroot 	}
51837741Smckusick 	xp = ndp->ni_dvp;
51937741Smckusick 	if (vp->v_mount != xp->v_mount)
52037741Smckusick 		error = EXDEV;
5216254Sroot out:
52237741Smckusick 	if (error)
52337741Smckusick 		VOP_ABORTOP(ndp);
52437741Smckusick 	else
52537741Smckusick 		error = VOP_LINK(vp, ndp);
52637741Smckusick out1:
52737741Smckusick 	vrele(vp);
52837741Smckusick 	RETURN (error);
5296254Sroot }
5306254Sroot 
5316254Sroot /*
5326254Sroot  * symlink -- make a symbolic link
5336254Sroot  */
534*38408Smckusick symlink(scp)
535*38408Smckusick 	register struct syscontext *scp;
5366254Sroot {
53737741Smckusick 	struct a {
5386254Sroot 		char	*target;
5396254Sroot 		char	*linkname;
540*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
541*38408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
54237741Smckusick 	register struct vnode *vp;
54337741Smckusick 	struct vattr vattr;
54437741Smckusick 	char *target;
54537741Smckusick 	int error;
5466254Sroot 
54716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
54816694Smckusick 	ndp->ni_dirp = uap->linkname;
54937741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
55037741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
55137741Smckusick 		goto out1;
55237741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
55337741Smckusick 	if (error = namei(ndp))
55437741Smckusick 		goto out1;
55537741Smckusick 	vp = ndp->ni_vp;
55637741Smckusick 	if (vp) {
55737741Smckusick 		error = EEXIST;
55837741Smckusick 		goto out;
5596254Sroot 	}
56037741Smckusick 	vp = ndp->ni_dvp;
56137741Smckusick 	vattr_null(&vattr);
562*38408Smckusick 	vattr.va_mode = 0777 &~ scp->sc_cmask;
56337741Smckusick out:
56437741Smckusick 	if (error)
56537741Smckusick 		VOP_ABORTOP(ndp);
56637741Smckusick 	else
56737741Smckusick 		error = VOP_SYMLINK(ndp, &vattr, target);
56837741Smckusick out1:
56937741Smckusick 	FREE(target, M_NAMEI);
57037741Smckusick 	RETURN (error);
5716254Sroot }
5726254Sroot 
5736254Sroot /*
5746254Sroot  * Unlink system call.
5756254Sroot  * Hard to avoid races here, especially
5766254Sroot  * in unlinking directories.
5776254Sroot  */
578*38408Smckusick unlink(scp)
579*38408Smckusick 	register struct syscontext *scp;
5806254Sroot {
5816254Sroot 	struct a {
5826254Sroot 		char	*fname;
583*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
584*38408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
58537741Smckusick 	register struct vnode *vp;
58637741Smckusick 	int error;
5876254Sroot 
58837741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
58916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
59016694Smckusick 	ndp->ni_dirp = uap->fname;
59137741Smckusick 	if (error = namei(ndp))
59237741Smckusick 		RETURN (error);
59337741Smckusick 	vp = ndp->ni_vp;
59437741Smckusick 	if (vp->v_type == VDIR &&
595*38408Smckusick 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
5966254Sroot 		goto out;
5976254Sroot 	/*
5986254Sroot 	 * Don't unlink a mounted file.
5996254Sroot 	 */
60037741Smckusick 	if (vp->v_flag & VROOT) {
60137741Smckusick 		error = EBUSY;
6026254Sroot 		goto out;
6036254Sroot 	}
60437741Smckusick 	if (vp->v_flag & VTEXT)
60537741Smckusick 		xrele(vp);	/* try once to free text */
6066254Sroot out:
60737741Smckusick 	if (error)
60837741Smckusick 		VOP_ABORTOP(ndp);
6097142Smckusick 	else
61037741Smckusick 		error = VOP_REMOVE(ndp);
61137741Smckusick 	RETURN (error);
6126254Sroot }
6136254Sroot 
6146254Sroot /*
6156254Sroot  * Seek system call
6166254Sroot  */
617*38408Smckusick lseek(scp)
618*38408Smckusick 	register struct syscontext *scp;
6196254Sroot {
6206254Sroot 	register struct file *fp;
6216254Sroot 	register struct a {
62237741Smckusick 		int	fdes;
6236254Sroot 		off_t	off;
6246254Sroot 		int	sbase;
625*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
62637741Smckusick 	struct vattr vattr;
62737741Smckusick 	int error;
6286254Sroot 
62937741Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
630*38408Smckusick 	    (fp = scp->sc_ofile[uap->fdes]) == NULL)
63137741Smckusick 		RETURN (EBADF);
63237741Smckusick 	if (fp->f_type != DTYPE_VNODE)
63337741Smckusick 		RETURN (ESPIPE);
63413878Ssam 	switch (uap->sbase) {
63513878Ssam 
63613878Ssam 	case L_INCR:
63713878Ssam 		fp->f_offset += uap->off;
63813878Ssam 		break;
63913878Ssam 
64013878Ssam 	case L_XTND:
64137741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
642*38408Smckusick 		    &vattr, scp->sc_cred))
64337741Smckusick 			RETURN (error);
64437741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
64513878Ssam 		break;
64613878Ssam 
64713878Ssam 	case L_SET:
64813878Ssam 		fp->f_offset = uap->off;
64913878Ssam 		break;
65013878Ssam 
65113878Ssam 	default:
65237741Smckusick 		RETURN (EINVAL);
65313878Ssam 	}
654*38408Smckusick 	scp->sc_offset = fp->f_offset;
65537741Smckusick 	RETURN (0);
6566254Sroot }
6576254Sroot 
6586254Sroot /*
6596254Sroot  * Access system call
6606254Sroot  */
661*38408Smckusick saccess(scp)
662*38408Smckusick 	register struct syscontext *scp;
6636254Sroot {
6646254Sroot 	register struct a {
6656254Sroot 		char	*fname;
6666254Sroot 		int	fmode;
667*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
668*38408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
66937741Smckusick 	register struct vnode *vp;
67037741Smckusick 	int error, mode, svuid, svgid;
6716254Sroot 
672*38408Smckusick 	svuid = scp->sc_uid;
673*38408Smckusick 	svgid = scp->sc_gid;
674*38408Smckusick 	scp->sc_uid = scp->sc_ruid;
675*38408Smckusick 	scp->sc_gid = scp->sc_rgid;
67637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
67716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
67816694Smckusick 	ndp->ni_dirp = uap->fname;
67937741Smckusick 	if (error = namei(ndp))
68037741Smckusick 		goto out1;
68137741Smckusick 	vp = ndp->ni_vp;
68237741Smckusick 	/*
68337741Smckusick 	 * fmode == 0 means only check for exist
68437741Smckusick 	 */
68537741Smckusick 	if (uap->fmode) {
68637741Smckusick 		mode = 0;
68737741Smckusick 		if (uap->fmode & R_OK)
68837741Smckusick 			mode |= VREAD;
68937741Smckusick 		if (uap->fmode & W_OK)
69037741Smckusick 			mode |= VWRITE;
69137741Smckusick 		if (uap->fmode & X_OK)
69237741Smckusick 			mode |= VEXEC;
69338399Smckusick 		if ((error = vn_writechk(vp)) == 0)
69438399Smckusick 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
6956254Sroot 	}
69637741Smckusick 	vput(vp);
69737741Smckusick out1:
698*38408Smckusick 	scp->sc_uid = svuid;
699*38408Smckusick 	scp->sc_gid = svgid;
70037741Smckusick 	RETURN (error);
7016254Sroot }
7026254Sroot 
7036254Sroot /*
7046574Smckusic  * Stat system call.  This version follows links.
70537Sbill  */
706*38408Smckusick stat(scp)
707*38408Smckusick 	struct syscontext *scp;
70837Sbill {
70937Sbill 
710*38408Smckusick 	stat1(scp, FOLLOW);
71137Sbill }
71237Sbill 
71337Sbill /*
7146574Smckusic  * Lstat system call.  This version does not follow links.
7155992Swnj  */
716*38408Smckusick lstat(scp)
717*38408Smckusick 	struct syscontext *scp;
7185992Swnj {
71912756Ssam 
720*38408Smckusick 	stat1(scp, NOFOLLOW);
72112756Ssam }
72212756Ssam 
723*38408Smckusick stat1(scp, follow)
724*38408Smckusick 	register struct syscontext *scp;
72512756Ssam 	int follow;
72612756Ssam {
7275992Swnj 	register struct a {
7285992Swnj 		char	*fname;
72912756Ssam 		struct stat *ub;
730*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
731*38408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
73212756Ssam 	struct stat sb;
73337741Smckusick 	int error;
7345992Swnj 
73537741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
73616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
73716694Smckusick 	ndp->ni_dirp = uap->fname;
73837741Smckusick 	if (error = namei(ndp))
73937741Smckusick 		RETURN (error);
74037741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
74137741Smckusick 	vput(ndp->ni_vp);
74237741Smckusick 	if (error)
74337741Smckusick 		RETURN (error);
74437741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
74537741Smckusick 	RETURN (error);
7465992Swnj }
7475992Swnj 
7485992Swnj /*
7495992Swnj  * Return target name of a symbolic link
75037Sbill  */
751*38408Smckusick readlink(scp)
752*38408Smckusick 	register struct syscontext *scp;
7535992Swnj {
7545992Swnj 	register struct a {
7555992Swnj 		char	*name;
7565992Swnj 		char	*buf;
7575992Swnj 		int	count;
758*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
759*38408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
76037741Smckusick 	register struct vnode *vp;
76137741Smckusick 	struct iovec aiov;
76237741Smckusick 	struct uio auio;
76337741Smckusick 	int error;
7645992Swnj 
76537741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
76616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
76716694Smckusick 	ndp->ni_dirp = uap->name;
76837741Smckusick 	if (error = namei(ndp))
76937741Smckusick 		RETURN (error);
77037741Smckusick 	vp = ndp->ni_vp;
77137741Smckusick 	if (vp->v_type != VLNK) {
77237741Smckusick 		error = EINVAL;
7735992Swnj 		goto out;
7745992Swnj 	}
77537741Smckusick 	aiov.iov_base = uap->buf;
77637741Smckusick 	aiov.iov_len = uap->count;
77737741Smckusick 	auio.uio_iov = &aiov;
77837741Smckusick 	auio.uio_iovcnt = 1;
77937741Smckusick 	auio.uio_offset = 0;
78037741Smckusick 	auio.uio_rw = UIO_READ;
78137741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
78237741Smckusick 	auio.uio_resid = uap->count;
78337741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
7845992Swnj out:
78537741Smckusick 	vput(vp);
786*38408Smckusick 	scp->sc_retval1 = uap->count - auio.uio_resid;
78737741Smckusick 	RETURN (error);
7885992Swnj }
7895992Swnj 
7909167Ssam /*
79138259Smckusick  * Change flags of a file given path name.
79238259Smckusick  */
793*38408Smckusick chflags(scp)
794*38408Smckusick 	register struct syscontext *scp;
79538259Smckusick {
79638259Smckusick 	struct a {
79738259Smckusick 		char	*fname;
79838259Smckusick 		int	flags;
799*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
800*38408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
80138259Smckusick 	register struct vnode *vp;
80238259Smckusick 	struct vattr vattr;
80338259Smckusick 	int error;
80438259Smckusick 
80538259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
80638259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
80738259Smckusick 	ndp->ni_dirp = uap->fname;
80838259Smckusick 	vattr_null(&vattr);
80938259Smckusick 	vattr.va_flags = uap->flags;
81038259Smckusick 	if (error = namei(ndp))
81138259Smckusick 		RETURN (error);
81238259Smckusick 	vp = ndp->ni_vp;
81338259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
81438259Smckusick 		error = EROFS;
81538259Smckusick 		goto out;
81638259Smckusick 	}
81738259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
81838259Smckusick out:
81938259Smckusick 	vput(vp);
82038259Smckusick 	RETURN (error);
82138259Smckusick }
82238259Smckusick 
82338259Smckusick /*
82438259Smckusick  * Change flags of a file given a file descriptor.
82538259Smckusick  */
826*38408Smckusick fchflags(scp)
827*38408Smckusick 	register struct syscontext *scp;
82838259Smckusick {
82938259Smckusick 	struct a {
83038259Smckusick 		int	fd;
83138259Smckusick 		int	flags;
832*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
83338259Smckusick 	struct vattr vattr;
83438259Smckusick 	struct vnode *vp;
83538259Smckusick 	struct file *fp;
83638259Smckusick 	int error;
83738259Smckusick 
838*38408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
83938259Smckusick 		RETURN (error);
84038259Smckusick 	vattr_null(&vattr);
84138259Smckusick 	vattr.va_flags = uap->flags;
84238259Smckusick 	vp = (struct vnode *)fp->f_data;
84338259Smckusick 	VOP_LOCK(vp);
84438259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
84538259Smckusick 		error = EROFS;
84638259Smckusick 		goto out;
84738259Smckusick 	}
84838259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
84938259Smckusick out:
85038259Smckusick 	VOP_UNLOCK(vp);
85138259Smckusick 	RETURN (error);
85238259Smckusick }
85338259Smckusick 
85438259Smckusick /*
8559167Ssam  * Change mode of a file given path name.
8569167Ssam  */
857*38408Smckusick chmod(scp)
858*38408Smckusick 	register struct syscontext *scp;
8595992Swnj {
8607701Ssam 	struct a {
8616254Sroot 		char	*fname;
8626254Sroot 		int	fmode;
863*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
864*38408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
86537741Smckusick 	register struct vnode *vp;
86637741Smckusick 	struct vattr vattr;
86737741Smckusick 	int error;
8685992Swnj 
86937741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
87037741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
87137741Smckusick 	ndp->ni_dirp = uap->fname;
87237741Smckusick 	vattr_null(&vattr);
87337741Smckusick 	vattr.va_mode = uap->fmode & 07777;
87437741Smckusick 	if (error = namei(ndp))
87537741Smckusick 		RETURN (error);
87637741Smckusick 	vp = ndp->ni_vp;
87737741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
87837741Smckusick 		error = EROFS;
87937741Smckusick 		goto out;
88037741Smckusick 	}
88137741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
88237741Smckusick out:
88337741Smckusick 	vput(vp);
88437741Smckusick 	RETURN (error);
8857701Ssam }
8867439Sroot 
8879167Ssam /*
8889167Ssam  * Change mode of a file given a file descriptor.
8899167Ssam  */
890*38408Smckusick fchmod(scp)
891*38408Smckusick 	register struct syscontext *scp;
8927701Ssam {
8937701Ssam 	struct a {
8947701Ssam 		int	fd;
8957701Ssam 		int	fmode;
896*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
89737741Smckusick 	struct vattr vattr;
89837741Smckusick 	struct vnode *vp;
89937741Smckusick 	struct file *fp;
90037741Smckusick 	int error;
9017701Ssam 
902*38408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
90337741Smckusick 		RETURN (error);
90437741Smckusick 	vattr_null(&vattr);
90537741Smckusick 	vattr.va_mode = uap->fmode & 07777;
90637741Smckusick 	vp = (struct vnode *)fp->f_data;
90737741Smckusick 	VOP_LOCK(vp);
90837741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
90937741Smckusick 		error = EROFS;
91037741Smckusick 		goto out;
9117439Sroot 	}
91237741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
91337741Smckusick out:
91437741Smckusick 	VOP_UNLOCK(vp);
91537741Smckusick 	RETURN (error);
9165992Swnj }
9175992Swnj 
9189167Ssam /*
9199167Ssam  * Set ownership given a path name.
9209167Ssam  */
921*38408Smckusick chown(scp)
922*38408Smckusick 	register struct syscontext *scp;
92337Sbill {
9247701Ssam 	struct a {
9256254Sroot 		char	*fname;
9266254Sroot 		int	uid;
9276254Sroot 		int	gid;
928*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
929*38408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
93037741Smckusick 	register struct vnode *vp;
93137741Smckusick 	struct vattr vattr;
93237741Smckusick 	int error;
93337Sbill 
93437741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
93536614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
93636614Sbostic 	ndp->ni_dirp = uap->fname;
93737741Smckusick 	vattr_null(&vattr);
93837741Smckusick 	vattr.va_uid = uap->uid;
93937741Smckusick 	vattr.va_gid = uap->gid;
94037741Smckusick 	if (error = namei(ndp))
94137741Smckusick 		RETURN (error);
94237741Smckusick 	vp = ndp->ni_vp;
94337741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
94437741Smckusick 		error = EROFS;
94537741Smckusick 		goto out;
94637741Smckusick 	}
94737741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
94837741Smckusick out:
94937741Smckusick 	vput(vp);
95037741Smckusick 	RETURN (error);
9517701Ssam }
9527439Sroot 
9539167Ssam /*
9549167Ssam  * Set ownership given a file descriptor.
9559167Ssam  */
956*38408Smckusick fchown(scp)
957*38408Smckusick 	register struct syscontext *scp;
9587701Ssam {
9597701Ssam 	struct a {
9607701Ssam 		int	fd;
9617701Ssam 		int	uid;
9627701Ssam 		int	gid;
963*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
96437741Smckusick 	struct vattr vattr;
96537741Smckusick 	struct vnode *vp;
96637741Smckusick 	struct file *fp;
96737741Smckusick 	int error;
9687701Ssam 
969*38408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
97037741Smckusick 		RETURN (error);
97137741Smckusick 	vattr_null(&vattr);
97237741Smckusick 	vattr.va_uid = uap->uid;
97337741Smckusick 	vattr.va_gid = uap->gid;
97437741Smckusick 	vp = (struct vnode *)fp->f_data;
97537741Smckusick 	VOP_LOCK(vp);
97637741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
97737741Smckusick 		error = EROFS;
97837741Smckusick 		goto out;
97937741Smckusick 	}
98037741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
98137741Smckusick out:
98237741Smckusick 	VOP_UNLOCK(vp);
98337741Smckusick 	RETURN (error);
9847701Ssam }
9857701Ssam 
986*38408Smckusick utimes(scp)
987*38408Smckusick 	register struct syscontext *scp;
98811811Ssam {
98911811Ssam 	register struct a {
99011811Ssam 		char	*fname;
99111811Ssam 		struct	timeval *tptr;
992*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
993*38408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
99437741Smckusick 	register struct vnode *vp;
99511811Ssam 	struct timeval tv[2];
99637741Smckusick 	struct vattr vattr;
99737741Smckusick 	int error;
99811811Ssam 
99937741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
100037741Smckusick 		RETURN (error);
100137741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
100237741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
100337741Smckusick 	ndp->ni_dirp = uap->fname;
100437741Smckusick 	vattr_null(&vattr);
100537741Smckusick 	vattr.va_atime = tv[0];
100637741Smckusick 	vattr.va_mtime = tv[1];
100737741Smckusick 	if (error = namei(ndp))
100837741Smckusick 		RETURN (error);
100937741Smckusick 	vp = ndp->ni_vp;
101037741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
101137741Smckusick 		error = EROFS;
101237741Smckusick 		goto out;
101321015Smckusick 	}
101437741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
101537741Smckusick out:
101637741Smckusick 	vput(vp);
101737741Smckusick 	RETURN (error);
101811811Ssam }
101911811Ssam 
10209167Ssam /*
10219167Ssam  * Truncate a file given its path name.
10229167Ssam  */
1023*38408Smckusick truncate(scp)
1024*38408Smckusick 	register struct syscontext *scp;
10257701Ssam {
10267701Ssam 	struct a {
10277701Ssam 		char	*fname;
102826473Skarels 		off_t	length;
1029*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
1030*38408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
103137741Smckusick 	register struct vnode *vp;
103237741Smckusick 	struct vattr vattr;
103337741Smckusick 	int error;
10347701Ssam 
103537741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
103616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
103716694Smckusick 	ndp->ni_dirp = uap->fname;
103837741Smckusick 	vattr_null(&vattr);
103937741Smckusick 	vattr.va_size = uap->length;
104037741Smckusick 	if (error = namei(ndp))
104137741Smckusick 		RETURN (error);
104237741Smckusick 	vp = ndp->ni_vp;
104337741Smckusick 	if (vp->v_type == VDIR) {
104437741Smckusick 		error = EISDIR;
104537741Smckusick 		goto out;
10467701Ssam 	}
104738399Smckusick 	if ((error = vn_writechk(vp)) ||
104838399Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
104937741Smckusick 		goto out;
105037741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
105137741Smckusick out:
105237741Smckusick 	vput(vp);
105337741Smckusick 	RETURN (error);
10547701Ssam }
10557701Ssam 
10569167Ssam /*
10579167Ssam  * Truncate a file given a file descriptor.
10589167Ssam  */
1059*38408Smckusick ftruncate(scp)
1060*38408Smckusick 	register struct syscontext *scp;
10617701Ssam {
10627701Ssam 	struct a {
10637701Ssam 		int	fd;
106426473Skarels 		off_t	length;
1065*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
106637741Smckusick 	struct vattr vattr;
106737741Smckusick 	struct vnode *vp;
10687701Ssam 	struct file *fp;
106937741Smckusick 	int error;
10707701Ssam 
1071*38408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
107237741Smckusick 		RETURN (error);
107337741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
107437741Smckusick 		RETURN (EINVAL);
107537741Smckusick 	vattr_null(&vattr);
107637741Smckusick 	vattr.va_size = uap->length;
107737741Smckusick 	vp = (struct vnode *)fp->f_data;
107837741Smckusick 	VOP_LOCK(vp);
107937741Smckusick 	if (vp->v_type == VDIR) {
108037741Smckusick 		error = EISDIR;
108137741Smckusick 		goto out;
10827701Ssam 	}
108338399Smckusick 	if (error = vn_writechk(vp))
108437741Smckusick 		goto out;
108537741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
108637741Smckusick out:
108737741Smckusick 	VOP_UNLOCK(vp);
108837741Smckusick 	RETURN (error);
10897701Ssam }
10907701Ssam 
10919167Ssam /*
10929167Ssam  * Synch an open file.
10939167Ssam  */
1094*38408Smckusick fsync(scp)
1095*38408Smckusick 	register struct syscontext *scp;
10969167Ssam {
10979167Ssam 	struct a {
10989167Ssam 		int	fd;
1099*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
11009167Ssam 	struct file *fp;
110137741Smckusick 	int error;
11029167Ssam 
1103*38408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
110437741Smckusick 		RETURN (error);
110537741Smckusick 	error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred);
110637741Smckusick 	RETURN (error);
11079167Ssam }
11089167Ssam 
11099167Ssam /*
11109167Ssam  * Rename system call.
11119167Ssam  *
11129167Ssam  * Source and destination must either both be directories, or both
11139167Ssam  * not be directories.  If target is a directory, it must be empty.
11149167Ssam  */
1115*38408Smckusick rename(scp)
1116*38408Smckusick 	register struct syscontext *scp;
11177701Ssam {
11187701Ssam 	struct a {
11197701Ssam 		char	*from;
11207701Ssam 		char	*to;
1121*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
112237741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
1123*38408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
112437741Smckusick 	struct nameidata tond;
112537741Smckusick 	int error;
11267701Ssam 
112737741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
112816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
112916694Smckusick 	ndp->ni_dirp = uap->from;
113037741Smckusick 	if (error = namei(ndp))
113137741Smckusick 		RETURN (error);
113237741Smckusick 	fvp = ndp->ni_vp;
113338266Smckusick 	nddup(ndp, &tond);
113437741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
113537741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
113637741Smckusick 	tond.ni_dirp = uap->to;
113737741Smckusick 	error = namei(&tond);
113837741Smckusick 	tdvp = tond.ni_dvp;
113937741Smckusick 	tvp = tond.ni_vp;
114037741Smckusick 	if (tvp != NULL) {
114137741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
114237741Smckusick 			error = EISDIR;
114337741Smckusick 			goto out;
114437741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
114537741Smckusick 			error = ENOTDIR;
114637741Smckusick 			goto out;
11479167Ssam 		}
11489167Ssam 	}
114937741Smckusick 	if (error) {
115037741Smckusick 		VOP_ABORTOP(ndp);
115137741Smckusick 		goto out1;
115237741Smckusick 	}
115337741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
115437741Smckusick 		error = EXDEV;
11559167Ssam 		goto out;
115610051Ssam 	}
115737741Smckusick 	if (fvp == tdvp || fvp == tvp)
115837741Smckusick 		error = EINVAL;
115937741Smckusick out:
116037741Smckusick 	if (error) {
116137741Smckusick 		VOP_ABORTOP(&tond);
116237741Smckusick 		VOP_ABORTOP(ndp);
11639167Ssam 	} else {
116437741Smckusick 		error = VOP_RENAME(ndp, &tond);
11659167Ssam 	}
116637741Smckusick out1:
116738266Smckusick 	ndrele(&tond);
116837741Smckusick 	RETURN (error);
11697701Ssam }
11707701Ssam 
11717535Sroot /*
117212756Ssam  * Mkdir system call
117312756Ssam  */
1174*38408Smckusick mkdir(scp)
1175*38408Smckusick 	register struct syscontext *scp;
117612756Ssam {
117712756Ssam 	struct a {
117812756Ssam 		char	*name;
117912756Ssam 		int	dmode;
1180*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
1181*38408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
118237741Smckusick 	register struct vnode *vp;
118337741Smckusick 	struct vattr vattr;
118437741Smckusick 	int error;
118512756Ssam 
118637741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
118716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
118816694Smckusick 	ndp->ni_dirp = uap->name;
118937741Smckusick 	if (error = namei(ndp))
119037741Smckusick 		RETURN (error);
119137741Smckusick 	vp = ndp->ni_vp;
119237741Smckusick 	if (vp != NULL) {
119337741Smckusick 		VOP_ABORTOP(ndp);
119437741Smckusick 		RETURN (EEXIST);
119512756Ssam 	}
119637741Smckusick 	vattr_null(&vattr);
119737741Smckusick 	vattr.va_type = VDIR;
1198*38408Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask;
119937741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
120038145Smckusick 	if (!error)
120138145Smckusick 		vput(ndp->ni_vp);
120237741Smckusick 	RETURN (error);
120312756Ssam }
120412756Ssam 
120512756Ssam /*
120612756Ssam  * Rmdir system call.
120712756Ssam  */
1208*38408Smckusick rmdir(scp)
1209*38408Smckusick 	register struct syscontext *scp;
121012756Ssam {
121112756Ssam 	struct a {
121212756Ssam 		char	*name;
1213*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
1214*38408Smckusick 	register struct nameidata *ndp = &scp->sc_nd;
121537741Smckusick 	register struct vnode *vp;
121637741Smckusick 	int error;
121712756Ssam 
121837741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
121916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
122016694Smckusick 	ndp->ni_dirp = uap->name;
122137741Smckusick 	if (error = namei(ndp))
122237741Smckusick 		RETURN (error);
122337741Smckusick 	vp = ndp->ni_vp;
122437741Smckusick 	if (vp->v_type != VDIR) {
122537741Smckusick 		error = ENOTDIR;
122612756Ssam 		goto out;
122712756Ssam 	}
122812756Ssam 	/*
122937741Smckusick 	 * No rmdir "." please.
123012756Ssam 	 */
123137741Smckusick 	if (ndp->ni_dvp == vp) {
123237741Smckusick 		error = EINVAL;
123312756Ssam 		goto out;
123412756Ssam 	}
123512756Ssam 	/*
123637741Smckusick 	 * Don't unlink a mounted file.
123712756Ssam 	 */
123837741Smckusick 	if (vp->v_flag & VROOT)
123937741Smckusick 		error = EBUSY;
124012756Ssam out:
124137741Smckusick 	if (error)
124237741Smckusick 		VOP_ABORTOP(ndp);
124337741Smckusick 	else
124437741Smckusick 		error = VOP_RMDIR(ndp);
124537741Smckusick 	RETURN (error);
124612756Ssam }
124712756Ssam 
124837741Smckusick /*
124937741Smckusick  * Read a block of directory entries in a file system independent format
125037741Smckusick  */
1251*38408Smckusick getdirentries(scp)
1252*38408Smckusick 	register struct syscontext *scp;
125312756Ssam {
125437741Smckusick 	register struct a {
125537741Smckusick 		int	fd;
125637741Smckusick 		char	*buf;
125737741Smckusick 		unsigned count;
125837741Smckusick 		long	*basep;
1259*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
126016540Ssam 	struct file *fp;
126137741Smckusick 	struct uio auio;
126237741Smckusick 	struct iovec aiov;
126338129Smckusick 	off_t off;
126437741Smckusick 	int error;
126512756Ssam 
1266*38408Smckusick 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
126737741Smckusick 		RETURN (error);
126837741Smckusick 	if ((fp->f_flag & FREAD) == 0)
126937741Smckusick 		RETURN (EBADF);
127037741Smckusick 	aiov.iov_base = uap->buf;
127137741Smckusick 	aiov.iov_len = uap->count;
127237741Smckusick 	auio.uio_iov = &aiov;
127337741Smckusick 	auio.uio_iovcnt = 1;
127437741Smckusick 	auio.uio_rw = UIO_READ;
127537741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
127637741Smckusick 	auio.uio_resid = uap->count;
127738129Smckusick 	off = fp->f_offset;
127837741Smckusick 	if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio,
127937741Smckusick 	    &(fp->f_offset), fp->f_cred))
128037741Smckusick 		RETURN (error);
128138129Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep,
128237741Smckusick 		sizeof(long));
1283*38408Smckusick 	scp->sc_retval1 = uap->count - auio.uio_resid;
128437741Smckusick 	RETURN (error);
128512756Ssam }
128612756Ssam 
128712756Ssam /*
128812756Ssam  * mode mask for creation of files
128912756Ssam  */
1290*38408Smckusick umask(scp)
1291*38408Smckusick 	register struct syscontext *scp;
129212756Ssam {
129312756Ssam 	register struct a {
129412756Ssam 		int	mask;
1295*38408Smckusick 	} *uap = (struct a *)scp->sc_ap;
129612756Ssam 
1297*38408Smckusick 	scp->sc_retval1 = scp->sc_cmask;
1298*38408Smckusick 	scp->sc_cmask = uap->mask & 07777;
129937741Smckusick 	RETURN (0);
130012756Ssam }
130137741Smckusick 
1302*38408Smckusick getvnode(ofile, fdes, fpp)
1303*38408Smckusick 	struct file *ofile[];
130437741Smckusick 	struct file **fpp;
130537741Smckusick 	int fdes;
130637741Smckusick {
130737741Smckusick 	struct file *fp;
130837741Smckusick 
1309*38408Smckusick 	if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
131037741Smckusick 		return (EBADF);
131137741Smckusick 	if (fp->f_type != DTYPE_VNODE)
131237741Smckusick 		return (EINVAL);
131337741Smckusick 	*fpp = fp;
131437741Smckusick 	return (0);
131537741Smckusick }
1316