xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 47540)
123405Smckusick /*
237741Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337741Smckusick  * All rights reserved.
423405Smckusick  *
544459Sbostic  * %sccs.include.redist.c%
637741Smckusick  *
7*47540Skarels  *	@(#)vfs_syscalls.c	7.65 (Berkeley) 03/17/91
823405Smckusick  */
937Sbill 
1017101Sbloom #include "param.h"
1117101Sbloom #include "systm.h"
12*47540Skarels #include "namei.h"
1345914Smckusick #include "filedesc.h"
1417101Sbloom #include "kernel.h"
1517101Sbloom #include "file.h"
1617101Sbloom #include "stat.h"
1737741Smckusick #include "vnode.h"
1837741Smckusick #include "mount.h"
1917101Sbloom #include "proc.h"
2017101Sbloom #include "uio.h"
2137741Smckusick #include "malloc.h"
2237Sbill 
2337741Smckusick /*
2437741Smckusick  * Virtual File System System Calls
2537741Smckusick  */
2612756Ssam 
279167Ssam /*
2837741Smckusick  * mount system call
299167Ssam  */
3042441Smckusick /* ARGSUSED */
3142441Smckusick mount(p, uap, retval)
3245914Smckusick 	struct proc *p;
3342441Smckusick 	register struct args {
3437741Smckusick 		int	type;
3537741Smckusick 		char	*dir;
3637741Smckusick 		int	flags;
3737741Smckusick 		caddr_t	data;
3842441Smckusick 	} *uap;
3942441Smckusick 	int *retval;
4042441Smckusick {
41*47540Skarels 	register struct nameidata *ndp;
4239335Smckusick 	register struct vnode *vp;
4339335Smckusick 	register struct mount *mp;
4440111Smckusick 	int error, flag;
45*47540Skarels 	struct nameidata nd;
466254Sroot 
4737741Smckusick 	/*
4837741Smckusick 	 * Must be super user
4937741Smckusick 	 */
50*47540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
51*47540Skarels 		return (error);
5237741Smckusick 	/*
5337741Smckusick 	 * Get vnode to be covered
5437741Smckusick 	 */
55*47540Skarels 	ndp = &nd;
5637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
5737741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
5837741Smckusick 	ndp->ni_dirp = uap->dir;
59*47540Skarels 	if (error = namei(ndp, p))
60*47540Skarels 		return (error);
6137741Smckusick 	vp = ndp->ni_vp;
6241400Smckusick 	if (uap->flags & MNT_UPDATE) {
6339335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
6439335Smckusick 			vput(vp);
65*47540Skarels 			return (EINVAL);
6639335Smckusick 		}
6739335Smckusick 		mp = vp->v_mount;
6839335Smckusick 		/*
6939335Smckusick 		 * We allow going from read-only to read-write,
7039335Smckusick 		 * but not from read-write to read-only.
7139335Smckusick 		 */
7241400Smckusick 		if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
7341400Smckusick 		    (uap->flags & MNT_RDONLY) != 0) {
7439335Smckusick 			vput(vp);
75*47540Skarels 			return (EOPNOTSUPP);	/* Needs translation */
7639335Smckusick 		}
7741400Smckusick 		flag = mp->mnt_flag;
7841400Smckusick 		mp->mnt_flag |= MNT_UPDATE;
7939335Smckusick 		VOP_UNLOCK(vp);
8039335Smckusick 		goto update;
8139335Smckusick 	}
8239665Smckusick 	vinvalbuf(vp, 1);
8339805Smckusick 	if (vp->v_usecount != 1) {
8437741Smckusick 		vput(vp);
85*47540Skarels 		return (EBUSY);
8637741Smckusick 	}
8737741Smckusick 	if (vp->v_type != VDIR) {
8837741Smckusick 		vput(vp);
89*47540Skarels 		return (ENOTDIR);
9037741Smckusick 	}
9139741Smckusick 	if ((unsigned long)uap->type > MOUNT_MAXTYPE ||
9237741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
9337741Smckusick 		vput(vp);
94*47540Skarels 		return (ENODEV);
9537741Smckusick 	}
9637741Smckusick 
9737741Smckusick 	/*
9839335Smckusick 	 * Allocate and initialize the file system.
9937741Smckusick 	 */
10037741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
10137741Smckusick 		M_MOUNT, M_WAITOK);
10241400Smckusick 	mp->mnt_op = vfssw[uap->type];
10341400Smckusick 	mp->mnt_flag = 0;
10441400Smckusick 	mp->mnt_exroot = 0;
10541400Smckusick 	mp->mnt_mounth = NULLVP;
10639335Smckusick 	if (error = vfs_lock(mp)) {
10739335Smckusick 		free((caddr_t)mp, M_MOUNT);
10839335Smckusick 		vput(vp);
109*47540Skarels 		return (error);
11039335Smckusick 	}
11139335Smckusick 	if (vp->v_mountedhere != (struct mount *)0) {
11239335Smckusick 		vfs_unlock(mp);
11339335Smckusick 		free((caddr_t)mp, M_MOUNT);
11439335Smckusick 		vput(vp);
115*47540Skarels 		return (EBUSY);
11639335Smckusick 	}
11739335Smckusick 	vp->v_mountedhere = mp;
11841400Smckusick 	mp->mnt_vnodecovered = vp;
11939335Smckusick update:
12039335Smckusick 	/*
12139335Smckusick 	 * Set the mount level flags.
12239335Smckusick 	 */
12341400Smckusick 	if (uap->flags & MNT_RDONLY)
12441400Smckusick 		mp->mnt_flag |= MNT_RDONLY;
12539335Smckusick 	else
12641400Smckusick 		mp->mnt_flag &= ~MNT_RDONLY;
12741400Smckusick 	if (uap->flags & MNT_NOSUID)
12841400Smckusick 		mp->mnt_flag |= MNT_NOSUID;
12939335Smckusick 	else
13041400Smckusick 		mp->mnt_flag &= ~MNT_NOSUID;
13141400Smckusick 	if (uap->flags & MNT_NOEXEC)
13241400Smckusick 		mp->mnt_flag |= MNT_NOEXEC;
13339335Smckusick 	else
13441400Smckusick 		mp->mnt_flag &= ~MNT_NOEXEC;
13541400Smckusick 	if (uap->flags & MNT_NODEV)
13641400Smckusick 		mp->mnt_flag |= MNT_NODEV;
13739335Smckusick 	else
13841400Smckusick 		mp->mnt_flag &= ~MNT_NODEV;
13941400Smckusick 	if (uap->flags & MNT_SYNCHRONOUS)
14041400Smckusick 		mp->mnt_flag |= MNT_SYNCHRONOUS;
14139335Smckusick 	else
14241400Smckusick 		mp->mnt_flag &= ~MNT_SYNCHRONOUS;
14339335Smckusick 	/*
14439335Smckusick 	 * Mount the filesystem.
14539335Smckusick 	 */
14639335Smckusick 	error = VFS_MOUNT(mp, uap->dir, uap->data, ndp);
14741400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
14841400Smckusick 		mp->mnt_flag &= ~MNT_UPDATE;
14939335Smckusick 		vrele(vp);
15040111Smckusick 		if (error)
15141400Smckusick 			mp->mnt_flag = flag;
152*47540Skarels 		return (error);
15339335Smckusick 	}
15440110Smckusick 	/*
15540110Smckusick 	 * Put the new filesystem on the mount list after root.
15640110Smckusick 	 */
15741400Smckusick 	mp->mnt_next = rootfs->mnt_next;
15841400Smckusick 	mp->mnt_prev = rootfs;
15941400Smckusick 	rootfs->mnt_next = mp;
16041400Smckusick 	mp->mnt_next->mnt_prev = mp;
16137741Smckusick 	cache_purge(vp);
16237741Smckusick 	if (!error) {
16339335Smckusick 		VOP_UNLOCK(vp);
16437741Smckusick 		vfs_unlock(mp);
16539044Smckusick 		error = VFS_START(mp, 0);
16637741Smckusick 	} else {
16737741Smckusick 		vfs_remove(mp);
16837741Smckusick 		free((caddr_t)mp, M_MOUNT);
16939335Smckusick 		vput(vp);
17037741Smckusick 	}
171*47540Skarels 	return (error);
1726254Sroot }
1736254Sroot 
1749167Ssam /*
17537741Smckusick  * Unmount system call.
17637741Smckusick  *
17737741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
17837741Smckusick  * not special file (as before).
1799167Ssam  */
18042441Smckusick /* ARGSUSED */
18142441Smckusick unmount(p, uap, retval)
18245914Smckusick 	struct proc *p;
18342441Smckusick 	register struct args {
18437741Smckusick 		char	*pathp;
18537741Smckusick 		int	flags;
18642441Smckusick 	} *uap;
18742441Smckusick 	int *retval;
18842441Smckusick {
18937741Smckusick 	register struct vnode *vp;
190*47540Skarels 	register struct nameidata *ndp;
19139356Smckusick 	struct mount *mp;
19237741Smckusick 	int error;
193*47540Skarels 	struct nameidata nd;
1946254Sroot 
19537741Smckusick 	/*
19637741Smckusick 	 * Must be super user
19737741Smckusick 	 */
198*47540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
199*47540Skarels 		return (error);
20037741Smckusick 
201*47540Skarels 	ndp = &nd;
20237741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
20337741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
20437741Smckusick 	ndp->ni_dirp = uap->pathp;
205*47540Skarels 	if (error = namei(ndp, p))
206*47540Skarels 		return (error);
20737741Smckusick 	vp = ndp->ni_vp;
20837741Smckusick 	/*
20937741Smckusick 	 * Must be the root of the filesystem
21037741Smckusick 	 */
21137741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
21237741Smckusick 		vput(vp);
213*47540Skarels 		return (EINVAL);
21437741Smckusick 	}
21537741Smckusick 	mp = vp->v_mount;
21637741Smckusick 	vput(vp);
217*47540Skarels 	return (dounmount(mp, uap->flags));
21839356Smckusick }
21939356Smckusick 
22039356Smckusick /*
22139356Smckusick  * Do an unmount.
22239356Smckusick  */
22339356Smckusick dounmount(mp, flags)
22439356Smckusick 	register struct mount *mp;
22539356Smckusick 	int flags;
22639356Smckusick {
22739356Smckusick 	struct vnode *coveredvp;
22839356Smckusick 	int error;
22939356Smckusick 
23041400Smckusick 	coveredvp = mp->mnt_vnodecovered;
23141298Smckusick 	if (vfs_busy(mp))
23241298Smckusick 		return (EBUSY);
23341400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
23437741Smckusick 	if (error = vfs_lock(mp))
23539356Smckusick 		return (error);
23637741Smckusick 
23745922Smckusick #ifdef NVM
23845738Smckusick 	vnode_pager_umount(mp);	/* release cached vnodes */
23945922Smckusick #else
24045922Smckusick 	xumount(mp);		/* remove unused sticky files from text table */
24145922Smckusick #endif
24237741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
24341676Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE))
24441676Smckusick 		error = VFS_UNMOUNT(mp, flags);
24541400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
24641298Smckusick 	vfs_unbusy(mp);
24737741Smckusick 	if (error) {
24837741Smckusick 		vfs_unlock(mp);
24937741Smckusick 	} else {
25037741Smckusick 		vrele(coveredvp);
25137741Smckusick 		vfs_remove(mp);
25237741Smckusick 		free((caddr_t)mp, M_MOUNT);
25337741Smckusick 	}
25439356Smckusick 	return (error);
2556254Sroot }
2566254Sroot 
2579167Ssam /*
25837741Smckusick  * Sync system call.
25937741Smckusick  * Sync each mounted filesystem.
2609167Ssam  */
26139491Smckusick /* ARGSUSED */
26242441Smckusick sync(p, uap, retval)
26345914Smckusick 	struct proc *p;
264*47540Skarels 	void *uap;
26542441Smckusick 	int *retval;
2666254Sroot {
26737741Smckusick 	register struct mount *mp;
26841298Smckusick 	struct mount *omp;
26937741Smckusick 
27037741Smckusick 	mp = rootfs;
27137741Smckusick 	do {
27240343Smckusick 		/*
27340343Smckusick 		 * The lock check below is to avoid races with mount
27440343Smckusick 		 * and unmount.
27540343Smckusick 		 */
27641400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
27741298Smckusick 		    !vfs_busy(mp)) {
27837741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
27941298Smckusick 			omp = mp;
28041400Smckusick 			mp = mp->mnt_next;
28141298Smckusick 			vfs_unbusy(omp);
28241298Smckusick 		} else
28341400Smckusick 			mp = mp->mnt_next;
28437741Smckusick 	} while (mp != rootfs);
28537741Smckusick }
28637741Smckusick 
28737741Smckusick /*
28841298Smckusick  * operate on filesystem quotas
28941298Smckusick  */
29042441Smckusick /* ARGSUSED */
29142441Smckusick quotactl(p, uap, retval)
29245914Smckusick 	struct proc *p;
29342441Smckusick 	register struct args {
29441298Smckusick 		char *path;
29541298Smckusick 		int cmd;
29641298Smckusick 		int uid;
29741298Smckusick 		caddr_t arg;
29842441Smckusick 	} *uap;
29942441Smckusick 	int *retval;
30042441Smckusick {
30141298Smckusick 	register struct mount *mp;
302*47540Skarels 	register struct nameidata *ndp;
30341298Smckusick 	int error;
304*47540Skarels 	struct nameidata nd;
30541298Smckusick 
306*47540Skarels 	ndp = &nd;
30741298Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
30841298Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
30941298Smckusick 	ndp->ni_dirp = uap->path;
310*47540Skarels 	if (error = namei(ndp, p))
311*47540Skarels 		return (error);
31241298Smckusick 	mp = ndp->ni_vp->v_mount;
31341298Smckusick 	vrele(ndp->ni_vp);
314*47540Skarels 	return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg));
31541298Smckusick }
31641298Smckusick 
31741298Smckusick /*
31837741Smckusick  * get filesystem statistics
31937741Smckusick  */
32042441Smckusick /* ARGSUSED */
32142441Smckusick statfs(p, uap, retval)
32245914Smckusick 	struct proc *p;
32342441Smckusick 	register struct args {
32437741Smckusick 		char *path;
32537741Smckusick 		struct statfs *buf;
32642441Smckusick 	} *uap;
32742441Smckusick 	int *retval;
32842441Smckusick {
32939464Smckusick 	register struct mount *mp;
330*47540Skarels 	register struct nameidata *ndp;
33140343Smckusick 	register struct statfs *sp;
33237741Smckusick 	int error;
333*47540Skarels 	struct nameidata nd;
33437741Smckusick 
335*47540Skarels 	ndp = &nd;
33639544Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
33737741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
33837741Smckusick 	ndp->ni_dirp = uap->path;
339*47540Skarels 	if (error = namei(ndp, p))
340*47540Skarels 		return (error);
34139544Smckusick 	mp = ndp->ni_vp->v_mount;
34241400Smckusick 	sp = &mp->mnt_stat;
34339544Smckusick 	vrele(ndp->ni_vp);
34440343Smckusick 	if (error = VFS_STATFS(mp, sp))
345*47540Skarels 		return (error);
34641400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
347*47540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
34837741Smckusick }
34937741Smckusick 
35042441Smckusick /*
35142441Smckusick  * get filesystem statistics
35242441Smckusick  */
35342441Smckusick /* ARGSUSED */
35442441Smckusick fstatfs(p, uap, retval)
35545914Smckusick 	struct proc *p;
35642441Smckusick 	register struct args {
35737741Smckusick 		int fd;
35837741Smckusick 		struct statfs *buf;
35942441Smckusick 	} *uap;
36042441Smckusick 	int *retval;
36142441Smckusick {
36237741Smckusick 	struct file *fp;
36339464Smckusick 	struct mount *mp;
36440343Smckusick 	register struct statfs *sp;
36537741Smckusick 	int error;
36637741Smckusick 
36745914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
368*47540Skarels 		return (error);
36939464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
37041400Smckusick 	sp = &mp->mnt_stat;
37140343Smckusick 	if (error = VFS_STATFS(mp, sp))
372*47540Skarels 		return (error);
37341400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
374*47540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
37537741Smckusick }
37637741Smckusick 
37737741Smckusick /*
37838270Smckusick  * get statistics on all filesystems
37938270Smckusick  */
38042441Smckusick getfsstat(p, uap, retval)
38145914Smckusick 	struct proc *p;
38242441Smckusick 	register struct args {
38338270Smckusick 		struct statfs *buf;
38438270Smckusick 		long bufsize;
38540343Smckusick 		int flags;
38642441Smckusick 	} *uap;
38742441Smckusick 	int *retval;
38842441Smckusick {
38938270Smckusick 	register struct mount *mp;
39040343Smckusick 	register struct statfs *sp;
39139606Smckusick 	caddr_t sfsp;
39238270Smckusick 	long count, maxcount, error;
39338270Smckusick 
39438270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
39539606Smckusick 	sfsp = (caddr_t)uap->buf;
39638270Smckusick 	mp = rootfs;
39738270Smckusick 	count = 0;
39838270Smckusick 	do {
39941400Smckusick 		if (sfsp && count < maxcount &&
40041400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
40141400Smckusick 			sp = &mp->mnt_stat;
40240343Smckusick 			/*
40340343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
40440343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
40540343Smckusick 			 */
40640343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
40740343Smckusick 			    (uap->flags & MNT_WAIT)) &&
40840343Smckusick 			    (error = VFS_STATFS(mp, sp))) {
40941400Smckusick 				mp = mp->mnt_prev;
41039607Smckusick 				continue;
41139607Smckusick 			}
41241400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
41340343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
414*47540Skarels 				return (error);
41540343Smckusick 			sfsp += sizeof(*sp);
41638270Smckusick 		}
41739606Smckusick 		count++;
41841400Smckusick 		mp = mp->mnt_prev;
41938270Smckusick 	} while (mp != rootfs);
42038270Smckusick 	if (sfsp && count > maxcount)
42142441Smckusick 		*retval = maxcount;
42238270Smckusick 	else
42342441Smckusick 		*retval = count;
424*47540Skarels 	return (0);
42538270Smckusick }
42638270Smckusick 
42738270Smckusick /*
42838259Smckusick  * Change current working directory to a given file descriptor.
42938259Smckusick  */
43042441Smckusick /* ARGSUSED */
43142441Smckusick fchdir(p, uap, retval)
43245914Smckusick 	struct proc *p;
43342441Smckusick 	struct args {
43442441Smckusick 		int	fd;
43542441Smckusick 	} *uap;
43642441Smckusick 	int *retval;
43738259Smckusick {
43845914Smckusick 	register struct filedesc *fdp = p->p_fd;
43938259Smckusick 	register struct vnode *vp;
44038259Smckusick 	struct file *fp;
44138259Smckusick 	int error;
44238259Smckusick 
44345914Smckusick 	if (error = getvnode(fdp, uap->fd, &fp))
444*47540Skarels 		return (error);
44538259Smckusick 	vp = (struct vnode *)fp->f_data;
44638259Smckusick 	VOP_LOCK(vp);
44738259Smckusick 	if (vp->v_type != VDIR)
44838259Smckusick 		error = ENOTDIR;
44938259Smckusick 	else
450*47540Skarels 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred);
45138259Smckusick 	VOP_UNLOCK(vp);
45239860Smckusick 	if (error)
453*47540Skarels 		return (error);
45439860Smckusick 	VREF(vp);
45545914Smckusick 	vrele(fdp->fd_cdir);
45645914Smckusick 	fdp->fd_cdir = vp;
457*47540Skarels 	return (0);
45838259Smckusick }
45938259Smckusick 
46038259Smckusick /*
46137741Smckusick  * Change current working directory (``.'').
46237741Smckusick  */
46342441Smckusick /* ARGSUSED */
46442441Smckusick chdir(p, uap, retval)
46545914Smckusick 	struct proc *p;
46642441Smckusick 	struct args {
46742441Smckusick 		char	*fname;
46842441Smckusick 	} *uap;
46942441Smckusick 	int *retval;
47037741Smckusick {
471*47540Skarels 	register struct nameidata *ndp;
47245914Smckusick 	register struct filedesc *fdp = p->p_fd;
47337741Smckusick 	int error;
474*47540Skarels 	struct nameidata nd;
4756254Sroot 
476*47540Skarels 	ndp = &nd;
47737741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
47816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
47916694Smckusick 	ndp->ni_dirp = uap->fname;
480*47540Skarels 	if (error = chdirec(ndp, p))
481*47540Skarels 		return (error);
48245914Smckusick 	vrele(fdp->fd_cdir);
48345914Smckusick 	fdp->fd_cdir = ndp->ni_vp;
484*47540Skarels 	return (0);
48537741Smckusick }
4866254Sroot 
48737741Smckusick /*
48837741Smckusick  * Change notion of root (``/'') directory.
48937741Smckusick  */
49042441Smckusick /* ARGSUSED */
49142441Smckusick chroot(p, uap, retval)
49245914Smckusick 	struct proc *p;
49342441Smckusick 	struct args {
49442441Smckusick 		char	*fname;
49542441Smckusick 	} *uap;
49642441Smckusick 	int *retval;
49737741Smckusick {
498*47540Skarels 	register struct nameidata *ndp;
49945914Smckusick 	register struct filedesc *fdp = p->p_fd;
50037741Smckusick 	int error;
501*47540Skarels 	struct nameidata nd;
50237741Smckusick 
503*47540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
504*47540Skarels 		return (error);
505*47540Skarels 	ndp = &nd;
50637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
50737741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
50837741Smckusick 	ndp->ni_dirp = uap->fname;
509*47540Skarels 	if (error = chdirec(ndp, p))
510*47540Skarels 		return (error);
51145914Smckusick 	if (fdp->fd_rdir != NULL)
51245914Smckusick 		vrele(fdp->fd_rdir);
51345914Smckusick 	fdp->fd_rdir = ndp->ni_vp;
514*47540Skarels 	return (0);
5156254Sroot }
5166254Sroot 
51737Sbill /*
51837741Smckusick  * Common routine for chroot and chdir.
51937741Smckusick  */
520*47540Skarels chdirec(ndp, p)
521*47540Skarels 	struct nameidata *ndp;
522*47540Skarels 	struct proc *p;
52337741Smckusick {
52437741Smckusick 	struct vnode *vp;
52537741Smckusick 	int error;
52637741Smckusick 
527*47540Skarels 	if (error = namei(ndp, p))
52837741Smckusick 		return (error);
52937741Smckusick 	vp = ndp->ni_vp;
53037741Smckusick 	if (vp->v_type != VDIR)
53137741Smckusick 		error = ENOTDIR;
53237741Smckusick 	else
533*47540Skarels 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred);
53437741Smckusick 	VOP_UNLOCK(vp);
53537741Smckusick 	if (error)
53637741Smckusick 		vrele(vp);
53737741Smckusick 	return (error);
53837741Smckusick }
53937741Smckusick 
54037741Smckusick /*
5416254Sroot  * Open system call.
54242441Smckusick  * Check permissions, allocate an open file structure,
54342441Smckusick  * and call the device open routine if any.
5446254Sroot  */
54542441Smckusick open(p, uap, retval)
54645914Smckusick 	struct proc *p;
54742441Smckusick 	register struct args {
5486254Sroot 		char	*fname;
5497701Ssam 		int	mode;
55012756Ssam 		int	crtmode;
55142441Smckusick 	} *uap;
55242441Smckusick 	int *retval;
5536254Sroot {
554*47540Skarels 	struct nameidata *ndp;
55545914Smckusick 	register struct filedesc *fdp = p->p_fd;
55642441Smckusick 	register struct file *fp;
55737741Smckusick 	int fmode, cmode;
55837741Smckusick 	struct file *nfp;
55937741Smckusick 	int indx, error;
560*47540Skarels 	struct nameidata nd;
56137741Smckusick 	extern struct fileops vnops;
5626254Sroot 
56345914Smckusick 	if (error = falloc(p, &nfp, &indx))
564*47540Skarels 		return (error);
56537741Smckusick 	fp = nfp;
56646553Skarels 	fmode = FFLAGS(uap->mode);
56745914Smckusick 	cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX;
568*47540Skarels 	ndp = &nd;
56942441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
57042441Smckusick 	ndp->ni_dirp = uap->fname;
57145202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
572*47540Skarels 	if (error = vn_open(ndp, p, fmode, cmode)) {
57337741Smckusick 		crfree(fp->f_cred);
57437741Smckusick 		fp->f_count--;
57543405Smckusick 		if (error == ENODEV &&		/* XXX from fdopen */
57645202Smckusick 		    p->p_dupfd >= 0 &&
57745914Smckusick 		    (error = dupfdopen(fdp, indx, p->p_dupfd, fmode)) == 0) {
57842441Smckusick 			*retval = indx;
579*47540Skarels 			return (0);
58042441Smckusick 		}
58140884Smckusick 		if (error == ERESTART)
58240884Smckusick 			error = EINTR;
58345914Smckusick 		OFILE(fdp, indx) = NULL;
584*47540Skarels 		return (error);
58512756Ssam 	}
58637741Smckusick 	fp->f_flag = fmode & FMASK;
58737741Smckusick 	fp->f_type = DTYPE_VNODE;
58837741Smckusick 	fp->f_ops = &vnops;
58937741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
59042441Smckusick 	*retval = indx;
591*47540Skarels 	return (0);
5926254Sroot }
5936254Sroot 
59442955Smckusick #ifdef COMPAT_43
5956254Sroot /*
59642441Smckusick  * Creat system call.
5976254Sroot  */
59842955Smckusick ocreat(p, uap, retval)
59942441Smckusick 	struct proc *p;
60042441Smckusick 	register struct args {
60142441Smckusick 		char	*fname;
60242441Smckusick 		int	fmode;
60342441Smckusick 	} *uap;
60442441Smckusick 	int *retval;
6056254Sroot {
60642441Smckusick 	struct args {
6076254Sroot 		char	*fname;
60842441Smckusick 		int	mode;
60942441Smckusick 		int	crtmode;
61042441Smckusick 	} openuap;
61142441Smckusick 
61242441Smckusick 	openuap.fname = uap->fname;
61342441Smckusick 	openuap.crtmode = uap->fmode;
61442441Smckusick 	openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
615*47540Skarels 	return (open(p, &openuap, retval));
61642441Smckusick }
61742955Smckusick #endif /* COMPAT_43 */
61842441Smckusick 
61942441Smckusick /*
62042441Smckusick  * Mknod system call
62142441Smckusick  */
62242441Smckusick /* ARGSUSED */
62342441Smckusick mknod(p, uap, retval)
62445914Smckusick 	struct proc *p;
62542441Smckusick 	register struct args {
62642441Smckusick 		char	*fname;
6276254Sroot 		int	fmode;
6286254Sroot 		int	dev;
62942441Smckusick 	} *uap;
63042441Smckusick 	int *retval;
63142441Smckusick {
632*47540Skarels 	register struct nameidata *ndp;
63337741Smckusick 	register struct vnode *vp;
63437741Smckusick 	struct vattr vattr;
63537741Smckusick 	int error;
636*47540Skarels 	struct nameidata nd;
6376254Sroot 
638*47540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
639*47540Skarels 		return (error);
640*47540Skarels 	ndp = &nd;
64137741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
64216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
64316694Smckusick 	ndp->ni_dirp = uap->fname;
644*47540Skarels 	if (error = namei(ndp, p))
645*47540Skarels 		return (error);
64637741Smckusick 	vp = ndp->ni_vp;
64737741Smckusick 	if (vp != NULL) {
64837741Smckusick 		error = EEXIST;
64912756Ssam 		goto out;
6506254Sroot 	}
65141362Smckusick 	VATTR_NULL(&vattr);
65240635Smckusick 	switch (uap->fmode & S_IFMT) {
65312756Ssam 
65440635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
65537741Smckusick 		vattr.va_type = VBAD;
65637741Smckusick 		break;
65740635Smckusick 	case S_IFCHR:
65837741Smckusick 		vattr.va_type = VCHR;
65937741Smckusick 		break;
66040635Smckusick 	case S_IFBLK:
66137741Smckusick 		vattr.va_type = VBLK;
66237741Smckusick 		break;
66337741Smckusick 	default:
66437741Smckusick 		error = EINVAL;
66537741Smckusick 		goto out;
6666254Sroot 	}
66745914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
66837741Smckusick 	vattr.va_rdev = uap->dev;
6696254Sroot out:
67042465Smckusick 	if (!error) {
671*47540Skarels 		error = VOP_MKNOD(ndp, &vattr, p->p_ucred);
67242465Smckusick 	} else {
67337741Smckusick 		VOP_ABORTOP(ndp);
67443344Smckusick 		if (ndp->ni_dvp == vp)
67543344Smckusick 			vrele(ndp->ni_dvp);
67643344Smckusick 		else
67743344Smckusick 			vput(ndp->ni_dvp);
67842465Smckusick 		if (vp)
67942465Smckusick 			vrele(vp);
68042465Smckusick 	}
681*47540Skarels 	return (error);
6826254Sroot }
6836254Sroot 
6846254Sroot /*
68540285Smckusick  * Mkfifo system call
68640285Smckusick  */
68742441Smckusick /* ARGSUSED */
68842441Smckusick mkfifo(p, uap, retval)
68945914Smckusick 	struct proc *p;
69042441Smckusick 	register struct args {
69140285Smckusick 		char	*fname;
69240285Smckusick 		int	fmode;
69342441Smckusick 	} *uap;
69442441Smckusick 	int *retval;
69542441Smckusick {
696*47540Skarels 	register struct nameidata *ndp;
69740285Smckusick 	struct vattr vattr;
69840285Smckusick 	int error;
699*47540Skarels 	struct nameidata nd;
70040285Smckusick 
70140285Smckusick #ifndef FIFO
702*47540Skarels 	return (EOPNOTSUPP);
70340285Smckusick #else
704*47540Skarels 	ndp = &nd;
70540285Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
70640285Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
70740285Smckusick 	ndp->ni_dirp = uap->fname;
708*47540Skarels 	if (error = namei(ndp, p))
709*47540Skarels 		return (error);
71040285Smckusick 	if (ndp->ni_vp != NULL) {
71140285Smckusick 		VOP_ABORTOP(ndp);
71243344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
71343344Smckusick 			vrele(ndp->ni_dvp);
71443344Smckusick 		else
71543344Smckusick 			vput(ndp->ni_dvp);
71642465Smckusick 		vrele(ndp->ni_vp);
717*47540Skarels 		return (EEXIST);
71840285Smckusick 	}
71945785Sbostic 	VATTR_NULL(&vattr);
72045785Sbostic 	vattr.va_type = VFIFO;
72145914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
722*47540Skarels 	return (VOP_MKNOD(ndp, &vattr, p->p_ucred));
72340285Smckusick #endif /* FIFO */
72440285Smckusick }
72540285Smckusick 
72640285Smckusick /*
7276254Sroot  * link system call
7286254Sroot  */
72942441Smckusick /* ARGSUSED */
73042441Smckusick link(p, uap, retval)
73145914Smckusick 	struct proc *p;
73242441Smckusick 	register struct args {
7336254Sroot 		char	*target;
7346254Sroot 		char	*linkname;
73542441Smckusick 	} *uap;
73642441Smckusick 	int *retval;
73742441Smckusick {
738*47540Skarels 	register struct nameidata *ndp;
73937741Smckusick 	register struct vnode *vp, *xp;
74037741Smckusick 	int error;
741*47540Skarels 	struct nameidata nd;
7426254Sroot 
743*47540Skarels 	ndp = &nd;
74416694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
74516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
74616694Smckusick 	ndp->ni_dirp = uap->target;
747*47540Skarels 	if (error = namei(ndp, p))
748*47540Skarels 		return (error);
74937741Smckusick 	vp = ndp->ni_vp;
75037741Smckusick 	if (vp->v_type == VDIR &&
751*47540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
75237741Smckusick 		goto out1;
75337741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
75416694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
755*47540Skarels 	if (error = namei(ndp, p))
75637741Smckusick 		goto out1;
75737741Smckusick 	xp = ndp->ni_vp;
7586254Sroot 	if (xp != NULL) {
75937741Smckusick 		error = EEXIST;
7606254Sroot 		goto out;
7616254Sroot 	}
76237741Smckusick 	xp = ndp->ni_dvp;
76337741Smckusick 	if (vp->v_mount != xp->v_mount)
76437741Smckusick 		error = EXDEV;
7656254Sroot out:
76642465Smckusick 	if (!error) {
76742465Smckusick 		error = VOP_LINK(vp, ndp);
76842465Smckusick 	} else {
76937741Smckusick 		VOP_ABORTOP(ndp);
77043344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
77143344Smckusick 			vrele(ndp->ni_dvp);
77243344Smckusick 		else
77343344Smckusick 			vput(ndp->ni_dvp);
77442465Smckusick 		if (ndp->ni_vp)
77542465Smckusick 			vrele(ndp->ni_vp);
77642465Smckusick 	}
77737741Smckusick out1:
77837741Smckusick 	vrele(vp);
779*47540Skarels 	return (error);
7806254Sroot }
7816254Sroot 
7826254Sroot /*
7836254Sroot  * symlink -- make a symbolic link
7846254Sroot  */
78542441Smckusick /* ARGSUSED */
78642441Smckusick symlink(p, uap, retval)
78745914Smckusick 	struct proc *p;
78842441Smckusick 	register struct args {
7896254Sroot 		char	*target;
7906254Sroot 		char	*linkname;
79142441Smckusick 	} *uap;
79242441Smckusick 	int *retval;
79342441Smckusick {
794*47540Skarels 	register struct nameidata *ndp;
79537741Smckusick 	struct vattr vattr;
79637741Smckusick 	char *target;
79737741Smckusick 	int error;
798*47540Skarels 	struct nameidata nd;
7996254Sroot 
800*47540Skarels 	ndp = &nd;
80116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
80216694Smckusick 	ndp->ni_dirp = uap->linkname;
80337741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
80437741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
80542465Smckusick 		goto out;
80637741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
807*47540Skarels 	if (error = namei(ndp, p))
80842465Smckusick 		goto out;
80942465Smckusick 	if (ndp->ni_vp) {
81042465Smckusick 		VOP_ABORTOP(ndp);
81143344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
81243344Smckusick 			vrele(ndp->ni_dvp);
81343344Smckusick 		else
81443344Smckusick 			vput(ndp->ni_dvp);
81542465Smckusick 		vrele(ndp->ni_vp);
81637741Smckusick 		error = EEXIST;
81737741Smckusick 		goto out;
8186254Sroot 	}
81941362Smckusick 	VATTR_NULL(&vattr);
82045914Smckusick 	vattr.va_mode = 0777 &~ p->p_fd->fd_cmask;
82142465Smckusick 	error = VOP_SYMLINK(ndp, &vattr, target);
82237741Smckusick out:
82337741Smckusick 	FREE(target, M_NAMEI);
824*47540Skarels 	return (error);
8256254Sroot }
8266254Sroot 
8276254Sroot /*
8286254Sroot  * Unlink system call.
8296254Sroot  * Hard to avoid races here, especially
8306254Sroot  * in unlinking directories.
8316254Sroot  */
83242441Smckusick /* ARGSUSED */
83342441Smckusick unlink(p, uap, retval)
83445914Smckusick 	struct proc *p;
83542441Smckusick 	struct args {
83642441Smckusick 		char	*fname;
83742441Smckusick 	} *uap;
83842441Smckusick 	int *retval;
8396254Sroot {
840*47540Skarels 	register struct nameidata *ndp;
84137741Smckusick 	register struct vnode *vp;
84237741Smckusick 	int error;
843*47540Skarels 	struct nameidata nd;
8446254Sroot 
845*47540Skarels 	ndp = &nd;
84637741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
84716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
84816694Smckusick 	ndp->ni_dirp = uap->fname;
849*47540Skarels 	if (error = namei(ndp, p))
850*47540Skarels 		return (error);
85137741Smckusick 	vp = ndp->ni_vp;
85237741Smckusick 	if (vp->v_type == VDIR &&
853*47540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
8546254Sroot 		goto out;
8556254Sroot 	/*
8566254Sroot 	 * Don't unlink a mounted file.
8576254Sroot 	 */
85837741Smckusick 	if (vp->v_flag & VROOT) {
85937741Smckusick 		error = EBUSY;
8606254Sroot 		goto out;
8616254Sroot 	}
86245922Smckusick #ifdef NVM
86345738Smckusick 	(void) vnode_pager_uncache(vp);
86445922Smckusick #else
86545922Smckusick 	if (vp->v_flag & VTEXT)
86645922Smckusick 		xrele(vp);	/* try once to free text */
86745922Smckusick #endif
8686254Sroot out:
86942465Smckusick 	if (!error) {
87042465Smckusick 		error = VOP_REMOVE(ndp);
87142465Smckusick 	} else {
87237741Smckusick 		VOP_ABORTOP(ndp);
87343344Smckusick 		if (ndp->ni_dvp == vp)
87443344Smckusick 			vrele(ndp->ni_dvp);
87543344Smckusick 		else
87643344Smckusick 			vput(ndp->ni_dvp);
87742465Smckusick 		vput(vp);
87842465Smckusick 	}
879*47540Skarels 	return (error);
8806254Sroot }
8816254Sroot 
8826254Sroot /*
8836254Sroot  * Seek system call
8846254Sroot  */
88542441Smckusick lseek(p, uap, retval)
88645914Smckusick 	struct proc *p;
88742441Smckusick 	register struct args {
88837741Smckusick 		int	fdes;
8896254Sroot 		off_t	off;
8906254Sroot 		int	sbase;
89142441Smckusick 	} *uap;
89242441Smckusick 	off_t *retval;
89342441Smckusick {
894*47540Skarels 	struct ucred *cred = p->p_ucred;
89545914Smckusick 	register struct filedesc *fdp = p->p_fd;
89642441Smckusick 	register struct file *fp;
89737741Smckusick 	struct vattr vattr;
89837741Smckusick 	int error;
8996254Sroot 
900*47540Skarels 	if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
90145914Smckusick 	    (fp = OFILE(fdp, uap->fdes)) == NULL)
902*47540Skarels 		return (EBADF);
90337741Smckusick 	if (fp->f_type != DTYPE_VNODE)
904*47540Skarels 		return (ESPIPE);
90513878Ssam 	switch (uap->sbase) {
90613878Ssam 
90713878Ssam 	case L_INCR:
90813878Ssam 		fp->f_offset += uap->off;
90913878Ssam 		break;
91013878Ssam 
91113878Ssam 	case L_XTND:
91237741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
91342441Smckusick 		    &vattr, cred))
914*47540Skarels 			return (error);
91537741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
91613878Ssam 		break;
91713878Ssam 
91813878Ssam 	case L_SET:
91913878Ssam 		fp->f_offset = uap->off;
92013878Ssam 		break;
92113878Ssam 
92213878Ssam 	default:
923*47540Skarels 		return (EINVAL);
92413878Ssam 	}
92542441Smckusick 	*retval = fp->f_offset;
926*47540Skarels 	return (0);
9276254Sroot }
9286254Sroot 
9296254Sroot /*
9306254Sroot  * Access system call
9316254Sroot  */
93242441Smckusick /* ARGSUSED */
93342441Smckusick saccess(p, uap, retval)
93445914Smckusick 	struct proc *p;
93542441Smckusick 	register struct args {
9366254Sroot 		char	*fname;
9376254Sroot 		int	fmode;
93842441Smckusick 	} *uap;
93942441Smckusick 	int *retval;
94042441Smckusick {
941*47540Skarels 	register struct nameidata *ndp;
942*47540Skarels 	register struct ucred *cred = p->p_ucred;
94337741Smckusick 	register struct vnode *vp;
94437741Smckusick 	int error, mode, svuid, svgid;
945*47540Skarels 	struct nameidata nd;
9466254Sroot 
947*47540Skarels 	ndp = &nd;
94842441Smckusick 	svuid = cred->cr_uid;
94942441Smckusick 	svgid = cred->cr_groups[0];
950*47540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
951*47540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
95237741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
95316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
95416694Smckusick 	ndp->ni_dirp = uap->fname;
955*47540Skarels 	if (error = namei(ndp, p))
95637741Smckusick 		goto out1;
95737741Smckusick 	vp = ndp->ni_vp;
95837741Smckusick 	/*
95937741Smckusick 	 * fmode == 0 means only check for exist
96037741Smckusick 	 */
96137741Smckusick 	if (uap->fmode) {
96237741Smckusick 		mode = 0;
96337741Smckusick 		if (uap->fmode & R_OK)
96437741Smckusick 			mode |= VREAD;
96537741Smckusick 		if (uap->fmode & W_OK)
96637741Smckusick 			mode |= VWRITE;
96737741Smckusick 		if (uap->fmode & X_OK)
96837741Smckusick 			mode |= VEXEC;
96939543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
970*47540Skarels 			error = VOP_ACCESS(vp, mode, cred);
9716254Sroot 	}
97237741Smckusick 	vput(vp);
97337741Smckusick out1:
97442441Smckusick 	cred->cr_uid = svuid;
97542441Smckusick 	cred->cr_groups[0] = svgid;
976*47540Skarels 	return (error);
9776254Sroot }
9786254Sroot 
9796254Sroot /*
9806574Smckusic  * Stat system call.  This version follows links.
98137Sbill  */
98242441Smckusick /* ARGSUSED */
98342441Smckusick stat(p, uap, retval)
98445914Smckusick 	struct proc *p;
98542441Smckusick 	register struct args {
98642441Smckusick 		char	*fname;
98742441Smckusick 		struct stat *ub;
98842441Smckusick 	} *uap;
98942441Smckusick 	int *retval;
99037Sbill {
991*47540Skarels 	register struct nameidata *ndp;
99242441Smckusick 	struct stat sb;
99342441Smckusick 	int error;
994*47540Skarels 	struct nameidata nd;
99537Sbill 
996*47540Skarels 	ndp = &nd;
99742441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
99842441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
99942441Smckusick 	ndp->ni_dirp = uap->fname;
1000*47540Skarels 	if (error = namei(ndp, p))
1001*47540Skarels 		return (error);
100242441Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
100342441Smckusick 	vput(ndp->ni_vp);
100442441Smckusick 	if (error)
1005*47540Skarels 		return (error);
100642441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
1007*47540Skarels 	return (error);
100837Sbill }
100937Sbill 
101037Sbill /*
10116574Smckusic  * Lstat system call.  This version does not follow links.
10125992Swnj  */
101342441Smckusick /* ARGSUSED */
101442441Smckusick lstat(p, uap, retval)
101545914Smckusick 	struct proc *p;
101642441Smckusick 	register struct args {
10175992Swnj 		char	*fname;
101812756Ssam 		struct stat *ub;
101942441Smckusick 	} *uap;
102042441Smckusick 	int *retval;
102142441Smckusick {
1022*47540Skarels 	register struct nameidata *ndp;
102312756Ssam 	struct stat sb;
102437741Smckusick 	int error;
1025*47540Skarels 	struct nameidata nd;
10265992Swnj 
1027*47540Skarels 	ndp = &nd;
102842441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW;
102916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
103016694Smckusick 	ndp->ni_dirp = uap->fname;
1031*47540Skarels 	if (error = namei(ndp, p))
1032*47540Skarels 		return (error);
103337741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
103437741Smckusick 	vput(ndp->ni_vp);
103537741Smckusick 	if (error)
1036*47540Skarels 		return (error);
103737741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
1038*47540Skarels 	return (error);
10395992Swnj }
10405992Swnj 
10415992Swnj /*
10425992Swnj  * Return target name of a symbolic link
104337Sbill  */
104442441Smckusick /* ARGSUSED */
104542441Smckusick readlink(p, uap, retval)
104645914Smckusick 	struct proc *p;
104742441Smckusick 	register struct args {
10485992Swnj 		char	*name;
10495992Swnj 		char	*buf;
10505992Swnj 		int	count;
105142441Smckusick 	} *uap;
105242441Smckusick 	int *retval;
105342441Smckusick {
1054*47540Skarels 	register struct nameidata *ndp;
105537741Smckusick 	register struct vnode *vp;
105637741Smckusick 	struct iovec aiov;
105737741Smckusick 	struct uio auio;
105837741Smckusick 	int error;
1059*47540Skarels 	struct nameidata nd;
10605992Swnj 
1061*47540Skarels 	ndp = &nd;
106237741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
106316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
106416694Smckusick 	ndp->ni_dirp = uap->name;
1065*47540Skarels 	if (error = namei(ndp, p))
1066*47540Skarels 		return (error);
106737741Smckusick 	vp = ndp->ni_vp;
106837741Smckusick 	if (vp->v_type != VLNK) {
106937741Smckusick 		error = EINVAL;
10705992Swnj 		goto out;
10715992Swnj 	}
107237741Smckusick 	aiov.iov_base = uap->buf;
107337741Smckusick 	aiov.iov_len = uap->count;
107437741Smckusick 	auio.uio_iov = &aiov;
107537741Smckusick 	auio.uio_iovcnt = 1;
107637741Smckusick 	auio.uio_offset = 0;
107737741Smckusick 	auio.uio_rw = UIO_READ;
107837741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
107937741Smckusick 	auio.uio_resid = uap->count;
1080*47540Skarels 	error = VOP_READLINK(vp, &auio, p->p_ucred);
10815992Swnj out:
108237741Smckusick 	vput(vp);
108342441Smckusick 	*retval = uap->count - auio.uio_resid;
1084*47540Skarels 	return (error);
10855992Swnj }
10865992Swnj 
10879167Ssam /*
108838259Smckusick  * Change flags of a file given path name.
108938259Smckusick  */
109042441Smckusick /* ARGSUSED */
109142441Smckusick chflags(p, uap, retval)
109245914Smckusick 	struct proc *p;
109342441Smckusick 	register struct args {
109438259Smckusick 		char	*fname;
109538259Smckusick 		int	flags;
109642441Smckusick 	} *uap;
109742441Smckusick 	int *retval;
109842441Smckusick {
1099*47540Skarels 	register struct nameidata *ndp;
110038259Smckusick 	register struct vnode *vp;
110138259Smckusick 	struct vattr vattr;
110238259Smckusick 	int error;
1103*47540Skarels 	struct nameidata nd;
110438259Smckusick 
1105*47540Skarels 	ndp = &nd;
110638259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
110738259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
110838259Smckusick 	ndp->ni_dirp = uap->fname;
1109*47540Skarels 	if (error = namei(ndp, p))
1110*47540Skarels 		return (error);
111138259Smckusick 	vp = ndp->ni_vp;
111241400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
111338259Smckusick 		error = EROFS;
111438259Smckusick 		goto out;
111538259Smckusick 	}
111645785Sbostic 	VATTR_NULL(&vattr);
111745785Sbostic 	vattr.va_flags = uap->flags;
1118*47540Skarels 	error = VOP_SETATTR(vp, &vattr, p->p_ucred);
111938259Smckusick out:
112038259Smckusick 	vput(vp);
1121*47540Skarels 	return (error);
112238259Smckusick }
112338259Smckusick 
112438259Smckusick /*
112538259Smckusick  * Change flags of a file given a file descriptor.
112638259Smckusick  */
112742441Smckusick /* ARGSUSED */
112842441Smckusick fchflags(p, uap, retval)
112945914Smckusick 	struct proc *p;
113042441Smckusick 	register struct args {
113138259Smckusick 		int	fd;
113238259Smckusick 		int	flags;
113342441Smckusick 	} *uap;
113442441Smckusick 	int *retval;
113542441Smckusick {
113638259Smckusick 	struct vattr vattr;
113738259Smckusick 	struct vnode *vp;
113838259Smckusick 	struct file *fp;
113938259Smckusick 	int error;
114038259Smckusick 
114145914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
1142*47540Skarels 		return (error);
114338259Smckusick 	vp = (struct vnode *)fp->f_data;
114438259Smckusick 	VOP_LOCK(vp);
114541400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
114638259Smckusick 		error = EROFS;
114738259Smckusick 		goto out;
114838259Smckusick 	}
114945785Sbostic 	VATTR_NULL(&vattr);
115045785Sbostic 	vattr.va_flags = uap->flags;
1151*47540Skarels 	error = VOP_SETATTR(vp, &vattr, p->p_ucred);
115238259Smckusick out:
115338259Smckusick 	VOP_UNLOCK(vp);
1154*47540Skarels 	return (error);
115538259Smckusick }
115638259Smckusick 
115738259Smckusick /*
11589167Ssam  * Change mode of a file given path name.
11599167Ssam  */
116042441Smckusick /* ARGSUSED */
116142441Smckusick chmod(p, uap, retval)
116245914Smckusick 	struct proc *p;
116342441Smckusick 	register struct args {
11646254Sroot 		char	*fname;
11656254Sroot 		int	fmode;
116642441Smckusick 	} *uap;
116742441Smckusick 	int *retval;
116842441Smckusick {
1169*47540Skarels 	register struct nameidata *ndp;
117037741Smckusick 	register struct vnode *vp;
117137741Smckusick 	struct vattr vattr;
117237741Smckusick 	int error;
1173*47540Skarels 	struct nameidata nd;
11745992Swnj 
1175*47540Skarels 	ndp = &nd;
117637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
117737741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
117837741Smckusick 	ndp->ni_dirp = uap->fname;
1179*47540Skarels 	if (error = namei(ndp, p))
1180*47540Skarels 		return (error);
118137741Smckusick 	vp = ndp->ni_vp;
118241400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
118337741Smckusick 		error = EROFS;
118437741Smckusick 		goto out;
118537741Smckusick 	}
118645785Sbostic 	VATTR_NULL(&vattr);
118745785Sbostic 	vattr.va_mode = uap->fmode & 07777;
1188*47540Skarels 	error = VOP_SETATTR(vp, &vattr, p->p_ucred);
118937741Smckusick out:
119037741Smckusick 	vput(vp);
1191*47540Skarels 	return (error);
11927701Ssam }
11937439Sroot 
11949167Ssam /*
11959167Ssam  * Change mode of a file given a file descriptor.
11969167Ssam  */
119742441Smckusick /* ARGSUSED */
119842441Smckusick fchmod(p, uap, retval)
119945914Smckusick 	struct proc *p;
120042441Smckusick 	register struct args {
12017701Ssam 		int	fd;
12027701Ssam 		int	fmode;
120342441Smckusick 	} *uap;
120442441Smckusick 	int *retval;
120542441Smckusick {
120637741Smckusick 	struct vattr vattr;
120737741Smckusick 	struct vnode *vp;
120837741Smckusick 	struct file *fp;
120937741Smckusick 	int error;
12107701Ssam 
121145914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
1212*47540Skarels 		return (error);
121337741Smckusick 	vp = (struct vnode *)fp->f_data;
121437741Smckusick 	VOP_LOCK(vp);
121541400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
121637741Smckusick 		error = EROFS;
121737741Smckusick 		goto out;
12187439Sroot 	}
121945785Sbostic 	VATTR_NULL(&vattr);
122045785Sbostic 	vattr.va_mode = uap->fmode & 07777;
1221*47540Skarels 	error = VOP_SETATTR(vp, &vattr, p->p_ucred);
122237741Smckusick out:
122337741Smckusick 	VOP_UNLOCK(vp);
1224*47540Skarels 	return (error);
12255992Swnj }
12265992Swnj 
12279167Ssam /*
12289167Ssam  * Set ownership given a path name.
12299167Ssam  */
123042441Smckusick /* ARGSUSED */
123142441Smckusick chown(p, uap, retval)
123245914Smckusick 	struct proc *p;
123342441Smckusick 	register struct args {
12346254Sroot 		char	*fname;
12356254Sroot 		int	uid;
12366254Sroot 		int	gid;
123742441Smckusick 	} *uap;
123842441Smckusick 	int *retval;
123942441Smckusick {
1240*47540Skarels 	register struct nameidata *ndp;
124137741Smckusick 	register struct vnode *vp;
124237741Smckusick 	struct vattr vattr;
124337741Smckusick 	int error;
1244*47540Skarels 	struct nameidata nd;
124537Sbill 
1246*47540Skarels 	ndp = &nd;
124737741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
124836614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
124936614Sbostic 	ndp->ni_dirp = uap->fname;
1250*47540Skarels 	if (error = namei(ndp, p))
1251*47540Skarels 		return (error);
125237741Smckusick 	vp = ndp->ni_vp;
125341400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
125437741Smckusick 		error = EROFS;
125537741Smckusick 		goto out;
125637741Smckusick 	}
125745785Sbostic 	VATTR_NULL(&vattr);
125845785Sbostic 	vattr.va_uid = uap->uid;
125945785Sbostic 	vattr.va_gid = uap->gid;
1260*47540Skarels 	error = VOP_SETATTR(vp, &vattr, p->p_ucred);
126137741Smckusick out:
126237741Smckusick 	vput(vp);
1263*47540Skarels 	return (error);
12647701Ssam }
12657439Sroot 
12669167Ssam /*
12679167Ssam  * Set ownership given a file descriptor.
12689167Ssam  */
126942441Smckusick /* ARGSUSED */
127042441Smckusick fchown(p, uap, retval)
127145914Smckusick 	struct proc *p;
127242441Smckusick 	register struct args {
12737701Ssam 		int	fd;
12747701Ssam 		int	uid;
12757701Ssam 		int	gid;
127642441Smckusick 	} *uap;
127742441Smckusick 	int *retval;
127842441Smckusick {
127937741Smckusick 	struct vattr vattr;
128037741Smckusick 	struct vnode *vp;
128137741Smckusick 	struct file *fp;
128237741Smckusick 	int error;
12837701Ssam 
128445914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
1285*47540Skarels 		return (error);
128637741Smckusick 	vp = (struct vnode *)fp->f_data;
128737741Smckusick 	VOP_LOCK(vp);
128841400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
128937741Smckusick 		error = EROFS;
129037741Smckusick 		goto out;
129137741Smckusick 	}
129245785Sbostic 	VATTR_NULL(&vattr);
129345785Sbostic 	vattr.va_uid = uap->uid;
129445785Sbostic 	vattr.va_gid = uap->gid;
1295*47540Skarels 	error = VOP_SETATTR(vp, &vattr, p->p_ucred);
129637741Smckusick out:
129737741Smckusick 	VOP_UNLOCK(vp);
1298*47540Skarels 	return (error);
12997701Ssam }
13007701Ssam 
130142441Smckusick /*
130242441Smckusick  * Set the access and modification times of a file.
130342441Smckusick  */
130442441Smckusick /* ARGSUSED */
130542441Smckusick utimes(p, uap, retval)
130645914Smckusick 	struct proc *p;
130742441Smckusick 	register struct args {
130811811Ssam 		char	*fname;
130911811Ssam 		struct	timeval *tptr;
131042441Smckusick 	} *uap;
131142441Smckusick 	int *retval;
131242441Smckusick {
1313*47540Skarels 	register struct nameidata *ndp;
131437741Smckusick 	register struct vnode *vp;
131511811Ssam 	struct timeval tv[2];
131637741Smckusick 	struct vattr vattr;
131737741Smckusick 	int error;
1318*47540Skarels 	struct nameidata nd;
131911811Ssam 
132037741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
1321*47540Skarels 		return (error);
1322*47540Skarels 	ndp = &nd;
132337741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
132437741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
132537741Smckusick 	ndp->ni_dirp = uap->fname;
1326*47540Skarels 	if (error = namei(ndp, p))
1327*47540Skarels 		return (error);
132837741Smckusick 	vp = ndp->ni_vp;
132941400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
133037741Smckusick 		error = EROFS;
133137741Smckusick 		goto out;
133221015Smckusick 	}
133345785Sbostic 	VATTR_NULL(&vattr);
133445785Sbostic 	vattr.va_atime = tv[0];
133545785Sbostic 	vattr.va_mtime = tv[1];
1336*47540Skarels 	error = VOP_SETATTR(vp, &vattr, p->p_ucred);
133737741Smckusick out:
133837741Smckusick 	vput(vp);
1339*47540Skarels 	return (error);
134011811Ssam }
134111811Ssam 
13429167Ssam /*
13439167Ssam  * Truncate a file given its path name.
13449167Ssam  */
134542441Smckusick /* ARGSUSED */
134642441Smckusick truncate(p, uap, retval)
134745914Smckusick 	struct proc *p;
134842441Smckusick 	register struct args {
13497701Ssam 		char	*fname;
135026473Skarels 		off_t	length;
135142441Smckusick 	} *uap;
135242441Smckusick 	int *retval;
135342441Smckusick {
1354*47540Skarels 	register struct nameidata *ndp;
135537741Smckusick 	register struct vnode *vp;
135637741Smckusick 	struct vattr vattr;
135737741Smckusick 	int error;
1358*47540Skarels 	struct nameidata nd;
13597701Ssam 
1360*47540Skarels 	ndp = &nd;
136137741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
136216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
136316694Smckusick 	ndp->ni_dirp = uap->fname;
1364*47540Skarels 	if (error = namei(ndp, p))
1365*47540Skarels 		return (error);
136637741Smckusick 	vp = ndp->ni_vp;
136737741Smckusick 	if (vp->v_type == VDIR) {
136837741Smckusick 		error = EISDIR;
136937741Smckusick 		goto out;
13707701Ssam 	}
137138399Smckusick 	if ((error = vn_writechk(vp)) ||
1372*47540Skarels 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred)))
137337741Smckusick 		goto out;
137445785Sbostic 	VATTR_NULL(&vattr);
137545785Sbostic 	vattr.va_size = uap->length;
1376*47540Skarels 	error = VOP_SETATTR(vp, &vattr, p->p_ucred);
137737741Smckusick out:
137837741Smckusick 	vput(vp);
1379*47540Skarels 	return (error);
13807701Ssam }
13817701Ssam 
13829167Ssam /*
13839167Ssam  * Truncate a file given a file descriptor.
13849167Ssam  */
138542441Smckusick /* ARGSUSED */
138642441Smckusick ftruncate(p, uap, retval)
138745914Smckusick 	struct proc *p;
138842441Smckusick 	register struct args {
13897701Ssam 		int	fd;
139026473Skarels 		off_t	length;
139142441Smckusick 	} *uap;
139242441Smckusick 	int *retval;
139342441Smckusick {
139437741Smckusick 	struct vattr vattr;
139537741Smckusick 	struct vnode *vp;
13967701Ssam 	struct file *fp;
139737741Smckusick 	int error;
13987701Ssam 
139945914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
1400*47540Skarels 		return (error);
140137741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
1402*47540Skarels 		return (EINVAL);
140337741Smckusick 	vp = (struct vnode *)fp->f_data;
140437741Smckusick 	VOP_LOCK(vp);
140537741Smckusick 	if (vp->v_type == VDIR) {
140637741Smckusick 		error = EISDIR;
140737741Smckusick 		goto out;
14087701Ssam 	}
140938399Smckusick 	if (error = vn_writechk(vp))
141037741Smckusick 		goto out;
141145785Sbostic 	VATTR_NULL(&vattr);
141245785Sbostic 	vattr.va_size = uap->length;
141337741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
141437741Smckusick out:
141537741Smckusick 	VOP_UNLOCK(vp);
1416*47540Skarels 	return (error);
14177701Ssam }
14187701Ssam 
14199167Ssam /*
14209167Ssam  * Synch an open file.
14219167Ssam  */
142242441Smckusick /* ARGSUSED */
142342441Smckusick fsync(p, uap, retval)
142445914Smckusick 	struct proc *p;
142542441Smckusick 	struct args {
142642441Smckusick 		int	fd;
142742441Smckusick 	} *uap;
142842441Smckusick 	int *retval;
14299167Ssam {
143039592Smckusick 	register struct vnode *vp;
14319167Ssam 	struct file *fp;
143237741Smckusick 	int error;
14339167Ssam 
143445914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
1435*47540Skarels 		return (error);
143639592Smckusick 	vp = (struct vnode *)fp->f_data;
143739592Smckusick 	VOP_LOCK(vp);
143839592Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT);
143939592Smckusick 	VOP_UNLOCK(vp);
1440*47540Skarels 	return (error);
14419167Ssam }
14429167Ssam 
14439167Ssam /*
14449167Ssam  * Rename system call.
14459167Ssam  *
14469167Ssam  * Source and destination must either both be directories, or both
14479167Ssam  * not be directories.  If target is a directory, it must be empty.
14489167Ssam  */
144942441Smckusick /* ARGSUSED */
145042441Smckusick rename(p, uap, retval)
145145914Smckusick 	struct proc *p;
145242441Smckusick 	register struct args {
14537701Ssam 		char	*from;
14547701Ssam 		char	*to;
145542441Smckusick 	} *uap;
145642441Smckusick 	int *retval;
145742441Smckusick {
145837741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
1459*47540Skarels 	register struct nameidata *ndp;
146037741Smckusick 	int error;
1461*47540Skarels 	struct nameidata nd, tond;
14627701Ssam 
1463*47540Skarels 	ndp = &nd;
146437741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
146516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
146616694Smckusick 	ndp->ni_dirp = uap->from;
1467*47540Skarels 	if (error = namei(ndp, p))
1468*47540Skarels 		return (error);
146937741Smckusick 	fvp = ndp->ni_vp;
147038266Smckusick 	nddup(ndp, &tond);
147137741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
147237741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
147337741Smckusick 	tond.ni_dirp = uap->to;
1474*47540Skarels 	if (error = namei(&tond, p)) {
147542465Smckusick 		VOP_ABORTOP(ndp);
147642465Smckusick 		vrele(ndp->ni_dvp);
147742465Smckusick 		vrele(fvp);
147842465Smckusick 		goto out1;
147942465Smckusick 	}
148037741Smckusick 	tdvp = tond.ni_dvp;
148137741Smckusick 	tvp = tond.ni_vp;
148237741Smckusick 	if (tvp != NULL) {
148337741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
148439242Sbostic 			error = ENOTDIR;
148537741Smckusick 			goto out;
148637741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
148739242Sbostic 			error = EISDIR;
148837741Smckusick 			goto out;
14899167Ssam 		}
149045240Smckusick 		if (fvp->v_mount != tvp->v_mount) {
149145240Smckusick 			error = EXDEV;
149245240Smckusick 			goto out;
149345240Smckusick 		}
14949167Ssam 	}
149537741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
149637741Smckusick 		error = EXDEV;
14979167Ssam 		goto out;
149810051Ssam 	}
149939286Smckusick 	if (fvp == tdvp)
150037741Smckusick 		error = EINVAL;
150139286Smckusick 	/*
150239286Smckusick 	 * If source is the same as the destination,
150339286Smckusick 	 * then there is nothing to do.
150439286Smckusick 	 */
150539286Smckusick 	if (fvp == tvp)
150639286Smckusick 		error = -1;
150737741Smckusick out:
150842465Smckusick 	if (!error) {
150942465Smckusick 		error = VOP_RENAME(ndp, &tond);
151042465Smckusick 	} else {
151137741Smckusick 		VOP_ABORTOP(&tond);
151243344Smckusick 		if (tdvp == tvp)
151343344Smckusick 			vrele(tdvp);
151443344Smckusick 		else
151543344Smckusick 			vput(tdvp);
151642465Smckusick 		if (tvp)
151742465Smckusick 			vput(tvp);
151837741Smckusick 		VOP_ABORTOP(ndp);
151942465Smckusick 		vrele(ndp->ni_dvp);
152042465Smckusick 		vrele(fvp);
15219167Ssam 	}
152237741Smckusick out1:
152338266Smckusick 	ndrele(&tond);
152439286Smckusick 	if (error == -1)
1525*47540Skarels 		return (0);
1526*47540Skarels 	return (error);
15277701Ssam }
15287701Ssam 
15297535Sroot /*
153012756Ssam  * Mkdir system call
153112756Ssam  */
153242441Smckusick /* ARGSUSED */
153342441Smckusick mkdir(p, uap, retval)
153445914Smckusick 	struct proc *p;
153542441Smckusick 	register struct args {
153612756Ssam 		char	*name;
153712756Ssam 		int	dmode;
153842441Smckusick 	} *uap;
153942441Smckusick 	int *retval;
154042441Smckusick {
1541*47540Skarels 	register struct nameidata *ndp;
154237741Smckusick 	register struct vnode *vp;
154337741Smckusick 	struct vattr vattr;
154437741Smckusick 	int error;
1545*47540Skarels 	struct nameidata nd;
154612756Ssam 
1547*47540Skarels 	ndp = &nd;
154837741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
154916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
155016694Smckusick 	ndp->ni_dirp = uap->name;
1551*47540Skarels 	if (error = namei(ndp, p))
1552*47540Skarels 		return (error);
155337741Smckusick 	vp = ndp->ni_vp;
155437741Smckusick 	if (vp != NULL) {
155537741Smckusick 		VOP_ABORTOP(ndp);
155643344Smckusick 		if (ndp->ni_dvp == vp)
155743344Smckusick 			vrele(ndp->ni_dvp);
155843344Smckusick 		else
155943344Smckusick 			vput(ndp->ni_dvp);
156042465Smckusick 		vrele(vp);
1561*47540Skarels 		return (EEXIST);
156212756Ssam 	}
156341362Smckusick 	VATTR_NULL(&vattr);
156437741Smckusick 	vattr.va_type = VDIR;
156545914Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask;
156637741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
156738145Smckusick 	if (!error)
156838145Smckusick 		vput(ndp->ni_vp);
1569*47540Skarels 	return (error);
157012756Ssam }
157112756Ssam 
157212756Ssam /*
157312756Ssam  * Rmdir system call.
157412756Ssam  */
157542441Smckusick /* ARGSUSED */
157642441Smckusick rmdir(p, uap, retval)
157745914Smckusick 	struct proc *p;
157842441Smckusick 	struct args {
157942441Smckusick 		char	*name;
158042441Smckusick 	} *uap;
158142441Smckusick 	int *retval;
158212756Ssam {
1583*47540Skarels 	register struct nameidata *ndp;
158437741Smckusick 	register struct vnode *vp;
158537741Smckusick 	int error;
1586*47540Skarels 	struct nameidata nd;
158712756Ssam 
1588*47540Skarels 	ndp = &nd;
158937741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
159016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
159116694Smckusick 	ndp->ni_dirp = uap->name;
1592*47540Skarels 	if (error = namei(ndp, p))
1593*47540Skarels 		return (error);
159437741Smckusick 	vp = ndp->ni_vp;
159537741Smckusick 	if (vp->v_type != VDIR) {
159637741Smckusick 		error = ENOTDIR;
159712756Ssam 		goto out;
159812756Ssam 	}
159912756Ssam 	/*
160037741Smckusick 	 * No rmdir "." please.
160112756Ssam 	 */
160237741Smckusick 	if (ndp->ni_dvp == vp) {
160337741Smckusick 		error = EINVAL;
160412756Ssam 		goto out;
160512756Ssam 	}
160612756Ssam 	/*
160737741Smckusick 	 * Don't unlink a mounted file.
160812756Ssam 	 */
160937741Smckusick 	if (vp->v_flag & VROOT)
161037741Smckusick 		error = EBUSY;
161112756Ssam out:
161242465Smckusick 	if (!error) {
161342465Smckusick 		error = VOP_RMDIR(ndp);
161442465Smckusick 	} else {
161537741Smckusick 		VOP_ABORTOP(ndp);
161643344Smckusick 		if (ndp->ni_dvp == vp)
161743344Smckusick 			vrele(ndp->ni_dvp);
161843344Smckusick 		else
161943344Smckusick 			vput(ndp->ni_dvp);
162042465Smckusick 		vput(vp);
162142465Smckusick 	}
1622*47540Skarels 	return (error);
162312756Ssam }
162412756Ssam 
162537741Smckusick /*
162637741Smckusick  * Read a block of directory entries in a file system independent format
162737741Smckusick  */
162842441Smckusick getdirentries(p, uap, retval)
162945914Smckusick 	struct proc *p;
163042441Smckusick 	register struct args {
163137741Smckusick 		int	fd;
163237741Smckusick 		char	*buf;
163337741Smckusick 		unsigned count;
163437741Smckusick 		long	*basep;
163542441Smckusick 	} *uap;
163642441Smckusick 	int *retval;
163742441Smckusick {
163839592Smckusick 	register struct vnode *vp;
163916540Ssam 	struct file *fp;
164037741Smckusick 	struct uio auio;
164137741Smckusick 	struct iovec aiov;
164238129Smckusick 	off_t off;
164340321Smckusick 	int error, eofflag;
164412756Ssam 
164545914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
1646*47540Skarels 		return (error);
164737741Smckusick 	if ((fp->f_flag & FREAD) == 0)
1648*47540Skarels 		return (EBADF);
164939592Smckusick 	vp = (struct vnode *)fp->f_data;
165039592Smckusick 	if (vp->v_type != VDIR)
1651*47540Skarels 		return (EINVAL);
165237741Smckusick 	aiov.iov_base = uap->buf;
165337741Smckusick 	aiov.iov_len = uap->count;
165437741Smckusick 	auio.uio_iov = &aiov;
165537741Smckusick 	auio.uio_iovcnt = 1;
165637741Smckusick 	auio.uio_rw = UIO_READ;
165737741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
165837741Smckusick 	auio.uio_resid = uap->count;
165939592Smckusick 	VOP_LOCK(vp);
166039592Smckusick 	auio.uio_offset = off = fp->f_offset;
166140321Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
166239592Smckusick 	fp->f_offset = auio.uio_offset;
166339592Smckusick 	VOP_UNLOCK(vp);
166439592Smckusick 	if (error)
1665*47540Skarels 		return (error);
166639592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
166742441Smckusick 	*retval = uap->count - auio.uio_resid;
1668*47540Skarels 	return (error);
166912756Ssam }
167012756Ssam 
167112756Ssam /*
167212756Ssam  * mode mask for creation of files
167312756Ssam  */
167442441Smckusick mode_t
167542441Smckusick umask(p, uap, retval)
167645914Smckusick 	struct proc *p;
167742441Smckusick 	struct args {
167842441Smckusick 		int	mask;
167942441Smckusick 	} *uap;
168042441Smckusick 	int *retval;
168112756Ssam {
168245914Smckusick 	register struct filedesc *fdp = p->p_fd;
168312756Ssam 
168445914Smckusick 	*retval = fdp->fd_cmask;
168545914Smckusick 	fdp->fd_cmask = uap->mask & 07777;
1686*47540Skarels 	return (0);
168712756Ssam }
168837741Smckusick 
168939566Smarc /*
169039566Smarc  * Void all references to file by ripping underlying filesystem
169139566Smarc  * away from vnode.
169239566Smarc  */
169342441Smckusick /* ARGSUSED */
169442441Smckusick revoke(p, uap, retval)
169545914Smckusick 	struct proc *p;
169642441Smckusick 	register struct args {
169739566Smarc 		char	*fname;
169842441Smckusick 	} *uap;
169942441Smckusick 	int *retval;
170042441Smckusick {
1701*47540Skarels 	register struct nameidata *ndp;
170239566Smarc 	register struct vnode *vp;
170339566Smarc 	struct vattr vattr;
170439566Smarc 	int error;
1705*47540Skarels 	struct nameidata nd;
170639566Smarc 
1707*47540Skarels 	ndp = &nd;
170839566Smarc 	ndp->ni_nameiop = LOOKUP | FOLLOW;
170939566Smarc 	ndp->ni_segflg = UIO_USERSPACE;
171039566Smarc 	ndp->ni_dirp = uap->fname;
1711*47540Skarels 	if (error = namei(ndp, p))
1712*47540Skarels 		return (error);
171339566Smarc 	vp = ndp->ni_vp;
171439566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
171539566Smarc 		error = EINVAL;
171639566Smarc 		goto out;
171739566Smarc 	}
1718*47540Skarels 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred))
171939566Smarc 		goto out;
1720*47540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
1721*47540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
172239566Smarc 		goto out;
172339805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
172439632Smckusick 		vgoneall(vp);
172539566Smarc out:
172639566Smarc 	vrele(vp);
1727*47540Skarels 	return (error);
172839566Smarc }
172939566Smarc 
173045914Smckusick getvnode(fdp, fdes, fpp)
173145914Smckusick 	struct filedesc *fdp;
173237741Smckusick 	struct file **fpp;
173337741Smckusick 	int fdes;
173437741Smckusick {
173537741Smckusick 	struct file *fp;
173637741Smckusick 
1737*47540Skarels 	if ((unsigned)fdes >= fdp->fd_nfiles ||
173845914Smckusick 	    (fp = OFILE(fdp, fdes)) == NULL)
173937741Smckusick 		return (EBADF);
174037741Smckusick 	if (fp->f_type != DTYPE_VNODE)
174137741Smckusick 		return (EINVAL);
174237741Smckusick 	*fpp = fp;
174337741Smckusick 	return (0);
174437741Smckusick }
1745