xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 48026)
123405Smckusick /*
237741Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337741Smckusick  * All rights reserved.
423405Smckusick  *
544459Sbostic  * %sccs.include.redist.c%
637741Smckusick  *
7*48026Smckusick  *	@(#)vfs_syscalls.c	7.67 (Berkeley) 04/15/91
823405Smckusick  */
937Sbill 
1017101Sbloom #include "param.h"
1117101Sbloom #include "systm.h"
1247540Skarels #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 {
4147540Skarels 	register struct nameidata *ndp;
4239335Smckusick 	register struct vnode *vp;
4339335Smckusick 	register struct mount *mp;
4440111Smckusick 	int error, flag;
4547540Skarels 	struct nameidata nd;
466254Sroot 
4737741Smckusick 	/*
4837741Smckusick 	 * Must be super user
4937741Smckusick 	 */
5047540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
5147540Skarels 		return (error);
5237741Smckusick 	/*
5337741Smckusick 	 * Get vnode to be covered
5437741Smckusick 	 */
5547540Skarels 	ndp = &nd;
5637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
5737741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
5837741Smckusick 	ndp->ni_dirp = uap->dir;
5947540Skarels 	if (error = namei(ndp, p))
6047540Skarels 		return (error);
6137741Smckusick 	vp = ndp->ni_vp;
6241400Smckusick 	if (uap->flags & MNT_UPDATE) {
6339335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
6439335Smckusick 			vput(vp);
6547540Skarels 			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);
7547540Skarels 			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);
8547540Skarels 		return (EBUSY);
8637741Smckusick 	}
8737741Smckusick 	if (vp->v_type != VDIR) {
8837741Smckusick 		vput(vp);
8947540Skarels 		return (ENOTDIR);
9037741Smckusick 	}
9139741Smckusick 	if ((unsigned long)uap->type > MOUNT_MAXTYPE ||
9237741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
9337741Smckusick 		vput(vp);
9447540Skarels 		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);
10947540Skarels 		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);
11547540Skarels 		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 	 */
146*48026Smckusick 	error = VFS_MOUNT(mp, uap->dir, uap->data, ndp, p);
14741400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
14841400Smckusick 		mp->mnt_flag &= ~MNT_UPDATE;
14939335Smckusick 		vrele(vp);
15040111Smckusick 		if (error)
15141400Smckusick 			mp->mnt_flag = flag;
15247540Skarels 		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);
165*48026Smckusick 		error = VFS_START(mp, 0, p);
16637741Smckusick 	} else {
16737741Smckusick 		vfs_remove(mp);
16837741Smckusick 		free((caddr_t)mp, M_MOUNT);
16939335Smckusick 		vput(vp);
17037741Smckusick 	}
17147540Skarels 	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;
19047540Skarels 	register struct nameidata *ndp;
19139356Smckusick 	struct mount *mp;
19237741Smckusick 	int error;
19347540Skarels 	struct nameidata nd;
1946254Sroot 
19537741Smckusick 	/*
19637741Smckusick 	 * Must be super user
19737741Smckusick 	 */
19847540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
19947540Skarels 		return (error);
20037741Smckusick 
20147540Skarels 	ndp = &nd;
20237741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
20337741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
20437741Smckusick 	ndp->ni_dirp = uap->pathp;
20547540Skarels 	if (error = namei(ndp, p))
20647540Skarels 		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);
21347540Skarels 		return (EINVAL);
21437741Smckusick 	}
21537741Smckusick 	mp = vp->v_mount;
21637741Smckusick 	vput(vp);
217*48026Smckusick 	return (dounmount(mp, uap->flags, p));
21839356Smckusick }
21939356Smckusick 
22039356Smckusick /*
22139356Smckusick  * Do an unmount.
22239356Smckusick  */
223*48026Smckusick dounmount(mp, flags, p)
22439356Smckusick 	register struct mount *mp;
22539356Smckusick 	int flags;
226*48026Smckusick 	struct proc *p;
22739356Smckusick {
22839356Smckusick 	struct vnode *coveredvp;
22939356Smckusick 	int error;
23039356Smckusick 
23141400Smckusick 	coveredvp = mp->mnt_vnodecovered;
23241298Smckusick 	if (vfs_busy(mp))
23341298Smckusick 		return (EBUSY);
23441400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
23537741Smckusick 	if (error = vfs_lock(mp))
23639356Smckusick 		return (error);
23737741Smckusick 
23845922Smckusick #ifdef NVM
23945738Smckusick 	vnode_pager_umount(mp);	/* release cached vnodes */
24045922Smckusick #else
24145922Smckusick 	xumount(mp);		/* remove unused sticky files from text table */
24245922Smckusick #endif
24337741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
24441676Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE))
245*48026Smckusick 		error = VFS_UNMOUNT(mp, flags, p);
24641400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
24741298Smckusick 	vfs_unbusy(mp);
24837741Smckusick 	if (error) {
24937741Smckusick 		vfs_unlock(mp);
25037741Smckusick 	} else {
25137741Smckusick 		vrele(coveredvp);
25237741Smckusick 		vfs_remove(mp);
25337741Smckusick 		free((caddr_t)mp, M_MOUNT);
25437741Smckusick 	}
25539356Smckusick 	return (error);
2566254Sroot }
2576254Sroot 
2589167Ssam /*
25937741Smckusick  * Sync system call.
26037741Smckusick  * Sync each mounted filesystem.
2619167Ssam  */
26239491Smckusick /* ARGSUSED */
26342441Smckusick sync(p, uap, retval)
26445914Smckusick 	struct proc *p;
26547540Skarels 	void *uap;
26642441Smckusick 	int *retval;
2676254Sroot {
26837741Smckusick 	register struct mount *mp;
26941298Smckusick 	struct mount *omp;
27037741Smckusick 
27137741Smckusick 	mp = rootfs;
27237741Smckusick 	do {
27340343Smckusick 		/*
27440343Smckusick 		 * The lock check below is to avoid races with mount
27540343Smckusick 		 * and unmount.
27640343Smckusick 		 */
27741400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
27841298Smckusick 		    !vfs_busy(mp)) {
27937741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
28041298Smckusick 			omp = mp;
28141400Smckusick 			mp = mp->mnt_next;
28241298Smckusick 			vfs_unbusy(omp);
28341298Smckusick 		} else
28441400Smckusick 			mp = mp->mnt_next;
28537741Smckusick 	} while (mp != rootfs);
28647688Skarels 	return (0);
28737741Smckusick }
28837741Smckusick 
28937741Smckusick /*
29041298Smckusick  * operate on filesystem quotas
29141298Smckusick  */
29242441Smckusick /* ARGSUSED */
29342441Smckusick quotactl(p, uap, retval)
29445914Smckusick 	struct proc *p;
29542441Smckusick 	register struct args {
29641298Smckusick 		char *path;
29741298Smckusick 		int cmd;
29841298Smckusick 		int uid;
29941298Smckusick 		caddr_t arg;
30042441Smckusick 	} *uap;
30142441Smckusick 	int *retval;
30242441Smckusick {
30341298Smckusick 	register struct mount *mp;
30447540Skarels 	register struct nameidata *ndp;
30541298Smckusick 	int error;
30647540Skarels 	struct nameidata nd;
30741298Smckusick 
30847540Skarels 	ndp = &nd;
30941298Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
31041298Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
31141298Smckusick 	ndp->ni_dirp = uap->path;
31247540Skarels 	if (error = namei(ndp, p))
31347540Skarels 		return (error);
31441298Smckusick 	mp = ndp->ni_vp->v_mount;
31541298Smckusick 	vrele(ndp->ni_vp);
316*48026Smckusick 	return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p));
31741298Smckusick }
31841298Smckusick 
31941298Smckusick /*
32037741Smckusick  * get filesystem statistics
32137741Smckusick  */
32242441Smckusick /* ARGSUSED */
32342441Smckusick statfs(p, uap, retval)
32445914Smckusick 	struct proc *p;
32542441Smckusick 	register struct args {
32637741Smckusick 		char *path;
32737741Smckusick 		struct statfs *buf;
32842441Smckusick 	} *uap;
32942441Smckusick 	int *retval;
33042441Smckusick {
33139464Smckusick 	register struct mount *mp;
33247540Skarels 	register struct nameidata *ndp;
33340343Smckusick 	register struct statfs *sp;
33437741Smckusick 	int error;
33547540Skarels 	struct nameidata nd;
33637741Smckusick 
33747540Skarels 	ndp = &nd;
33839544Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
33937741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
34037741Smckusick 	ndp->ni_dirp = uap->path;
34147540Skarels 	if (error = namei(ndp, p))
34247540Skarels 		return (error);
34339544Smckusick 	mp = ndp->ni_vp->v_mount;
34441400Smckusick 	sp = &mp->mnt_stat;
34539544Smckusick 	vrele(ndp->ni_vp);
346*48026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
34747540Skarels 		return (error);
34841400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
34947540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
35037741Smckusick }
35137741Smckusick 
35242441Smckusick /*
35342441Smckusick  * get filesystem statistics
35442441Smckusick  */
35542441Smckusick /* ARGSUSED */
35642441Smckusick fstatfs(p, uap, retval)
35745914Smckusick 	struct proc *p;
35842441Smckusick 	register struct args {
35937741Smckusick 		int fd;
36037741Smckusick 		struct statfs *buf;
36142441Smckusick 	} *uap;
36242441Smckusick 	int *retval;
36342441Smckusick {
36437741Smckusick 	struct file *fp;
36539464Smckusick 	struct mount *mp;
36640343Smckusick 	register struct statfs *sp;
36737741Smckusick 	int error;
36837741Smckusick 
36945914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
37047540Skarels 		return (error);
37139464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
37241400Smckusick 	sp = &mp->mnt_stat;
373*48026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
37447540Skarels 		return (error);
37541400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
37647540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
37737741Smckusick }
37837741Smckusick 
37937741Smckusick /*
38038270Smckusick  * get statistics on all filesystems
38138270Smckusick  */
38242441Smckusick getfsstat(p, uap, retval)
38345914Smckusick 	struct proc *p;
38442441Smckusick 	register struct args {
38538270Smckusick 		struct statfs *buf;
38638270Smckusick 		long bufsize;
38740343Smckusick 		int flags;
38842441Smckusick 	} *uap;
38942441Smckusick 	int *retval;
39042441Smckusick {
39138270Smckusick 	register struct mount *mp;
39240343Smckusick 	register struct statfs *sp;
39339606Smckusick 	caddr_t sfsp;
39438270Smckusick 	long count, maxcount, error;
39538270Smckusick 
39638270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
39739606Smckusick 	sfsp = (caddr_t)uap->buf;
39838270Smckusick 	mp = rootfs;
39938270Smckusick 	count = 0;
40038270Smckusick 	do {
40141400Smckusick 		if (sfsp && count < maxcount &&
40241400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
40341400Smckusick 			sp = &mp->mnt_stat;
40440343Smckusick 			/*
40540343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
40640343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
40740343Smckusick 			 */
40840343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
40940343Smckusick 			    (uap->flags & MNT_WAIT)) &&
410*48026Smckusick 			    (error = VFS_STATFS(mp, sp, p))) {
41141400Smckusick 				mp = mp->mnt_prev;
41239607Smckusick 				continue;
41339607Smckusick 			}
41441400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
41540343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
41647540Skarels 				return (error);
41740343Smckusick 			sfsp += sizeof(*sp);
41838270Smckusick 		}
41939606Smckusick 		count++;
42041400Smckusick 		mp = mp->mnt_prev;
42138270Smckusick 	} while (mp != rootfs);
42238270Smckusick 	if (sfsp && count > maxcount)
42342441Smckusick 		*retval = maxcount;
42438270Smckusick 	else
42542441Smckusick 		*retval = count;
42647540Skarels 	return (0);
42738270Smckusick }
42838270Smckusick 
42938270Smckusick /*
43038259Smckusick  * Change current working directory to a given file descriptor.
43138259Smckusick  */
43242441Smckusick /* ARGSUSED */
43342441Smckusick fchdir(p, uap, retval)
43445914Smckusick 	struct proc *p;
43542441Smckusick 	struct args {
43642441Smckusick 		int	fd;
43742441Smckusick 	} *uap;
43842441Smckusick 	int *retval;
43938259Smckusick {
44045914Smckusick 	register struct filedesc *fdp = p->p_fd;
44138259Smckusick 	register struct vnode *vp;
44238259Smckusick 	struct file *fp;
44338259Smckusick 	int error;
44438259Smckusick 
44545914Smckusick 	if (error = getvnode(fdp, uap->fd, &fp))
44647540Skarels 		return (error);
44738259Smckusick 	vp = (struct vnode *)fp->f_data;
44838259Smckusick 	VOP_LOCK(vp);
44938259Smckusick 	if (vp->v_type != VDIR)
45038259Smckusick 		error = ENOTDIR;
45138259Smckusick 	else
452*48026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
45338259Smckusick 	VOP_UNLOCK(vp);
45439860Smckusick 	if (error)
45547540Skarels 		return (error);
45639860Smckusick 	VREF(vp);
45745914Smckusick 	vrele(fdp->fd_cdir);
45845914Smckusick 	fdp->fd_cdir = vp;
45947540Skarels 	return (0);
46038259Smckusick }
46138259Smckusick 
46238259Smckusick /*
46337741Smckusick  * Change current working directory (``.'').
46437741Smckusick  */
46542441Smckusick /* ARGSUSED */
46642441Smckusick chdir(p, uap, retval)
46745914Smckusick 	struct proc *p;
46842441Smckusick 	struct args {
46942441Smckusick 		char	*fname;
47042441Smckusick 	} *uap;
47142441Smckusick 	int *retval;
47237741Smckusick {
47347540Skarels 	register struct nameidata *ndp;
47445914Smckusick 	register struct filedesc *fdp = p->p_fd;
47537741Smckusick 	int error;
47647540Skarels 	struct nameidata nd;
4776254Sroot 
47847540Skarels 	ndp = &nd;
47937741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
48016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
48116694Smckusick 	ndp->ni_dirp = uap->fname;
48247540Skarels 	if (error = chdirec(ndp, p))
48347540Skarels 		return (error);
48445914Smckusick 	vrele(fdp->fd_cdir);
48545914Smckusick 	fdp->fd_cdir = ndp->ni_vp;
48647540Skarels 	return (0);
48737741Smckusick }
4886254Sroot 
48937741Smckusick /*
49037741Smckusick  * Change notion of root (``/'') directory.
49137741Smckusick  */
49242441Smckusick /* ARGSUSED */
49342441Smckusick chroot(p, uap, retval)
49445914Smckusick 	struct proc *p;
49542441Smckusick 	struct args {
49642441Smckusick 		char	*fname;
49742441Smckusick 	} *uap;
49842441Smckusick 	int *retval;
49937741Smckusick {
50047540Skarels 	register struct nameidata *ndp;
50145914Smckusick 	register struct filedesc *fdp = p->p_fd;
50237741Smckusick 	int error;
50347540Skarels 	struct nameidata nd;
50437741Smckusick 
50547540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
50647540Skarels 		return (error);
50747540Skarels 	ndp = &nd;
50837741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
50937741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
51037741Smckusick 	ndp->ni_dirp = uap->fname;
51147540Skarels 	if (error = chdirec(ndp, p))
51247540Skarels 		return (error);
51345914Smckusick 	if (fdp->fd_rdir != NULL)
51445914Smckusick 		vrele(fdp->fd_rdir);
51545914Smckusick 	fdp->fd_rdir = ndp->ni_vp;
51647540Skarels 	return (0);
5176254Sroot }
5186254Sroot 
51937Sbill /*
52037741Smckusick  * Common routine for chroot and chdir.
52137741Smckusick  */
52247540Skarels chdirec(ndp, p)
52347540Skarels 	struct nameidata *ndp;
52447540Skarels 	struct proc *p;
52537741Smckusick {
52637741Smckusick 	struct vnode *vp;
52737741Smckusick 	int error;
52837741Smckusick 
52947540Skarels 	if (error = namei(ndp, p))
53037741Smckusick 		return (error);
53137741Smckusick 	vp = ndp->ni_vp;
53237741Smckusick 	if (vp->v_type != VDIR)
53337741Smckusick 		error = ENOTDIR;
53437741Smckusick 	else
535*48026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
53637741Smckusick 	VOP_UNLOCK(vp);
53737741Smckusick 	if (error)
53837741Smckusick 		vrele(vp);
53937741Smckusick 	return (error);
54037741Smckusick }
54137741Smckusick 
54237741Smckusick /*
5436254Sroot  * Open system call.
54442441Smckusick  * Check permissions, allocate an open file structure,
54542441Smckusick  * and call the device open routine if any.
5466254Sroot  */
54742441Smckusick open(p, uap, retval)
54845914Smckusick 	struct proc *p;
54942441Smckusick 	register struct args {
5506254Sroot 		char	*fname;
5517701Ssam 		int	mode;
55212756Ssam 		int	crtmode;
55342441Smckusick 	} *uap;
55442441Smckusick 	int *retval;
5556254Sroot {
55647540Skarels 	struct nameidata *ndp;
55745914Smckusick 	register struct filedesc *fdp = p->p_fd;
55842441Smckusick 	register struct file *fp;
55937741Smckusick 	int fmode, cmode;
56037741Smckusick 	struct file *nfp;
56137741Smckusick 	int indx, error;
56247540Skarels 	struct nameidata nd;
56337741Smckusick 	extern struct fileops vnops;
5646254Sroot 
56545914Smckusick 	if (error = falloc(p, &nfp, &indx))
56647540Skarels 		return (error);
56737741Smckusick 	fp = nfp;
56846553Skarels 	fmode = FFLAGS(uap->mode);
56945914Smckusick 	cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX;
57047540Skarels 	ndp = &nd;
57142441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
57242441Smckusick 	ndp->ni_dirp = uap->fname;
57345202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
57447540Skarels 	if (error = vn_open(ndp, p, fmode, cmode)) {
57537741Smckusick 		crfree(fp->f_cred);
57637741Smckusick 		fp->f_count--;
57743405Smckusick 		if (error == ENODEV &&		/* XXX from fdopen */
57845202Smckusick 		    p->p_dupfd >= 0 &&
57945914Smckusick 		    (error = dupfdopen(fdp, indx, p->p_dupfd, fmode)) == 0) {
58042441Smckusick 			*retval = indx;
58147540Skarels 			return (0);
58242441Smckusick 		}
58340884Smckusick 		if (error == ERESTART)
58440884Smckusick 			error = EINTR;
58547688Skarels 		fdp->fd_ofiles[indx] = NULL;
58647540Skarels 		return (error);
58712756Ssam 	}
58837741Smckusick 	fp->f_flag = fmode & FMASK;
58937741Smckusick 	fp->f_type = DTYPE_VNODE;
59037741Smckusick 	fp->f_ops = &vnops;
59137741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
59242441Smckusick 	*retval = indx;
59347540Skarels 	return (0);
5946254Sroot }
5956254Sroot 
59642955Smckusick #ifdef COMPAT_43
5976254Sroot /*
59842441Smckusick  * Creat system call.
5996254Sroot  */
60042955Smckusick ocreat(p, uap, retval)
60142441Smckusick 	struct proc *p;
60242441Smckusick 	register struct args {
60342441Smckusick 		char	*fname;
60442441Smckusick 		int	fmode;
60542441Smckusick 	} *uap;
60642441Smckusick 	int *retval;
6076254Sroot {
60842441Smckusick 	struct args {
6096254Sroot 		char	*fname;
61042441Smckusick 		int	mode;
61142441Smckusick 		int	crtmode;
61242441Smckusick 	} openuap;
61342441Smckusick 
61442441Smckusick 	openuap.fname = uap->fname;
61542441Smckusick 	openuap.crtmode = uap->fmode;
61642441Smckusick 	openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
61747540Skarels 	return (open(p, &openuap, retval));
61842441Smckusick }
61942955Smckusick #endif /* COMPAT_43 */
62042441Smckusick 
62142441Smckusick /*
62242441Smckusick  * Mknod system call
62342441Smckusick  */
62442441Smckusick /* ARGSUSED */
62542441Smckusick mknod(p, uap, retval)
62645914Smckusick 	struct proc *p;
62742441Smckusick 	register struct args {
62842441Smckusick 		char	*fname;
6296254Sroot 		int	fmode;
6306254Sroot 		int	dev;
63142441Smckusick 	} *uap;
63242441Smckusick 	int *retval;
63342441Smckusick {
63447540Skarels 	register struct nameidata *ndp;
63537741Smckusick 	register struct vnode *vp;
63637741Smckusick 	struct vattr vattr;
63737741Smckusick 	int error;
63847540Skarels 	struct nameidata nd;
6396254Sroot 
64047540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
64147540Skarels 		return (error);
64247540Skarels 	ndp = &nd;
64337741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
64416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
64516694Smckusick 	ndp->ni_dirp = uap->fname;
64647540Skarels 	if (error = namei(ndp, p))
64747540Skarels 		return (error);
64837741Smckusick 	vp = ndp->ni_vp;
64937741Smckusick 	if (vp != NULL) {
65037741Smckusick 		error = EEXIST;
65112756Ssam 		goto out;
6526254Sroot 	}
65341362Smckusick 	VATTR_NULL(&vattr);
65440635Smckusick 	switch (uap->fmode & S_IFMT) {
65512756Ssam 
65640635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
65737741Smckusick 		vattr.va_type = VBAD;
65837741Smckusick 		break;
65940635Smckusick 	case S_IFCHR:
66037741Smckusick 		vattr.va_type = VCHR;
66137741Smckusick 		break;
66240635Smckusick 	case S_IFBLK:
66337741Smckusick 		vattr.va_type = VBLK;
66437741Smckusick 		break;
66537741Smckusick 	default:
66637741Smckusick 		error = EINVAL;
66737741Smckusick 		goto out;
6686254Sroot 	}
66945914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
67037741Smckusick 	vattr.va_rdev = uap->dev;
6716254Sroot out:
67242465Smckusick 	if (!error) {
673*48026Smckusick 		error = VOP_MKNOD(ndp, &vattr, p->p_ucred, p);
67442465Smckusick 	} else {
67537741Smckusick 		VOP_ABORTOP(ndp);
67643344Smckusick 		if (ndp->ni_dvp == vp)
67743344Smckusick 			vrele(ndp->ni_dvp);
67843344Smckusick 		else
67943344Smckusick 			vput(ndp->ni_dvp);
68042465Smckusick 		if (vp)
68142465Smckusick 			vrele(vp);
68242465Smckusick 	}
68347540Skarels 	return (error);
6846254Sroot }
6856254Sroot 
6866254Sroot /*
68740285Smckusick  * Mkfifo system call
68840285Smckusick  */
68942441Smckusick /* ARGSUSED */
69042441Smckusick mkfifo(p, uap, retval)
69145914Smckusick 	struct proc *p;
69242441Smckusick 	register struct args {
69340285Smckusick 		char	*fname;
69440285Smckusick 		int	fmode;
69542441Smckusick 	} *uap;
69642441Smckusick 	int *retval;
69742441Smckusick {
69847540Skarels 	register struct nameidata *ndp;
69940285Smckusick 	struct vattr vattr;
70040285Smckusick 	int error;
70147540Skarels 	struct nameidata nd;
70240285Smckusick 
70340285Smckusick #ifndef FIFO
70447540Skarels 	return (EOPNOTSUPP);
70540285Smckusick #else
70647540Skarels 	ndp = &nd;
70740285Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
70840285Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
70940285Smckusick 	ndp->ni_dirp = uap->fname;
71047540Skarels 	if (error = namei(ndp, p))
71147540Skarels 		return (error);
71240285Smckusick 	if (ndp->ni_vp != NULL) {
71340285Smckusick 		VOP_ABORTOP(ndp);
71443344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
71543344Smckusick 			vrele(ndp->ni_dvp);
71643344Smckusick 		else
71743344Smckusick 			vput(ndp->ni_dvp);
71842465Smckusick 		vrele(ndp->ni_vp);
71947540Skarels 		return (EEXIST);
72040285Smckusick 	}
72145785Sbostic 	VATTR_NULL(&vattr);
72245785Sbostic 	vattr.va_type = VFIFO;
72345914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
724*48026Smckusick 	return (VOP_MKNOD(ndp, &vattr, p->p_ucred, p));
72540285Smckusick #endif /* FIFO */
72640285Smckusick }
72740285Smckusick 
72840285Smckusick /*
7296254Sroot  * link system call
7306254Sroot  */
73142441Smckusick /* ARGSUSED */
73242441Smckusick link(p, uap, retval)
73345914Smckusick 	struct proc *p;
73442441Smckusick 	register struct args {
7356254Sroot 		char	*target;
7366254Sroot 		char	*linkname;
73742441Smckusick 	} *uap;
73842441Smckusick 	int *retval;
73942441Smckusick {
74047540Skarels 	register struct nameidata *ndp;
74137741Smckusick 	register struct vnode *vp, *xp;
74237741Smckusick 	int error;
74347540Skarels 	struct nameidata nd;
7446254Sroot 
74547540Skarels 	ndp = &nd;
74616694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
74716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
74816694Smckusick 	ndp->ni_dirp = uap->target;
74947540Skarels 	if (error = namei(ndp, p))
75047540Skarels 		return (error);
75137741Smckusick 	vp = ndp->ni_vp;
75237741Smckusick 	if (vp->v_type == VDIR &&
75347540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
75437741Smckusick 		goto out1;
75537741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
75616694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
75747540Skarels 	if (error = namei(ndp, p))
75837741Smckusick 		goto out1;
75937741Smckusick 	xp = ndp->ni_vp;
7606254Sroot 	if (xp != NULL) {
76137741Smckusick 		error = EEXIST;
7626254Sroot 		goto out;
7636254Sroot 	}
76437741Smckusick 	xp = ndp->ni_dvp;
76537741Smckusick 	if (vp->v_mount != xp->v_mount)
76637741Smckusick 		error = EXDEV;
7676254Sroot out:
76842465Smckusick 	if (!error) {
769*48026Smckusick 		error = VOP_LINK(vp, ndp, p);
77042465Smckusick 	} else {
77137741Smckusick 		VOP_ABORTOP(ndp);
77243344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
77343344Smckusick 			vrele(ndp->ni_dvp);
77443344Smckusick 		else
77543344Smckusick 			vput(ndp->ni_dvp);
77642465Smckusick 		if (ndp->ni_vp)
77742465Smckusick 			vrele(ndp->ni_vp);
77842465Smckusick 	}
77937741Smckusick out1:
78037741Smckusick 	vrele(vp);
78147540Skarels 	return (error);
7826254Sroot }
7836254Sroot 
7846254Sroot /*
7856254Sroot  * symlink -- make a symbolic link
7866254Sroot  */
78742441Smckusick /* ARGSUSED */
78842441Smckusick symlink(p, uap, retval)
78945914Smckusick 	struct proc *p;
79042441Smckusick 	register struct args {
7916254Sroot 		char	*target;
7926254Sroot 		char	*linkname;
79342441Smckusick 	} *uap;
79442441Smckusick 	int *retval;
79542441Smckusick {
79647540Skarels 	register struct nameidata *ndp;
79737741Smckusick 	struct vattr vattr;
79837741Smckusick 	char *target;
79937741Smckusick 	int error;
80047540Skarels 	struct nameidata nd;
8016254Sroot 
80247540Skarels 	ndp = &nd;
80316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
80416694Smckusick 	ndp->ni_dirp = uap->linkname;
80537741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
80637741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
80742465Smckusick 		goto out;
80837741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
80947540Skarels 	if (error = namei(ndp, p))
81042465Smckusick 		goto out;
81142465Smckusick 	if (ndp->ni_vp) {
81242465Smckusick 		VOP_ABORTOP(ndp);
81343344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
81443344Smckusick 			vrele(ndp->ni_dvp);
81543344Smckusick 		else
81643344Smckusick 			vput(ndp->ni_dvp);
81742465Smckusick 		vrele(ndp->ni_vp);
81837741Smckusick 		error = EEXIST;
81937741Smckusick 		goto out;
8206254Sroot 	}
82141362Smckusick 	VATTR_NULL(&vattr);
82245914Smckusick 	vattr.va_mode = 0777 &~ p->p_fd->fd_cmask;
823*48026Smckusick 	error = VOP_SYMLINK(ndp, &vattr, target, p);
82437741Smckusick out:
82537741Smckusick 	FREE(target, M_NAMEI);
82647540Skarels 	return (error);
8276254Sroot }
8286254Sroot 
8296254Sroot /*
8306254Sroot  * Unlink system call.
8316254Sroot  * Hard to avoid races here, especially
8326254Sroot  * in unlinking directories.
8336254Sroot  */
83442441Smckusick /* ARGSUSED */
83542441Smckusick unlink(p, uap, retval)
83645914Smckusick 	struct proc *p;
83742441Smckusick 	struct args {
83842441Smckusick 		char	*fname;
83942441Smckusick 	} *uap;
84042441Smckusick 	int *retval;
8416254Sroot {
84247540Skarels 	register struct nameidata *ndp;
84337741Smckusick 	register struct vnode *vp;
84437741Smckusick 	int error;
84547540Skarels 	struct nameidata nd;
8466254Sroot 
84747540Skarels 	ndp = &nd;
84837741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
84916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
85016694Smckusick 	ndp->ni_dirp = uap->fname;
85147540Skarels 	if (error = namei(ndp, p))
85247540Skarels 		return (error);
85337741Smckusick 	vp = ndp->ni_vp;
85437741Smckusick 	if (vp->v_type == VDIR &&
85547540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
8566254Sroot 		goto out;
8576254Sroot 	/*
8586254Sroot 	 * Don't unlink a mounted file.
8596254Sroot 	 */
86037741Smckusick 	if (vp->v_flag & VROOT) {
86137741Smckusick 		error = EBUSY;
8626254Sroot 		goto out;
8636254Sroot 	}
86445922Smckusick #ifdef NVM
86545738Smckusick 	(void) vnode_pager_uncache(vp);
86645922Smckusick #else
86745922Smckusick 	if (vp->v_flag & VTEXT)
86845922Smckusick 		xrele(vp);	/* try once to free text */
86945922Smckusick #endif
8706254Sroot out:
87142465Smckusick 	if (!error) {
872*48026Smckusick 		error = VOP_REMOVE(ndp, p);
87342465Smckusick 	} else {
87437741Smckusick 		VOP_ABORTOP(ndp);
87543344Smckusick 		if (ndp->ni_dvp == vp)
87643344Smckusick 			vrele(ndp->ni_dvp);
87743344Smckusick 		else
87843344Smckusick 			vput(ndp->ni_dvp);
87942465Smckusick 		vput(vp);
88042465Smckusick 	}
88147540Skarels 	return (error);
8826254Sroot }
8836254Sroot 
8846254Sroot /*
8856254Sroot  * Seek system call
8866254Sroot  */
88742441Smckusick lseek(p, uap, retval)
88845914Smckusick 	struct proc *p;
88942441Smckusick 	register struct args {
89037741Smckusick 		int	fdes;
8916254Sroot 		off_t	off;
8926254Sroot 		int	sbase;
89342441Smckusick 	} *uap;
89442441Smckusick 	off_t *retval;
89542441Smckusick {
89647540Skarels 	struct ucred *cred = p->p_ucred;
89745914Smckusick 	register struct filedesc *fdp = p->p_fd;
89842441Smckusick 	register struct file *fp;
89937741Smckusick 	struct vattr vattr;
90037741Smckusick 	int error;
9016254Sroot 
90247540Skarels 	if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
90347688Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL)
90447540Skarels 		return (EBADF);
90537741Smckusick 	if (fp->f_type != DTYPE_VNODE)
90647540Skarels 		return (ESPIPE);
90713878Ssam 	switch (uap->sbase) {
90813878Ssam 
90913878Ssam 	case L_INCR:
91013878Ssam 		fp->f_offset += uap->off;
91113878Ssam 		break;
91213878Ssam 
91313878Ssam 	case L_XTND:
91437741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
915*48026Smckusick 		    &vattr, cred, p))
91647540Skarels 			return (error);
91737741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
91813878Ssam 		break;
91913878Ssam 
92013878Ssam 	case L_SET:
92113878Ssam 		fp->f_offset = uap->off;
92213878Ssam 		break;
92313878Ssam 
92413878Ssam 	default:
92547540Skarels 		return (EINVAL);
92613878Ssam 	}
92742441Smckusick 	*retval = fp->f_offset;
92847540Skarels 	return (0);
9296254Sroot }
9306254Sroot 
9316254Sroot /*
9326254Sroot  * Access system call
9336254Sroot  */
93442441Smckusick /* ARGSUSED */
93542441Smckusick saccess(p, uap, retval)
93645914Smckusick 	struct proc *p;
93742441Smckusick 	register struct args {
9386254Sroot 		char	*fname;
9396254Sroot 		int	fmode;
94042441Smckusick 	} *uap;
94142441Smckusick 	int *retval;
94242441Smckusick {
94347540Skarels 	register struct nameidata *ndp;
94447540Skarels 	register struct ucred *cred = p->p_ucred;
94537741Smckusick 	register struct vnode *vp;
94637741Smckusick 	int error, mode, svuid, svgid;
94747540Skarels 	struct nameidata nd;
9486254Sroot 
94947540Skarels 	ndp = &nd;
95042441Smckusick 	svuid = cred->cr_uid;
95142441Smckusick 	svgid = cred->cr_groups[0];
95247540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
95347540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
95437741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
95516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
95616694Smckusick 	ndp->ni_dirp = uap->fname;
95747540Skarels 	if (error = namei(ndp, p))
95837741Smckusick 		goto out1;
95937741Smckusick 	vp = ndp->ni_vp;
96037741Smckusick 	/*
96137741Smckusick 	 * fmode == 0 means only check for exist
96237741Smckusick 	 */
96337741Smckusick 	if (uap->fmode) {
96437741Smckusick 		mode = 0;
96537741Smckusick 		if (uap->fmode & R_OK)
96637741Smckusick 			mode |= VREAD;
96737741Smckusick 		if (uap->fmode & W_OK)
96837741Smckusick 			mode |= VWRITE;
96937741Smckusick 		if (uap->fmode & X_OK)
97037741Smckusick 			mode |= VEXEC;
97139543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
972*48026Smckusick 			error = VOP_ACCESS(vp, mode, cred, p);
9736254Sroot 	}
97437741Smckusick 	vput(vp);
97537741Smckusick out1:
97642441Smckusick 	cred->cr_uid = svuid;
97742441Smckusick 	cred->cr_groups[0] = svgid;
97847540Skarels 	return (error);
9796254Sroot }
9806254Sroot 
9816254Sroot /*
9826574Smckusic  * Stat system call.  This version follows links.
98337Sbill  */
98442441Smckusick /* ARGSUSED */
98542441Smckusick stat(p, uap, retval)
98645914Smckusick 	struct proc *p;
98742441Smckusick 	register struct args {
98842441Smckusick 		char	*fname;
98942441Smckusick 		struct stat *ub;
99042441Smckusick 	} *uap;
99142441Smckusick 	int *retval;
99237Sbill {
99347540Skarels 	register struct nameidata *ndp;
99442441Smckusick 	struct stat sb;
99542441Smckusick 	int error;
99647540Skarels 	struct nameidata nd;
99737Sbill 
99847540Skarels 	ndp = &nd;
99942441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
100042441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
100142441Smckusick 	ndp->ni_dirp = uap->fname;
100247540Skarels 	if (error = namei(ndp, p))
100347540Skarels 		return (error);
1004*48026Smckusick 	error = vn_stat(ndp->ni_vp, &sb, p);
100542441Smckusick 	vput(ndp->ni_vp);
100642441Smckusick 	if (error)
100747540Skarels 		return (error);
100842441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
100947540Skarels 	return (error);
101037Sbill }
101137Sbill 
101237Sbill /*
10136574Smckusic  * Lstat system call.  This version does not follow links.
10145992Swnj  */
101542441Smckusick /* ARGSUSED */
101642441Smckusick lstat(p, uap, retval)
101745914Smckusick 	struct proc *p;
101842441Smckusick 	register struct args {
10195992Swnj 		char	*fname;
102012756Ssam 		struct stat *ub;
102142441Smckusick 	} *uap;
102242441Smckusick 	int *retval;
102342441Smckusick {
102447540Skarels 	register struct nameidata *ndp;
102512756Ssam 	struct stat sb;
102637741Smckusick 	int error;
102747540Skarels 	struct nameidata nd;
10285992Swnj 
102947540Skarels 	ndp = &nd;
103042441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW;
103116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
103216694Smckusick 	ndp->ni_dirp = uap->fname;
103347540Skarels 	if (error = namei(ndp, p))
103447540Skarels 		return (error);
1035*48026Smckusick 	error = vn_stat(ndp->ni_vp, &sb, p);
103637741Smckusick 	vput(ndp->ni_vp);
103737741Smckusick 	if (error)
103847540Skarels 		return (error);
103937741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
104047540Skarels 	return (error);
10415992Swnj }
10425992Swnj 
10435992Swnj /*
10445992Swnj  * Return target name of a symbolic link
104537Sbill  */
104642441Smckusick /* ARGSUSED */
104742441Smckusick readlink(p, uap, retval)
104845914Smckusick 	struct proc *p;
104942441Smckusick 	register struct args {
10505992Swnj 		char	*name;
10515992Swnj 		char	*buf;
10525992Swnj 		int	count;
105342441Smckusick 	} *uap;
105442441Smckusick 	int *retval;
105542441Smckusick {
105647540Skarels 	register struct nameidata *ndp;
105737741Smckusick 	register struct vnode *vp;
105837741Smckusick 	struct iovec aiov;
105937741Smckusick 	struct uio auio;
106037741Smckusick 	int error;
106147540Skarels 	struct nameidata nd;
10625992Swnj 
106347540Skarels 	ndp = &nd;
106437741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
106516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
106616694Smckusick 	ndp->ni_dirp = uap->name;
106747540Skarels 	if (error = namei(ndp, p))
106847540Skarels 		return (error);
106937741Smckusick 	vp = ndp->ni_vp;
107037741Smckusick 	if (vp->v_type != VLNK) {
107137741Smckusick 		error = EINVAL;
10725992Swnj 		goto out;
10735992Swnj 	}
107437741Smckusick 	aiov.iov_base = uap->buf;
107537741Smckusick 	aiov.iov_len = uap->count;
107637741Smckusick 	auio.uio_iov = &aiov;
107737741Smckusick 	auio.uio_iovcnt = 1;
107837741Smckusick 	auio.uio_offset = 0;
107937741Smckusick 	auio.uio_rw = UIO_READ;
108037741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
1081*48026Smckusick 	auio.uio_procp = p;
108237741Smckusick 	auio.uio_resid = uap->count;
108347540Skarels 	error = VOP_READLINK(vp, &auio, p->p_ucred);
10845992Swnj out:
108537741Smckusick 	vput(vp);
108642441Smckusick 	*retval = uap->count - auio.uio_resid;
108747540Skarels 	return (error);
10885992Swnj }
10895992Swnj 
10909167Ssam /*
109138259Smckusick  * Change flags of a file given path name.
109238259Smckusick  */
109342441Smckusick /* ARGSUSED */
109442441Smckusick chflags(p, uap, retval)
109545914Smckusick 	struct proc *p;
109642441Smckusick 	register struct args {
109738259Smckusick 		char	*fname;
109838259Smckusick 		int	flags;
109942441Smckusick 	} *uap;
110042441Smckusick 	int *retval;
110142441Smckusick {
110247540Skarels 	register struct nameidata *ndp;
110338259Smckusick 	register struct vnode *vp;
110438259Smckusick 	struct vattr vattr;
110538259Smckusick 	int error;
110647540Skarels 	struct nameidata nd;
110738259Smckusick 
110847540Skarels 	ndp = &nd;
110938259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
111038259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
111138259Smckusick 	ndp->ni_dirp = uap->fname;
111247540Skarels 	if (error = namei(ndp, p))
111347540Skarels 		return (error);
111438259Smckusick 	vp = ndp->ni_vp;
111541400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
111638259Smckusick 		error = EROFS;
111738259Smckusick 		goto out;
111838259Smckusick 	}
111945785Sbostic 	VATTR_NULL(&vattr);
112045785Sbostic 	vattr.va_flags = uap->flags;
1121*48026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
112238259Smckusick out:
112338259Smckusick 	vput(vp);
112447540Skarels 	return (error);
112538259Smckusick }
112638259Smckusick 
112738259Smckusick /*
112838259Smckusick  * Change flags of a file given a file descriptor.
112938259Smckusick  */
113042441Smckusick /* ARGSUSED */
113142441Smckusick fchflags(p, uap, retval)
113245914Smckusick 	struct proc *p;
113342441Smckusick 	register struct args {
113438259Smckusick 		int	fd;
113538259Smckusick 		int	flags;
113642441Smckusick 	} *uap;
113742441Smckusick 	int *retval;
113842441Smckusick {
113938259Smckusick 	struct vattr vattr;
114038259Smckusick 	struct vnode *vp;
114138259Smckusick 	struct file *fp;
114238259Smckusick 	int error;
114338259Smckusick 
114445914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
114547540Skarels 		return (error);
114638259Smckusick 	vp = (struct vnode *)fp->f_data;
114738259Smckusick 	VOP_LOCK(vp);
114841400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
114938259Smckusick 		error = EROFS;
115038259Smckusick 		goto out;
115138259Smckusick 	}
115245785Sbostic 	VATTR_NULL(&vattr);
115345785Sbostic 	vattr.va_flags = uap->flags;
1154*48026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
115538259Smckusick out:
115638259Smckusick 	VOP_UNLOCK(vp);
115747540Skarels 	return (error);
115838259Smckusick }
115938259Smckusick 
116038259Smckusick /*
11619167Ssam  * Change mode of a file given path name.
11629167Ssam  */
116342441Smckusick /* ARGSUSED */
116442441Smckusick chmod(p, uap, retval)
116545914Smckusick 	struct proc *p;
116642441Smckusick 	register struct args {
11676254Sroot 		char	*fname;
11686254Sroot 		int	fmode;
116942441Smckusick 	} *uap;
117042441Smckusick 	int *retval;
117142441Smckusick {
117247540Skarels 	register struct nameidata *ndp;
117337741Smckusick 	register struct vnode *vp;
117437741Smckusick 	struct vattr vattr;
117537741Smckusick 	int error;
117647540Skarels 	struct nameidata nd;
11775992Swnj 
117847540Skarels 	ndp = &nd;
117937741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
118037741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
118137741Smckusick 	ndp->ni_dirp = uap->fname;
118247540Skarels 	if (error = namei(ndp, p))
118347540Skarels 		return (error);
118437741Smckusick 	vp = ndp->ni_vp;
118541400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
118637741Smckusick 		error = EROFS;
118737741Smckusick 		goto out;
118837741Smckusick 	}
118945785Sbostic 	VATTR_NULL(&vattr);
119045785Sbostic 	vattr.va_mode = uap->fmode & 07777;
1191*48026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
119237741Smckusick out:
119337741Smckusick 	vput(vp);
119447540Skarels 	return (error);
11957701Ssam }
11967439Sroot 
11979167Ssam /*
11989167Ssam  * Change mode of a file given a file descriptor.
11999167Ssam  */
120042441Smckusick /* ARGSUSED */
120142441Smckusick fchmod(p, uap, retval)
120245914Smckusick 	struct proc *p;
120342441Smckusick 	register struct args {
12047701Ssam 		int	fd;
12057701Ssam 		int	fmode;
120642441Smckusick 	} *uap;
120742441Smckusick 	int *retval;
120842441Smckusick {
120937741Smckusick 	struct vattr vattr;
121037741Smckusick 	struct vnode *vp;
121137741Smckusick 	struct file *fp;
121237741Smckusick 	int error;
12137701Ssam 
121445914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
121547540Skarels 		return (error);
121637741Smckusick 	vp = (struct vnode *)fp->f_data;
121737741Smckusick 	VOP_LOCK(vp);
121841400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
121937741Smckusick 		error = EROFS;
122037741Smckusick 		goto out;
12217439Sroot 	}
122245785Sbostic 	VATTR_NULL(&vattr);
122345785Sbostic 	vattr.va_mode = uap->fmode & 07777;
1224*48026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
122537741Smckusick out:
122637741Smckusick 	VOP_UNLOCK(vp);
122747540Skarels 	return (error);
12285992Swnj }
12295992Swnj 
12309167Ssam /*
12319167Ssam  * Set ownership given a path name.
12329167Ssam  */
123342441Smckusick /* ARGSUSED */
123442441Smckusick chown(p, uap, retval)
123545914Smckusick 	struct proc *p;
123642441Smckusick 	register struct args {
12376254Sroot 		char	*fname;
12386254Sroot 		int	uid;
12396254Sroot 		int	gid;
124042441Smckusick 	} *uap;
124142441Smckusick 	int *retval;
124242441Smckusick {
124347540Skarels 	register struct nameidata *ndp;
124437741Smckusick 	register struct vnode *vp;
124537741Smckusick 	struct vattr vattr;
124637741Smckusick 	int error;
124747540Skarels 	struct nameidata nd;
124837Sbill 
124947540Skarels 	ndp = &nd;
125037741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
125136614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
125236614Sbostic 	ndp->ni_dirp = uap->fname;
125347540Skarels 	if (error = namei(ndp, p))
125447540Skarels 		return (error);
125537741Smckusick 	vp = ndp->ni_vp;
125641400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
125737741Smckusick 		error = EROFS;
125837741Smckusick 		goto out;
125937741Smckusick 	}
126045785Sbostic 	VATTR_NULL(&vattr);
126145785Sbostic 	vattr.va_uid = uap->uid;
126245785Sbostic 	vattr.va_gid = uap->gid;
1263*48026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
126437741Smckusick out:
126537741Smckusick 	vput(vp);
126647540Skarels 	return (error);
12677701Ssam }
12687439Sroot 
12699167Ssam /*
12709167Ssam  * Set ownership given a file descriptor.
12719167Ssam  */
127242441Smckusick /* ARGSUSED */
127342441Smckusick fchown(p, uap, retval)
127445914Smckusick 	struct proc *p;
127542441Smckusick 	register struct args {
12767701Ssam 		int	fd;
12777701Ssam 		int	uid;
12787701Ssam 		int	gid;
127942441Smckusick 	} *uap;
128042441Smckusick 	int *retval;
128142441Smckusick {
128237741Smckusick 	struct vattr vattr;
128337741Smckusick 	struct vnode *vp;
128437741Smckusick 	struct file *fp;
128537741Smckusick 	int error;
12867701Ssam 
128745914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
128847540Skarels 		return (error);
128937741Smckusick 	vp = (struct vnode *)fp->f_data;
129037741Smckusick 	VOP_LOCK(vp);
129141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
129237741Smckusick 		error = EROFS;
129337741Smckusick 		goto out;
129437741Smckusick 	}
129545785Sbostic 	VATTR_NULL(&vattr);
129645785Sbostic 	vattr.va_uid = uap->uid;
129745785Sbostic 	vattr.va_gid = uap->gid;
1298*48026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
129937741Smckusick out:
130037741Smckusick 	VOP_UNLOCK(vp);
130147540Skarels 	return (error);
13027701Ssam }
13037701Ssam 
130442441Smckusick /*
130542441Smckusick  * Set the access and modification times of a file.
130642441Smckusick  */
130742441Smckusick /* ARGSUSED */
130842441Smckusick utimes(p, uap, retval)
130945914Smckusick 	struct proc *p;
131042441Smckusick 	register struct args {
131111811Ssam 		char	*fname;
131211811Ssam 		struct	timeval *tptr;
131342441Smckusick 	} *uap;
131442441Smckusick 	int *retval;
131542441Smckusick {
131647540Skarels 	register struct nameidata *ndp;
131737741Smckusick 	register struct vnode *vp;
131811811Ssam 	struct timeval tv[2];
131937741Smckusick 	struct vattr vattr;
132037741Smckusick 	int error;
132147540Skarels 	struct nameidata nd;
132211811Ssam 
132337741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
132447540Skarels 		return (error);
132547540Skarels 	ndp = &nd;
132637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
132737741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
132837741Smckusick 	ndp->ni_dirp = uap->fname;
132947540Skarels 	if (error = namei(ndp, p))
133047540Skarels 		return (error);
133137741Smckusick 	vp = ndp->ni_vp;
133241400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
133337741Smckusick 		error = EROFS;
133437741Smckusick 		goto out;
133521015Smckusick 	}
133645785Sbostic 	VATTR_NULL(&vattr);
133745785Sbostic 	vattr.va_atime = tv[0];
133845785Sbostic 	vattr.va_mtime = tv[1];
1339*48026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
134037741Smckusick out:
134137741Smckusick 	vput(vp);
134247540Skarels 	return (error);
134311811Ssam }
134411811Ssam 
13459167Ssam /*
13469167Ssam  * Truncate a file given its path name.
13479167Ssam  */
134842441Smckusick /* ARGSUSED */
134942441Smckusick truncate(p, uap, retval)
135045914Smckusick 	struct proc *p;
135142441Smckusick 	register struct args {
13527701Ssam 		char	*fname;
135326473Skarels 		off_t	length;
135442441Smckusick 	} *uap;
135542441Smckusick 	int *retval;
135642441Smckusick {
135747540Skarels 	register struct nameidata *ndp;
135837741Smckusick 	register struct vnode *vp;
135937741Smckusick 	struct vattr vattr;
136037741Smckusick 	int error;
136147540Skarels 	struct nameidata nd;
13627701Ssam 
136347540Skarels 	ndp = &nd;
136437741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
136516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
136616694Smckusick 	ndp->ni_dirp = uap->fname;
136747540Skarels 	if (error = namei(ndp, p))
136847540Skarels 		return (error);
136937741Smckusick 	vp = ndp->ni_vp;
137037741Smckusick 	if (vp->v_type == VDIR) {
137137741Smckusick 		error = EISDIR;
137237741Smckusick 		goto out;
13737701Ssam 	}
137438399Smckusick 	if ((error = vn_writechk(vp)) ||
1375*48026Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)))
137637741Smckusick 		goto out;
137745785Sbostic 	VATTR_NULL(&vattr);
137845785Sbostic 	vattr.va_size = uap->length;
1379*48026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
138037741Smckusick out:
138137741Smckusick 	vput(vp);
138247540Skarels 	return (error);
13837701Ssam }
13847701Ssam 
13859167Ssam /*
13869167Ssam  * Truncate a file given a file descriptor.
13879167Ssam  */
138842441Smckusick /* ARGSUSED */
138942441Smckusick ftruncate(p, uap, retval)
139045914Smckusick 	struct proc *p;
139142441Smckusick 	register struct args {
13927701Ssam 		int	fd;
139326473Skarels 		off_t	length;
139442441Smckusick 	} *uap;
139542441Smckusick 	int *retval;
139642441Smckusick {
139737741Smckusick 	struct vattr vattr;
139837741Smckusick 	struct vnode *vp;
13997701Ssam 	struct file *fp;
140037741Smckusick 	int error;
14017701Ssam 
140245914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
140347540Skarels 		return (error);
140437741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
140547540Skarels 		return (EINVAL);
140637741Smckusick 	vp = (struct vnode *)fp->f_data;
140737741Smckusick 	VOP_LOCK(vp);
140837741Smckusick 	if (vp->v_type == VDIR) {
140937741Smckusick 		error = EISDIR;
141037741Smckusick 		goto out;
14117701Ssam 	}
141238399Smckusick 	if (error = vn_writechk(vp))
141337741Smckusick 		goto out;
141445785Sbostic 	VATTR_NULL(&vattr);
141545785Sbostic 	vattr.va_size = uap->length;
1416*48026Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
141737741Smckusick out:
141837741Smckusick 	VOP_UNLOCK(vp);
141947540Skarels 	return (error);
14207701Ssam }
14217701Ssam 
14229167Ssam /*
14239167Ssam  * Synch an open file.
14249167Ssam  */
142542441Smckusick /* ARGSUSED */
142642441Smckusick fsync(p, uap, retval)
142745914Smckusick 	struct proc *p;
142842441Smckusick 	struct args {
142942441Smckusick 		int	fd;
143042441Smckusick 	} *uap;
143142441Smckusick 	int *retval;
14329167Ssam {
143339592Smckusick 	register struct vnode *vp;
14349167Ssam 	struct file *fp;
143537741Smckusick 	int error;
14369167Ssam 
143745914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
143847540Skarels 		return (error);
143939592Smckusick 	vp = (struct vnode *)fp->f_data;
144039592Smckusick 	VOP_LOCK(vp);
1441*48026Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT, p);
144239592Smckusick 	VOP_UNLOCK(vp);
144347540Skarels 	return (error);
14449167Ssam }
14459167Ssam 
14469167Ssam /*
14479167Ssam  * Rename system call.
14489167Ssam  *
14499167Ssam  * Source and destination must either both be directories, or both
14509167Ssam  * not be directories.  If target is a directory, it must be empty.
14519167Ssam  */
145242441Smckusick /* ARGSUSED */
145342441Smckusick rename(p, uap, retval)
145445914Smckusick 	struct proc *p;
145542441Smckusick 	register struct args {
14567701Ssam 		char	*from;
14577701Ssam 		char	*to;
145842441Smckusick 	} *uap;
145942441Smckusick 	int *retval;
146042441Smckusick {
146137741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
146247540Skarels 	register struct nameidata *ndp;
146337741Smckusick 	int error;
146447540Skarels 	struct nameidata nd, tond;
14657701Ssam 
146647540Skarels 	ndp = &nd;
146737741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
146816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
146916694Smckusick 	ndp->ni_dirp = uap->from;
147047540Skarels 	if (error = namei(ndp, p))
147147540Skarels 		return (error);
147237741Smckusick 	fvp = ndp->ni_vp;
147338266Smckusick 	nddup(ndp, &tond);
147437741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
147537741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
147637741Smckusick 	tond.ni_dirp = uap->to;
147747540Skarels 	if (error = namei(&tond, p)) {
147842465Smckusick 		VOP_ABORTOP(ndp);
147942465Smckusick 		vrele(ndp->ni_dvp);
148042465Smckusick 		vrele(fvp);
148142465Smckusick 		goto out1;
148242465Smckusick 	}
148337741Smckusick 	tdvp = tond.ni_dvp;
148437741Smckusick 	tvp = tond.ni_vp;
148537741Smckusick 	if (tvp != NULL) {
148637741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
148739242Sbostic 			error = ENOTDIR;
148837741Smckusick 			goto out;
148937741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
149039242Sbostic 			error = EISDIR;
149137741Smckusick 			goto out;
14929167Ssam 		}
149345240Smckusick 		if (fvp->v_mount != tvp->v_mount) {
149445240Smckusick 			error = EXDEV;
149545240Smckusick 			goto out;
149645240Smckusick 		}
14979167Ssam 	}
149837741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
149937741Smckusick 		error = EXDEV;
15009167Ssam 		goto out;
150110051Ssam 	}
150239286Smckusick 	if (fvp == tdvp)
150337741Smckusick 		error = EINVAL;
150439286Smckusick 	/*
150539286Smckusick 	 * If source is the same as the destination,
150639286Smckusick 	 * then there is nothing to do.
150739286Smckusick 	 */
150839286Smckusick 	if (fvp == tvp)
150939286Smckusick 		error = -1;
151037741Smckusick out:
151142465Smckusick 	if (!error) {
1512*48026Smckusick 		error = VOP_RENAME(ndp, &tond, p);
151342465Smckusick 	} else {
151437741Smckusick 		VOP_ABORTOP(&tond);
151543344Smckusick 		if (tdvp == tvp)
151643344Smckusick 			vrele(tdvp);
151743344Smckusick 		else
151843344Smckusick 			vput(tdvp);
151942465Smckusick 		if (tvp)
152042465Smckusick 			vput(tvp);
152137741Smckusick 		VOP_ABORTOP(ndp);
152242465Smckusick 		vrele(ndp->ni_dvp);
152342465Smckusick 		vrele(fvp);
15249167Ssam 	}
152537741Smckusick out1:
152638266Smckusick 	ndrele(&tond);
152739286Smckusick 	if (error == -1)
152847540Skarels 		return (0);
152947540Skarels 	return (error);
15307701Ssam }
15317701Ssam 
15327535Sroot /*
153312756Ssam  * Mkdir system call
153412756Ssam  */
153542441Smckusick /* ARGSUSED */
153642441Smckusick mkdir(p, uap, retval)
153745914Smckusick 	struct proc *p;
153842441Smckusick 	register struct args {
153912756Ssam 		char	*name;
154012756Ssam 		int	dmode;
154142441Smckusick 	} *uap;
154242441Smckusick 	int *retval;
154342441Smckusick {
154447540Skarels 	register struct nameidata *ndp;
154537741Smckusick 	register struct vnode *vp;
154637741Smckusick 	struct vattr vattr;
154737741Smckusick 	int error;
154847540Skarels 	struct nameidata nd;
154912756Ssam 
155047540Skarels 	ndp = &nd;
155137741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
155216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
155316694Smckusick 	ndp->ni_dirp = uap->name;
155447540Skarels 	if (error = namei(ndp, p))
155547540Skarels 		return (error);
155637741Smckusick 	vp = ndp->ni_vp;
155737741Smckusick 	if (vp != NULL) {
155837741Smckusick 		VOP_ABORTOP(ndp);
155943344Smckusick 		if (ndp->ni_dvp == vp)
156043344Smckusick 			vrele(ndp->ni_dvp);
156143344Smckusick 		else
156243344Smckusick 			vput(ndp->ni_dvp);
156342465Smckusick 		vrele(vp);
156447540Skarels 		return (EEXIST);
156512756Ssam 	}
156641362Smckusick 	VATTR_NULL(&vattr);
156737741Smckusick 	vattr.va_type = VDIR;
156845914Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask;
1569*48026Smckusick 	error = VOP_MKDIR(ndp, &vattr, p);
157038145Smckusick 	if (!error)
157138145Smckusick 		vput(ndp->ni_vp);
157247540Skarels 	return (error);
157312756Ssam }
157412756Ssam 
157512756Ssam /*
157612756Ssam  * Rmdir system call.
157712756Ssam  */
157842441Smckusick /* ARGSUSED */
157942441Smckusick rmdir(p, uap, retval)
158045914Smckusick 	struct proc *p;
158142441Smckusick 	struct args {
158242441Smckusick 		char	*name;
158342441Smckusick 	} *uap;
158442441Smckusick 	int *retval;
158512756Ssam {
158647540Skarels 	register struct nameidata *ndp;
158737741Smckusick 	register struct vnode *vp;
158837741Smckusick 	int error;
158947540Skarels 	struct nameidata nd;
159012756Ssam 
159147540Skarels 	ndp = &nd;
159237741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
159316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
159416694Smckusick 	ndp->ni_dirp = uap->name;
159547540Skarels 	if (error = namei(ndp, p))
159647540Skarels 		return (error);
159737741Smckusick 	vp = ndp->ni_vp;
159837741Smckusick 	if (vp->v_type != VDIR) {
159937741Smckusick 		error = ENOTDIR;
160012756Ssam 		goto out;
160112756Ssam 	}
160212756Ssam 	/*
160337741Smckusick 	 * No rmdir "." please.
160412756Ssam 	 */
160537741Smckusick 	if (ndp->ni_dvp == vp) {
160637741Smckusick 		error = EINVAL;
160712756Ssam 		goto out;
160812756Ssam 	}
160912756Ssam 	/*
161037741Smckusick 	 * Don't unlink a mounted file.
161112756Ssam 	 */
161237741Smckusick 	if (vp->v_flag & VROOT)
161337741Smckusick 		error = EBUSY;
161412756Ssam out:
161542465Smckusick 	if (!error) {
1616*48026Smckusick 		error = VOP_RMDIR(ndp, p);
161742465Smckusick 	} else {
161837741Smckusick 		VOP_ABORTOP(ndp);
161943344Smckusick 		if (ndp->ni_dvp == vp)
162043344Smckusick 			vrele(ndp->ni_dvp);
162143344Smckusick 		else
162243344Smckusick 			vput(ndp->ni_dvp);
162342465Smckusick 		vput(vp);
162442465Smckusick 	}
162547540Skarels 	return (error);
162612756Ssam }
162712756Ssam 
162837741Smckusick /*
162937741Smckusick  * Read a block of directory entries in a file system independent format
163037741Smckusick  */
163142441Smckusick getdirentries(p, uap, retval)
163245914Smckusick 	struct proc *p;
163342441Smckusick 	register struct args {
163437741Smckusick 		int	fd;
163537741Smckusick 		char	*buf;
163637741Smckusick 		unsigned count;
163737741Smckusick 		long	*basep;
163842441Smckusick 	} *uap;
163942441Smckusick 	int *retval;
164042441Smckusick {
164139592Smckusick 	register struct vnode *vp;
164216540Ssam 	struct file *fp;
164337741Smckusick 	struct uio auio;
164437741Smckusick 	struct iovec aiov;
164538129Smckusick 	off_t off;
164640321Smckusick 	int error, eofflag;
164712756Ssam 
164845914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
164947540Skarels 		return (error);
165037741Smckusick 	if ((fp->f_flag & FREAD) == 0)
165147540Skarels 		return (EBADF);
165239592Smckusick 	vp = (struct vnode *)fp->f_data;
165339592Smckusick 	if (vp->v_type != VDIR)
165447540Skarels 		return (EINVAL);
165537741Smckusick 	aiov.iov_base = uap->buf;
165637741Smckusick 	aiov.iov_len = uap->count;
165737741Smckusick 	auio.uio_iov = &aiov;
165837741Smckusick 	auio.uio_iovcnt = 1;
165937741Smckusick 	auio.uio_rw = UIO_READ;
166037741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
1661*48026Smckusick 	auio.uio_procp = p;
166237741Smckusick 	auio.uio_resid = uap->count;
166339592Smckusick 	VOP_LOCK(vp);
166439592Smckusick 	auio.uio_offset = off = fp->f_offset;
166540321Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
166639592Smckusick 	fp->f_offset = auio.uio_offset;
166739592Smckusick 	VOP_UNLOCK(vp);
166839592Smckusick 	if (error)
166947540Skarels 		return (error);
167039592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
167142441Smckusick 	*retval = uap->count - auio.uio_resid;
167247540Skarels 	return (error);
167312756Ssam }
167412756Ssam 
167512756Ssam /*
167612756Ssam  * mode mask for creation of files
167712756Ssam  */
167842441Smckusick mode_t
167942441Smckusick umask(p, uap, retval)
168045914Smckusick 	struct proc *p;
168142441Smckusick 	struct args {
168242441Smckusick 		int	mask;
168342441Smckusick 	} *uap;
168442441Smckusick 	int *retval;
168512756Ssam {
168645914Smckusick 	register struct filedesc *fdp = p->p_fd;
168712756Ssam 
168845914Smckusick 	*retval = fdp->fd_cmask;
168945914Smckusick 	fdp->fd_cmask = uap->mask & 07777;
169047540Skarels 	return (0);
169112756Ssam }
169237741Smckusick 
169339566Smarc /*
169439566Smarc  * Void all references to file by ripping underlying filesystem
169539566Smarc  * away from vnode.
169639566Smarc  */
169742441Smckusick /* ARGSUSED */
169842441Smckusick revoke(p, uap, retval)
169945914Smckusick 	struct proc *p;
170042441Smckusick 	register struct args {
170139566Smarc 		char	*fname;
170242441Smckusick 	} *uap;
170342441Smckusick 	int *retval;
170442441Smckusick {
170547540Skarels 	register struct nameidata *ndp;
170639566Smarc 	register struct vnode *vp;
170739566Smarc 	struct vattr vattr;
170839566Smarc 	int error;
170947540Skarels 	struct nameidata nd;
171039566Smarc 
171147540Skarels 	ndp = &nd;
171239566Smarc 	ndp->ni_nameiop = LOOKUP | FOLLOW;
171339566Smarc 	ndp->ni_segflg = UIO_USERSPACE;
171439566Smarc 	ndp->ni_dirp = uap->fname;
171547540Skarels 	if (error = namei(ndp, p))
171647540Skarels 		return (error);
171739566Smarc 	vp = ndp->ni_vp;
171839566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
171939566Smarc 		error = EINVAL;
172039566Smarc 		goto out;
172139566Smarc 	}
1722*48026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
172339566Smarc 		goto out;
172447540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
172547540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
172639566Smarc 		goto out;
172739805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
172839632Smckusick 		vgoneall(vp);
172939566Smarc out:
173039566Smarc 	vrele(vp);
173147540Skarels 	return (error);
173239566Smarc }
173339566Smarc 
173445914Smckusick getvnode(fdp, fdes, fpp)
173545914Smckusick 	struct filedesc *fdp;
173637741Smckusick 	struct file **fpp;
173737741Smckusick 	int fdes;
173837741Smckusick {
173937741Smckusick 	struct file *fp;
174037741Smckusick 
174147540Skarels 	if ((unsigned)fdes >= fdp->fd_nfiles ||
174247688Skarels 	    (fp = fdp->fd_ofiles[fdes]) == NULL)
174337741Smckusick 		return (EBADF);
174437741Smckusick 	if (fp->f_type != DTYPE_VNODE)
174537741Smckusick 		return (EINVAL);
174637741Smckusick 	*fpp = fp;
174737741Smckusick 	return (0);
174837741Smckusick }
1749