xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 38266)
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*38266Smckusick  *	@(#)vfs_syscalls.c	7.11 (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 /*
22738259Smckusick  * Change current working directory to a given file descriptor.
22838259Smckusick  */
22938259Smckusick fchdir()
23038259Smckusick {
23138259Smckusick 	struct a {
23238259Smckusick 		int	fd;
23338259Smckusick 	} *uap = (struct a *)u.u_ap;
23438259Smckusick 	register struct vnode *vp;
23538259Smckusick 	struct file *fp;
23638259Smckusick 	int error;
23738259Smckusick 
23838259Smckusick 	if (error = getvnode(uap->fd, &fp))
23938259Smckusick 		RETURN (error);
24038259Smckusick 	vp = (struct vnode *)fp->f_data;
24138259Smckusick 	VOP_LOCK(vp);
24238259Smckusick 	if (vp->v_type != VDIR)
24338259Smckusick 		error = ENOTDIR;
24438259Smckusick 	else
24538259Smckusick 		error = vn_access(vp, VEXEC, u.u_cred);
24638259Smckusick 	VOP_UNLOCK(vp);
24738259Smckusick 	vrele(u.u_cdir);
24838259Smckusick 	u.u_cdir = vp;
24938259Smckusick 	RETURN (error);
25038259Smckusick }
25138259Smckusick 
25238259Smckusick /*
25337741Smckusick  * Change current working directory (``.'').
25437741Smckusick  */
25537741Smckusick chdir()
25637741Smckusick {
25737741Smckusick 	struct a {
2586254Sroot 		char	*fname;
25916694Smckusick 	} *uap = (struct a *)u.u_ap;
26016694Smckusick 	register struct nameidata *ndp = &u.u_nd;
26137741Smckusick 	int error;
2626254Sroot 
26337741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
26416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
26516694Smckusick 	ndp->ni_dirp = uap->fname;
26637741Smckusick 	if (error = chdirec(ndp))
26737741Smckusick 		RETURN (error);
26837741Smckusick 	vrele(u.u_cdir);
26937741Smckusick 	u.u_cdir = ndp->ni_vp;
27037741Smckusick 	RETURN (0);
27137741Smckusick }
2726254Sroot 
27337741Smckusick /*
27437741Smckusick  * Change notion of root (``/'') directory.
27537741Smckusick  */
27637741Smckusick chroot()
27737741Smckusick {
27837741Smckusick 	struct a {
27937741Smckusick 		char	*fname;
28037741Smckusick 	} *uap = (struct a *)u.u_ap;
28137741Smckusick 	register struct nameidata *ndp = &u.u_nd;
28237741Smckusick 	int error;
28337741Smckusick 
28437741Smckusick 	if (error = suser(u.u_cred, &u.u_acflag))
28537741Smckusick 		RETURN (error);
28637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
28737741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
28837741Smckusick 	ndp->ni_dirp = uap->fname;
28937741Smckusick 	if (error = chdirec(ndp))
29037741Smckusick 		RETURN (error);
29137741Smckusick 	vrele(u.u_rdir);
29237741Smckusick 	u.u_rdir = ndp->ni_vp;
29337741Smckusick 	RETURN (0);
2946254Sroot }
2956254Sroot 
29637Sbill /*
29737741Smckusick  * Common routine for chroot and chdir.
29837741Smckusick  */
29937741Smckusick chdirec(ndp)
30037741Smckusick 	register struct nameidata *ndp;
30137741Smckusick {
30237741Smckusick 	struct vnode *vp;
30337741Smckusick 	int error;
30437741Smckusick 
30537741Smckusick 	if (error = namei(ndp))
30637741Smckusick 		return (error);
30737741Smckusick 	vp = ndp->ni_vp;
30837741Smckusick 	if (vp->v_type != VDIR)
30937741Smckusick 		error = ENOTDIR;
31037741Smckusick 	else
31137741Smckusick 		error = vn_access(vp, VEXEC, ndp->ni_cred);
31237741Smckusick 	VOP_UNLOCK(vp);
31337741Smckusick 	if (error)
31437741Smckusick 		vrele(vp);
31537741Smckusick 	return (error);
31637741Smckusick }
31737741Smckusick 
31837741Smckusick /*
3196254Sroot  * Open system call.
3206254Sroot  */
3216254Sroot open()
3226254Sroot {
32312756Ssam 	struct a {
3246254Sroot 		char	*fname;
3257701Ssam 		int	mode;
32612756Ssam 		int	crtmode;
32712756Ssam 	} *uap = (struct a *) u.u_ap;
32837741Smckusick 	struct nameidata *ndp = &u.u_nd;
3296254Sroot 
33037741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
33137741Smckusick 	ndp->ni_dirp = uap->fname;
33237741Smckusick 	RETURN (copen(uap->mode-FOPEN, uap->crtmode &~ u.u_cmask, ndp,
33337741Smckusick 		&u.u_r.r_val1));
3346254Sroot }
3356254Sroot 
3366254Sroot /*
3376254Sroot  * Creat system call.
3386254Sroot  */
33912756Ssam creat()
3406254Sroot {
34112756Ssam 	struct a {
3426254Sroot 		char	*fname;
3436254Sroot 		int	fmode;
34412756Ssam 	} *uap = (struct a *)u.u_ap;
34537741Smckusick 	struct nameidata *ndp = &u.u_nd;
3466254Sroot 
34737741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
34837741Smckusick 	ndp->ni_dirp = uap->fname;
34937741Smckusick 	RETURN (copen(FWRITE|FCREAT|FTRUNC, uap->fmode &~ u.u_cmask, ndp,
35037741Smckusick 		&u.u_r.r_val1));
3516254Sroot }
3526254Sroot 
3536254Sroot /*
3546254Sroot  * Common code for open and creat.
35512756Ssam  * Check permissions, allocate an open file structure,
35612756Ssam  * and call the device open routine if any.
3576254Sroot  */
35837741Smckusick copen(fmode, cmode, ndp, resultfd)
35937741Smckusick 	int fmode, cmode;
36037741Smckusick 	struct nameidata *ndp;
36137741Smckusick 	int *resultfd;
36212756Ssam {
3636254Sroot 	register struct file *fp;
36437741Smckusick 	struct file *nfp;
36537741Smckusick 	int indx, error;
36637741Smckusick 	extern struct fileops vnops;
3676254Sroot 
36837741Smckusick 	if (error = falloc(&nfp, &indx))
36937741Smckusick 		return (error);
37037741Smckusick 	fp = nfp;
37137741Smckusick 	u.u_r.r_val1 = indx;	/* XXX for fdopen() */
37237741Smckusick 	if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) {
37324543Smckusick 		u.u_ofile[indx] = NULL;
37437741Smckusick 		crfree(fp->f_cred);
37537741Smckusick 		fp->f_count--;
37637741Smckusick 		return (error);
37712756Ssam 	}
37837741Smckusick 	fp->f_flag = fmode & FMASK;
37937741Smckusick 	fp->f_type = DTYPE_VNODE;
38037741Smckusick 	fp->f_ops = &vnops;
38137741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
38237741Smckusick 	if (resultfd)
38337741Smckusick 		*resultfd = indx;
38437741Smckusick 	return (0);
3856254Sroot }
3866254Sroot 
3876254Sroot /*
3886254Sroot  * Mknod system call
3896254Sroot  */
3906254Sroot mknod()
3916254Sroot {
3926254Sroot 	register struct a {
3936254Sroot 		char	*fname;
3946254Sroot 		int	fmode;
3956254Sroot 		int	dev;
39616694Smckusick 	} *uap = (struct a *)u.u_ap;
39716694Smckusick 	register struct nameidata *ndp = &u.u_nd;
39837741Smckusick 	register struct vnode *vp;
39937741Smckusick 	struct vattr vattr;
40037741Smckusick 	int error;
4016254Sroot 
40237741Smckusick 	if (error = suser(u.u_cred, &u.u_acflag))
40337741Smckusick 		RETURN (error);
40437741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
40516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
40616694Smckusick 	ndp->ni_dirp = uap->fname;
40737741Smckusick 	if (error = namei(ndp))
40837741Smckusick 		RETURN (error);
40937741Smckusick 	vp = ndp->ni_vp;
41037741Smckusick 	if (vp != NULL) {
41137741Smckusick 		error = EEXIST;
41212756Ssam 		goto out;
4136254Sroot 	}
41437741Smckusick 	vattr_null(&vattr);
41537741Smckusick 	switch (uap->fmode & IFMT) {
41612756Ssam 
41715093Smckusick 	case IFMT:	/* used by badsect to flag bad sectors */
41837741Smckusick 		vattr.va_type = VBAD;
41937741Smckusick 		break;
42012756Ssam 	case IFCHR:
42137741Smckusick 		vattr.va_type = VCHR;
42237741Smckusick 		break;
42312756Ssam 	case IFBLK:
42437741Smckusick 		vattr.va_type = VBLK;
42537741Smckusick 		break;
42637741Smckusick 	default:
42737741Smckusick 		error = EINVAL;
42837741Smckusick 		goto out;
4296254Sroot 	}
43037741Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask;
43137741Smckusick 	vattr.va_rdev = uap->dev;
4326254Sroot out:
43337741Smckusick 	if (error)
43437741Smckusick 		VOP_ABORTOP(ndp);
43537741Smckusick 	else
43637741Smckusick 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
43737741Smckusick 	RETURN (error);
4386254Sroot }
4396254Sroot 
4406254Sroot /*
4416254Sroot  * link system call
4426254Sroot  */
4436254Sroot link()
4446254Sroot {
4456254Sroot 	register struct a {
4466254Sroot 		char	*target;
4476254Sroot 		char	*linkname;
44816694Smckusick 	} *uap = (struct a *)u.u_ap;
44916694Smckusick 	register struct nameidata *ndp = &u.u_nd;
45037741Smckusick 	register struct vnode *vp, *xp;
45137741Smckusick 	int error;
4526254Sroot 
45316694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
45416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
45516694Smckusick 	ndp->ni_dirp = uap->target;
45637741Smckusick 	if (error = namei(ndp))
45737741Smckusick 		RETURN (error);
45837741Smckusick 	vp = ndp->ni_vp;
45937741Smckusick 	if (vp->v_type == VDIR &&
46037741Smckusick 	    (error = suser(u.u_cred, &u.u_acflag)))
46137741Smckusick 		goto out1;
46237741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
46316694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
46437741Smckusick 	if (error = namei(ndp))
46537741Smckusick 		goto out1;
46637741Smckusick 	xp = ndp->ni_vp;
4676254Sroot 	if (xp != NULL) {
46837741Smckusick 		error = EEXIST;
4696254Sroot 		goto out;
4706254Sroot 	}
47137741Smckusick 	xp = ndp->ni_dvp;
47237741Smckusick 	if (vp->v_mount != xp->v_mount)
47337741Smckusick 		error = EXDEV;
4746254Sroot out:
47537741Smckusick 	if (error)
47637741Smckusick 		VOP_ABORTOP(ndp);
47737741Smckusick 	else
47837741Smckusick 		error = VOP_LINK(vp, ndp);
47937741Smckusick out1:
48037741Smckusick 	vrele(vp);
48137741Smckusick 	RETURN (error);
4826254Sroot }
4836254Sroot 
4846254Sroot /*
4856254Sroot  * symlink -- make a symbolic link
4866254Sroot  */
4876254Sroot symlink()
4886254Sroot {
48937741Smckusick 	struct a {
4906254Sroot 		char	*target;
4916254Sroot 		char	*linkname;
49216694Smckusick 	} *uap = (struct a *)u.u_ap;
49316694Smckusick 	register struct nameidata *ndp = &u.u_nd;
49437741Smckusick 	register struct vnode *vp;
49537741Smckusick 	struct vattr vattr;
49637741Smckusick 	char *target;
49737741Smckusick 	int error;
4986254Sroot 
49916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
50016694Smckusick 	ndp->ni_dirp = uap->linkname;
50137741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
50237741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
50337741Smckusick 		goto out1;
50437741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
50537741Smckusick 	if (error = namei(ndp))
50637741Smckusick 		goto out1;
50737741Smckusick 	vp = ndp->ni_vp;
50837741Smckusick 	if (vp) {
50937741Smckusick 		error = EEXIST;
51037741Smckusick 		goto out;
5116254Sroot 	}
51237741Smckusick 	vp = ndp->ni_dvp;
51337741Smckusick 	vattr_null(&vattr);
51437741Smckusick 	vattr.va_mode = 0777 &~ u.u_cmask;
51537741Smckusick out:
51637741Smckusick 	if (error)
51737741Smckusick 		VOP_ABORTOP(ndp);
51837741Smckusick 	else
51937741Smckusick 		error = VOP_SYMLINK(ndp, &vattr, target);
52037741Smckusick out1:
52137741Smckusick 	FREE(target, M_NAMEI);
52237741Smckusick 	RETURN (error);
5236254Sroot }
5246254Sroot 
5256254Sroot /*
5266254Sroot  * Unlink system call.
5276254Sroot  * Hard to avoid races here, especially
5286254Sroot  * in unlinking directories.
5296254Sroot  */
5306254Sroot unlink()
5316254Sroot {
5326254Sroot 	struct a {
5336254Sroot 		char	*fname;
53416694Smckusick 	} *uap = (struct a *)u.u_ap;
53516694Smckusick 	register struct nameidata *ndp = &u.u_nd;
53637741Smckusick 	register struct vnode *vp;
53737741Smckusick 	int error;
5386254Sroot 
53937741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
54016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
54116694Smckusick 	ndp->ni_dirp = uap->fname;
54237741Smckusick 	if (error = namei(ndp))
54337741Smckusick 		RETURN (error);
54437741Smckusick 	vp = ndp->ni_vp;
54537741Smckusick 	if (vp->v_type == VDIR &&
54637741Smckusick 	    (error = suser(u.u_cred, &u.u_acflag)))
5476254Sroot 		goto out;
5486254Sroot 	/*
5496254Sroot 	 * Don't unlink a mounted file.
5506254Sroot 	 */
55137741Smckusick 	if (vp->v_flag & VROOT) {
55237741Smckusick 		error = EBUSY;
5536254Sroot 		goto out;
5546254Sroot 	}
55537741Smckusick 	if (vp->v_flag & VTEXT)
55637741Smckusick 		xrele(vp);	/* try once to free text */
5576254Sroot out:
55837741Smckusick 	if (error)
55937741Smckusick 		VOP_ABORTOP(ndp);
5607142Smckusick 	else
56137741Smckusick 		error = VOP_REMOVE(ndp);
56237741Smckusick 	RETURN (error);
5636254Sroot }
5646254Sroot 
5656254Sroot /*
5666254Sroot  * Seek system call
5676254Sroot  */
5688040Sroot lseek()
5696254Sroot {
5706254Sroot 	register struct file *fp;
5716254Sroot 	register struct a {
57237741Smckusick 		int	fdes;
5736254Sroot 		off_t	off;
5746254Sroot 		int	sbase;
57516694Smckusick 	} *uap = (struct a *)u.u_ap;
57637741Smckusick 	struct vattr vattr;
57737741Smckusick 	int error;
5786254Sroot 
57937741Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
58037741Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
58137741Smckusick 		RETURN (EBADF);
58237741Smckusick 	if (fp->f_type != DTYPE_VNODE)
58337741Smckusick 		RETURN (ESPIPE);
58413878Ssam 	switch (uap->sbase) {
58513878Ssam 
58613878Ssam 	case L_INCR:
58713878Ssam 		fp->f_offset += uap->off;
58813878Ssam 		break;
58913878Ssam 
59013878Ssam 	case L_XTND:
59137741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
59237741Smckusick 		    &vattr, u.u_cred))
59337741Smckusick 			RETURN (error);
59437741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
59513878Ssam 		break;
59613878Ssam 
59713878Ssam 	case L_SET:
59813878Ssam 		fp->f_offset = uap->off;
59913878Ssam 		break;
60013878Ssam 
60113878Ssam 	default:
60237741Smckusick 		RETURN (EINVAL);
60313878Ssam 	}
60413878Ssam 	u.u_r.r_off = fp->f_offset;
60537741Smckusick 	RETURN (0);
6066254Sroot }
6076254Sroot 
6086254Sroot /*
6096254Sroot  * Access system call
6106254Sroot  */
6116254Sroot saccess()
6126254Sroot {
6136254Sroot 	register struct a {
6146254Sroot 		char	*fname;
6156254Sroot 		int	fmode;
61616694Smckusick 	} *uap = (struct a *)u.u_ap;
61716694Smckusick 	register struct nameidata *ndp = &u.u_nd;
61837741Smckusick 	register struct vnode *vp;
61937741Smckusick 	int error, mode, svuid, svgid;
6206254Sroot 
6216254Sroot 	svuid = u.u_uid;
6226254Sroot 	svgid = u.u_gid;
6236254Sroot 	u.u_uid = u.u_ruid;
6246254Sroot 	u.u_gid = u.u_rgid;
62537741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
62616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
62716694Smckusick 	ndp->ni_dirp = uap->fname;
62837741Smckusick 	if (error = namei(ndp))
62937741Smckusick 		goto out1;
63037741Smckusick 	vp = ndp->ni_vp;
63137741Smckusick 	/*
63237741Smckusick 	 * fmode == 0 means only check for exist
63337741Smckusick 	 */
63437741Smckusick 	if (uap->fmode) {
63537741Smckusick 		mode = 0;
63637741Smckusick 		if (uap->fmode & R_OK)
63737741Smckusick 			mode |= VREAD;
63837741Smckusick 		if (uap->fmode & W_OK)
63937741Smckusick 			mode |= VWRITE;
64037741Smckusick 		if (uap->fmode & X_OK)
64137741Smckusick 			mode |= VEXEC;
64237741Smckusick 		error = vn_access(vp, mode, u.u_cred);
6436254Sroot 	}
64437741Smckusick 	vput(vp);
64537741Smckusick out1:
6466254Sroot 	u.u_uid = svuid;
6476254Sroot 	u.u_gid = svgid;
64837741Smckusick 	RETURN (error);
6496254Sroot }
6506254Sroot 
6516254Sroot /*
6526574Smckusic  * Stat system call.  This version follows links.
65337Sbill  */
65437Sbill stat()
65537Sbill {
65637Sbill 
65716694Smckusick 	stat1(FOLLOW);
65837Sbill }
65937Sbill 
66037Sbill /*
6616574Smckusic  * Lstat system call.  This version does not follow links.
6625992Swnj  */
6635992Swnj lstat()
6645992Swnj {
66512756Ssam 
66616694Smckusick 	stat1(NOFOLLOW);
66712756Ssam }
66812756Ssam 
66912756Ssam stat1(follow)
67012756Ssam 	int follow;
67112756Ssam {
6725992Swnj 	register struct a {
6735992Swnj 		char	*fname;
67412756Ssam 		struct stat *ub;
67516694Smckusick 	} *uap = (struct a *)u.u_ap;
67637741Smckusick 	register struct nameidata *ndp = &u.u_nd;
67712756Ssam 	struct stat sb;
67837741Smckusick 	int error;
6795992Swnj 
68037741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
68116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
68216694Smckusick 	ndp->ni_dirp = uap->fname;
68337741Smckusick 	if (error = namei(ndp))
68437741Smckusick 		RETURN (error);
68537741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
68637741Smckusick 	vput(ndp->ni_vp);
68737741Smckusick 	if (error)
68837741Smckusick 		RETURN (error);
68937741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
69037741Smckusick 	RETURN (error);
6915992Swnj }
6925992Swnj 
6935992Swnj /*
6945992Swnj  * Return target name of a symbolic link
69537Sbill  */
6965992Swnj readlink()
6975992Swnj {
6985992Swnj 	register struct a {
6995992Swnj 		char	*name;
7005992Swnj 		char	*buf;
7015992Swnj 		int	count;
7027826Sroot 	} *uap = (struct a *)u.u_ap;
70316694Smckusick 	register struct nameidata *ndp = &u.u_nd;
70437741Smckusick 	register struct vnode *vp;
70537741Smckusick 	struct iovec aiov;
70637741Smckusick 	struct uio auio;
70737741Smckusick 	int error;
7085992Swnj 
70937741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
71016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
71116694Smckusick 	ndp->ni_dirp = uap->name;
71237741Smckusick 	if (error = namei(ndp))
71337741Smckusick 		RETURN (error);
71437741Smckusick 	vp = ndp->ni_vp;
71537741Smckusick 	if (vp->v_type != VLNK) {
71637741Smckusick 		error = EINVAL;
7175992Swnj 		goto out;
7185992Swnj 	}
71937741Smckusick 	aiov.iov_base = uap->buf;
72037741Smckusick 	aiov.iov_len = uap->count;
72137741Smckusick 	auio.uio_iov = &aiov;
72237741Smckusick 	auio.uio_iovcnt = 1;
72337741Smckusick 	auio.uio_offset = 0;
72437741Smckusick 	auio.uio_rw = UIO_READ;
72537741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
72637741Smckusick 	auio.uio_resid = uap->count;
72737741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
7285992Swnj out:
72937741Smckusick 	vput(vp);
73037741Smckusick 	u.u_r.r_val1 = uap->count - auio.uio_resid;
73137741Smckusick 	RETURN (error);
7325992Swnj }
7335992Swnj 
7349167Ssam /*
73538259Smckusick  * Change flags of a file given path name.
73638259Smckusick  */
73738259Smckusick chflags()
73838259Smckusick {
73938259Smckusick 	struct a {
74038259Smckusick 		char	*fname;
74138259Smckusick 		int	flags;
74238259Smckusick 	} *uap = (struct a *)u.u_ap;
74338259Smckusick 	register struct nameidata *ndp = &u.u_nd;
74438259Smckusick 	register struct vnode *vp;
74538259Smckusick 	struct vattr vattr;
74638259Smckusick 	int error;
74738259Smckusick 
74838259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
74938259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
75038259Smckusick 	ndp->ni_dirp = uap->fname;
75138259Smckusick 	vattr_null(&vattr);
75238259Smckusick 	vattr.va_flags = uap->flags;
75338259Smckusick 	if (error = namei(ndp))
75438259Smckusick 		RETURN (error);
75538259Smckusick 	vp = ndp->ni_vp;
75638259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
75738259Smckusick 		error = EROFS;
75838259Smckusick 		goto out;
75938259Smckusick 	}
76038259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
76138259Smckusick out:
76238259Smckusick 	vput(vp);
76338259Smckusick 	RETURN (error);
76438259Smckusick }
76538259Smckusick 
76638259Smckusick /*
76738259Smckusick  * Change flags of a file given a file descriptor.
76838259Smckusick  */
76938259Smckusick fchflags()
77038259Smckusick {
77138259Smckusick 	struct a {
77238259Smckusick 		int	fd;
77338259Smckusick 		int	flags;
77438259Smckusick 	} *uap = (struct a *)u.u_ap;
77538259Smckusick 	struct vattr vattr;
77638259Smckusick 	struct vnode *vp;
77738259Smckusick 	struct file *fp;
77838259Smckusick 	int error;
77938259Smckusick 
78038259Smckusick 	if (error = getvnode(uap->fd, &fp))
78138259Smckusick 		RETURN (error);
78238259Smckusick 	vattr_null(&vattr);
78338259Smckusick 	vattr.va_flags = uap->flags;
78438259Smckusick 	vp = (struct vnode *)fp->f_data;
78538259Smckusick 	VOP_LOCK(vp);
78638259Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
78738259Smckusick 		error = EROFS;
78838259Smckusick 		goto out;
78938259Smckusick 	}
79038259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
79138259Smckusick out:
79238259Smckusick 	VOP_UNLOCK(vp);
79338259Smckusick 	RETURN (error);
79438259Smckusick }
79538259Smckusick 
79638259Smckusick /*
7979167Ssam  * Change mode of a file given path name.
7989167Ssam  */
7996254Sroot chmod()
8005992Swnj {
8017701Ssam 	struct a {
8026254Sroot 		char	*fname;
8036254Sroot 		int	fmode;
80416694Smckusick 	} *uap = (struct a *)u.u_ap;
80537741Smckusick 	register struct nameidata *ndp = &u.u_nd;
80637741Smckusick 	register struct vnode *vp;
80737741Smckusick 	struct vattr vattr;
80837741Smckusick 	int error;
8095992Swnj 
81037741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
81137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
81237741Smckusick 	ndp->ni_dirp = uap->fname;
81337741Smckusick 	vattr_null(&vattr);
81437741Smckusick 	vattr.va_mode = uap->fmode & 07777;
81537741Smckusick 	if (error = namei(ndp))
81637741Smckusick 		RETURN (error);
81737741Smckusick 	vp = ndp->ni_vp;
81837741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
81937741Smckusick 		error = EROFS;
82037741Smckusick 		goto out;
82137741Smckusick 	}
82237741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
82337741Smckusick out:
82437741Smckusick 	vput(vp);
82537741Smckusick 	RETURN (error);
8267701Ssam }
8277439Sroot 
8289167Ssam /*
8299167Ssam  * Change mode of a file given a file descriptor.
8309167Ssam  */
8317701Ssam fchmod()
8327701Ssam {
8337701Ssam 	struct a {
8347701Ssam 		int	fd;
8357701Ssam 		int	fmode;
83616694Smckusick 	} *uap = (struct a *)u.u_ap;
83737741Smckusick 	struct vattr vattr;
83837741Smckusick 	struct vnode *vp;
83937741Smckusick 	struct file *fp;
84037741Smckusick 	int error;
8417701Ssam 
84237741Smckusick 	if (error = getvnode(uap->fd, &fp))
84337741Smckusick 		RETURN (error);
84437741Smckusick 	vattr_null(&vattr);
84537741Smckusick 	vattr.va_mode = uap->fmode & 07777;
84637741Smckusick 	vp = (struct vnode *)fp->f_data;
84737741Smckusick 	VOP_LOCK(vp);
84837741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
84937741Smckusick 		error = EROFS;
85037741Smckusick 		goto out;
8517439Sroot 	}
85237741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
85337741Smckusick out:
85437741Smckusick 	VOP_UNLOCK(vp);
85537741Smckusick 	RETURN (error);
8565992Swnj }
8575992Swnj 
8589167Ssam /*
8599167Ssam  * Set ownership given a path name.
8609167Ssam  */
8616254Sroot chown()
86237Sbill {
8637701Ssam 	struct a {
8646254Sroot 		char	*fname;
8656254Sroot 		int	uid;
8666254Sroot 		int	gid;
86716694Smckusick 	} *uap = (struct a *)u.u_ap;
86836614Sbostic 	register struct nameidata *ndp = &u.u_nd;
86937741Smckusick 	register struct vnode *vp;
87037741Smckusick 	struct vattr vattr;
87137741Smckusick 	int error;
87237Sbill 
87337741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
87436614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
87536614Sbostic 	ndp->ni_dirp = uap->fname;
87637741Smckusick 	vattr_null(&vattr);
87737741Smckusick 	vattr.va_uid = uap->uid;
87837741Smckusick 	vattr.va_gid = uap->gid;
87937741Smckusick 	if (error = namei(ndp))
88037741Smckusick 		RETURN (error);
88137741Smckusick 	vp = ndp->ni_vp;
88237741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
88337741Smckusick 		error = EROFS;
88437741Smckusick 		goto out;
88537741Smckusick 	}
88637741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
88737741Smckusick out:
88837741Smckusick 	vput(vp);
88937741Smckusick 	RETURN (error);
8907701Ssam }
8917439Sroot 
8929167Ssam /*
8939167Ssam  * Set ownership given a file descriptor.
8949167Ssam  */
8957701Ssam fchown()
8967701Ssam {
8977701Ssam 	struct a {
8987701Ssam 		int	fd;
8997701Ssam 		int	uid;
9007701Ssam 		int	gid;
90116694Smckusick 	} *uap = (struct a *)u.u_ap;
90237741Smckusick 	struct vattr vattr;
90337741Smckusick 	struct vnode *vp;
90437741Smckusick 	struct file *fp;
90537741Smckusick 	int error;
9067701Ssam 
90737741Smckusick 	if (error = getvnode(uap->fd, &fp))
90837741Smckusick 		RETURN (error);
90937741Smckusick 	vattr_null(&vattr);
91037741Smckusick 	vattr.va_uid = uap->uid;
91137741Smckusick 	vattr.va_gid = uap->gid;
91237741Smckusick 	vp = (struct vnode *)fp->f_data;
91337741Smckusick 	VOP_LOCK(vp);
91437741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
91537741Smckusick 		error = EROFS;
91637741Smckusick 		goto out;
91737741Smckusick 	}
91837741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
91937741Smckusick out:
92037741Smckusick 	VOP_UNLOCK(vp);
92137741Smckusick 	RETURN (error);
9227701Ssam }
9237701Ssam 
92411811Ssam utimes()
92511811Ssam {
92611811Ssam 	register struct a {
92711811Ssam 		char	*fname;
92811811Ssam 		struct	timeval *tptr;
92911811Ssam 	} *uap = (struct a *)u.u_ap;
93037741Smckusick 	register struct nameidata *ndp = &u.u_nd;
93137741Smckusick 	register struct vnode *vp;
93211811Ssam 	struct timeval tv[2];
93337741Smckusick 	struct vattr vattr;
93437741Smckusick 	int error;
93511811Ssam 
93637741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
93737741Smckusick 		RETURN (error);
93837741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
93937741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
94037741Smckusick 	ndp->ni_dirp = uap->fname;
94137741Smckusick 	vattr_null(&vattr);
94237741Smckusick 	vattr.va_atime = tv[0];
94337741Smckusick 	vattr.va_mtime = tv[1];
94437741Smckusick 	if (error = namei(ndp))
94537741Smckusick 		RETURN (error);
94637741Smckusick 	vp = ndp->ni_vp;
94737741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
94837741Smckusick 		error = EROFS;
94937741Smckusick 		goto out;
95021015Smckusick 	}
95137741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
95237741Smckusick out:
95337741Smckusick 	vput(vp);
95437741Smckusick 	RETURN (error);
95511811Ssam }
95611811Ssam 
9579167Ssam /*
9589167Ssam  * Truncate a file given its path name.
9599167Ssam  */
9607701Ssam truncate()
9617701Ssam {
9627701Ssam 	struct a {
9637701Ssam 		char	*fname;
96426473Skarels 		off_t	length;
9657826Sroot 	} *uap = (struct a *)u.u_ap;
96616694Smckusick 	register struct nameidata *ndp = &u.u_nd;
96737741Smckusick 	register struct vnode *vp;
96837741Smckusick 	struct vattr vattr;
96937741Smckusick 	int error;
9707701Ssam 
97137741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
97216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
97316694Smckusick 	ndp->ni_dirp = uap->fname;
97437741Smckusick 	vattr_null(&vattr);
97537741Smckusick 	vattr.va_size = uap->length;
97637741Smckusick 	if (error = namei(ndp))
97737741Smckusick 		RETURN (error);
97837741Smckusick 	vp = ndp->ni_vp;
97937741Smckusick 	if (vp->v_type == VDIR) {
98037741Smckusick 		error = EISDIR;
98137741Smckusick 		goto out;
9827701Ssam 	}
98337741Smckusick 	if (error = vn_access(vp, VWRITE, ndp->ni_cred))
98437741Smckusick 		goto out;
98537741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
98637741Smckusick out:
98737741Smckusick 	vput(vp);
98837741Smckusick 	RETURN (error);
9897701Ssam }
9907701Ssam 
9919167Ssam /*
9929167Ssam  * Truncate a file given a file descriptor.
9939167Ssam  */
9947701Ssam ftruncate()
9957701Ssam {
9967701Ssam 	struct a {
9977701Ssam 		int	fd;
99826473Skarels 		off_t	length;
9997826Sroot 	} *uap = (struct a *)u.u_ap;
100037741Smckusick 	struct vattr vattr;
100137741Smckusick 	struct vnode *vp;
10027701Ssam 	struct file *fp;
100337741Smckusick 	int error;
10047701Ssam 
100537741Smckusick 	if (error = getvnode(uap->fd, &fp))
100637741Smckusick 		RETURN (error);
100737741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
100837741Smckusick 		RETURN (EINVAL);
100937741Smckusick 	vattr_null(&vattr);
101037741Smckusick 	vattr.va_size = uap->length;
101137741Smckusick 	vp = (struct vnode *)fp->f_data;
101237741Smckusick 	VOP_LOCK(vp);
101337741Smckusick 	if (vp->v_type == VDIR) {
101437741Smckusick 		error = EISDIR;
101537741Smckusick 		goto out;
10167701Ssam 	}
101737741Smckusick 	if (error = vn_access(vp, VWRITE, fp->f_cred))
101837741Smckusick 		goto out;
101937741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
102037741Smckusick out:
102137741Smckusick 	VOP_UNLOCK(vp);
102237741Smckusick 	RETURN (error);
10237701Ssam }
10247701Ssam 
10259167Ssam /*
10269167Ssam  * Synch an open file.
10279167Ssam  */
10289167Ssam fsync()
10299167Ssam {
10309167Ssam 	struct a {
10319167Ssam 		int	fd;
10329167Ssam 	} *uap = (struct a *)u.u_ap;
10339167Ssam 	struct file *fp;
103437741Smckusick 	int error;
10359167Ssam 
103637741Smckusick 	if (error = getvnode(uap->fd, &fp))
103737741Smckusick 		RETURN (error);
103837741Smckusick 	error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred);
103937741Smckusick 	RETURN (error);
10409167Ssam }
10419167Ssam 
10429167Ssam /*
10439167Ssam  * Rename system call.
10449167Ssam  *
10459167Ssam  * Source and destination must either both be directories, or both
10469167Ssam  * not be directories.  If target is a directory, it must be empty.
10479167Ssam  */
10487701Ssam rename()
10497701Ssam {
10507701Ssam 	struct a {
10517701Ssam 		char	*from;
10527701Ssam 		char	*to;
105316694Smckusick 	} *uap = (struct a *)u.u_ap;
105437741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
105516694Smckusick 	register struct nameidata *ndp = &u.u_nd;
105637741Smckusick 	struct nameidata tond;
105737741Smckusick 	int error;
10587701Ssam 
105937741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
106016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
106116694Smckusick 	ndp->ni_dirp = uap->from;
106237741Smckusick 	if (error = namei(ndp))
106337741Smckusick 		RETURN (error);
106437741Smckusick 	fvp = ndp->ni_vp;
1065*38266Smckusick 	nddup(ndp, &tond);
106637741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
106737741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
106837741Smckusick 	tond.ni_dirp = uap->to;
106937741Smckusick 	error = namei(&tond);
107037741Smckusick 	tdvp = tond.ni_dvp;
107137741Smckusick 	tvp = tond.ni_vp;
107237741Smckusick 	if (tvp != NULL) {
107337741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
107437741Smckusick 			error = EISDIR;
107537741Smckusick 			goto out;
107637741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
107737741Smckusick 			error = ENOTDIR;
107837741Smckusick 			goto out;
10799167Ssam 		}
10809167Ssam 	}
108137741Smckusick 	if (error) {
108237741Smckusick 		VOP_ABORTOP(ndp);
108337741Smckusick 		goto out1;
108437741Smckusick 	}
108537741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
108637741Smckusick 		error = EXDEV;
10879167Ssam 		goto out;
108810051Ssam 	}
108937741Smckusick 	if (fvp == tdvp || fvp == tvp)
109037741Smckusick 		error = EINVAL;
109137741Smckusick out:
109237741Smckusick 	if (error) {
109337741Smckusick 		VOP_ABORTOP(&tond);
109437741Smckusick 		VOP_ABORTOP(ndp);
10959167Ssam 	} else {
109637741Smckusick 		error = VOP_RENAME(ndp, &tond);
10979167Ssam 	}
109837741Smckusick out1:
1099*38266Smckusick 	ndrele(&tond);
110037741Smckusick 	RETURN (error);
11017701Ssam }
11027701Ssam 
11037535Sroot /*
110412756Ssam  * Mkdir system call
110512756Ssam  */
110612756Ssam mkdir()
110712756Ssam {
110812756Ssam 	struct a {
110912756Ssam 		char	*name;
111012756Ssam 		int	dmode;
111116694Smckusick 	} *uap = (struct a *)u.u_ap;
111216694Smckusick 	register struct nameidata *ndp = &u.u_nd;
111337741Smckusick 	register struct vnode *vp;
111437741Smckusick 	struct vattr vattr;
111537741Smckusick 	int error;
111612756Ssam 
111737741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
111816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
111916694Smckusick 	ndp->ni_dirp = uap->name;
112037741Smckusick 	if (error = namei(ndp))
112137741Smckusick 		RETURN (error);
112237741Smckusick 	vp = ndp->ni_vp;
112337741Smckusick 	if (vp != NULL) {
112437741Smckusick 		VOP_ABORTOP(ndp);
112537741Smckusick 		RETURN (EEXIST);
112612756Ssam 	}
112737741Smckusick 	vattr_null(&vattr);
112837741Smckusick 	vattr.va_type = VDIR;
112937741Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask;
113037741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
113138145Smckusick 	if (!error)
113238145Smckusick 		vput(ndp->ni_vp);
113337741Smckusick 	RETURN (error);
113412756Ssam }
113512756Ssam 
113612756Ssam /*
113712756Ssam  * Rmdir system call.
113812756Ssam  */
113912756Ssam rmdir()
114012756Ssam {
114112756Ssam 	struct a {
114212756Ssam 		char	*name;
114316694Smckusick 	} *uap = (struct a *)u.u_ap;
114416694Smckusick 	register struct nameidata *ndp = &u.u_nd;
114537741Smckusick 	register struct vnode *vp;
114637741Smckusick 	int error;
114712756Ssam 
114837741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
114916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
115016694Smckusick 	ndp->ni_dirp = uap->name;
115137741Smckusick 	if (error = namei(ndp))
115237741Smckusick 		RETURN (error);
115337741Smckusick 	vp = ndp->ni_vp;
115437741Smckusick 	if (vp->v_type != VDIR) {
115537741Smckusick 		error = ENOTDIR;
115612756Ssam 		goto out;
115712756Ssam 	}
115812756Ssam 	/*
115937741Smckusick 	 * No rmdir "." please.
116012756Ssam 	 */
116137741Smckusick 	if (ndp->ni_dvp == vp) {
116237741Smckusick 		error = EINVAL;
116312756Ssam 		goto out;
116412756Ssam 	}
116512756Ssam 	/*
116637741Smckusick 	 * Don't unlink a mounted file.
116712756Ssam 	 */
116837741Smckusick 	if (vp->v_flag & VROOT)
116937741Smckusick 		error = EBUSY;
117012756Ssam out:
117137741Smckusick 	if (error)
117237741Smckusick 		VOP_ABORTOP(ndp);
117337741Smckusick 	else
117437741Smckusick 		error = VOP_RMDIR(ndp);
117537741Smckusick 	RETURN (error);
117612756Ssam }
117712756Ssam 
117837741Smckusick /*
117937741Smckusick  * Read a block of directory entries in a file system independent format
118037741Smckusick  */
118137741Smckusick getdirentries()
118212756Ssam {
118337741Smckusick 	register struct a {
118437741Smckusick 		int	fd;
118537741Smckusick 		char	*buf;
118637741Smckusick 		unsigned count;
118737741Smckusick 		long	*basep;
118837741Smckusick 	} *uap = (struct a *)u.u_ap;
118916540Ssam 	struct file *fp;
119037741Smckusick 	struct uio auio;
119137741Smckusick 	struct iovec aiov;
119238129Smckusick 	off_t off;
119337741Smckusick 	int error;
119412756Ssam 
119537741Smckusick 	if (error = getvnode(uap->fd, &fp))
119637741Smckusick 		RETURN (error);
119737741Smckusick 	if ((fp->f_flag & FREAD) == 0)
119837741Smckusick 		RETURN (EBADF);
119937741Smckusick 	aiov.iov_base = uap->buf;
120037741Smckusick 	aiov.iov_len = uap->count;
120137741Smckusick 	auio.uio_iov = &aiov;
120237741Smckusick 	auio.uio_iovcnt = 1;
120337741Smckusick 	auio.uio_rw = UIO_READ;
120437741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
120537741Smckusick 	auio.uio_resid = uap->count;
120638129Smckusick 	off = fp->f_offset;
120737741Smckusick 	if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio,
120837741Smckusick 	    &(fp->f_offset), fp->f_cred))
120937741Smckusick 		RETURN (error);
121038129Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep,
121137741Smckusick 		sizeof(long));
121237741Smckusick 	u.u_r.r_val1 = uap->count - auio.uio_resid;
121337741Smckusick 	RETURN (error);
121412756Ssam }
121512756Ssam 
121612756Ssam /*
121712756Ssam  * mode mask for creation of files
121812756Ssam  */
121912756Ssam umask()
122012756Ssam {
122112756Ssam 	register struct a {
122212756Ssam 		int	mask;
122316694Smckusick 	} *uap = (struct a *)u.u_ap;
122412756Ssam 
122512756Ssam 	u.u_r.r_val1 = u.u_cmask;
122612756Ssam 	u.u_cmask = uap->mask & 07777;
122737741Smckusick 	RETURN (0);
122812756Ssam }
122937741Smckusick 
123037741Smckusick getvnode(fdes, fpp)
123137741Smckusick 	struct file **fpp;
123237741Smckusick 	int fdes;
123337741Smckusick {
123437741Smckusick 	struct file *fp;
123537741Smckusick 
123637741Smckusick 	if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL)
123737741Smckusick 		return (EBADF);
123837741Smckusick 	if (fp->f_type != DTYPE_VNODE)
123937741Smckusick 		return (EINVAL);
124037741Smckusick 	*fpp = fp;
124137741Smckusick 	return (0);
124237741Smckusick }
1243