xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 38399)
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*38399Smckusick  *	@(#)vfs_syscalls.c	7.13 (Berkeley) 07/03/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  */
4037741Smckusick mount()
416254Sroot {
4237741Smckusick 	register struct a {
4337741Smckusick 		int	type;
4437741Smckusick 		char	*dir;
4537741Smckusick 		int	flags;
4637741Smckusick 		caddr_t	data;
4737741Smckusick 	} *uap = (struct a *)u.u_ap;
4837741Smckusick 	register struct nameidata *ndp = &u.u_nd;
4937741Smckusick 	struct vnode *vp;
5037741Smckusick 	struct mount *mp;
5137741Smckusick 	int error;
526254Sroot 
5337741Smckusick 	/*
5437741Smckusick 	 * Must be super user
5537741Smckusick 	 */
5637741Smckusick 	if (error = suser(u.u_cred, &u.u_acflag))
5737741Smckusick 		RETURN (error);
5837741Smckusick 	/*
5937741Smckusick 	 * Get vnode to be covered
6037741Smckusick 	 */
6137741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
6237741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
6337741Smckusick 	ndp->ni_dirp = uap->dir;
6437741Smckusick 	if (error = namei(ndp))
6537741Smckusick 		RETURN (error);
6637741Smckusick 	vp = ndp->ni_vp;
6737741Smckusick 	if (vp->v_count != 1) {
6837741Smckusick 		vput(vp);
6937741Smckusick 		RETURN (EBUSY);
7037741Smckusick 	}
7137741Smckusick 	if (vp->v_type != VDIR) {
7237741Smckusick 		vput(vp);
7337741Smckusick 		RETURN (ENOTDIR);
7437741Smckusick 	}
7537741Smckusick 	if (uap->type > MOUNT_MAXTYPE ||
7637741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
7737741Smckusick 		vput(vp);
7837741Smckusick 		RETURN (ENODEV);
7937741Smckusick 	}
8037741Smckusick 
8137741Smckusick 	/*
8237741Smckusick 	 * Mount the filesystem.
8337741Smckusick 	 */
8437741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
8537741Smckusick 		M_MOUNT, M_WAITOK);
8637741Smckusick 	mp->m_op = vfssw[uap->type];
8737741Smckusick 	mp->m_flag = 0;
8837741Smckusick 	mp->m_exroot = 0;
8937741Smckusick 	error = vfs_add(vp, mp, uap->flags);
9037741Smckusick 	if (!error)
9137741Smckusick 		error = VFS_MOUNT(mp, uap->dir, uap->data, ndp);
9237741Smckusick 	cache_purge(vp);
9337741Smckusick 	VOP_UNLOCK(vp);
9437741Smckusick 	if (!error) {
9537741Smckusick 		vfs_unlock(mp);
9637741Smckusick 	} else {
9737741Smckusick 		vfs_remove(mp);
9837741Smckusick 		free((caddr_t)mp, M_MOUNT);
9937741Smckusick 		vrele(vp);
10037741Smckusick 	}
10137741Smckusick 	RETURN (error);
1026254Sroot }
1036254Sroot 
1049167Ssam /*
10537741Smckusick  * Unmount system call.
10637741Smckusick  *
10737741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
10837741Smckusick  * not special file (as before).
1099167Ssam  */
11037741Smckusick unmount()
1116254Sroot {
11237741Smckusick 	struct a {
11337741Smckusick 		char	*pathp;
11437741Smckusick 		int	flags;
11537741Smckusick 	} *uap = (struct a *)u.u_ap;
11637741Smckusick 	register struct vnode *vp;
11737741Smckusick 	register struct mount *mp;
11837741Smckusick 	register struct nameidata *ndp = &u.u_nd;
11937741Smckusick 	struct vnode *coveredvp;
12037741Smckusick 	int error;
1216254Sroot 
12237741Smckusick 	/*
12337741Smckusick 	 * Must be super user
12437741Smckusick 	 */
12537741Smckusick 	if (error = suser(u.u_cred, &u.u_acflag))
12637741Smckusick 		RETURN (error);
12737741Smckusick 
12837741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
12937741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
13037741Smckusick 	ndp->ni_dirp = uap->pathp;
13137741Smckusick 	if (error = namei(ndp))
13237741Smckusick 		RETURN (error);
13337741Smckusick 	vp = ndp->ni_vp;
13437741Smckusick 	/*
13537741Smckusick 	 * Must be the root of the filesystem
13637741Smckusick 	 */
13737741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
13837741Smckusick 		vput(vp);
13937741Smckusick 		RETURN (EINVAL);
14037741Smckusick 	}
14137741Smckusick 	mp = vp->v_mount;
14237741Smckusick 	vput(vp);
14337741Smckusick 	/*
14437741Smckusick 	 * Do the unmount.
14537741Smckusick 	 */
14637741Smckusick 	coveredvp = mp->m_vnodecovered;
14737741Smckusick 	if (error = vfs_lock(mp))
14837741Smckusick 		RETURN (error);
14937741Smckusick 
15037741Smckusick 	xumount(mp);		/* remove unused sticky files from text table */
15137741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
15237741Smckusick 	VFS_SYNC(mp, MNT_WAIT);
15337741Smckusick 
15437741Smckusick 	error = VFS_UNMOUNT(mp, uap->flags);
15537741Smckusick 	if (error) {
15637741Smckusick 		vfs_unlock(mp);
15737741Smckusick 	} else {
15837741Smckusick 		vrele(coveredvp);
15937741Smckusick 		vfs_remove(mp);
16037741Smckusick 		free((caddr_t)mp, M_MOUNT);
16137741Smckusick 	}
16237741Smckusick 	RETURN (error);
1636254Sroot }
1646254Sroot 
1659167Ssam /*
16637741Smckusick  * Sync system call.
16737741Smckusick  * Sync each mounted filesystem.
1689167Ssam  */
16937741Smckusick sync()
1706254Sroot {
17137741Smckusick 	register struct mount *mp;
17237741Smckusick 
17337741Smckusick 	mp = rootfs;
17437741Smckusick 	do {
17537741Smckusick 		if ((mp->m_flag & M_RDONLY) == 0)
17637741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
17737741Smckusick 		mp = mp->m_next;
17837741Smckusick 	} while (mp != rootfs);
17937741Smckusick }
18037741Smckusick 
18137741Smckusick /*
18237741Smckusick  * get filesystem statistics
18337741Smckusick  */
18437741Smckusick statfs()
18537741Smckusick {
1866254Sroot 	struct a {
18737741Smckusick 		char *path;
18837741Smckusick 		struct statfs *buf;
18937741Smckusick 	} *uap = (struct a *)u.u_ap;
19037741Smckusick 	register struct vnode *vp;
19137741Smckusick 	register struct nameidata *ndp = &u.u_nd;
19237741Smckusick 	struct statfs sb;
19337741Smckusick 	int error;
19437741Smckusick 
19537741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
19637741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
19737741Smckusick 	ndp->ni_dirp = uap->path;
19837741Smckusick 	if (error = namei(ndp))
19937741Smckusick 		RETURN (error);
20037741Smckusick 	vp = ndp->ni_vp;
20137741Smckusick 	if (error = VFS_STATFS(vp->v_mount, &sb))
20237741Smckusick 		goto out;
20337741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb));
20437741Smckusick out:
20537741Smckusick 	vput(vp);
20637741Smckusick 	RETURN (error);
20737741Smckusick }
20837741Smckusick 
20937741Smckusick fstatfs()
21037741Smckusick {
21137741Smckusick 	struct a {
21237741Smckusick 		int fd;
21337741Smckusick 		struct statfs *buf;
21437741Smckusick 	} *uap = (struct a *)u.u_ap;
21537741Smckusick 	struct file *fp;
21637741Smckusick 	struct statfs sb;
21737741Smckusick 	int error;
21837741Smckusick 
21937741Smckusick 	if (error = getvnode(uap->fd, &fp))
22037741Smckusick 		RETURN (error);
22137741Smckusick 	if (error = VFS_STATFS(((struct vnode *)fp->f_data)->v_mount, &sb))
22237741Smckusick 		RETURN (error);
22337741Smckusick 	RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)));
22437741Smckusick }
22537741Smckusick 
22637741Smckusick /*
22738270Smckusick  * get statistics on all filesystems
22838270Smckusick  */
22938270Smckusick getfsstat()
23038270Smckusick {
23138270Smckusick 	struct a {
23238270Smckusick 		struct statfs *buf;
23338270Smckusick 		long bufsize;
23438270Smckusick 	} *uap = (struct a *)u.u_ap;
23538270Smckusick 	register struct mount *mp;
23638270Smckusick 	register struct statfs *sfsp;
23738270Smckusick 	long count, maxcount, error;
23838270Smckusick 
23938270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
24038270Smckusick 	sfsp = uap->buf;
24138270Smckusick 	mp = rootfs;
24238270Smckusick 	count = 0;
24338270Smckusick 	do {
24438270Smckusick 		count++;
24538270Smckusick 		if (sfsp && count <= maxcount) {
24638270Smckusick 			if (error = VFS_STATFS(mp, sfsp))
24738270Smckusick 				RETURN (error);
24838270Smckusick 			sfsp++;
24938270Smckusick 		}
25038270Smckusick 		mp = mp->m_prev;
25138270Smckusick 	} while (mp != rootfs);
25238270Smckusick 	if (sfsp && count > maxcount)
25338270Smckusick 		u.u_r.r_val1 = maxcount;
25438270Smckusick 	else
25538270Smckusick 		u.u_r.r_val1 = count;
25638270Smckusick 	RETURN (0);
25738270Smckusick }
25838270Smckusick 
25938270Smckusick /*
26038259Smckusick  * Change current working directory to a given file descriptor.
26138259Smckusick  */
26238259Smckusick fchdir()
26338259Smckusick {
26438259Smckusick 	struct a {
26538259Smckusick 		int	fd;
26638259Smckusick 	} *uap = (struct a *)u.u_ap;
26738259Smckusick 	register struct vnode *vp;
26838259Smckusick 	struct file *fp;
26938259Smckusick 	int error;
27038259Smckusick 
27138259Smckusick 	if (error = getvnode(uap->fd, &fp))
27238259Smckusick 		RETURN (error);
27338259Smckusick 	vp = (struct vnode *)fp->f_data;
27438259Smckusick 	VOP_LOCK(vp);
27538259Smckusick 	if (vp->v_type != VDIR)
27638259Smckusick 		error = ENOTDIR;
27738259Smckusick 	else
278*38399Smckusick 		error = VOP_ACCESS(vp, VEXEC, u.u_cred);
27938259Smckusick 	VOP_UNLOCK(vp);
28038259Smckusick 	vrele(u.u_cdir);
28138259Smckusick 	u.u_cdir = vp;
28238259Smckusick 	RETURN (error);
28338259Smckusick }
28438259Smckusick 
28538259Smckusick /*
28637741Smckusick  * Change current working directory (``.'').
28737741Smckusick  */
28837741Smckusick chdir()
28937741Smckusick {
29037741Smckusick 	struct a {
2916254Sroot 		char	*fname;
29216694Smckusick 	} *uap = (struct a *)u.u_ap;
29316694Smckusick 	register struct nameidata *ndp = &u.u_nd;
29437741Smckusick 	int error;
2956254Sroot 
29637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
29716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
29816694Smckusick 	ndp->ni_dirp = uap->fname;
29937741Smckusick 	if (error = chdirec(ndp))
30037741Smckusick 		RETURN (error);
30137741Smckusick 	vrele(u.u_cdir);
30237741Smckusick 	u.u_cdir = ndp->ni_vp;
30337741Smckusick 	RETURN (0);
30437741Smckusick }
3056254Sroot 
30637741Smckusick /*
30737741Smckusick  * Change notion of root (``/'') directory.
30837741Smckusick  */
30937741Smckusick chroot()
31037741Smckusick {
31137741Smckusick 	struct a {
31237741Smckusick 		char	*fname;
31337741Smckusick 	} *uap = (struct a *)u.u_ap;
31437741Smckusick 	register struct nameidata *ndp = &u.u_nd;
31537741Smckusick 	int error;
31637741Smckusick 
31737741Smckusick 	if (error = suser(u.u_cred, &u.u_acflag))
31837741Smckusick 		RETURN (error);
31937741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
32037741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
32137741Smckusick 	ndp->ni_dirp = uap->fname;
32237741Smckusick 	if (error = chdirec(ndp))
32337741Smckusick 		RETURN (error);
32437741Smckusick 	vrele(u.u_rdir);
32537741Smckusick 	u.u_rdir = ndp->ni_vp;
32637741Smckusick 	RETURN (0);
3276254Sroot }
3286254Sroot 
32937Sbill /*
33037741Smckusick  * Common routine for chroot and chdir.
33137741Smckusick  */
33237741Smckusick chdirec(ndp)
33337741Smckusick 	register struct nameidata *ndp;
33437741Smckusick {
33537741Smckusick 	struct vnode *vp;
33637741Smckusick 	int error;
33737741Smckusick 
33837741Smckusick 	if (error = namei(ndp))
33937741Smckusick 		return (error);
34037741Smckusick 	vp = ndp->ni_vp;
34137741Smckusick 	if (vp->v_type != VDIR)
34237741Smckusick 		error = ENOTDIR;
34337741Smckusick 	else
344*38399Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
34537741Smckusick 	VOP_UNLOCK(vp);
34637741Smckusick 	if (error)
34737741Smckusick 		vrele(vp);
34837741Smckusick 	return (error);
34937741Smckusick }
35037741Smckusick 
35137741Smckusick /*
3526254Sroot  * Open system call.
3536254Sroot  */
3546254Sroot open()
3556254Sroot {
35612756Ssam 	struct a {
3576254Sroot 		char	*fname;
3587701Ssam 		int	mode;
35912756Ssam 		int	crtmode;
36012756Ssam 	} *uap = (struct a *) u.u_ap;
36137741Smckusick 	struct nameidata *ndp = &u.u_nd;
3626254Sroot 
36337741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
36437741Smckusick 	ndp->ni_dirp = uap->fname;
36537741Smckusick 	RETURN (copen(uap->mode-FOPEN, uap->crtmode &~ u.u_cmask, ndp,
36637741Smckusick 		&u.u_r.r_val1));
3676254Sroot }
3686254Sroot 
3696254Sroot /*
3706254Sroot  * Creat system call.
3716254Sroot  */
37212756Ssam creat()
3736254Sroot {
37412756Ssam 	struct a {
3756254Sroot 		char	*fname;
3766254Sroot 		int	fmode;
37712756Ssam 	} *uap = (struct a *)u.u_ap;
37837741Smckusick 	struct nameidata *ndp = &u.u_nd;
3796254Sroot 
38037741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
38137741Smckusick 	ndp->ni_dirp = uap->fname;
38237741Smckusick 	RETURN (copen(FWRITE|FCREAT|FTRUNC, uap->fmode &~ u.u_cmask, ndp,
38337741Smckusick 		&u.u_r.r_val1));
3846254Sroot }
3856254Sroot 
3866254Sroot /*
3876254Sroot  * Common code for open and creat.
38812756Ssam  * Check permissions, allocate an open file structure,
38912756Ssam  * and call the device open routine if any.
3906254Sroot  */
39137741Smckusick copen(fmode, cmode, ndp, resultfd)
39237741Smckusick 	int fmode, cmode;
39337741Smckusick 	struct nameidata *ndp;
39437741Smckusick 	int *resultfd;
39512756Ssam {
3966254Sroot 	register struct file *fp;
39737741Smckusick 	struct file *nfp;
39837741Smckusick 	int indx, error;
39937741Smckusick 	extern struct fileops vnops;
4006254Sroot 
40137741Smckusick 	if (error = falloc(&nfp, &indx))
40237741Smckusick 		return (error);
40337741Smckusick 	fp = nfp;
40437741Smckusick 	u.u_r.r_val1 = indx;	/* XXX for fdopen() */
40537741Smckusick 	if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) {
40624543Smckusick 		u.u_ofile[indx] = NULL;
40737741Smckusick 		crfree(fp->f_cred);
40837741Smckusick 		fp->f_count--;
40937741Smckusick 		return (error);
41012756Ssam 	}
41137741Smckusick 	fp->f_flag = fmode & FMASK;
41237741Smckusick 	fp->f_type = DTYPE_VNODE;
41337741Smckusick 	fp->f_ops = &vnops;
41437741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
41537741Smckusick 	if (resultfd)
41637741Smckusick 		*resultfd = indx;
41737741Smckusick 	return (0);
4186254Sroot }
4196254Sroot 
4206254Sroot /*
4216254Sroot  * Mknod system call
4226254Sroot  */
4236254Sroot mknod()
4246254Sroot {
4256254Sroot 	register struct a {
4266254Sroot 		char	*fname;
4276254Sroot 		int	fmode;
4286254Sroot 		int	dev;
42916694Smckusick 	} *uap = (struct a *)u.u_ap;
43016694Smckusick 	register struct nameidata *ndp = &u.u_nd;
43137741Smckusick 	register struct vnode *vp;
43237741Smckusick 	struct vattr vattr;
43337741Smckusick 	int error;
4346254Sroot 
43537741Smckusick 	if (error = suser(u.u_cred, &u.u_acflag))
43637741Smckusick 		RETURN (error);
43737741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
43816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
43916694Smckusick 	ndp->ni_dirp = uap->fname;
44037741Smckusick 	if (error = namei(ndp))
44137741Smckusick 		RETURN (error);
44237741Smckusick 	vp = ndp->ni_vp;
44337741Smckusick 	if (vp != NULL) {
44437741Smckusick 		error = EEXIST;
44512756Ssam 		goto out;
4466254Sroot 	}
44737741Smckusick 	vattr_null(&vattr);
44837741Smckusick 	switch (uap->fmode & IFMT) {
44912756Ssam 
45015093Smckusick 	case IFMT:	/* used by badsect to flag bad sectors */
45137741Smckusick 		vattr.va_type = VBAD;
45237741Smckusick 		break;
45312756Ssam 	case IFCHR:
45437741Smckusick 		vattr.va_type = VCHR;
45537741Smckusick 		break;
45612756Ssam 	case IFBLK:
45737741Smckusick 		vattr.va_type = VBLK;
45837741Smckusick 		break;
45937741Smckusick 	default:
46037741Smckusick 		error = EINVAL;
46137741Smckusick 		goto out;
4626254Sroot 	}
46337741Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask;
46437741Smckusick 	vattr.va_rdev = uap->dev;
4656254Sroot out:
46637741Smckusick 	if (error)
46737741Smckusick 		VOP_ABORTOP(ndp);
46837741Smckusick 	else
46937741Smckusick 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
47037741Smckusick 	RETURN (error);
4716254Sroot }
4726254Sroot 
4736254Sroot /*
4746254Sroot  * link system call
4756254Sroot  */
4766254Sroot link()
4776254Sroot {
4786254Sroot 	register struct a {
4796254Sroot 		char	*target;
4806254Sroot 		char	*linkname;
48116694Smckusick 	} *uap = (struct a *)u.u_ap;
48216694Smckusick 	register struct nameidata *ndp = &u.u_nd;
48337741Smckusick 	register struct vnode *vp, *xp;
48437741Smckusick 	int error;
4856254Sroot 
48616694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
48716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
48816694Smckusick 	ndp->ni_dirp = uap->target;
48937741Smckusick 	if (error = namei(ndp))
49037741Smckusick 		RETURN (error);
49137741Smckusick 	vp = ndp->ni_vp;
49237741Smckusick 	if (vp->v_type == VDIR &&
49337741Smckusick 	    (error = suser(u.u_cred, &u.u_acflag)))
49437741Smckusick 		goto out1;
49537741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
49616694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
49737741Smckusick 	if (error = namei(ndp))
49837741Smckusick 		goto out1;
49937741Smckusick 	xp = ndp->ni_vp;
5006254Sroot 	if (xp != NULL) {
50137741Smckusick 		error = EEXIST;
5026254Sroot 		goto out;
5036254Sroot 	}
50437741Smckusick 	xp = ndp->ni_dvp;
50537741Smckusick 	if (vp->v_mount != xp->v_mount)
50637741Smckusick 		error = EXDEV;
5076254Sroot out:
50837741Smckusick 	if (error)
50937741Smckusick 		VOP_ABORTOP(ndp);
51037741Smckusick 	else
51137741Smckusick 		error = VOP_LINK(vp, ndp);
51237741Smckusick out1:
51337741Smckusick 	vrele(vp);
51437741Smckusick 	RETURN (error);
5156254Sroot }
5166254Sroot 
5176254Sroot /*
5186254Sroot  * symlink -- make a symbolic link
5196254Sroot  */
5206254Sroot symlink()
5216254Sroot {
52237741Smckusick 	struct a {
5236254Sroot 		char	*target;
5246254Sroot 		char	*linkname;
52516694Smckusick 	} *uap = (struct a *)u.u_ap;
52616694Smckusick 	register struct nameidata *ndp = &u.u_nd;
52737741Smckusick 	register struct vnode *vp;
52837741Smckusick 	struct vattr vattr;
52937741Smckusick 	char *target;
53037741Smckusick 	int error;
5316254Sroot 
53216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
53316694Smckusick 	ndp->ni_dirp = uap->linkname;
53437741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
53537741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
53637741Smckusick 		goto out1;
53737741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
53837741Smckusick 	if (error = namei(ndp))
53937741Smckusick 		goto out1;
54037741Smckusick 	vp = ndp->ni_vp;
54137741Smckusick 	if (vp) {
54237741Smckusick 		error = EEXIST;
54337741Smckusick 		goto out;
5446254Sroot 	}
54537741Smckusick 	vp = ndp->ni_dvp;
54637741Smckusick 	vattr_null(&vattr);
54737741Smckusick 	vattr.va_mode = 0777 &~ u.u_cmask;
54837741Smckusick out:
54937741Smckusick 	if (error)
55037741Smckusick 		VOP_ABORTOP(ndp);
55137741Smckusick 	else
55237741Smckusick 		error = VOP_SYMLINK(ndp, &vattr, target);
55337741Smckusick out1:
55437741Smckusick 	FREE(target, M_NAMEI);
55537741Smckusick 	RETURN (error);
5566254Sroot }
5576254Sroot 
5586254Sroot /*
5596254Sroot  * Unlink system call.
5606254Sroot  * Hard to avoid races here, especially
5616254Sroot  * in unlinking directories.
5626254Sroot  */
5636254Sroot unlink()
5646254Sroot {
5656254Sroot 	struct a {
5666254Sroot 		char	*fname;
56716694Smckusick 	} *uap = (struct a *)u.u_ap;
56816694Smckusick 	register struct nameidata *ndp = &u.u_nd;
56937741Smckusick 	register struct vnode *vp;
57037741Smckusick 	int error;
5716254Sroot 
57237741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
57316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
57416694Smckusick 	ndp->ni_dirp = uap->fname;
57537741Smckusick 	if (error = namei(ndp))
57637741Smckusick 		RETURN (error);
57737741Smckusick 	vp = ndp->ni_vp;
57837741Smckusick 	if (vp->v_type == VDIR &&
57937741Smckusick 	    (error = suser(u.u_cred, &u.u_acflag)))
5806254Sroot 		goto out;
5816254Sroot 	/*
5826254Sroot 	 * Don't unlink a mounted file.
5836254Sroot 	 */
58437741Smckusick 	if (vp->v_flag & VROOT) {
58537741Smckusick 		error = EBUSY;
5866254Sroot 		goto out;
5876254Sroot 	}
58837741Smckusick 	if (vp->v_flag & VTEXT)
58937741Smckusick 		xrele(vp);	/* try once to free text */
5906254Sroot out:
59137741Smckusick 	if (error)
59237741Smckusick 		VOP_ABORTOP(ndp);
5937142Smckusick 	else
59437741Smckusick 		error = VOP_REMOVE(ndp);
59537741Smckusick 	RETURN (error);
5966254Sroot }
5976254Sroot 
5986254Sroot /*
5996254Sroot  * Seek system call
6006254Sroot  */
6018040Sroot lseek()
6026254Sroot {
6036254Sroot 	register struct file *fp;
6046254Sroot 	register struct a {
60537741Smckusick 		int	fdes;
6066254Sroot 		off_t	off;
6076254Sroot 		int	sbase;
60816694Smckusick 	} *uap = (struct a *)u.u_ap;
60937741Smckusick 	struct vattr vattr;
61037741Smckusick 	int error;
6116254Sroot 
61237741Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
61337741Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
61437741Smckusick 		RETURN (EBADF);
61537741Smckusick 	if (fp->f_type != DTYPE_VNODE)
61637741Smckusick 		RETURN (ESPIPE);
61713878Ssam 	switch (uap->sbase) {
61813878Ssam 
61913878Ssam 	case L_INCR:
62013878Ssam 		fp->f_offset += uap->off;
62113878Ssam 		break;
62213878Ssam 
62313878Ssam 	case L_XTND:
62437741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
62537741Smckusick 		    &vattr, u.u_cred))
62637741Smckusick 			RETURN (error);
62737741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
62813878Ssam 		break;
62913878Ssam 
63013878Ssam 	case L_SET:
63113878Ssam 		fp->f_offset = uap->off;
63213878Ssam 		break;
63313878Ssam 
63413878Ssam 	default:
63537741Smckusick 		RETURN (EINVAL);
63613878Ssam 	}
63713878Ssam 	u.u_r.r_off = fp->f_offset;
63837741Smckusick 	RETURN (0);
6396254Sroot }
6406254Sroot 
6416254Sroot /*
6426254Sroot  * Access system call
6436254Sroot  */
6446254Sroot saccess()
6456254Sroot {
6466254Sroot 	register struct a {
6476254Sroot 		char	*fname;
6486254Sroot 		int	fmode;
64916694Smckusick 	} *uap = (struct a *)u.u_ap;
65016694Smckusick 	register struct nameidata *ndp = &u.u_nd;
65137741Smckusick 	register struct vnode *vp;
65237741Smckusick 	int error, mode, svuid, svgid;
6536254Sroot 
6546254Sroot 	svuid = u.u_uid;
6556254Sroot 	svgid = u.u_gid;
6566254Sroot 	u.u_uid = u.u_ruid;
6576254Sroot 	u.u_gid = u.u_rgid;
65837741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
65916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
66016694Smckusick 	ndp->ni_dirp = uap->fname;
66137741Smckusick 	if (error = namei(ndp))
66237741Smckusick 		goto out1;
66337741Smckusick 	vp = ndp->ni_vp;
66437741Smckusick 	/*
66537741Smckusick 	 * fmode == 0 means only check for exist
66637741Smckusick 	 */
66737741Smckusick 	if (uap->fmode) {
66837741Smckusick 		mode = 0;
66937741Smckusick 		if (uap->fmode & R_OK)
67037741Smckusick 			mode |= VREAD;
67137741Smckusick 		if (uap->fmode & W_OK)
67237741Smckusick 			mode |= VWRITE;
67337741Smckusick 		if (uap->fmode & X_OK)
67437741Smckusick 			mode |= VEXEC;
675*38399Smckusick 		if ((error = vn_writechk(vp)) == 0)
676*38399Smckusick 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
6776254Sroot 	}
67837741Smckusick 	vput(vp);
67937741Smckusick out1:
6806254Sroot 	u.u_uid = svuid;
6816254Sroot 	u.u_gid = svgid;
68237741Smckusick 	RETURN (error);
6836254Sroot }
6846254Sroot 
6856254Sroot /*
6866574Smckusic  * Stat system call.  This version follows links.
68737Sbill  */
68837Sbill stat()
68937Sbill {
69037Sbill 
69116694Smckusick 	stat1(FOLLOW);
69237Sbill }
69337Sbill 
69437Sbill /*
6956574Smckusic  * Lstat system call.  This version does not follow links.
6965992Swnj  */
6975992Swnj lstat()
6985992Swnj {
69912756Ssam 
70016694Smckusick 	stat1(NOFOLLOW);
70112756Ssam }
70212756Ssam 
70312756Ssam stat1(follow)
70412756Ssam 	int follow;
70512756Ssam {
7065992Swnj 	register struct a {
7075992Swnj 		char	*fname;
70812756Ssam 		struct stat *ub;
70916694Smckusick 	} *uap = (struct a *)u.u_ap;
71037741Smckusick 	register struct nameidata *ndp = &u.u_nd;
71112756Ssam 	struct stat sb;
71237741Smckusick 	int error;
7135992Swnj 
71437741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
71516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
71616694Smckusick 	ndp->ni_dirp = uap->fname;
71737741Smckusick 	if (error = namei(ndp))
71837741Smckusick 		RETURN (error);
71937741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
72037741Smckusick 	vput(ndp->ni_vp);
72137741Smckusick 	if (error)
72237741Smckusick 		RETURN (error);
72337741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
72437741Smckusick 	RETURN (error);
7255992Swnj }
7265992Swnj 
7275992Swnj /*
7285992Swnj  * Return target name of a symbolic link
72937Sbill  */
7305992Swnj readlink()
7315992Swnj {
7325992Swnj 	register struct a {
7335992Swnj 		char	*name;
7345992Swnj 		char	*buf;
7355992Swnj 		int	count;
7367826Sroot 	} *uap = (struct a *)u.u_ap;
73716694Smckusick 	register struct nameidata *ndp = &u.u_nd;
73837741Smckusick 	register struct vnode *vp;
73937741Smckusick 	struct iovec aiov;
74037741Smckusick 	struct uio auio;
74137741Smckusick 	int error;
7425992Swnj 
74337741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
74416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
74516694Smckusick 	ndp->ni_dirp = uap->name;
74637741Smckusick 	if (error = namei(ndp))
74737741Smckusick 		RETURN (error);
74837741Smckusick 	vp = ndp->ni_vp;
74937741Smckusick 	if (vp->v_type != VLNK) {
75037741Smckusick 		error = EINVAL;
7515992Swnj 		goto out;
7525992Swnj 	}
75337741Smckusick 	aiov.iov_base = uap->buf;
75437741Smckusick 	aiov.iov_len = uap->count;
75537741Smckusick 	auio.uio_iov = &aiov;
75637741Smckusick 	auio.uio_iovcnt = 1;
75737741Smckusick 	auio.uio_offset = 0;
75837741Smckusick 	auio.uio_rw = UIO_READ;
75937741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
76037741Smckusick 	auio.uio_resid = uap->count;
76137741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
7625992Swnj out:
76337741Smckusick 	vput(vp);
76437741Smckusick 	u.u_r.r_val1 = uap->count - auio.uio_resid;
76537741Smckusick 	RETURN (error);
7665992Swnj }
7675992Swnj 
7689167Ssam /*
76938259Smckusick  * Change flags of a file given path name.
77038259Smckusick  */
77138259Smckusick chflags()
77238259Smckusick {
77338259Smckusick 	struct a {
77438259Smckusick 		char	*fname;
77538259Smckusick 		int	flags;
77638259Smckusick 	} *uap = (struct a *)u.u_ap;
77738259Smckusick 	register struct nameidata *ndp = &u.u_nd;
77838259Smckusick 	register struct vnode *vp;
77938259Smckusick 	struct vattr vattr;
78038259Smckusick 	int error;
78138259Smckusick 
78238259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
78338259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
78438259Smckusick 	ndp->ni_dirp = uap->fname;
78538259Smckusick 	vattr_null(&vattr);
78638259Smckusick 	vattr.va_flags = uap->flags;
78738259Smckusick 	if (error = namei(ndp))
78838259Smckusick 		RETURN (error);
78938259Smckusick 	vp = ndp->ni_vp;
79038259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
79138259Smckusick 		error = EROFS;
79238259Smckusick 		goto out;
79338259Smckusick 	}
79438259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
79538259Smckusick out:
79638259Smckusick 	vput(vp);
79738259Smckusick 	RETURN (error);
79838259Smckusick }
79938259Smckusick 
80038259Smckusick /*
80138259Smckusick  * Change flags of a file given a file descriptor.
80238259Smckusick  */
80338259Smckusick fchflags()
80438259Smckusick {
80538259Smckusick 	struct a {
80638259Smckusick 		int	fd;
80738259Smckusick 		int	flags;
80838259Smckusick 	} *uap = (struct a *)u.u_ap;
80938259Smckusick 	struct vattr vattr;
81038259Smckusick 	struct vnode *vp;
81138259Smckusick 	struct file *fp;
81238259Smckusick 	int error;
81338259Smckusick 
81438259Smckusick 	if (error = getvnode(uap->fd, &fp))
81538259Smckusick 		RETURN (error);
81638259Smckusick 	vattr_null(&vattr);
81738259Smckusick 	vattr.va_flags = uap->flags;
81838259Smckusick 	vp = (struct vnode *)fp->f_data;
81938259Smckusick 	VOP_LOCK(vp);
82038259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
82138259Smckusick 		error = EROFS;
82238259Smckusick 		goto out;
82338259Smckusick 	}
82438259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
82538259Smckusick out:
82638259Smckusick 	VOP_UNLOCK(vp);
82738259Smckusick 	RETURN (error);
82838259Smckusick }
82938259Smckusick 
83038259Smckusick /*
8319167Ssam  * Change mode of a file given path name.
8329167Ssam  */
8336254Sroot chmod()
8345992Swnj {
8357701Ssam 	struct a {
8366254Sroot 		char	*fname;
8376254Sroot 		int	fmode;
83816694Smckusick 	} *uap = (struct a *)u.u_ap;
83937741Smckusick 	register struct nameidata *ndp = &u.u_nd;
84037741Smckusick 	register struct vnode *vp;
84137741Smckusick 	struct vattr vattr;
84237741Smckusick 	int error;
8435992Swnj 
84437741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
84537741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
84637741Smckusick 	ndp->ni_dirp = uap->fname;
84737741Smckusick 	vattr_null(&vattr);
84837741Smckusick 	vattr.va_mode = uap->fmode & 07777;
84937741Smckusick 	if (error = namei(ndp))
85037741Smckusick 		RETURN (error);
85137741Smckusick 	vp = ndp->ni_vp;
85237741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
85337741Smckusick 		error = EROFS;
85437741Smckusick 		goto out;
85537741Smckusick 	}
85637741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
85737741Smckusick out:
85837741Smckusick 	vput(vp);
85937741Smckusick 	RETURN (error);
8607701Ssam }
8617439Sroot 
8629167Ssam /*
8639167Ssam  * Change mode of a file given a file descriptor.
8649167Ssam  */
8657701Ssam fchmod()
8667701Ssam {
8677701Ssam 	struct a {
8687701Ssam 		int	fd;
8697701Ssam 		int	fmode;
87016694Smckusick 	} *uap = (struct a *)u.u_ap;
87137741Smckusick 	struct vattr vattr;
87237741Smckusick 	struct vnode *vp;
87337741Smckusick 	struct file *fp;
87437741Smckusick 	int error;
8757701Ssam 
87637741Smckusick 	if (error = getvnode(uap->fd, &fp))
87737741Smckusick 		RETURN (error);
87837741Smckusick 	vattr_null(&vattr);
87937741Smckusick 	vattr.va_mode = uap->fmode & 07777;
88037741Smckusick 	vp = (struct vnode *)fp->f_data;
88137741Smckusick 	VOP_LOCK(vp);
88237741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
88337741Smckusick 		error = EROFS;
88437741Smckusick 		goto out;
8857439Sroot 	}
88637741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
88737741Smckusick out:
88837741Smckusick 	VOP_UNLOCK(vp);
88937741Smckusick 	RETURN (error);
8905992Swnj }
8915992Swnj 
8929167Ssam /*
8939167Ssam  * Set ownership given a path name.
8949167Ssam  */
8956254Sroot chown()
89637Sbill {
8977701Ssam 	struct a {
8986254Sroot 		char	*fname;
8996254Sroot 		int	uid;
9006254Sroot 		int	gid;
90116694Smckusick 	} *uap = (struct a *)u.u_ap;
90236614Sbostic 	register struct nameidata *ndp = &u.u_nd;
90337741Smckusick 	register struct vnode *vp;
90437741Smckusick 	struct vattr vattr;
90537741Smckusick 	int error;
90637Sbill 
90737741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
90836614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
90936614Sbostic 	ndp->ni_dirp = uap->fname;
91037741Smckusick 	vattr_null(&vattr);
91137741Smckusick 	vattr.va_uid = uap->uid;
91237741Smckusick 	vattr.va_gid = uap->gid;
91337741Smckusick 	if (error = namei(ndp))
91437741Smckusick 		RETURN (error);
91537741Smckusick 	vp = ndp->ni_vp;
91637741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
91737741Smckusick 		error = EROFS;
91837741Smckusick 		goto out;
91937741Smckusick 	}
92037741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
92137741Smckusick out:
92237741Smckusick 	vput(vp);
92337741Smckusick 	RETURN (error);
9247701Ssam }
9257439Sroot 
9269167Ssam /*
9279167Ssam  * Set ownership given a file descriptor.
9289167Ssam  */
9297701Ssam fchown()
9307701Ssam {
9317701Ssam 	struct a {
9327701Ssam 		int	fd;
9337701Ssam 		int	uid;
9347701Ssam 		int	gid;
93516694Smckusick 	} *uap = (struct a *)u.u_ap;
93637741Smckusick 	struct vattr vattr;
93737741Smckusick 	struct vnode *vp;
93837741Smckusick 	struct file *fp;
93937741Smckusick 	int error;
9407701Ssam 
94137741Smckusick 	if (error = getvnode(uap->fd, &fp))
94237741Smckusick 		RETURN (error);
94337741Smckusick 	vattr_null(&vattr);
94437741Smckusick 	vattr.va_uid = uap->uid;
94537741Smckusick 	vattr.va_gid = uap->gid;
94637741Smckusick 	vp = (struct vnode *)fp->f_data;
94737741Smckusick 	VOP_LOCK(vp);
94837741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
94937741Smckusick 		error = EROFS;
95037741Smckusick 		goto out;
95137741Smckusick 	}
95237741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
95337741Smckusick out:
95437741Smckusick 	VOP_UNLOCK(vp);
95537741Smckusick 	RETURN (error);
9567701Ssam }
9577701Ssam 
95811811Ssam utimes()
95911811Ssam {
96011811Ssam 	register struct a {
96111811Ssam 		char	*fname;
96211811Ssam 		struct	timeval *tptr;
96311811Ssam 	} *uap = (struct a *)u.u_ap;
96437741Smckusick 	register struct nameidata *ndp = &u.u_nd;
96537741Smckusick 	register struct vnode *vp;
96611811Ssam 	struct timeval tv[2];
96737741Smckusick 	struct vattr vattr;
96837741Smckusick 	int error;
96911811Ssam 
97037741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
97137741Smckusick 		RETURN (error);
97237741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
97337741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
97437741Smckusick 	ndp->ni_dirp = uap->fname;
97537741Smckusick 	vattr_null(&vattr);
97637741Smckusick 	vattr.va_atime = tv[0];
97737741Smckusick 	vattr.va_mtime = tv[1];
97837741Smckusick 	if (error = namei(ndp))
97937741Smckusick 		RETURN (error);
98037741Smckusick 	vp = ndp->ni_vp;
98137741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
98237741Smckusick 		error = EROFS;
98337741Smckusick 		goto out;
98421015Smckusick 	}
98537741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
98637741Smckusick out:
98737741Smckusick 	vput(vp);
98837741Smckusick 	RETURN (error);
98911811Ssam }
99011811Ssam 
9919167Ssam /*
9929167Ssam  * Truncate a file given its path name.
9939167Ssam  */
9947701Ssam truncate()
9957701Ssam {
9967701Ssam 	struct a {
9977701Ssam 		char	*fname;
99826473Skarels 		off_t	length;
9997826Sroot 	} *uap = (struct a *)u.u_ap;
100016694Smckusick 	register struct nameidata *ndp = &u.u_nd;
100137741Smckusick 	register struct vnode *vp;
100237741Smckusick 	struct vattr vattr;
100337741Smckusick 	int error;
10047701Ssam 
100537741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
100616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
100716694Smckusick 	ndp->ni_dirp = uap->fname;
100837741Smckusick 	vattr_null(&vattr);
100937741Smckusick 	vattr.va_size = uap->length;
101037741Smckusick 	if (error = namei(ndp))
101137741Smckusick 		RETURN (error);
101237741Smckusick 	vp = ndp->ni_vp;
101337741Smckusick 	if (vp->v_type == VDIR) {
101437741Smckusick 		error = EISDIR;
101537741Smckusick 		goto out;
10167701Ssam 	}
1017*38399Smckusick 	if ((error = vn_writechk(vp)) ||
1018*38399Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
101937741Smckusick 		goto out;
102037741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
102137741Smckusick out:
102237741Smckusick 	vput(vp);
102337741Smckusick 	RETURN (error);
10247701Ssam }
10257701Ssam 
10269167Ssam /*
10279167Ssam  * Truncate a file given a file descriptor.
10289167Ssam  */
10297701Ssam ftruncate()
10307701Ssam {
10317701Ssam 	struct a {
10327701Ssam 		int	fd;
103326473Skarels 		off_t	length;
10347826Sroot 	} *uap = (struct a *)u.u_ap;
103537741Smckusick 	struct vattr vattr;
103637741Smckusick 	struct vnode *vp;
10377701Ssam 	struct file *fp;
103837741Smckusick 	int error;
10397701Ssam 
104037741Smckusick 	if (error = getvnode(uap->fd, &fp))
104137741Smckusick 		RETURN (error);
104237741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
104337741Smckusick 		RETURN (EINVAL);
104437741Smckusick 	vattr_null(&vattr);
104537741Smckusick 	vattr.va_size = uap->length;
104637741Smckusick 	vp = (struct vnode *)fp->f_data;
104737741Smckusick 	VOP_LOCK(vp);
104837741Smckusick 	if (vp->v_type == VDIR) {
104937741Smckusick 		error = EISDIR;
105037741Smckusick 		goto out;
10517701Ssam 	}
1052*38399Smckusick 	if (error = vn_writechk(vp))
105337741Smckusick 		goto out;
105437741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
105537741Smckusick out:
105637741Smckusick 	VOP_UNLOCK(vp);
105737741Smckusick 	RETURN (error);
10587701Ssam }
10597701Ssam 
10609167Ssam /*
10619167Ssam  * Synch an open file.
10629167Ssam  */
10639167Ssam fsync()
10649167Ssam {
10659167Ssam 	struct a {
10669167Ssam 		int	fd;
10679167Ssam 	} *uap = (struct a *)u.u_ap;
10689167Ssam 	struct file *fp;
106937741Smckusick 	int error;
10709167Ssam 
107137741Smckusick 	if (error = getvnode(uap->fd, &fp))
107237741Smckusick 		RETURN (error);
107337741Smckusick 	error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred);
107437741Smckusick 	RETURN (error);
10759167Ssam }
10769167Ssam 
10779167Ssam /*
10789167Ssam  * Rename system call.
10799167Ssam  *
10809167Ssam  * Source and destination must either both be directories, or both
10819167Ssam  * not be directories.  If target is a directory, it must be empty.
10829167Ssam  */
10837701Ssam rename()
10847701Ssam {
10857701Ssam 	struct a {
10867701Ssam 		char	*from;
10877701Ssam 		char	*to;
108816694Smckusick 	} *uap = (struct a *)u.u_ap;
108937741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
109016694Smckusick 	register struct nameidata *ndp = &u.u_nd;
109137741Smckusick 	struct nameidata tond;
109237741Smckusick 	int error;
10937701Ssam 
109437741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
109516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
109616694Smckusick 	ndp->ni_dirp = uap->from;
109737741Smckusick 	if (error = namei(ndp))
109837741Smckusick 		RETURN (error);
109937741Smckusick 	fvp = ndp->ni_vp;
110038266Smckusick 	nddup(ndp, &tond);
110137741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
110237741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
110337741Smckusick 	tond.ni_dirp = uap->to;
110437741Smckusick 	error = namei(&tond);
110537741Smckusick 	tdvp = tond.ni_dvp;
110637741Smckusick 	tvp = tond.ni_vp;
110737741Smckusick 	if (tvp != NULL) {
110837741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
110937741Smckusick 			error = EISDIR;
111037741Smckusick 			goto out;
111137741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
111237741Smckusick 			error = ENOTDIR;
111337741Smckusick 			goto out;
11149167Ssam 		}
11159167Ssam 	}
111637741Smckusick 	if (error) {
111737741Smckusick 		VOP_ABORTOP(ndp);
111837741Smckusick 		goto out1;
111937741Smckusick 	}
112037741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
112137741Smckusick 		error = EXDEV;
11229167Ssam 		goto out;
112310051Ssam 	}
112437741Smckusick 	if (fvp == tdvp || fvp == tvp)
112537741Smckusick 		error = EINVAL;
112637741Smckusick out:
112737741Smckusick 	if (error) {
112837741Smckusick 		VOP_ABORTOP(&tond);
112937741Smckusick 		VOP_ABORTOP(ndp);
11309167Ssam 	} else {
113137741Smckusick 		error = VOP_RENAME(ndp, &tond);
11329167Ssam 	}
113337741Smckusick out1:
113438266Smckusick 	ndrele(&tond);
113537741Smckusick 	RETURN (error);
11367701Ssam }
11377701Ssam 
11387535Sroot /*
113912756Ssam  * Mkdir system call
114012756Ssam  */
114112756Ssam mkdir()
114212756Ssam {
114312756Ssam 	struct a {
114412756Ssam 		char	*name;
114512756Ssam 		int	dmode;
114616694Smckusick 	} *uap = (struct a *)u.u_ap;
114716694Smckusick 	register struct nameidata *ndp = &u.u_nd;
114837741Smckusick 	register struct vnode *vp;
114937741Smckusick 	struct vattr vattr;
115037741Smckusick 	int error;
115112756Ssam 
115237741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
115316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
115416694Smckusick 	ndp->ni_dirp = uap->name;
115537741Smckusick 	if (error = namei(ndp))
115637741Smckusick 		RETURN (error);
115737741Smckusick 	vp = ndp->ni_vp;
115837741Smckusick 	if (vp != NULL) {
115937741Smckusick 		VOP_ABORTOP(ndp);
116037741Smckusick 		RETURN (EEXIST);
116112756Ssam 	}
116237741Smckusick 	vattr_null(&vattr);
116337741Smckusick 	vattr.va_type = VDIR;
116437741Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask;
116537741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
116638145Smckusick 	if (!error)
116738145Smckusick 		vput(ndp->ni_vp);
116837741Smckusick 	RETURN (error);
116912756Ssam }
117012756Ssam 
117112756Ssam /*
117212756Ssam  * Rmdir system call.
117312756Ssam  */
117412756Ssam rmdir()
117512756Ssam {
117612756Ssam 	struct a {
117712756Ssam 		char	*name;
117816694Smckusick 	} *uap = (struct a *)u.u_ap;
117916694Smckusick 	register struct nameidata *ndp = &u.u_nd;
118037741Smckusick 	register struct vnode *vp;
118137741Smckusick 	int error;
118212756Ssam 
118337741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
118416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
118516694Smckusick 	ndp->ni_dirp = uap->name;
118637741Smckusick 	if (error = namei(ndp))
118737741Smckusick 		RETURN (error);
118837741Smckusick 	vp = ndp->ni_vp;
118937741Smckusick 	if (vp->v_type != VDIR) {
119037741Smckusick 		error = ENOTDIR;
119112756Ssam 		goto out;
119212756Ssam 	}
119312756Ssam 	/*
119437741Smckusick 	 * No rmdir "." please.
119512756Ssam 	 */
119637741Smckusick 	if (ndp->ni_dvp == vp) {
119737741Smckusick 		error = EINVAL;
119812756Ssam 		goto out;
119912756Ssam 	}
120012756Ssam 	/*
120137741Smckusick 	 * Don't unlink a mounted file.
120212756Ssam 	 */
120337741Smckusick 	if (vp->v_flag & VROOT)
120437741Smckusick 		error = EBUSY;
120512756Ssam out:
120637741Smckusick 	if (error)
120737741Smckusick 		VOP_ABORTOP(ndp);
120837741Smckusick 	else
120937741Smckusick 		error = VOP_RMDIR(ndp);
121037741Smckusick 	RETURN (error);
121112756Ssam }
121212756Ssam 
121337741Smckusick /*
121437741Smckusick  * Read a block of directory entries in a file system independent format
121537741Smckusick  */
121637741Smckusick getdirentries()
121712756Ssam {
121837741Smckusick 	register struct a {
121937741Smckusick 		int	fd;
122037741Smckusick 		char	*buf;
122137741Smckusick 		unsigned count;
122237741Smckusick 		long	*basep;
122337741Smckusick 	} *uap = (struct a *)u.u_ap;
122416540Ssam 	struct file *fp;
122537741Smckusick 	struct uio auio;
122637741Smckusick 	struct iovec aiov;
122738129Smckusick 	off_t off;
122837741Smckusick 	int error;
122912756Ssam 
123037741Smckusick 	if (error = getvnode(uap->fd, &fp))
123137741Smckusick 		RETURN (error);
123237741Smckusick 	if ((fp->f_flag & FREAD) == 0)
123337741Smckusick 		RETURN (EBADF);
123437741Smckusick 	aiov.iov_base = uap->buf;
123537741Smckusick 	aiov.iov_len = uap->count;
123637741Smckusick 	auio.uio_iov = &aiov;
123737741Smckusick 	auio.uio_iovcnt = 1;
123837741Smckusick 	auio.uio_rw = UIO_READ;
123937741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
124037741Smckusick 	auio.uio_resid = uap->count;
124138129Smckusick 	off = fp->f_offset;
124237741Smckusick 	if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio,
124337741Smckusick 	    &(fp->f_offset), fp->f_cred))
124437741Smckusick 		RETURN (error);
124538129Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep,
124637741Smckusick 		sizeof(long));
124737741Smckusick 	u.u_r.r_val1 = uap->count - auio.uio_resid;
124837741Smckusick 	RETURN (error);
124912756Ssam }
125012756Ssam 
125112756Ssam /*
125212756Ssam  * mode mask for creation of files
125312756Ssam  */
125412756Ssam umask()
125512756Ssam {
125612756Ssam 	register struct a {
125712756Ssam 		int	mask;
125816694Smckusick 	} *uap = (struct a *)u.u_ap;
125912756Ssam 
126012756Ssam 	u.u_r.r_val1 = u.u_cmask;
126112756Ssam 	u.u_cmask = uap->mask & 07777;
126237741Smckusick 	RETURN (0);
126312756Ssam }
126437741Smckusick 
126537741Smckusick getvnode(fdes, fpp)
126637741Smckusick 	struct file **fpp;
126737741Smckusick 	int fdes;
126837741Smckusick {
126937741Smckusick 	struct file *fp;
127037741Smckusick 
127137741Smckusick 	if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL)
127237741Smckusick 		return (EBADF);
127337741Smckusick 	if (fp->f_type != DTYPE_VNODE)
127437741Smckusick 		return (EINVAL);
127537741Smckusick 	*fpp = fp;
127637741Smckusick 	return (0);
127737741Smckusick }
1278