xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 38270)
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*38270Smckusick  *	@(#)vfs_syscalls.c	7.12 (Berkeley) 06/08/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 /*
227*38270Smckusick  * get statistics on all filesystems
228*38270Smckusick  */
229*38270Smckusick getfsstat()
230*38270Smckusick {
231*38270Smckusick 	struct a {
232*38270Smckusick 		struct statfs *buf;
233*38270Smckusick 		long bufsize;
234*38270Smckusick 	} *uap = (struct a *)u.u_ap;
235*38270Smckusick 	register struct mount *mp;
236*38270Smckusick 	register struct statfs *sfsp;
237*38270Smckusick 	long count, maxcount, error;
238*38270Smckusick 
239*38270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
240*38270Smckusick 	sfsp = uap->buf;
241*38270Smckusick 	mp = rootfs;
242*38270Smckusick 	count = 0;
243*38270Smckusick 	do {
244*38270Smckusick 		count++;
245*38270Smckusick 		if (sfsp && count <= maxcount) {
246*38270Smckusick 			if (error = VFS_STATFS(mp, sfsp))
247*38270Smckusick 				RETURN (error);
248*38270Smckusick 			sfsp++;
249*38270Smckusick 		}
250*38270Smckusick 		mp = mp->m_prev;
251*38270Smckusick 	} while (mp != rootfs);
252*38270Smckusick 	if (sfsp && count > maxcount)
253*38270Smckusick 		u.u_r.r_val1 = maxcount;
254*38270Smckusick 	else
255*38270Smckusick 		u.u_r.r_val1 = count;
256*38270Smckusick 	RETURN (0);
257*38270Smckusick }
258*38270Smckusick 
259*38270Smckusick /*
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
27838259Smckusick 		error = vn_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
34437741Smckusick 		error = vn_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;
67537741Smckusick 		error = vn_access(vp, mode, u.u_cred);
6766254Sroot 	}
67737741Smckusick 	vput(vp);
67837741Smckusick out1:
6796254Sroot 	u.u_uid = svuid;
6806254Sroot 	u.u_gid = svgid;
68137741Smckusick 	RETURN (error);
6826254Sroot }
6836254Sroot 
6846254Sroot /*
6856574Smckusic  * Stat system call.  This version follows links.
68637Sbill  */
68737Sbill stat()
68837Sbill {
68937Sbill 
69016694Smckusick 	stat1(FOLLOW);
69137Sbill }
69237Sbill 
69337Sbill /*
6946574Smckusic  * Lstat system call.  This version does not follow links.
6955992Swnj  */
6965992Swnj lstat()
6975992Swnj {
69812756Ssam 
69916694Smckusick 	stat1(NOFOLLOW);
70012756Ssam }
70112756Ssam 
70212756Ssam stat1(follow)
70312756Ssam 	int follow;
70412756Ssam {
7055992Swnj 	register struct a {
7065992Swnj 		char	*fname;
70712756Ssam 		struct stat *ub;
70816694Smckusick 	} *uap = (struct a *)u.u_ap;
70937741Smckusick 	register struct nameidata *ndp = &u.u_nd;
71012756Ssam 	struct stat sb;
71137741Smckusick 	int error;
7125992Swnj 
71337741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
71416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
71516694Smckusick 	ndp->ni_dirp = uap->fname;
71637741Smckusick 	if (error = namei(ndp))
71737741Smckusick 		RETURN (error);
71837741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
71937741Smckusick 	vput(ndp->ni_vp);
72037741Smckusick 	if (error)
72137741Smckusick 		RETURN (error);
72237741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
72337741Smckusick 	RETURN (error);
7245992Swnj }
7255992Swnj 
7265992Swnj /*
7275992Swnj  * Return target name of a symbolic link
72837Sbill  */
7295992Swnj readlink()
7305992Swnj {
7315992Swnj 	register struct a {
7325992Swnj 		char	*name;
7335992Swnj 		char	*buf;
7345992Swnj 		int	count;
7357826Sroot 	} *uap = (struct a *)u.u_ap;
73616694Smckusick 	register struct nameidata *ndp = &u.u_nd;
73737741Smckusick 	register struct vnode *vp;
73837741Smckusick 	struct iovec aiov;
73937741Smckusick 	struct uio auio;
74037741Smckusick 	int error;
7415992Swnj 
74237741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
74316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
74416694Smckusick 	ndp->ni_dirp = uap->name;
74537741Smckusick 	if (error = namei(ndp))
74637741Smckusick 		RETURN (error);
74737741Smckusick 	vp = ndp->ni_vp;
74837741Smckusick 	if (vp->v_type != VLNK) {
74937741Smckusick 		error = EINVAL;
7505992Swnj 		goto out;
7515992Swnj 	}
75237741Smckusick 	aiov.iov_base = uap->buf;
75337741Smckusick 	aiov.iov_len = uap->count;
75437741Smckusick 	auio.uio_iov = &aiov;
75537741Smckusick 	auio.uio_iovcnt = 1;
75637741Smckusick 	auio.uio_offset = 0;
75737741Smckusick 	auio.uio_rw = UIO_READ;
75837741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
75937741Smckusick 	auio.uio_resid = uap->count;
76037741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
7615992Swnj out:
76237741Smckusick 	vput(vp);
76337741Smckusick 	u.u_r.r_val1 = uap->count - auio.uio_resid;
76437741Smckusick 	RETURN (error);
7655992Swnj }
7665992Swnj 
7679167Ssam /*
76838259Smckusick  * Change flags of a file given path name.
76938259Smckusick  */
77038259Smckusick chflags()
77138259Smckusick {
77238259Smckusick 	struct a {
77338259Smckusick 		char	*fname;
77438259Smckusick 		int	flags;
77538259Smckusick 	} *uap = (struct a *)u.u_ap;
77638259Smckusick 	register struct nameidata *ndp = &u.u_nd;
77738259Smckusick 	register struct vnode *vp;
77838259Smckusick 	struct vattr vattr;
77938259Smckusick 	int error;
78038259Smckusick 
78138259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
78238259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
78338259Smckusick 	ndp->ni_dirp = uap->fname;
78438259Smckusick 	vattr_null(&vattr);
78538259Smckusick 	vattr.va_flags = uap->flags;
78638259Smckusick 	if (error = namei(ndp))
78738259Smckusick 		RETURN (error);
78838259Smckusick 	vp = ndp->ni_vp;
78938259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
79038259Smckusick 		error = EROFS;
79138259Smckusick 		goto out;
79238259Smckusick 	}
79338259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
79438259Smckusick out:
79538259Smckusick 	vput(vp);
79638259Smckusick 	RETURN (error);
79738259Smckusick }
79838259Smckusick 
79938259Smckusick /*
80038259Smckusick  * Change flags of a file given a file descriptor.
80138259Smckusick  */
80238259Smckusick fchflags()
80338259Smckusick {
80438259Smckusick 	struct a {
80538259Smckusick 		int	fd;
80638259Smckusick 		int	flags;
80738259Smckusick 	} *uap = (struct a *)u.u_ap;
80838259Smckusick 	struct vattr vattr;
80938259Smckusick 	struct vnode *vp;
81038259Smckusick 	struct file *fp;
81138259Smckusick 	int error;
81238259Smckusick 
81338259Smckusick 	if (error = getvnode(uap->fd, &fp))
81438259Smckusick 		RETURN (error);
81538259Smckusick 	vattr_null(&vattr);
81638259Smckusick 	vattr.va_flags = uap->flags;
81738259Smckusick 	vp = (struct vnode *)fp->f_data;
81838259Smckusick 	VOP_LOCK(vp);
81938259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
82038259Smckusick 		error = EROFS;
82138259Smckusick 		goto out;
82238259Smckusick 	}
82338259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
82438259Smckusick out:
82538259Smckusick 	VOP_UNLOCK(vp);
82638259Smckusick 	RETURN (error);
82738259Smckusick }
82838259Smckusick 
82938259Smckusick /*
8309167Ssam  * Change mode of a file given path name.
8319167Ssam  */
8326254Sroot chmod()
8335992Swnj {
8347701Ssam 	struct a {
8356254Sroot 		char	*fname;
8366254Sroot 		int	fmode;
83716694Smckusick 	} *uap = (struct a *)u.u_ap;
83837741Smckusick 	register struct nameidata *ndp = &u.u_nd;
83937741Smckusick 	register struct vnode *vp;
84037741Smckusick 	struct vattr vattr;
84137741Smckusick 	int error;
8425992Swnj 
84337741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
84437741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
84537741Smckusick 	ndp->ni_dirp = uap->fname;
84637741Smckusick 	vattr_null(&vattr);
84737741Smckusick 	vattr.va_mode = uap->fmode & 07777;
84837741Smckusick 	if (error = namei(ndp))
84937741Smckusick 		RETURN (error);
85037741Smckusick 	vp = ndp->ni_vp;
85137741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
85237741Smckusick 		error = EROFS;
85337741Smckusick 		goto out;
85437741Smckusick 	}
85537741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
85637741Smckusick out:
85737741Smckusick 	vput(vp);
85837741Smckusick 	RETURN (error);
8597701Ssam }
8607439Sroot 
8619167Ssam /*
8629167Ssam  * Change mode of a file given a file descriptor.
8639167Ssam  */
8647701Ssam fchmod()
8657701Ssam {
8667701Ssam 	struct a {
8677701Ssam 		int	fd;
8687701Ssam 		int	fmode;
86916694Smckusick 	} *uap = (struct a *)u.u_ap;
87037741Smckusick 	struct vattr vattr;
87137741Smckusick 	struct vnode *vp;
87237741Smckusick 	struct file *fp;
87337741Smckusick 	int error;
8747701Ssam 
87537741Smckusick 	if (error = getvnode(uap->fd, &fp))
87637741Smckusick 		RETURN (error);
87737741Smckusick 	vattr_null(&vattr);
87837741Smckusick 	vattr.va_mode = uap->fmode & 07777;
87937741Smckusick 	vp = (struct vnode *)fp->f_data;
88037741Smckusick 	VOP_LOCK(vp);
88137741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
88237741Smckusick 		error = EROFS;
88337741Smckusick 		goto out;
8847439Sroot 	}
88537741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
88637741Smckusick out:
88737741Smckusick 	VOP_UNLOCK(vp);
88837741Smckusick 	RETURN (error);
8895992Swnj }
8905992Swnj 
8919167Ssam /*
8929167Ssam  * Set ownership given a path name.
8939167Ssam  */
8946254Sroot chown()
89537Sbill {
8967701Ssam 	struct a {
8976254Sroot 		char	*fname;
8986254Sroot 		int	uid;
8996254Sroot 		int	gid;
90016694Smckusick 	} *uap = (struct a *)u.u_ap;
90136614Sbostic 	register struct nameidata *ndp = &u.u_nd;
90237741Smckusick 	register struct vnode *vp;
90337741Smckusick 	struct vattr vattr;
90437741Smckusick 	int error;
90537Sbill 
90637741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
90736614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
90836614Sbostic 	ndp->ni_dirp = uap->fname;
90937741Smckusick 	vattr_null(&vattr);
91037741Smckusick 	vattr.va_uid = uap->uid;
91137741Smckusick 	vattr.va_gid = uap->gid;
91237741Smckusick 	if (error = namei(ndp))
91337741Smckusick 		RETURN (error);
91437741Smckusick 	vp = ndp->ni_vp;
91537741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
91637741Smckusick 		error = EROFS;
91737741Smckusick 		goto out;
91837741Smckusick 	}
91937741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
92037741Smckusick out:
92137741Smckusick 	vput(vp);
92237741Smckusick 	RETURN (error);
9237701Ssam }
9247439Sroot 
9259167Ssam /*
9269167Ssam  * Set ownership given a file descriptor.
9279167Ssam  */
9287701Ssam fchown()
9297701Ssam {
9307701Ssam 	struct a {
9317701Ssam 		int	fd;
9327701Ssam 		int	uid;
9337701Ssam 		int	gid;
93416694Smckusick 	} *uap = (struct a *)u.u_ap;
93537741Smckusick 	struct vattr vattr;
93637741Smckusick 	struct vnode *vp;
93737741Smckusick 	struct file *fp;
93837741Smckusick 	int error;
9397701Ssam 
94037741Smckusick 	if (error = getvnode(uap->fd, &fp))
94137741Smckusick 		RETURN (error);
94237741Smckusick 	vattr_null(&vattr);
94337741Smckusick 	vattr.va_uid = uap->uid;
94437741Smckusick 	vattr.va_gid = uap->gid;
94537741Smckusick 	vp = (struct vnode *)fp->f_data;
94637741Smckusick 	VOP_LOCK(vp);
94737741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
94837741Smckusick 		error = EROFS;
94937741Smckusick 		goto out;
95037741Smckusick 	}
95137741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
95237741Smckusick out:
95337741Smckusick 	VOP_UNLOCK(vp);
95437741Smckusick 	RETURN (error);
9557701Ssam }
9567701Ssam 
95711811Ssam utimes()
95811811Ssam {
95911811Ssam 	register struct a {
96011811Ssam 		char	*fname;
96111811Ssam 		struct	timeval *tptr;
96211811Ssam 	} *uap = (struct a *)u.u_ap;
96337741Smckusick 	register struct nameidata *ndp = &u.u_nd;
96437741Smckusick 	register struct vnode *vp;
96511811Ssam 	struct timeval tv[2];
96637741Smckusick 	struct vattr vattr;
96737741Smckusick 	int error;
96811811Ssam 
96937741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
97037741Smckusick 		RETURN (error);
97137741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
97237741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
97337741Smckusick 	ndp->ni_dirp = uap->fname;
97437741Smckusick 	vattr_null(&vattr);
97537741Smckusick 	vattr.va_atime = tv[0];
97637741Smckusick 	vattr.va_mtime = tv[1];
97737741Smckusick 	if (error = namei(ndp))
97837741Smckusick 		RETURN (error);
97937741Smckusick 	vp = ndp->ni_vp;
98037741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
98137741Smckusick 		error = EROFS;
98237741Smckusick 		goto out;
98321015Smckusick 	}
98437741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
98537741Smckusick out:
98637741Smckusick 	vput(vp);
98737741Smckusick 	RETURN (error);
98811811Ssam }
98911811Ssam 
9909167Ssam /*
9919167Ssam  * Truncate a file given its path name.
9929167Ssam  */
9937701Ssam truncate()
9947701Ssam {
9957701Ssam 	struct a {
9967701Ssam 		char	*fname;
99726473Skarels 		off_t	length;
9987826Sroot 	} *uap = (struct a *)u.u_ap;
99916694Smckusick 	register struct nameidata *ndp = &u.u_nd;
100037741Smckusick 	register struct vnode *vp;
100137741Smckusick 	struct vattr vattr;
100237741Smckusick 	int error;
10037701Ssam 
100437741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
100516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
100616694Smckusick 	ndp->ni_dirp = uap->fname;
100737741Smckusick 	vattr_null(&vattr);
100837741Smckusick 	vattr.va_size = uap->length;
100937741Smckusick 	if (error = namei(ndp))
101037741Smckusick 		RETURN (error);
101137741Smckusick 	vp = ndp->ni_vp;
101237741Smckusick 	if (vp->v_type == VDIR) {
101337741Smckusick 		error = EISDIR;
101437741Smckusick 		goto out;
10157701Ssam 	}
101637741Smckusick 	if (error = vn_access(vp, VWRITE, ndp->ni_cred))
101737741Smckusick 		goto out;
101837741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
101937741Smckusick out:
102037741Smckusick 	vput(vp);
102137741Smckusick 	RETURN (error);
10227701Ssam }
10237701Ssam 
10249167Ssam /*
10259167Ssam  * Truncate a file given a file descriptor.
10269167Ssam  */
10277701Ssam ftruncate()
10287701Ssam {
10297701Ssam 	struct a {
10307701Ssam 		int	fd;
103126473Skarels 		off_t	length;
10327826Sroot 	} *uap = (struct a *)u.u_ap;
103337741Smckusick 	struct vattr vattr;
103437741Smckusick 	struct vnode *vp;
10357701Ssam 	struct file *fp;
103637741Smckusick 	int error;
10377701Ssam 
103837741Smckusick 	if (error = getvnode(uap->fd, &fp))
103937741Smckusick 		RETURN (error);
104037741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
104137741Smckusick 		RETURN (EINVAL);
104237741Smckusick 	vattr_null(&vattr);
104337741Smckusick 	vattr.va_size = uap->length;
104437741Smckusick 	vp = (struct vnode *)fp->f_data;
104537741Smckusick 	VOP_LOCK(vp);
104637741Smckusick 	if (vp->v_type == VDIR) {
104737741Smckusick 		error = EISDIR;
104837741Smckusick 		goto out;
10497701Ssam 	}
105037741Smckusick 	if (error = vn_access(vp, VWRITE, fp->f_cred))
105137741Smckusick 		goto out;
105237741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
105337741Smckusick out:
105437741Smckusick 	VOP_UNLOCK(vp);
105537741Smckusick 	RETURN (error);
10567701Ssam }
10577701Ssam 
10589167Ssam /*
10599167Ssam  * Synch an open file.
10609167Ssam  */
10619167Ssam fsync()
10629167Ssam {
10639167Ssam 	struct a {
10649167Ssam 		int	fd;
10659167Ssam 	} *uap = (struct a *)u.u_ap;
10669167Ssam 	struct file *fp;
106737741Smckusick 	int error;
10689167Ssam 
106937741Smckusick 	if (error = getvnode(uap->fd, &fp))
107037741Smckusick 		RETURN (error);
107137741Smckusick 	error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred);
107237741Smckusick 	RETURN (error);
10739167Ssam }
10749167Ssam 
10759167Ssam /*
10769167Ssam  * Rename system call.
10779167Ssam  *
10789167Ssam  * Source and destination must either both be directories, or both
10799167Ssam  * not be directories.  If target is a directory, it must be empty.
10809167Ssam  */
10817701Ssam rename()
10827701Ssam {
10837701Ssam 	struct a {
10847701Ssam 		char	*from;
10857701Ssam 		char	*to;
108616694Smckusick 	} *uap = (struct a *)u.u_ap;
108737741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
108816694Smckusick 	register struct nameidata *ndp = &u.u_nd;
108937741Smckusick 	struct nameidata tond;
109037741Smckusick 	int error;
10917701Ssam 
109237741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
109316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
109416694Smckusick 	ndp->ni_dirp = uap->from;
109537741Smckusick 	if (error = namei(ndp))
109637741Smckusick 		RETURN (error);
109737741Smckusick 	fvp = ndp->ni_vp;
109838266Smckusick 	nddup(ndp, &tond);
109937741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
110037741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
110137741Smckusick 	tond.ni_dirp = uap->to;
110237741Smckusick 	error = namei(&tond);
110337741Smckusick 	tdvp = tond.ni_dvp;
110437741Smckusick 	tvp = tond.ni_vp;
110537741Smckusick 	if (tvp != NULL) {
110637741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
110737741Smckusick 			error = EISDIR;
110837741Smckusick 			goto out;
110937741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
111037741Smckusick 			error = ENOTDIR;
111137741Smckusick 			goto out;
11129167Ssam 		}
11139167Ssam 	}
111437741Smckusick 	if (error) {
111537741Smckusick 		VOP_ABORTOP(ndp);
111637741Smckusick 		goto out1;
111737741Smckusick 	}
111837741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
111937741Smckusick 		error = EXDEV;
11209167Ssam 		goto out;
112110051Ssam 	}
112237741Smckusick 	if (fvp == tdvp || fvp == tvp)
112337741Smckusick 		error = EINVAL;
112437741Smckusick out:
112537741Smckusick 	if (error) {
112637741Smckusick 		VOP_ABORTOP(&tond);
112737741Smckusick 		VOP_ABORTOP(ndp);
11289167Ssam 	} else {
112937741Smckusick 		error = VOP_RENAME(ndp, &tond);
11309167Ssam 	}
113137741Smckusick out1:
113238266Smckusick 	ndrele(&tond);
113337741Smckusick 	RETURN (error);
11347701Ssam }
11357701Ssam 
11367535Sroot /*
113712756Ssam  * Mkdir system call
113812756Ssam  */
113912756Ssam mkdir()
114012756Ssam {
114112756Ssam 	struct a {
114212756Ssam 		char	*name;
114312756Ssam 		int	dmode;
114416694Smckusick 	} *uap = (struct a *)u.u_ap;
114516694Smckusick 	register struct nameidata *ndp = &u.u_nd;
114637741Smckusick 	register struct vnode *vp;
114737741Smckusick 	struct vattr vattr;
114837741Smckusick 	int error;
114912756Ssam 
115037741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
115116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
115216694Smckusick 	ndp->ni_dirp = uap->name;
115337741Smckusick 	if (error = namei(ndp))
115437741Smckusick 		RETURN (error);
115537741Smckusick 	vp = ndp->ni_vp;
115637741Smckusick 	if (vp != NULL) {
115737741Smckusick 		VOP_ABORTOP(ndp);
115837741Smckusick 		RETURN (EEXIST);
115912756Ssam 	}
116037741Smckusick 	vattr_null(&vattr);
116137741Smckusick 	vattr.va_type = VDIR;
116237741Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask;
116337741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
116438145Smckusick 	if (!error)
116538145Smckusick 		vput(ndp->ni_vp);
116637741Smckusick 	RETURN (error);
116712756Ssam }
116812756Ssam 
116912756Ssam /*
117012756Ssam  * Rmdir system call.
117112756Ssam  */
117212756Ssam rmdir()
117312756Ssam {
117412756Ssam 	struct a {
117512756Ssam 		char	*name;
117616694Smckusick 	} *uap = (struct a *)u.u_ap;
117716694Smckusick 	register struct nameidata *ndp = &u.u_nd;
117837741Smckusick 	register struct vnode *vp;
117937741Smckusick 	int error;
118012756Ssam 
118137741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
118216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
118316694Smckusick 	ndp->ni_dirp = uap->name;
118437741Smckusick 	if (error = namei(ndp))
118537741Smckusick 		RETURN (error);
118637741Smckusick 	vp = ndp->ni_vp;
118737741Smckusick 	if (vp->v_type != VDIR) {
118837741Smckusick 		error = ENOTDIR;
118912756Ssam 		goto out;
119012756Ssam 	}
119112756Ssam 	/*
119237741Smckusick 	 * No rmdir "." please.
119312756Ssam 	 */
119437741Smckusick 	if (ndp->ni_dvp == vp) {
119537741Smckusick 		error = EINVAL;
119612756Ssam 		goto out;
119712756Ssam 	}
119812756Ssam 	/*
119937741Smckusick 	 * Don't unlink a mounted file.
120012756Ssam 	 */
120137741Smckusick 	if (vp->v_flag & VROOT)
120237741Smckusick 		error = EBUSY;
120312756Ssam out:
120437741Smckusick 	if (error)
120537741Smckusick 		VOP_ABORTOP(ndp);
120637741Smckusick 	else
120737741Smckusick 		error = VOP_RMDIR(ndp);
120837741Smckusick 	RETURN (error);
120912756Ssam }
121012756Ssam 
121137741Smckusick /*
121237741Smckusick  * Read a block of directory entries in a file system independent format
121337741Smckusick  */
121437741Smckusick getdirentries()
121512756Ssam {
121637741Smckusick 	register struct a {
121737741Smckusick 		int	fd;
121837741Smckusick 		char	*buf;
121937741Smckusick 		unsigned count;
122037741Smckusick 		long	*basep;
122137741Smckusick 	} *uap = (struct a *)u.u_ap;
122216540Ssam 	struct file *fp;
122337741Smckusick 	struct uio auio;
122437741Smckusick 	struct iovec aiov;
122538129Smckusick 	off_t off;
122637741Smckusick 	int error;
122712756Ssam 
122837741Smckusick 	if (error = getvnode(uap->fd, &fp))
122937741Smckusick 		RETURN (error);
123037741Smckusick 	if ((fp->f_flag & FREAD) == 0)
123137741Smckusick 		RETURN (EBADF);
123237741Smckusick 	aiov.iov_base = uap->buf;
123337741Smckusick 	aiov.iov_len = uap->count;
123437741Smckusick 	auio.uio_iov = &aiov;
123537741Smckusick 	auio.uio_iovcnt = 1;
123637741Smckusick 	auio.uio_rw = UIO_READ;
123737741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
123837741Smckusick 	auio.uio_resid = uap->count;
123938129Smckusick 	off = fp->f_offset;
124037741Smckusick 	if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio,
124137741Smckusick 	    &(fp->f_offset), fp->f_cred))
124237741Smckusick 		RETURN (error);
124338129Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep,
124437741Smckusick 		sizeof(long));
124537741Smckusick 	u.u_r.r_val1 = uap->count - auio.uio_resid;
124637741Smckusick 	RETURN (error);
124712756Ssam }
124812756Ssam 
124912756Ssam /*
125012756Ssam  * mode mask for creation of files
125112756Ssam  */
125212756Ssam umask()
125312756Ssam {
125412756Ssam 	register struct a {
125512756Ssam 		int	mask;
125616694Smckusick 	} *uap = (struct a *)u.u_ap;
125712756Ssam 
125812756Ssam 	u.u_r.r_val1 = u.u_cmask;
125912756Ssam 	u.u_cmask = uap->mask & 07777;
126037741Smckusick 	RETURN (0);
126112756Ssam }
126237741Smckusick 
126337741Smckusick getvnode(fdes, fpp)
126437741Smckusick 	struct file **fpp;
126537741Smckusick 	int fdes;
126637741Smckusick {
126737741Smckusick 	struct file *fp;
126837741Smckusick 
126937741Smckusick 	if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL)
127037741Smckusick 		return (EBADF);
127137741Smckusick 	if (fp->f_type != DTYPE_VNODE)
127237741Smckusick 		return (EINVAL);
127337741Smckusick 	*fpp = fp;
127437741Smckusick 	return (0);
127537741Smckusick }
1276