xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 38129)
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*38129Smckusick  *	@(#)vfs_syscalls.c	7.8 (Berkeley) 05/25/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 /*
22737741Smckusick  * Change current working directory (``.'').
22837741Smckusick  */
22937741Smckusick chdir()
23037741Smckusick {
23137741Smckusick 	struct a {
2326254Sroot 		char	*fname;
23316694Smckusick 	} *uap = (struct a *)u.u_ap;
23416694Smckusick 	register struct nameidata *ndp = &u.u_nd;
23537741Smckusick 	int error;
2366254Sroot 
23737741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
23816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
23916694Smckusick 	ndp->ni_dirp = uap->fname;
24037741Smckusick 	if (error = chdirec(ndp))
24137741Smckusick 		RETURN (error);
24237741Smckusick 	vrele(u.u_cdir);
24337741Smckusick 	u.u_cdir = ndp->ni_vp;
24437741Smckusick 	RETURN (0);
24537741Smckusick }
2466254Sroot 
24737741Smckusick /*
24837741Smckusick  * Change notion of root (``/'') directory.
24937741Smckusick  */
25037741Smckusick chroot()
25137741Smckusick {
25237741Smckusick 	struct a {
25337741Smckusick 		char	*fname;
25437741Smckusick 	} *uap = (struct a *)u.u_ap;
25537741Smckusick 	register struct nameidata *ndp = &u.u_nd;
25637741Smckusick 	int error;
25737741Smckusick 
25837741Smckusick 	if (error = suser(u.u_cred, &u.u_acflag))
25937741Smckusick 		RETURN (error);
26037741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
26137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
26237741Smckusick 	ndp->ni_dirp = uap->fname;
26337741Smckusick 	if (error = chdirec(ndp))
26437741Smckusick 		RETURN (error);
26537741Smckusick 	vrele(u.u_rdir);
26637741Smckusick 	u.u_rdir = ndp->ni_vp;
26737741Smckusick 	RETURN (0);
2686254Sroot }
2696254Sroot 
27037Sbill /*
27137741Smckusick  * Common routine for chroot and chdir.
27237741Smckusick  */
27337741Smckusick chdirec(ndp)
27437741Smckusick 	register struct nameidata *ndp;
27537741Smckusick {
27637741Smckusick 	struct vnode *vp;
27737741Smckusick 	int error;
27837741Smckusick 
27937741Smckusick 	if (error = namei(ndp))
28037741Smckusick 		return (error);
28137741Smckusick 	vp = ndp->ni_vp;
28237741Smckusick 	if (vp->v_type != VDIR)
28337741Smckusick 		error = ENOTDIR;
28437741Smckusick 	else
28537741Smckusick 		error = vn_access(vp, VEXEC, ndp->ni_cred);
28637741Smckusick 	VOP_UNLOCK(vp);
28737741Smckusick 	if (error)
28837741Smckusick 		vrele(vp);
28937741Smckusick 	return (error);
29037741Smckusick }
29137741Smckusick 
29237741Smckusick /*
2936254Sroot  * Open system call.
2946254Sroot  */
2956254Sroot open()
2966254Sroot {
29712756Ssam 	struct a {
2986254Sroot 		char	*fname;
2997701Ssam 		int	mode;
30012756Ssam 		int	crtmode;
30112756Ssam 	} *uap = (struct a *) u.u_ap;
30237741Smckusick 	struct nameidata *ndp = &u.u_nd;
3036254Sroot 
30437741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
30537741Smckusick 	ndp->ni_dirp = uap->fname;
30637741Smckusick 	RETURN (copen(uap->mode-FOPEN, uap->crtmode &~ u.u_cmask, ndp,
30737741Smckusick 		&u.u_r.r_val1));
3086254Sroot }
3096254Sroot 
3106254Sroot /*
3116254Sroot  * Creat system call.
3126254Sroot  */
31312756Ssam creat()
3146254Sroot {
31512756Ssam 	struct a {
3166254Sroot 		char	*fname;
3176254Sroot 		int	fmode;
31812756Ssam 	} *uap = (struct a *)u.u_ap;
31937741Smckusick 	struct nameidata *ndp = &u.u_nd;
3206254Sroot 
32137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
32237741Smckusick 	ndp->ni_dirp = uap->fname;
32337741Smckusick 	RETURN (copen(FWRITE|FCREAT|FTRUNC, uap->fmode &~ u.u_cmask, ndp,
32437741Smckusick 		&u.u_r.r_val1));
3256254Sroot }
3266254Sroot 
3276254Sroot /*
3286254Sroot  * Common code for open and creat.
32912756Ssam  * Check permissions, allocate an open file structure,
33012756Ssam  * and call the device open routine if any.
3316254Sroot  */
33237741Smckusick copen(fmode, cmode, ndp, resultfd)
33337741Smckusick 	int fmode, cmode;
33437741Smckusick 	struct nameidata *ndp;
33537741Smckusick 	int *resultfd;
33612756Ssam {
3376254Sroot 	register struct file *fp;
33837741Smckusick 	struct file *nfp;
33937741Smckusick 	int indx, error;
34037741Smckusick 	extern struct fileops vnops;
3416254Sroot 
34237741Smckusick 	if (error = falloc(&nfp, &indx))
34337741Smckusick 		return (error);
34437741Smckusick 	fp = nfp;
34537741Smckusick 	u.u_r.r_val1 = indx;	/* XXX for fdopen() */
34637741Smckusick 	if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) {
34724543Smckusick 		u.u_ofile[indx] = NULL;
34837741Smckusick 		crfree(fp->f_cred);
34937741Smckusick 		fp->f_count--;
35037741Smckusick 		return (error);
35112756Ssam 	}
35237741Smckusick 	fp->f_flag = fmode & FMASK;
35337741Smckusick 	fp->f_type = DTYPE_VNODE;
35437741Smckusick 	fp->f_ops = &vnops;
35537741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
35637741Smckusick 	if (resultfd)
35737741Smckusick 		*resultfd = indx;
35837741Smckusick 	return (0);
3596254Sroot }
3606254Sroot 
3616254Sroot /*
3626254Sroot  * Mknod system call
3636254Sroot  */
3646254Sroot mknod()
3656254Sroot {
3666254Sroot 	register struct a {
3676254Sroot 		char	*fname;
3686254Sroot 		int	fmode;
3696254Sroot 		int	dev;
37016694Smckusick 	} *uap = (struct a *)u.u_ap;
37116694Smckusick 	register struct nameidata *ndp = &u.u_nd;
37237741Smckusick 	register struct vnode *vp;
37337741Smckusick 	struct vattr vattr;
37437741Smckusick 	int error;
3756254Sroot 
37637741Smckusick 	if (error = suser(u.u_cred, &u.u_acflag))
37737741Smckusick 		RETURN (error);
37837741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
37916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
38016694Smckusick 	ndp->ni_dirp = uap->fname;
38137741Smckusick 	if (error = namei(ndp))
38237741Smckusick 		RETURN (error);
38337741Smckusick 	vp = ndp->ni_vp;
38437741Smckusick 	if (vp != NULL) {
38537741Smckusick 		error = EEXIST;
38612756Ssam 		goto out;
3876254Sroot 	}
38837741Smckusick 	vattr_null(&vattr);
38937741Smckusick 	switch (uap->fmode & IFMT) {
39012756Ssam 
39115093Smckusick 	case IFMT:	/* used by badsect to flag bad sectors */
39237741Smckusick 		vattr.va_type = VBAD;
39337741Smckusick 		break;
39412756Ssam 	case IFCHR:
39537741Smckusick 		vattr.va_type = VCHR;
39637741Smckusick 		break;
39712756Ssam 	case IFBLK:
39837741Smckusick 		vattr.va_type = VBLK;
39937741Smckusick 		break;
40037741Smckusick 	default:
40137741Smckusick 		error = EINVAL;
40237741Smckusick 		goto out;
4036254Sroot 	}
40437741Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask;
40537741Smckusick 	vattr.va_rdev = uap->dev;
4066254Sroot out:
40737741Smckusick 	if (error)
40837741Smckusick 		VOP_ABORTOP(ndp);
40937741Smckusick 	else
41037741Smckusick 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
41137741Smckusick 	RETURN (error);
4126254Sroot }
4136254Sroot 
4146254Sroot /*
4156254Sroot  * link system call
4166254Sroot  */
4176254Sroot link()
4186254Sroot {
4196254Sroot 	register struct a {
4206254Sroot 		char	*target;
4216254Sroot 		char	*linkname;
42216694Smckusick 	} *uap = (struct a *)u.u_ap;
42316694Smckusick 	register struct nameidata *ndp = &u.u_nd;
42437741Smckusick 	register struct vnode *vp, *xp;
42537741Smckusick 	int error;
4266254Sroot 
42716694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
42816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
42916694Smckusick 	ndp->ni_dirp = uap->target;
43037741Smckusick 	if (error = namei(ndp))
43137741Smckusick 		RETURN (error);
43237741Smckusick 	vp = ndp->ni_vp;
43337741Smckusick 	if (vp->v_type == VDIR &&
43437741Smckusick 	    (error = suser(u.u_cred, &u.u_acflag)))
43537741Smckusick 		goto out1;
43637741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
43716694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
43837741Smckusick 	if (error = namei(ndp))
43937741Smckusick 		goto out1;
44037741Smckusick 	xp = ndp->ni_vp;
4416254Sroot 	if (xp != NULL) {
44237741Smckusick 		error = EEXIST;
4436254Sroot 		goto out;
4446254Sroot 	}
44537741Smckusick 	xp = ndp->ni_dvp;
44637741Smckusick 	if (vp->v_mount != xp->v_mount)
44737741Smckusick 		error = EXDEV;
4486254Sroot out:
44937741Smckusick 	if (error)
45037741Smckusick 		VOP_ABORTOP(ndp);
45137741Smckusick 	else
45237741Smckusick 		error = VOP_LINK(vp, ndp);
45337741Smckusick out1:
45437741Smckusick 	vrele(vp);
45537741Smckusick 	RETURN (error);
4566254Sroot }
4576254Sroot 
4586254Sroot /*
4596254Sroot  * symlink -- make a symbolic link
4606254Sroot  */
4616254Sroot symlink()
4626254Sroot {
46337741Smckusick 	struct a {
4646254Sroot 		char	*target;
4656254Sroot 		char	*linkname;
46616694Smckusick 	} *uap = (struct a *)u.u_ap;
46716694Smckusick 	register struct nameidata *ndp = &u.u_nd;
46837741Smckusick 	register struct vnode *vp;
46937741Smckusick 	struct vattr vattr;
47037741Smckusick 	char *target;
47137741Smckusick 	int error;
4726254Sroot 
47316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
47416694Smckusick 	ndp->ni_dirp = uap->linkname;
47537741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
47637741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
47737741Smckusick 		goto out1;
47837741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
47937741Smckusick 	if (error = namei(ndp))
48037741Smckusick 		goto out1;
48137741Smckusick 	vp = ndp->ni_vp;
48237741Smckusick 	if (vp) {
48337741Smckusick 		error = EEXIST;
48437741Smckusick 		goto out;
4856254Sroot 	}
48637741Smckusick 	vp = ndp->ni_dvp;
48737741Smckusick 	vattr_null(&vattr);
48837741Smckusick 	vattr.va_mode = 0777 &~ u.u_cmask;
48937741Smckusick out:
49037741Smckusick 	if (error)
49137741Smckusick 		VOP_ABORTOP(ndp);
49237741Smckusick 	else
49337741Smckusick 		error = VOP_SYMLINK(ndp, &vattr, target);
49437741Smckusick out1:
49537741Smckusick 	FREE(target, M_NAMEI);
49637741Smckusick 	RETURN (error);
4976254Sroot }
4986254Sroot 
4996254Sroot /*
5006254Sroot  * Unlink system call.
5016254Sroot  * Hard to avoid races here, especially
5026254Sroot  * in unlinking directories.
5036254Sroot  */
5046254Sroot unlink()
5056254Sroot {
5066254Sroot 	struct a {
5076254Sroot 		char	*fname;
50816694Smckusick 	} *uap = (struct a *)u.u_ap;
50916694Smckusick 	register struct nameidata *ndp = &u.u_nd;
51037741Smckusick 	register struct vnode *vp;
51137741Smckusick 	int error;
5126254Sroot 
51337741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
51416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
51516694Smckusick 	ndp->ni_dirp = uap->fname;
51637741Smckusick 	if (error = namei(ndp))
51737741Smckusick 		RETURN (error);
51837741Smckusick 	vp = ndp->ni_vp;
51937741Smckusick 	if (vp->v_type == VDIR &&
52037741Smckusick 	    (error = suser(u.u_cred, &u.u_acflag)))
5216254Sroot 		goto out;
5226254Sroot 	/*
5236254Sroot 	 * Don't unlink a mounted file.
5246254Sroot 	 */
52537741Smckusick 	if (vp->v_flag & VROOT) {
52637741Smckusick 		error = EBUSY;
5276254Sroot 		goto out;
5286254Sroot 	}
52937741Smckusick 	if (vp->v_flag & VTEXT)
53037741Smckusick 		xrele(vp);	/* try once to free text */
5316254Sroot out:
53237741Smckusick 	if (error)
53337741Smckusick 		VOP_ABORTOP(ndp);
5347142Smckusick 	else
53537741Smckusick 		error = VOP_REMOVE(ndp);
53637741Smckusick 	RETURN (error);
5376254Sroot }
5386254Sroot 
5396254Sroot /*
5406254Sroot  * Seek system call
5416254Sroot  */
5428040Sroot lseek()
5436254Sroot {
5446254Sroot 	register struct file *fp;
5456254Sroot 	register struct a {
54637741Smckusick 		int	fdes;
5476254Sroot 		off_t	off;
5486254Sroot 		int	sbase;
54916694Smckusick 	} *uap = (struct a *)u.u_ap;
55037741Smckusick 	struct vattr vattr;
55137741Smckusick 	int error;
5526254Sroot 
55337741Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
55437741Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
55537741Smckusick 		RETURN (EBADF);
55637741Smckusick 	if (fp->f_type != DTYPE_VNODE)
55737741Smckusick 		RETURN (ESPIPE);
55813878Ssam 	switch (uap->sbase) {
55913878Ssam 
56013878Ssam 	case L_INCR:
56113878Ssam 		fp->f_offset += uap->off;
56213878Ssam 		break;
56313878Ssam 
56413878Ssam 	case L_XTND:
56537741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
56637741Smckusick 		    &vattr, u.u_cred))
56737741Smckusick 			RETURN (error);
56837741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
56913878Ssam 		break;
57013878Ssam 
57113878Ssam 	case L_SET:
57213878Ssam 		fp->f_offset = uap->off;
57313878Ssam 		break;
57413878Ssam 
57513878Ssam 	default:
57637741Smckusick 		RETURN (EINVAL);
57713878Ssam 	}
57813878Ssam 	u.u_r.r_off = fp->f_offset;
57937741Smckusick 	RETURN (0);
5806254Sroot }
5816254Sroot 
5826254Sroot /*
5836254Sroot  * Access system call
5846254Sroot  */
5856254Sroot saccess()
5866254Sroot {
5876254Sroot 	register struct a {
5886254Sroot 		char	*fname;
5896254Sroot 		int	fmode;
59016694Smckusick 	} *uap = (struct a *)u.u_ap;
59116694Smckusick 	register struct nameidata *ndp = &u.u_nd;
59237741Smckusick 	register struct vnode *vp;
59337741Smckusick 	int error, mode, svuid, svgid;
5946254Sroot 
5956254Sroot 	svuid = u.u_uid;
5966254Sroot 	svgid = u.u_gid;
5976254Sroot 	u.u_uid = u.u_ruid;
5986254Sroot 	u.u_gid = u.u_rgid;
59937741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
60016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
60116694Smckusick 	ndp->ni_dirp = uap->fname;
60237741Smckusick 	if (error = namei(ndp))
60337741Smckusick 		goto out1;
60437741Smckusick 	vp = ndp->ni_vp;
60537741Smckusick 	/*
60637741Smckusick 	 * fmode == 0 means only check for exist
60737741Smckusick 	 */
60837741Smckusick 	if (uap->fmode) {
60937741Smckusick 		mode = 0;
61037741Smckusick 		if (uap->fmode & R_OK)
61137741Smckusick 			mode |= VREAD;
61237741Smckusick 		if (uap->fmode & W_OK)
61337741Smckusick 			mode |= VWRITE;
61437741Smckusick 		if (uap->fmode & X_OK)
61537741Smckusick 			mode |= VEXEC;
61637741Smckusick 		error = vn_access(vp, mode, u.u_cred);
6176254Sroot 	}
61837741Smckusick 	vput(vp);
61937741Smckusick out1:
6206254Sroot 	u.u_uid = svuid;
6216254Sroot 	u.u_gid = svgid;
62237741Smckusick 	RETURN (error);
6236254Sroot }
6246254Sroot 
6256254Sroot /*
6266574Smckusic  * Stat system call.  This version follows links.
62737Sbill  */
62837Sbill stat()
62937Sbill {
63037Sbill 
63116694Smckusick 	stat1(FOLLOW);
63237Sbill }
63337Sbill 
63437Sbill /*
6356574Smckusic  * Lstat system call.  This version does not follow links.
6365992Swnj  */
6375992Swnj lstat()
6385992Swnj {
63912756Ssam 
64016694Smckusick 	stat1(NOFOLLOW);
64112756Ssam }
64212756Ssam 
64312756Ssam stat1(follow)
64412756Ssam 	int follow;
64512756Ssam {
6465992Swnj 	register struct a {
6475992Swnj 		char	*fname;
64812756Ssam 		struct stat *ub;
64916694Smckusick 	} *uap = (struct a *)u.u_ap;
65037741Smckusick 	register struct nameidata *ndp = &u.u_nd;
65112756Ssam 	struct stat sb;
65237741Smckusick 	int error;
6535992Swnj 
65437741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
65516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
65616694Smckusick 	ndp->ni_dirp = uap->fname;
65737741Smckusick 	if (error = namei(ndp))
65837741Smckusick 		RETURN (error);
65937741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
66037741Smckusick 	vput(ndp->ni_vp);
66137741Smckusick 	if (error)
66237741Smckusick 		RETURN (error);
66337741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
66437741Smckusick 	RETURN (error);
6655992Swnj }
6665992Swnj 
6675992Swnj /*
6685992Swnj  * Return target name of a symbolic link
66937Sbill  */
6705992Swnj readlink()
6715992Swnj {
6725992Swnj 	register struct a {
6735992Swnj 		char	*name;
6745992Swnj 		char	*buf;
6755992Swnj 		int	count;
6767826Sroot 	} *uap = (struct a *)u.u_ap;
67716694Smckusick 	register struct nameidata *ndp = &u.u_nd;
67837741Smckusick 	register struct vnode *vp;
67937741Smckusick 	struct iovec aiov;
68037741Smckusick 	struct uio auio;
68137741Smckusick 	int error;
6825992Swnj 
68337741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
68416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
68516694Smckusick 	ndp->ni_dirp = uap->name;
68637741Smckusick 	if (error = namei(ndp))
68737741Smckusick 		RETURN (error);
68837741Smckusick 	vp = ndp->ni_vp;
68937741Smckusick 	if (vp->v_type != VLNK) {
69037741Smckusick 		error = EINVAL;
6915992Swnj 		goto out;
6925992Swnj 	}
69337741Smckusick 	aiov.iov_base = uap->buf;
69437741Smckusick 	aiov.iov_len = uap->count;
69537741Smckusick 	auio.uio_iov = &aiov;
69637741Smckusick 	auio.uio_iovcnt = 1;
69737741Smckusick 	auio.uio_offset = 0;
69837741Smckusick 	auio.uio_rw = UIO_READ;
69937741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
70037741Smckusick 	auio.uio_resid = uap->count;
70137741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
7025992Swnj out:
70337741Smckusick 	vput(vp);
70437741Smckusick 	u.u_r.r_val1 = uap->count - auio.uio_resid;
70537741Smckusick 	RETURN (error);
7065992Swnj }
7075992Swnj 
7089167Ssam /*
7099167Ssam  * Change mode of a file given path name.
7109167Ssam  */
7116254Sroot chmod()
7125992Swnj {
7137701Ssam 	struct a {
7146254Sroot 		char	*fname;
7156254Sroot 		int	fmode;
71616694Smckusick 	} *uap = (struct a *)u.u_ap;
71737741Smckusick 	register struct nameidata *ndp = &u.u_nd;
71837741Smckusick 	register struct vnode *vp;
71937741Smckusick 	struct vattr vattr;
72037741Smckusick 	int error;
7215992Swnj 
72237741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
72337741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
72437741Smckusick 	ndp->ni_dirp = uap->fname;
72537741Smckusick 	vattr_null(&vattr);
72637741Smckusick 	vattr.va_mode = uap->fmode & 07777;
72737741Smckusick 	if (error = namei(ndp))
72837741Smckusick 		RETURN (error);
72937741Smckusick 	vp = ndp->ni_vp;
73037741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
73137741Smckusick 		error = EROFS;
73237741Smckusick 		goto out;
73337741Smckusick 	}
73437741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
73537741Smckusick out:
73637741Smckusick 	vput(vp);
73737741Smckusick 	RETURN (error);
7387701Ssam }
7397439Sroot 
7409167Ssam /*
7419167Ssam  * Change mode of a file given a file descriptor.
7429167Ssam  */
7437701Ssam fchmod()
7447701Ssam {
7457701Ssam 	struct a {
7467701Ssam 		int	fd;
7477701Ssam 		int	fmode;
74816694Smckusick 	} *uap = (struct a *)u.u_ap;
74937741Smckusick 	struct vattr vattr;
75037741Smckusick 	struct vnode *vp;
75137741Smckusick 	struct file *fp;
75237741Smckusick 	int error;
7537701Ssam 
75437741Smckusick 	if (error = getvnode(uap->fd, &fp))
75537741Smckusick 		RETURN (error);
75637741Smckusick 	vattr_null(&vattr);
75737741Smckusick 	vattr.va_mode = uap->fmode & 07777;
75837741Smckusick 	vp = (struct vnode *)fp->f_data;
75937741Smckusick 	VOP_LOCK(vp);
76037741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
76137741Smckusick 		error = EROFS;
76237741Smckusick 		goto out;
7637439Sroot 	}
76437741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
76537741Smckusick out:
76637741Smckusick 	VOP_UNLOCK(vp);
76737741Smckusick 	RETURN (error);
7685992Swnj }
7695992Swnj 
7709167Ssam /*
7719167Ssam  * Set ownership given a path name.
7729167Ssam  */
7736254Sroot chown()
77437Sbill {
7757701Ssam 	struct a {
7766254Sroot 		char	*fname;
7776254Sroot 		int	uid;
7786254Sroot 		int	gid;
77916694Smckusick 	} *uap = (struct a *)u.u_ap;
78036614Sbostic 	register struct nameidata *ndp = &u.u_nd;
78137741Smckusick 	register struct vnode *vp;
78237741Smckusick 	struct vattr vattr;
78337741Smckusick 	int error;
78437Sbill 
78537741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
78636614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
78736614Sbostic 	ndp->ni_dirp = uap->fname;
78837741Smckusick 	vattr_null(&vattr);
78937741Smckusick 	vattr.va_uid = uap->uid;
79037741Smckusick 	vattr.va_gid = uap->gid;
79137741Smckusick 	if (error = namei(ndp))
79237741Smckusick 		RETURN (error);
79337741Smckusick 	vp = ndp->ni_vp;
79437741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
79537741Smckusick 		error = EROFS;
79637741Smckusick 		goto out;
79737741Smckusick 	}
79837741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
79937741Smckusick out:
80037741Smckusick 	vput(vp);
80137741Smckusick 	RETURN (error);
8027701Ssam }
8037439Sroot 
8049167Ssam /*
8059167Ssam  * Set ownership given a file descriptor.
8069167Ssam  */
8077701Ssam fchown()
8087701Ssam {
8097701Ssam 	struct a {
8107701Ssam 		int	fd;
8117701Ssam 		int	uid;
8127701Ssam 		int	gid;
81316694Smckusick 	} *uap = (struct a *)u.u_ap;
81437741Smckusick 	struct vattr vattr;
81537741Smckusick 	struct vnode *vp;
81637741Smckusick 	struct file *fp;
81737741Smckusick 	int error;
8187701Ssam 
81937741Smckusick 	if (error = getvnode(uap->fd, &fp))
82037741Smckusick 		RETURN (error);
82137741Smckusick 	vattr_null(&vattr);
82237741Smckusick 	vattr.va_uid = uap->uid;
82337741Smckusick 	vattr.va_gid = uap->gid;
82437741Smckusick 	vp = (struct vnode *)fp->f_data;
82537741Smckusick 	VOP_LOCK(vp);
82637741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
82737741Smckusick 		error = EROFS;
82837741Smckusick 		goto out;
82937741Smckusick 	}
83037741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
83137741Smckusick out:
83237741Smckusick 	VOP_UNLOCK(vp);
83337741Smckusick 	RETURN (error);
8347701Ssam }
8357701Ssam 
83611811Ssam utimes()
83711811Ssam {
83811811Ssam 	register struct a {
83911811Ssam 		char	*fname;
84011811Ssam 		struct	timeval *tptr;
84111811Ssam 	} *uap = (struct a *)u.u_ap;
84237741Smckusick 	register struct nameidata *ndp = &u.u_nd;
84337741Smckusick 	register struct vnode *vp;
84411811Ssam 	struct timeval tv[2];
84537741Smckusick 	struct vattr vattr;
84637741Smckusick 	int error;
84711811Ssam 
84837741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
84937741Smckusick 		RETURN (error);
85037741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
85137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
85237741Smckusick 	ndp->ni_dirp = uap->fname;
85337741Smckusick 	vattr_null(&vattr);
85437741Smckusick 	vattr.va_atime = tv[0];
85537741Smckusick 	vattr.va_mtime = tv[1];
85637741Smckusick 	if (error = namei(ndp))
85737741Smckusick 		RETURN (error);
85837741Smckusick 	vp = ndp->ni_vp;
85937741Smckusick 	if (vp->v_mount->m_flag & M_RDONLY) {
86037741Smckusick 		error = EROFS;
86137741Smckusick 		goto out;
86221015Smckusick 	}
86337741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
86437741Smckusick out:
86537741Smckusick 	vput(vp);
86637741Smckusick 	RETURN (error);
86711811Ssam }
86811811Ssam 
8699167Ssam /*
8709167Ssam  * Truncate a file given its path name.
8719167Ssam  */
8727701Ssam truncate()
8737701Ssam {
8747701Ssam 	struct a {
8757701Ssam 		char	*fname;
87626473Skarels 		off_t	length;
8777826Sroot 	} *uap = (struct a *)u.u_ap;
87816694Smckusick 	register struct nameidata *ndp = &u.u_nd;
87937741Smckusick 	register struct vnode *vp;
88037741Smckusick 	struct vattr vattr;
88137741Smckusick 	int error;
8827701Ssam 
88337741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
88416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
88516694Smckusick 	ndp->ni_dirp = uap->fname;
88637741Smckusick 	vattr_null(&vattr);
88737741Smckusick 	vattr.va_size = uap->length;
88837741Smckusick 	if (error = namei(ndp))
88937741Smckusick 		RETURN (error);
89037741Smckusick 	vp = ndp->ni_vp;
89137741Smckusick 	if (vp->v_type == VDIR) {
89237741Smckusick 		error = EISDIR;
89337741Smckusick 		goto out;
8947701Ssam 	}
89537741Smckusick 	if (error = vn_access(vp, VWRITE, ndp->ni_cred))
89637741Smckusick 		goto out;
89737741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
89837741Smckusick out:
89937741Smckusick 	vput(vp);
90037741Smckusick 	RETURN (error);
9017701Ssam }
9027701Ssam 
9039167Ssam /*
9049167Ssam  * Truncate a file given a file descriptor.
9059167Ssam  */
9067701Ssam ftruncate()
9077701Ssam {
9087701Ssam 	struct a {
9097701Ssam 		int	fd;
91026473Skarels 		off_t	length;
9117826Sroot 	} *uap = (struct a *)u.u_ap;
91237741Smckusick 	struct vattr vattr;
91337741Smckusick 	struct vnode *vp;
9147701Ssam 	struct file *fp;
91537741Smckusick 	int error;
9167701Ssam 
91737741Smckusick 	if (error = getvnode(uap->fd, &fp))
91837741Smckusick 		RETURN (error);
91937741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
92037741Smckusick 		RETURN (EINVAL);
92137741Smckusick 	vattr_null(&vattr);
92237741Smckusick 	vattr.va_size = uap->length;
92337741Smckusick 	vp = (struct vnode *)fp->f_data;
92437741Smckusick 	VOP_LOCK(vp);
92537741Smckusick 	if (vp->v_type == VDIR) {
92637741Smckusick 		error = EISDIR;
92737741Smckusick 		goto out;
9287701Ssam 	}
92937741Smckusick 	if (error = vn_access(vp, VWRITE, fp->f_cred))
93037741Smckusick 		goto out;
93137741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
93237741Smckusick out:
93337741Smckusick 	VOP_UNLOCK(vp);
93437741Smckusick 	RETURN (error);
9357701Ssam }
9367701Ssam 
9379167Ssam /*
9389167Ssam  * Synch an open file.
9399167Ssam  */
9409167Ssam fsync()
9419167Ssam {
9429167Ssam 	struct a {
9439167Ssam 		int	fd;
9449167Ssam 	} *uap = (struct a *)u.u_ap;
9459167Ssam 	struct file *fp;
94637741Smckusick 	int error;
9479167Ssam 
94837741Smckusick 	if (error = getvnode(uap->fd, &fp))
94937741Smckusick 		RETURN (error);
95037741Smckusick 	error = VOP_FSYNC((struct vnode *)fp->f_data, fp->f_flag, fp->f_cred);
95137741Smckusick 	RETURN (error);
9529167Ssam }
9539167Ssam 
9549167Ssam /*
9559167Ssam  * Rename system call.
9569167Ssam  *
9579167Ssam  * Source and destination must either both be directories, or both
9589167Ssam  * not be directories.  If target is a directory, it must be empty.
9599167Ssam  */
9607701Ssam rename()
9617701Ssam {
9627701Ssam 	struct a {
9637701Ssam 		char	*from;
9647701Ssam 		char	*to;
96516694Smckusick 	} *uap = (struct a *)u.u_ap;
96637741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
96716694Smckusick 	register struct nameidata *ndp = &u.u_nd;
96837741Smckusick 	struct nameidata tond;
96937741Smckusick 	int error;
9707701Ssam 
97137741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
97216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
97316694Smckusick 	ndp->ni_dirp = uap->from;
97437741Smckusick 	if (error = namei(ndp))
97537741Smckusick 		RETURN (error);
97637741Smckusick 	fvp = ndp->ni_vp;
97737741Smckusick 	bzero((caddr_t)&tond, sizeof(tond));
97837741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
97937741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
98037741Smckusick 	tond.ni_dirp = uap->to;
98137741Smckusick 	tond.ni_cdir = ndp->ni_cdir;
98237741Smckusick 	tond.ni_cdir->v_count++;
98337741Smckusick 	tond.ni_rdir = ndp->ni_rdir;
98437741Smckusick 	if (tond.ni_rdir)
98537741Smckusick 		tond.ni_rdir->v_count++;
98637741Smckusick 	tond.ni_cred = ndp->ni_cred;
98737741Smckusick 	crhold(tond.ni_cred);
98837741Smckusick 	error = namei(&tond);
98937741Smckusick 	tdvp = tond.ni_dvp;
99037741Smckusick 	tvp = tond.ni_vp;
99137741Smckusick 	if (tvp != NULL) {
99237741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
99337741Smckusick 			error = EISDIR;
99437741Smckusick 			goto out;
99537741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
99637741Smckusick 			error = ENOTDIR;
99737741Smckusick 			goto out;
9989167Ssam 		}
9999167Ssam 	}
100037741Smckusick 	if (error) {
100137741Smckusick 		VOP_ABORTOP(ndp);
100237741Smckusick 		goto out1;
100337741Smckusick 	}
100437741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
100537741Smckusick 		error = EXDEV;
10069167Ssam 		goto out;
100710051Ssam 	}
100837741Smckusick 	if (fvp == tdvp || fvp == tvp)
100937741Smckusick 		error = EINVAL;
101037741Smckusick out:
101137741Smckusick 	if (error) {
101237741Smckusick 		VOP_ABORTOP(&tond);
101337741Smckusick 		VOP_ABORTOP(ndp);
10149167Ssam 	} else {
101537741Smckusick 		error = VOP_RENAME(ndp, &tond);
10169167Ssam 	}
101737741Smckusick out1:
101837741Smckusick 	vrele(tond.ni_cdir);
101937741Smckusick 	if (tond.ni_rdir)
102037741Smckusick 		vrele(tond.ni_rdir);
102137741Smckusick 	crfree(tond.ni_cred);
102237741Smckusick 	RETURN (error);
10237701Ssam }
10247701Ssam 
10257535Sroot /*
102612756Ssam  * Mkdir system call
102712756Ssam  */
102812756Ssam mkdir()
102912756Ssam {
103012756Ssam 	struct a {
103112756Ssam 		char	*name;
103212756Ssam 		int	dmode;
103316694Smckusick 	} *uap = (struct a *)u.u_ap;
103416694Smckusick 	register struct nameidata *ndp = &u.u_nd;
103537741Smckusick 	register struct vnode *vp;
103637741Smckusick 	struct vattr vattr;
103737741Smckusick 	int error;
103812756Ssam 
103937741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
104016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
104116694Smckusick 	ndp->ni_dirp = uap->name;
104237741Smckusick 	if (error = namei(ndp))
104337741Smckusick 		RETURN (error);
104437741Smckusick 	vp = ndp->ni_vp;
104537741Smckusick 	if (vp != NULL) {
104637741Smckusick 		VOP_ABORTOP(ndp);
104737741Smckusick 		RETURN (EEXIST);
104812756Ssam 	}
104937741Smckusick 	vattr_null(&vattr);
105037741Smckusick 	vattr.va_type = VDIR;
105137741Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask;
105237741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
105337741Smckusick 	RETURN (error);
105412756Ssam }
105512756Ssam 
105612756Ssam /*
105712756Ssam  * Rmdir system call.
105812756Ssam  */
105912756Ssam rmdir()
106012756Ssam {
106112756Ssam 	struct a {
106212756Ssam 		char	*name;
106316694Smckusick 	} *uap = (struct a *)u.u_ap;
106416694Smckusick 	register struct nameidata *ndp = &u.u_nd;
106537741Smckusick 	register struct vnode *vp;
106637741Smckusick 	int error;
106712756Ssam 
106837741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
106916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
107016694Smckusick 	ndp->ni_dirp = uap->name;
107137741Smckusick 	if (error = namei(ndp))
107237741Smckusick 		RETURN (error);
107337741Smckusick 	vp = ndp->ni_vp;
107437741Smckusick 	if (vp->v_type != VDIR) {
107537741Smckusick 		error = ENOTDIR;
107612756Ssam 		goto out;
107712756Ssam 	}
107812756Ssam 	/*
107937741Smckusick 	 * No rmdir "." please.
108012756Ssam 	 */
108137741Smckusick 	if (ndp->ni_dvp == vp) {
108237741Smckusick 		error = EINVAL;
108312756Ssam 		goto out;
108412756Ssam 	}
108512756Ssam 	/*
108637741Smckusick 	 * Don't unlink a mounted file.
108712756Ssam 	 */
108837741Smckusick 	if (vp->v_flag & VROOT)
108937741Smckusick 		error = EBUSY;
109012756Ssam out:
109137741Smckusick 	if (error)
109237741Smckusick 		VOP_ABORTOP(ndp);
109337741Smckusick 	else
109437741Smckusick 		error = VOP_RMDIR(ndp);
109537741Smckusick 	RETURN (error);
109612756Ssam }
109712756Ssam 
109837741Smckusick /*
109937741Smckusick  * Read a block of directory entries in a file system independent format
110037741Smckusick  */
110137741Smckusick getdirentries()
110212756Ssam {
110337741Smckusick 	register struct a {
110437741Smckusick 		int	fd;
110537741Smckusick 		char	*buf;
110637741Smckusick 		unsigned count;
110737741Smckusick 		long	*basep;
110837741Smckusick 	} *uap = (struct a *)u.u_ap;
110916540Ssam 	struct file *fp;
111037741Smckusick 	struct uio auio;
111137741Smckusick 	struct iovec aiov;
1112*38129Smckusick 	off_t off;
111337741Smckusick 	int error;
111412756Ssam 
111537741Smckusick 	if (error = getvnode(uap->fd, &fp))
111637741Smckusick 		RETURN (error);
111737741Smckusick 	if ((fp->f_flag & FREAD) == 0)
111837741Smckusick 		RETURN (EBADF);
111937741Smckusick 	aiov.iov_base = uap->buf;
112037741Smckusick 	aiov.iov_len = uap->count;
112137741Smckusick 	auio.uio_iov = &aiov;
112237741Smckusick 	auio.uio_iovcnt = 1;
112337741Smckusick 	auio.uio_rw = UIO_READ;
112437741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
112537741Smckusick 	auio.uio_resid = uap->count;
1126*38129Smckusick 	off = fp->f_offset;
112737741Smckusick 	if (error = VOP_READDIR((struct vnode *)fp->f_data, &auio,
112837741Smckusick 	    &(fp->f_offset), fp->f_cred))
112937741Smckusick 		RETURN (error);
1130*38129Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep,
113137741Smckusick 		sizeof(long));
113237741Smckusick 	u.u_r.r_val1 = uap->count - auio.uio_resid;
113337741Smckusick 	RETURN (error);
113412756Ssam }
113512756Ssam 
113612756Ssam /*
113712756Ssam  * mode mask for creation of files
113812756Ssam  */
113912756Ssam umask()
114012756Ssam {
114112756Ssam 	register struct a {
114212756Ssam 		int	mask;
114316694Smckusick 	} *uap = (struct a *)u.u_ap;
114412756Ssam 
114512756Ssam 	u.u_r.r_val1 = u.u_cmask;
114612756Ssam 	u.u_cmask = uap->mask & 07777;
114737741Smckusick 	RETURN (0);
114812756Ssam }
114937741Smckusick 
115037741Smckusick getvnode(fdes, fpp)
115137741Smckusick 	struct file **fpp;
115237741Smckusick 	int fdes;
115337741Smckusick {
115437741Smckusick 	struct file *fp;
115537741Smckusick 
115637741Smckusick 	if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL)
115737741Smckusick 		return (EBADF);
115837741Smckusick 	if (fp->f_type != DTYPE_VNODE)
115937741Smckusick 		return (EINVAL);
116037741Smckusick 	*fpp = fp;
116137741Smckusick 	return (0);
116237741Smckusick }
1163