xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 52781)
123405Smckusick /*
237741Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337741Smckusick  * All rights reserved.
423405Smckusick  *
544459Sbostic  * %sccs.include.redist.c%
637741Smckusick  *
7*52781Sralph  *	@(#)vfs_syscalls.c	7.79 (Berkeley) 03/01/92
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 /*
2849365Smckusick  * 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 {
4139335Smckusick 	register struct vnode *vp;
4239335Smckusick 	register struct mount *mp;
4340111Smckusick 	int error, flag;
4447540Skarels 	struct nameidata nd;
456254Sroot 
4637741Smckusick 	/*
4737741Smckusick 	 * Must be super user
4837741Smckusick 	 */
4947540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
5047540Skarels 		return (error);
5137741Smckusick 	/*
5237741Smckusick 	 * Get vnode to be covered
5337741Smckusick 	 */
5452322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->dir, p);
5552322Smckusick 	if (error = namei(&nd))
5647540Skarels 		return (error);
5752322Smckusick 	vp = nd.ni_vp;
5841400Smckusick 	if (uap->flags & MNT_UPDATE) {
5939335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
6039335Smckusick 			vput(vp);
6147540Skarels 			return (EINVAL);
6239335Smckusick 		}
6339335Smckusick 		mp = vp->v_mount;
6439335Smckusick 		/*
6539335Smckusick 		 * We allow going from read-only to read-write,
6639335Smckusick 		 * but not from read-write to read-only.
6739335Smckusick 		 */
6841400Smckusick 		if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
6941400Smckusick 		    (uap->flags & MNT_RDONLY) != 0) {
7039335Smckusick 			vput(vp);
7147540Skarels 			return (EOPNOTSUPP);	/* Needs translation */
7239335Smckusick 		}
7341400Smckusick 		flag = mp->mnt_flag;
7441400Smckusick 		mp->mnt_flag |= MNT_UPDATE;
7539335Smckusick 		VOP_UNLOCK(vp);
7639335Smckusick 		goto update;
7739335Smckusick 	}
7839665Smckusick 	vinvalbuf(vp, 1);
7939805Smckusick 	if (vp->v_usecount != 1) {
8037741Smckusick 		vput(vp);
8147540Skarels 		return (EBUSY);
8237741Smckusick 	}
8337741Smckusick 	if (vp->v_type != VDIR) {
8437741Smckusick 		vput(vp);
8547540Skarels 		return (ENOTDIR);
8637741Smckusick 	}
8739741Smckusick 	if ((unsigned long)uap->type > MOUNT_MAXTYPE ||
8837741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
8937741Smckusick 		vput(vp);
9047540Skarels 		return (ENODEV);
9137741Smckusick 	}
9237741Smckusick 
9337741Smckusick 	/*
9439335Smckusick 	 * Allocate and initialize the file system.
9537741Smckusick 	 */
9637741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
9737741Smckusick 		M_MOUNT, M_WAITOK);
9841400Smckusick 	mp->mnt_op = vfssw[uap->type];
9941400Smckusick 	mp->mnt_flag = 0;
10041400Smckusick 	mp->mnt_mounth = NULLVP;
10139335Smckusick 	if (error = vfs_lock(mp)) {
10239335Smckusick 		free((caddr_t)mp, M_MOUNT);
10339335Smckusick 		vput(vp);
10447540Skarels 		return (error);
10539335Smckusick 	}
10639335Smckusick 	if (vp->v_mountedhere != (struct mount *)0) {
10739335Smckusick 		vfs_unlock(mp);
10839335Smckusick 		free((caddr_t)mp, M_MOUNT);
10939335Smckusick 		vput(vp);
11047540Skarels 		return (EBUSY);
11139335Smckusick 	}
11239335Smckusick 	vp->v_mountedhere = mp;
11341400Smckusick 	mp->mnt_vnodecovered = vp;
11439335Smckusick update:
11539335Smckusick 	/*
11639335Smckusick 	 * Set the mount level flags.
11739335Smckusick 	 */
11841400Smckusick 	if (uap->flags & MNT_RDONLY)
11941400Smckusick 		mp->mnt_flag |= MNT_RDONLY;
12039335Smckusick 	else
12141400Smckusick 		mp->mnt_flag &= ~MNT_RDONLY;
12241400Smckusick 	if (uap->flags & MNT_NOSUID)
12341400Smckusick 		mp->mnt_flag |= MNT_NOSUID;
12439335Smckusick 	else
12541400Smckusick 		mp->mnt_flag &= ~MNT_NOSUID;
12641400Smckusick 	if (uap->flags & MNT_NOEXEC)
12741400Smckusick 		mp->mnt_flag |= MNT_NOEXEC;
12839335Smckusick 	else
12941400Smckusick 		mp->mnt_flag &= ~MNT_NOEXEC;
13041400Smckusick 	if (uap->flags & MNT_NODEV)
13141400Smckusick 		mp->mnt_flag |= MNT_NODEV;
13239335Smckusick 	else
13341400Smckusick 		mp->mnt_flag &= ~MNT_NODEV;
13441400Smckusick 	if (uap->flags & MNT_SYNCHRONOUS)
13541400Smckusick 		mp->mnt_flag |= MNT_SYNCHRONOUS;
13639335Smckusick 	else
13741400Smckusick 		mp->mnt_flag &= ~MNT_SYNCHRONOUS;
13839335Smckusick 	/*
13939335Smckusick 	 * Mount the filesystem.
14039335Smckusick 	 */
14152322Smckusick 	error = VFS_MOUNT(mp, uap->dir, uap->data, &nd, p);
14241400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
14341400Smckusick 		mp->mnt_flag &= ~MNT_UPDATE;
14439335Smckusick 		vrele(vp);
14540111Smckusick 		if (error)
14641400Smckusick 			mp->mnt_flag = flag;
14747540Skarels 		return (error);
14839335Smckusick 	}
14940110Smckusick 	/*
15040110Smckusick 	 * Put the new filesystem on the mount list after root.
15140110Smckusick 	 */
15241400Smckusick 	mp->mnt_next = rootfs->mnt_next;
15341400Smckusick 	mp->mnt_prev = rootfs;
15441400Smckusick 	rootfs->mnt_next = mp;
15541400Smckusick 	mp->mnt_next->mnt_prev = mp;
15637741Smckusick 	cache_purge(vp);
15737741Smckusick 	if (!error) {
15839335Smckusick 		VOP_UNLOCK(vp);
15937741Smckusick 		vfs_unlock(mp);
16048026Smckusick 		error = VFS_START(mp, 0, p);
16137741Smckusick 	} else {
16237741Smckusick 		vfs_remove(mp);
16337741Smckusick 		free((caddr_t)mp, M_MOUNT);
16439335Smckusick 		vput(vp);
16537741Smckusick 	}
16647540Skarels 	return (error);
1676254Sroot }
1686254Sroot 
1699167Ssam /*
17037741Smckusick  * Unmount system call.
17137741Smckusick  *
17237741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
17337741Smckusick  * not special file (as before).
1749167Ssam  */
17542441Smckusick /* ARGSUSED */
17642441Smckusick unmount(p, uap, retval)
17745914Smckusick 	struct proc *p;
17842441Smckusick 	register struct args {
17937741Smckusick 		char	*pathp;
18037741Smckusick 		int	flags;
18142441Smckusick 	} *uap;
18242441Smckusick 	int *retval;
18342441Smckusick {
18437741Smckusick 	register struct vnode *vp;
18539356Smckusick 	struct mount *mp;
18637741Smckusick 	int error;
18747540Skarels 	struct nameidata nd;
1886254Sroot 
18937741Smckusick 	/*
19037741Smckusick 	 * Must be super user
19137741Smckusick 	 */
19247540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
19347540Skarels 		return (error);
19437741Smckusick 
19552322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->pathp, p);
19652322Smckusick 	if (error = namei(&nd))
19747540Skarels 		return (error);
19852322Smckusick 	vp = nd.ni_vp;
19937741Smckusick 	/*
20037741Smckusick 	 * Must be the root of the filesystem
20137741Smckusick 	 */
20237741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
20337741Smckusick 		vput(vp);
20447540Skarels 		return (EINVAL);
20537741Smckusick 	}
20637741Smckusick 	mp = vp->v_mount;
20737741Smckusick 	vput(vp);
20848026Smckusick 	return (dounmount(mp, uap->flags, p));
20939356Smckusick }
21039356Smckusick 
21139356Smckusick /*
21239356Smckusick  * Do an unmount.
21339356Smckusick  */
21448026Smckusick dounmount(mp, flags, p)
21539356Smckusick 	register struct mount *mp;
21639356Smckusick 	int flags;
21748026Smckusick 	struct proc *p;
21839356Smckusick {
21939356Smckusick 	struct vnode *coveredvp;
22039356Smckusick 	int error;
22139356Smckusick 
22241400Smckusick 	coveredvp = mp->mnt_vnodecovered;
22341298Smckusick 	if (vfs_busy(mp))
22441298Smckusick 		return (EBUSY);
22541400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
22637741Smckusick 	if (error = vfs_lock(mp))
22739356Smckusick 		return (error);
22837741Smckusick 
22945738Smckusick 	vnode_pager_umount(mp);	/* release cached vnodes */
23037741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
23141676Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE))
23248026Smckusick 		error = VFS_UNMOUNT(mp, flags, p);
23341400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
23441298Smckusick 	vfs_unbusy(mp);
23537741Smckusick 	if (error) {
23637741Smckusick 		vfs_unlock(mp);
23737741Smckusick 	} else {
23837741Smckusick 		vrele(coveredvp);
23937741Smckusick 		vfs_remove(mp);
24052287Smckusick 		if (mp->mnt_mounth != NULL)
24152287Smckusick 			panic("unmount: dangling vnode");
24237741Smckusick 		free((caddr_t)mp, M_MOUNT);
24337741Smckusick 	}
24439356Smckusick 	return (error);
2456254Sroot }
2466254Sroot 
2479167Ssam /*
24837741Smckusick  * Sync system call.
24937741Smckusick  * Sync each mounted filesystem.
2509167Ssam  */
25139491Smckusick /* ARGSUSED */
25242441Smckusick sync(p, uap, retval)
25345914Smckusick 	struct proc *p;
25447540Skarels 	void *uap;
25542441Smckusick 	int *retval;
2566254Sroot {
25737741Smckusick 	register struct mount *mp;
25841298Smckusick 	struct mount *omp;
25937741Smckusick 
26037741Smckusick 	mp = rootfs;
26137741Smckusick 	do {
26240343Smckusick 		/*
26340343Smckusick 		 * The lock check below is to avoid races with mount
26440343Smckusick 		 * and unmount.
26540343Smckusick 		 */
26641400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
26741298Smckusick 		    !vfs_busy(mp)) {
26837741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
26941298Smckusick 			omp = mp;
27041400Smckusick 			mp = mp->mnt_next;
27141298Smckusick 			vfs_unbusy(omp);
27241298Smckusick 		} else
27341400Smckusick 			mp = mp->mnt_next;
27437741Smckusick 	} while (mp != rootfs);
27547688Skarels 	return (0);
27637741Smckusick }
27737741Smckusick 
27837741Smckusick /*
27949365Smckusick  * Operate on filesystem quotas.
28041298Smckusick  */
28142441Smckusick /* ARGSUSED */
28242441Smckusick quotactl(p, uap, retval)
28345914Smckusick 	struct proc *p;
28442441Smckusick 	register struct args {
28541298Smckusick 		char *path;
28641298Smckusick 		int cmd;
28741298Smckusick 		int uid;
28841298Smckusick 		caddr_t arg;
28942441Smckusick 	} *uap;
29042441Smckusick 	int *retval;
29142441Smckusick {
29241298Smckusick 	register struct mount *mp;
29341298Smckusick 	int error;
29447540Skarels 	struct nameidata nd;
29541298Smckusick 
29652322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
29752322Smckusick 	if (error = namei(&nd))
29847540Skarels 		return (error);
29952322Smckusick 	mp = nd.ni_vp->v_mount;
30052322Smckusick 	vrele(nd.ni_vp);
30148026Smckusick 	return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p));
30241298Smckusick }
30341298Smckusick 
30441298Smckusick /*
30549365Smckusick  * Get filesystem statistics.
30637741Smckusick  */
30742441Smckusick /* ARGSUSED */
30842441Smckusick statfs(p, uap, retval)
30945914Smckusick 	struct proc *p;
31042441Smckusick 	register struct args {
31137741Smckusick 		char *path;
31237741Smckusick 		struct statfs *buf;
31342441Smckusick 	} *uap;
31442441Smckusick 	int *retval;
31542441Smckusick {
31639464Smckusick 	register struct mount *mp;
31740343Smckusick 	register struct statfs *sp;
31837741Smckusick 	int error;
31947540Skarels 	struct nameidata nd;
32037741Smckusick 
32152322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
32252322Smckusick 	if (error = namei(&nd))
32347540Skarels 		return (error);
32452322Smckusick 	mp = nd.ni_vp->v_mount;
32541400Smckusick 	sp = &mp->mnt_stat;
32652322Smckusick 	vrele(nd.ni_vp);
32748026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
32847540Skarels 		return (error);
32941400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
33047540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
33137741Smckusick }
33237741Smckusick 
33342441Smckusick /*
33449365Smckusick  * Get filesystem statistics.
33542441Smckusick  */
33642441Smckusick /* ARGSUSED */
33742441Smckusick fstatfs(p, uap, retval)
33845914Smckusick 	struct proc *p;
33942441Smckusick 	register struct args {
34037741Smckusick 		int fd;
34137741Smckusick 		struct statfs *buf;
34242441Smckusick 	} *uap;
34342441Smckusick 	int *retval;
34442441Smckusick {
34537741Smckusick 	struct file *fp;
34639464Smckusick 	struct mount *mp;
34740343Smckusick 	register struct statfs *sp;
34837741Smckusick 	int error;
34937741Smckusick 
35045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
35147540Skarels 		return (error);
35239464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
35341400Smckusick 	sp = &mp->mnt_stat;
35448026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
35547540Skarels 		return (error);
35641400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
35747540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
35837741Smckusick }
35937741Smckusick 
36037741Smckusick /*
36149365Smckusick  * Get statistics on all filesystems.
36238270Smckusick  */
36342441Smckusick getfsstat(p, uap, retval)
36445914Smckusick 	struct proc *p;
36542441Smckusick 	register struct args {
36638270Smckusick 		struct statfs *buf;
36738270Smckusick 		long bufsize;
36840343Smckusick 		int flags;
36942441Smckusick 	} *uap;
37042441Smckusick 	int *retval;
37142441Smckusick {
37238270Smckusick 	register struct mount *mp;
37340343Smckusick 	register struct statfs *sp;
37439606Smckusick 	caddr_t sfsp;
37538270Smckusick 	long count, maxcount, error;
37638270Smckusick 
37738270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
37839606Smckusick 	sfsp = (caddr_t)uap->buf;
37938270Smckusick 	mp = rootfs;
38038270Smckusick 	count = 0;
38138270Smckusick 	do {
38241400Smckusick 		if (sfsp && count < maxcount &&
38341400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
38441400Smckusick 			sp = &mp->mnt_stat;
38540343Smckusick 			/*
38640343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
38740343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
38840343Smckusick 			 */
38940343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
39040343Smckusick 			    (uap->flags & MNT_WAIT)) &&
39148026Smckusick 			    (error = VFS_STATFS(mp, sp, p))) {
39241400Smckusick 				mp = mp->mnt_prev;
39339607Smckusick 				continue;
39439607Smckusick 			}
39541400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
39640343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
39747540Skarels 				return (error);
39840343Smckusick 			sfsp += sizeof(*sp);
39938270Smckusick 		}
40039606Smckusick 		count++;
40141400Smckusick 		mp = mp->mnt_prev;
40238270Smckusick 	} while (mp != rootfs);
40338270Smckusick 	if (sfsp && count > maxcount)
40442441Smckusick 		*retval = maxcount;
40538270Smckusick 	else
40642441Smckusick 		*retval = count;
40747540Skarels 	return (0);
40838270Smckusick }
40938270Smckusick 
41038270Smckusick /*
41138259Smckusick  * Change current working directory to a given file descriptor.
41238259Smckusick  */
41342441Smckusick /* ARGSUSED */
41442441Smckusick fchdir(p, uap, retval)
41545914Smckusick 	struct proc *p;
41642441Smckusick 	struct args {
41742441Smckusick 		int	fd;
41842441Smckusick 	} *uap;
41942441Smckusick 	int *retval;
42038259Smckusick {
42145914Smckusick 	register struct filedesc *fdp = p->p_fd;
42238259Smckusick 	register struct vnode *vp;
42338259Smckusick 	struct file *fp;
42438259Smckusick 	int error;
42538259Smckusick 
42645914Smckusick 	if (error = getvnode(fdp, uap->fd, &fp))
42747540Skarels 		return (error);
42838259Smckusick 	vp = (struct vnode *)fp->f_data;
42938259Smckusick 	VOP_LOCK(vp);
43038259Smckusick 	if (vp->v_type != VDIR)
43138259Smckusick 		error = ENOTDIR;
43238259Smckusick 	else
43348026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
43438259Smckusick 	VOP_UNLOCK(vp);
43539860Smckusick 	if (error)
43647540Skarels 		return (error);
43739860Smckusick 	VREF(vp);
43845914Smckusick 	vrele(fdp->fd_cdir);
43945914Smckusick 	fdp->fd_cdir = vp;
44047540Skarels 	return (0);
44138259Smckusick }
44238259Smckusick 
44338259Smckusick /*
44437741Smckusick  * Change current working directory (``.'').
44537741Smckusick  */
44642441Smckusick /* ARGSUSED */
44742441Smckusick chdir(p, uap, retval)
44845914Smckusick 	struct proc *p;
44942441Smckusick 	struct args {
45042441Smckusick 		char	*fname;
45142441Smckusick 	} *uap;
45242441Smckusick 	int *retval;
45337741Smckusick {
45445914Smckusick 	register struct filedesc *fdp = p->p_fd;
45537741Smckusick 	int error;
45647540Skarels 	struct nameidata nd;
4576254Sroot 
45852322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
459*52781Sralph 	if (error = chdirec(&nd, p))
46047540Skarels 		return (error);
46145914Smckusick 	vrele(fdp->fd_cdir);
46252322Smckusick 	fdp->fd_cdir = nd.ni_vp;
46347540Skarels 	return (0);
46437741Smckusick }
4656254Sroot 
46637741Smckusick /*
46737741Smckusick  * Change notion of root (``/'') directory.
46837741Smckusick  */
46942441Smckusick /* ARGSUSED */
47042441Smckusick chroot(p, uap, retval)
47145914Smckusick 	struct proc *p;
47242441Smckusick 	struct args {
47342441Smckusick 		char	*fname;
47442441Smckusick 	} *uap;
47542441Smckusick 	int *retval;
47637741Smckusick {
47745914Smckusick 	register struct filedesc *fdp = p->p_fd;
47837741Smckusick 	int error;
47947540Skarels 	struct nameidata nd;
48037741Smckusick 
48147540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
48247540Skarels 		return (error);
48352322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
484*52781Sralph 	if (error = chdirec(&nd, p))
48547540Skarels 		return (error);
48645914Smckusick 	if (fdp->fd_rdir != NULL)
48745914Smckusick 		vrele(fdp->fd_rdir);
48852322Smckusick 	fdp->fd_rdir = nd.ni_vp;
48947540Skarels 	return (0);
4906254Sroot }
4916254Sroot 
49237Sbill /*
49337741Smckusick  * Common routine for chroot and chdir.
49437741Smckusick  */
49547540Skarels chdirec(ndp, p)
49652322Smckusick 	register struct nameidata *ndp;
49747540Skarels 	struct proc *p;
49837741Smckusick {
49937741Smckusick 	struct vnode *vp;
50037741Smckusick 	int error;
50137741Smckusick 
50252322Smckusick 	if (error = namei(ndp))
50337741Smckusick 		return (error);
50437741Smckusick 	vp = ndp->ni_vp;
50537741Smckusick 	if (vp->v_type != VDIR)
50637741Smckusick 		error = ENOTDIR;
50737741Smckusick 	else
50848026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
50937741Smckusick 	VOP_UNLOCK(vp);
51037741Smckusick 	if (error)
51137741Smckusick 		vrele(vp);
51237741Smckusick 	return (error);
51337741Smckusick }
51437741Smckusick 
51537741Smckusick /*
5166254Sroot  * Open system call.
51742441Smckusick  * Check permissions, allocate an open file structure,
51842441Smckusick  * and call the device open routine if any.
5196254Sroot  */
52042441Smckusick open(p, uap, retval)
52145914Smckusick 	struct proc *p;
52242441Smckusick 	register struct args {
5236254Sroot 		char	*fname;
5247701Ssam 		int	mode;
52512756Ssam 		int	crtmode;
52642441Smckusick 	} *uap;
52742441Smckusick 	int *retval;
5286254Sroot {
52945914Smckusick 	register struct filedesc *fdp = p->p_fd;
53042441Smckusick 	register struct file *fp;
53150111Smckusick 	register struct vnode *vp;
53237741Smckusick 	int fmode, cmode;
53337741Smckusick 	struct file *nfp;
53449945Smckusick 	int type, indx, error;
53549945Smckusick 	struct flock lf;
53647540Skarels 	struct nameidata nd;
53737741Smckusick 	extern struct fileops vnops;
5386254Sroot 
53945914Smckusick 	if (error = falloc(p, &nfp, &indx))
54047540Skarels 		return (error);
54137741Smckusick 	fp = nfp;
54246553Skarels 	fmode = FFLAGS(uap->mode);
54345914Smckusick 	cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX;
54452322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
54545202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
54652322Smckusick 	if (error = vn_open(&nd, fmode, cmode)) {
54749980Smckusick 		ffree(fp);
54843405Smckusick 		if (error == ENODEV &&		/* XXX from fdopen */
54945202Smckusick 		    p->p_dupfd >= 0 &&
55045914Smckusick 		    (error = dupfdopen(fdp, indx, p->p_dupfd, fmode)) == 0) {
55142441Smckusick 			*retval = indx;
55247540Skarels 			return (0);
55342441Smckusick 		}
55440884Smckusick 		if (error == ERESTART)
55540884Smckusick 			error = EINTR;
55647688Skarels 		fdp->fd_ofiles[indx] = NULL;
55747540Skarels 		return (error);
55812756Ssam 	}
55952322Smckusick 	vp = nd.ni_vp;
56049949Smckusick 	fp->f_flag = fmode & FMASK;
56149945Smckusick 	if (fmode & (O_EXLOCK | O_SHLOCK)) {
56249945Smckusick 		lf.l_whence = SEEK_SET;
56349945Smckusick 		lf.l_start = 0;
56449945Smckusick 		lf.l_len = 0;
56549945Smckusick 		if (fmode & O_EXLOCK)
56649945Smckusick 			lf.l_type = F_WRLCK;
56749945Smckusick 		else
56849945Smckusick 			lf.l_type = F_RDLCK;
56949945Smckusick 		type = F_FLOCK;
57049945Smckusick 		if ((fmode & FNONBLOCK) == 0)
57149945Smckusick 			type |= F_WAIT;
57250111Smckusick 		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
57350111Smckusick 			VOP_UNLOCK(vp);
57450111Smckusick 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
57549980Smckusick 			ffree(fp);
57649945Smckusick 			fdp->fd_ofiles[indx] = NULL;
57749945Smckusick 			return (error);
57849945Smckusick 		}
57949949Smckusick 		fp->f_flag |= FHASLOCK;
58049945Smckusick 	}
58150111Smckusick 	VOP_UNLOCK(vp);
58237741Smckusick 	fp->f_type = DTYPE_VNODE;
58337741Smckusick 	fp->f_ops = &vnops;
58450111Smckusick 	fp->f_data = (caddr_t)vp;
58542441Smckusick 	*retval = indx;
58647540Skarels 	return (0);
5876254Sroot }
5886254Sroot 
58942955Smckusick #ifdef COMPAT_43
5906254Sroot /*
59142441Smckusick  * Creat system call.
5926254Sroot  */
59342955Smckusick ocreat(p, uap, retval)
59442441Smckusick 	struct proc *p;
59542441Smckusick 	register struct args {
59642441Smckusick 		char	*fname;
59742441Smckusick 		int	fmode;
59842441Smckusick 	} *uap;
59942441Smckusick 	int *retval;
6006254Sroot {
60142441Smckusick 	struct args {
6026254Sroot 		char	*fname;
60342441Smckusick 		int	mode;
60442441Smckusick 		int	crtmode;
60542441Smckusick 	} openuap;
60642441Smckusick 
60742441Smckusick 	openuap.fname = uap->fname;
60842441Smckusick 	openuap.crtmode = uap->fmode;
60942441Smckusick 	openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
61047540Skarels 	return (open(p, &openuap, retval));
61142441Smckusick }
61242955Smckusick #endif /* COMPAT_43 */
61342441Smckusick 
61442441Smckusick /*
61549365Smckusick  * Mknod system call.
61642441Smckusick  */
61742441Smckusick /* ARGSUSED */
61842441Smckusick mknod(p, uap, retval)
61945914Smckusick 	struct proc *p;
62042441Smckusick 	register struct args {
62142441Smckusick 		char	*fname;
6226254Sroot 		int	fmode;
6236254Sroot 		int	dev;
62442441Smckusick 	} *uap;
62542441Smckusick 	int *retval;
62642441Smckusick {
62737741Smckusick 	register struct vnode *vp;
62837741Smckusick 	struct vattr vattr;
62937741Smckusick 	int error;
63047540Skarels 	struct nameidata nd;
6316254Sroot 
63247540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
63347540Skarels 		return (error);
63452322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p);
63552322Smckusick 	if (error = namei(&nd))
63647540Skarels 		return (error);
63752322Smckusick 	vp = nd.ni_vp;
63837741Smckusick 	if (vp != NULL) {
63937741Smckusick 		error = EEXIST;
64012756Ssam 		goto out;
6416254Sroot 	}
64241362Smckusick 	VATTR_NULL(&vattr);
64340635Smckusick 	switch (uap->fmode & S_IFMT) {
64412756Ssam 
64540635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
64637741Smckusick 		vattr.va_type = VBAD;
64737741Smckusick 		break;
64840635Smckusick 	case S_IFCHR:
64937741Smckusick 		vattr.va_type = VCHR;
65037741Smckusick 		break;
65140635Smckusick 	case S_IFBLK:
65237741Smckusick 		vattr.va_type = VBLK;
65337741Smckusick 		break;
65437741Smckusick 	default:
65537741Smckusick 		error = EINVAL;
65637741Smckusick 		goto out;
6576254Sroot 	}
65845914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
65937741Smckusick 	vattr.va_rdev = uap->dev;
6606254Sroot out:
66142465Smckusick 	if (!error) {
66252322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
66352322Smckusick 		error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
66442465Smckusick 	} else {
66552322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
66652322Smckusick 		if (nd.ni_dvp == vp)
66752322Smckusick 			vrele(nd.ni_dvp);
66843344Smckusick 		else
66952322Smckusick 			vput(nd.ni_dvp);
67042465Smckusick 		if (vp)
67142465Smckusick 			vrele(vp);
67242465Smckusick 	}
67347540Skarels 	return (error);
6746254Sroot }
6756254Sroot 
6766254Sroot /*
67749365Smckusick  * Mkfifo system call.
67840285Smckusick  */
67942441Smckusick /* ARGSUSED */
68042441Smckusick mkfifo(p, uap, retval)
68145914Smckusick 	struct proc *p;
68242441Smckusick 	register struct args {
68340285Smckusick 		char	*fname;
68440285Smckusick 		int	fmode;
68542441Smckusick 	} *uap;
68642441Smckusick 	int *retval;
68742441Smckusick {
68840285Smckusick 	struct vattr vattr;
68940285Smckusick 	int error;
69047540Skarels 	struct nameidata nd;
69140285Smckusick 
69240285Smckusick #ifndef FIFO
69347540Skarels 	return (EOPNOTSUPP);
69440285Smckusick #else
69552322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p);
69652322Smckusick 	if (error = namei(&nd))
69747540Skarels 		return (error);
69852322Smckusick 	if (nd.ni_vp != NULL) {
69952322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
70052322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
70152322Smckusick 			vrele(nd.ni_dvp);
70243344Smckusick 		else
70352322Smckusick 			vput(nd.ni_dvp);
70452322Smckusick 		vrele(nd.ni_vp);
70547540Skarels 		return (EEXIST);
70640285Smckusick 	}
70745785Sbostic 	VATTR_NULL(&vattr);
70845785Sbostic 	vattr.va_type = VFIFO;
70945914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
71052322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
71152322Smckusick 	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
71240285Smckusick #endif /* FIFO */
71340285Smckusick }
71440285Smckusick 
71540285Smckusick /*
71649365Smckusick  * Link system call.
7176254Sroot  */
71842441Smckusick /* ARGSUSED */
71942441Smckusick link(p, uap, retval)
72045914Smckusick 	struct proc *p;
72142441Smckusick 	register struct args {
7226254Sroot 		char	*target;
7236254Sroot 		char	*linkname;
72442441Smckusick 	} *uap;
72542441Smckusick 	int *retval;
72642441Smckusick {
72737741Smckusick 	register struct vnode *vp, *xp;
72837741Smckusick 	int error;
72947540Skarels 	struct nameidata nd;
7306254Sroot 
73152322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->target, p);
73252322Smckusick 	if (error = namei(&nd))
73347540Skarels 		return (error);
73452322Smckusick 	vp = nd.ni_vp;
73537741Smckusick 	if (vp->v_type == VDIR &&
73647540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
73737741Smckusick 		goto out1;
73852322Smckusick 	nd.ni_cnd.cn_nameiop = CREATE;
73952322Smckusick 	nd.ni_cnd.cn_flags = LOCKPARENT;
74052322Smckusick 	nd.ni_dirp = (caddr_t)uap->linkname;
74152322Smckusick 	if (error = namei(&nd))
74237741Smckusick 		goto out1;
74352322Smckusick 	xp = nd.ni_vp;
7446254Sroot 	if (xp != NULL) {
74537741Smckusick 		error = EEXIST;
7466254Sroot 		goto out;
7476254Sroot 	}
74852322Smckusick 	xp = nd.ni_dvp;
74937741Smckusick 	if (vp->v_mount != xp->v_mount)
75037741Smckusick 		error = EXDEV;
7516254Sroot out:
75242465Smckusick 	if (!error) {
75352192Smckusick 		LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE);
75452192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
75552322Smckusick 		error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd);
75642465Smckusick 	} else {
75752322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
75852322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
75952322Smckusick 			vrele(nd.ni_dvp);
76043344Smckusick 		else
76152322Smckusick 			vput(nd.ni_dvp);
76252322Smckusick 		if (nd.ni_vp)
76352322Smckusick 			vrele(nd.ni_vp);
76442465Smckusick 	}
76537741Smckusick out1:
76637741Smckusick 	vrele(vp);
76747540Skarels 	return (error);
7686254Sroot }
7696254Sroot 
7706254Sroot /*
77149365Smckusick  * Make a symbolic link.
7726254Sroot  */
77342441Smckusick /* ARGSUSED */
77442441Smckusick symlink(p, uap, retval)
77545914Smckusick 	struct proc *p;
77642441Smckusick 	register struct args {
7776254Sroot 		char	*target;
7786254Sroot 		char	*linkname;
77942441Smckusick 	} *uap;
78042441Smckusick 	int *retval;
78142441Smckusick {
78237741Smckusick 	struct vattr vattr;
78337741Smckusick 	char *target;
78437741Smckusick 	int error;
78547540Skarels 	struct nameidata nd;
7866254Sroot 
78737741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
78837741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
78942465Smckusick 		goto out;
79052322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->linkname, p);
79152322Smckusick 	if (error = namei(&nd))
79242465Smckusick 		goto out;
79352322Smckusick 	if (nd.ni_vp) {
79452322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
79552322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
79652322Smckusick 			vrele(nd.ni_dvp);
79743344Smckusick 		else
79852322Smckusick 			vput(nd.ni_dvp);
79952322Smckusick 		vrele(nd.ni_vp);
80037741Smckusick 		error = EEXIST;
80137741Smckusick 		goto out;
8026254Sroot 	}
80341362Smckusick 	VATTR_NULL(&vattr);
80445914Smckusick 	vattr.va_mode = 0777 &~ p->p_fd->fd_cmask;
80552322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
80652322Smckusick 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, target);
80737741Smckusick out:
80837741Smckusick 	FREE(target, M_NAMEI);
80947540Skarels 	return (error);
8106254Sroot }
8116254Sroot 
8126254Sroot /*
81349365Smckusick  * Delete a name from the filesystem.
8146254Sroot  */
81542441Smckusick /* ARGSUSED */
81642441Smckusick unlink(p, uap, retval)
81745914Smckusick 	struct proc *p;
81842441Smckusick 	struct args {
81952322Smckusick 		char	*name;
82042441Smckusick 	} *uap;
82142441Smckusick 	int *retval;
8226254Sroot {
82337741Smckusick 	register struct vnode *vp;
82437741Smckusick 	int error;
82547540Skarels 	struct nameidata nd;
8266254Sroot 
82752322Smckusick 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p);
82852322Smckusick 	if (error = namei(&nd))
82947540Skarels 		return (error);
83052322Smckusick 	vp = nd.ni_vp;
83137741Smckusick 	if (vp->v_type == VDIR &&
83247540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
8336254Sroot 		goto out;
8346254Sroot 	/*
83549365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
8366254Sroot 	 */
83737741Smckusick 	if (vp->v_flag & VROOT) {
83837741Smckusick 		error = EBUSY;
8396254Sroot 		goto out;
8406254Sroot 	}
84145738Smckusick 	(void) vnode_pager_uncache(vp);
8426254Sroot out:
84342465Smckusick 	if (!error) {
84452322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
84552192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
84652322Smckusick 		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
84742465Smckusick 	} else {
84852322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
84952322Smckusick 		if (nd.ni_dvp == vp)
85052322Smckusick 			vrele(nd.ni_dvp);
85143344Smckusick 		else
85252322Smckusick 			vput(nd.ni_dvp);
85342465Smckusick 		vput(vp);
85442465Smckusick 	}
85547540Skarels 	return (error);
8566254Sroot }
8576254Sroot 
8586254Sroot /*
85949365Smckusick  * Seek system call.
8606254Sroot  */
86142441Smckusick lseek(p, uap, retval)
86245914Smckusick 	struct proc *p;
86342441Smckusick 	register struct args {
86437741Smckusick 		int	fdes;
8656254Sroot 		off_t	off;
8666254Sroot 		int	sbase;
86742441Smckusick 	} *uap;
86842441Smckusick 	off_t *retval;
86942441Smckusick {
87047540Skarels 	struct ucred *cred = p->p_ucred;
87145914Smckusick 	register struct filedesc *fdp = p->p_fd;
87242441Smckusick 	register struct file *fp;
87337741Smckusick 	struct vattr vattr;
87437741Smckusick 	int error;
8756254Sroot 
87647540Skarels 	if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
87747688Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL)
87847540Skarels 		return (EBADF);
87937741Smckusick 	if (fp->f_type != DTYPE_VNODE)
88047540Skarels 		return (ESPIPE);
88113878Ssam 	switch (uap->sbase) {
88213878Ssam 
88313878Ssam 	case L_INCR:
88413878Ssam 		fp->f_offset += uap->off;
88513878Ssam 		break;
88613878Ssam 
88713878Ssam 	case L_XTND:
88837741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
88948026Smckusick 		    &vattr, cred, p))
89047540Skarels 			return (error);
89137741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
89213878Ssam 		break;
89313878Ssam 
89413878Ssam 	case L_SET:
89513878Ssam 		fp->f_offset = uap->off;
89613878Ssam 		break;
89713878Ssam 
89813878Ssam 	default:
89947540Skarels 		return (EINVAL);
90013878Ssam 	}
90142441Smckusick 	*retval = fp->f_offset;
90247540Skarels 	return (0);
9036254Sroot }
9046254Sroot 
9056254Sroot /*
90649365Smckusick  * Check access permissions.
9076254Sroot  */
90842441Smckusick /* ARGSUSED */
90942441Smckusick saccess(p, uap, retval)
91045914Smckusick 	struct proc *p;
91142441Smckusick 	register struct args {
9126254Sroot 		char	*fname;
9136254Sroot 		int	fmode;
91442441Smckusick 	} *uap;
91542441Smckusick 	int *retval;
91642441Smckusick {
91747540Skarels 	register struct ucred *cred = p->p_ucred;
91837741Smckusick 	register struct vnode *vp;
91937741Smckusick 	int error, mode, svuid, svgid;
92047540Skarels 	struct nameidata nd;
9216254Sroot 
92242441Smckusick 	svuid = cred->cr_uid;
92342441Smckusick 	svgid = cred->cr_groups[0];
92447540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
92547540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
92652322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
92752322Smckusick 	if (error = namei(&nd))
92837741Smckusick 		goto out1;
92952322Smckusick 	vp = nd.ni_vp;
93037741Smckusick 	/*
93137741Smckusick 	 * fmode == 0 means only check for exist
93237741Smckusick 	 */
93337741Smckusick 	if (uap->fmode) {
93437741Smckusick 		mode = 0;
93537741Smckusick 		if (uap->fmode & R_OK)
93637741Smckusick 			mode |= VREAD;
93737741Smckusick 		if (uap->fmode & W_OK)
93837741Smckusick 			mode |= VWRITE;
93937741Smckusick 		if (uap->fmode & X_OK)
94037741Smckusick 			mode |= VEXEC;
94139543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
94248026Smckusick 			error = VOP_ACCESS(vp, mode, cred, p);
9436254Sroot 	}
94437741Smckusick 	vput(vp);
94537741Smckusick out1:
94642441Smckusick 	cred->cr_uid = svuid;
94742441Smckusick 	cred->cr_groups[0] = svgid;
94847540Skarels 	return (error);
9496254Sroot }
9506254Sroot 
9516254Sroot /*
95249365Smckusick  * Stat system call.
95349365Smckusick  * This version follows links.
95437Sbill  */
95542441Smckusick /* ARGSUSED */
95642441Smckusick stat(p, uap, retval)
95745914Smckusick 	struct proc *p;
95842441Smckusick 	register struct args {
95942441Smckusick 		char	*fname;
96042441Smckusick 		struct stat *ub;
96142441Smckusick 	} *uap;
96242441Smckusick 	int *retval;
96337Sbill {
96442441Smckusick 	struct stat sb;
96542441Smckusick 	int error;
96647540Skarels 	struct nameidata nd;
96737Sbill 
96852322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
96952322Smckusick 	if (error = namei(&nd))
97047540Skarels 		return (error);
97152322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
97252322Smckusick 	vput(nd.ni_vp);
97342441Smckusick 	if (error)
97447540Skarels 		return (error);
97542441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
97647540Skarels 	return (error);
97737Sbill }
97837Sbill 
97937Sbill /*
98049365Smckusick  * Lstat system call.
98149365Smckusick  * This version does not follow links.
9825992Swnj  */
98342441Smckusick /* ARGSUSED */
98442441Smckusick lstat(p, uap, retval)
98545914Smckusick 	struct proc *p;
98642441Smckusick 	register struct args {
9875992Swnj 		char	*fname;
98812756Ssam 		struct stat *ub;
98942441Smckusick 	} *uap;
99042441Smckusick 	int *retval;
99142441Smckusick {
99212756Ssam 	struct stat sb;
99337741Smckusick 	int error;
99447540Skarels 	struct nameidata nd;
9955992Swnj 
99652322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
99752322Smckusick 	if (error = namei(&nd))
99847540Skarels 		return (error);
99952322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
100052322Smckusick 	vput(nd.ni_vp);
100137741Smckusick 	if (error)
100247540Skarels 		return (error);
100337741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
100447540Skarels 	return (error);
10055992Swnj }
10065992Swnj 
10075992Swnj /*
100849365Smckusick  * Return target name of a symbolic link.
100937Sbill  */
101042441Smckusick /* ARGSUSED */
101142441Smckusick readlink(p, uap, retval)
101245914Smckusick 	struct proc *p;
101342441Smckusick 	register struct args {
10145992Swnj 		char	*name;
10155992Swnj 		char	*buf;
10165992Swnj 		int	count;
101742441Smckusick 	} *uap;
101842441Smckusick 	int *retval;
101942441Smckusick {
102037741Smckusick 	register struct vnode *vp;
102137741Smckusick 	struct iovec aiov;
102237741Smckusick 	struct uio auio;
102337741Smckusick 	int error;
102447540Skarels 	struct nameidata nd;
10255992Swnj 
102652322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p);
102752322Smckusick 	if (error = namei(&nd))
102847540Skarels 		return (error);
102952322Smckusick 	vp = nd.ni_vp;
103037741Smckusick 	if (vp->v_type != VLNK) {
103137741Smckusick 		error = EINVAL;
10325992Swnj 		goto out;
10335992Swnj 	}
103437741Smckusick 	aiov.iov_base = uap->buf;
103537741Smckusick 	aiov.iov_len = uap->count;
103637741Smckusick 	auio.uio_iov = &aiov;
103737741Smckusick 	auio.uio_iovcnt = 1;
103837741Smckusick 	auio.uio_offset = 0;
103937741Smckusick 	auio.uio_rw = UIO_READ;
104037741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
104148026Smckusick 	auio.uio_procp = p;
104237741Smckusick 	auio.uio_resid = uap->count;
104347540Skarels 	error = VOP_READLINK(vp, &auio, p->p_ucred);
10445992Swnj out:
104537741Smckusick 	vput(vp);
104642441Smckusick 	*retval = uap->count - auio.uio_resid;
104747540Skarels 	return (error);
10485992Swnj }
10495992Swnj 
10509167Ssam /*
105138259Smckusick  * Change flags of a file given path name.
105238259Smckusick  */
105342441Smckusick /* ARGSUSED */
105442441Smckusick chflags(p, uap, retval)
105545914Smckusick 	struct proc *p;
105642441Smckusick 	register struct args {
105738259Smckusick 		char	*fname;
105838259Smckusick 		int	flags;
105942441Smckusick 	} *uap;
106042441Smckusick 	int *retval;
106142441Smckusick {
106238259Smckusick 	register struct vnode *vp;
106338259Smckusick 	struct vattr vattr;
106438259Smckusick 	int error;
106547540Skarels 	struct nameidata nd;
106638259Smckusick 
106752322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
106852322Smckusick 	if (error = namei(&nd))
106947540Skarels 		return (error);
107052322Smckusick 	vp = nd.ni_vp;
107141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
107238259Smckusick 		error = EROFS;
107338259Smckusick 		goto out;
107438259Smckusick 	}
107545785Sbostic 	VATTR_NULL(&vattr);
107645785Sbostic 	vattr.va_flags = uap->flags;
107752192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
107848026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
107938259Smckusick out:
108038259Smckusick 	vput(vp);
108147540Skarels 	return (error);
108238259Smckusick }
108338259Smckusick 
108438259Smckusick /*
108538259Smckusick  * Change flags of a file given a file descriptor.
108638259Smckusick  */
108742441Smckusick /* ARGSUSED */
108842441Smckusick fchflags(p, uap, retval)
108945914Smckusick 	struct proc *p;
109042441Smckusick 	register struct args {
109138259Smckusick 		int	fd;
109238259Smckusick 		int	flags;
109342441Smckusick 	} *uap;
109442441Smckusick 	int *retval;
109542441Smckusick {
109638259Smckusick 	struct vattr vattr;
109738259Smckusick 	struct vnode *vp;
109838259Smckusick 	struct file *fp;
109938259Smckusick 	int error;
110038259Smckusick 
110145914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
110247540Skarels 		return (error);
110338259Smckusick 	vp = (struct vnode *)fp->f_data;
110438259Smckusick 	VOP_LOCK(vp);
110541400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
110638259Smckusick 		error = EROFS;
110738259Smckusick 		goto out;
110838259Smckusick 	}
110945785Sbostic 	VATTR_NULL(&vattr);
111045785Sbostic 	vattr.va_flags = uap->flags;
111152192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
111248026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
111338259Smckusick out:
111438259Smckusick 	VOP_UNLOCK(vp);
111547540Skarels 	return (error);
111638259Smckusick }
111738259Smckusick 
111838259Smckusick /*
11199167Ssam  * Change mode of a file given path name.
11209167Ssam  */
112142441Smckusick /* ARGSUSED */
112242441Smckusick chmod(p, uap, retval)
112345914Smckusick 	struct proc *p;
112442441Smckusick 	register struct args {
11256254Sroot 		char	*fname;
11266254Sroot 		int	fmode;
112742441Smckusick 	} *uap;
112842441Smckusick 	int *retval;
112942441Smckusick {
113037741Smckusick 	register struct vnode *vp;
113137741Smckusick 	struct vattr vattr;
113237741Smckusick 	int error;
113347540Skarels 	struct nameidata nd;
11345992Swnj 
113552322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
113652322Smckusick 	if (error = namei(&nd))
113747540Skarels 		return (error);
113852322Smckusick 	vp = nd.ni_vp;
113941400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
114037741Smckusick 		error = EROFS;
114137741Smckusick 		goto out;
114237741Smckusick 	}
114345785Sbostic 	VATTR_NULL(&vattr);
114445785Sbostic 	vattr.va_mode = uap->fmode & 07777;
114552192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
114648026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
114737741Smckusick out:
114837741Smckusick 	vput(vp);
114947540Skarels 	return (error);
11507701Ssam }
11517439Sroot 
11529167Ssam /*
11539167Ssam  * Change mode of a file given a file descriptor.
11549167Ssam  */
115542441Smckusick /* ARGSUSED */
115642441Smckusick fchmod(p, uap, retval)
115745914Smckusick 	struct proc *p;
115842441Smckusick 	register struct args {
11597701Ssam 		int	fd;
11607701Ssam 		int	fmode;
116142441Smckusick 	} *uap;
116242441Smckusick 	int *retval;
116342441Smckusick {
116437741Smckusick 	struct vattr vattr;
116537741Smckusick 	struct vnode *vp;
116637741Smckusick 	struct file *fp;
116737741Smckusick 	int error;
11687701Ssam 
116945914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
117047540Skarels 		return (error);
117137741Smckusick 	vp = (struct vnode *)fp->f_data;
117237741Smckusick 	VOP_LOCK(vp);
117341400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
117437741Smckusick 		error = EROFS;
117537741Smckusick 		goto out;
11767439Sroot 	}
117745785Sbostic 	VATTR_NULL(&vattr);
117845785Sbostic 	vattr.va_mode = uap->fmode & 07777;
117952192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
118048026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
118137741Smckusick out:
118237741Smckusick 	VOP_UNLOCK(vp);
118347540Skarels 	return (error);
11845992Swnj }
11855992Swnj 
11869167Ssam /*
11879167Ssam  * Set ownership given a path name.
11889167Ssam  */
118942441Smckusick /* ARGSUSED */
119042441Smckusick chown(p, uap, retval)
119145914Smckusick 	struct proc *p;
119242441Smckusick 	register struct args {
11936254Sroot 		char	*fname;
11946254Sroot 		int	uid;
11956254Sroot 		int	gid;
119642441Smckusick 	} *uap;
119742441Smckusick 	int *retval;
119842441Smckusick {
119937741Smckusick 	register struct vnode *vp;
120037741Smckusick 	struct vattr vattr;
120137741Smckusick 	int error;
120247540Skarels 	struct nameidata nd;
120337Sbill 
120452322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
120552322Smckusick 	if (error = namei(&nd))
120647540Skarels 		return (error);
120752322Smckusick 	vp = nd.ni_vp;
120841400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
120937741Smckusick 		error = EROFS;
121037741Smckusick 		goto out;
121137741Smckusick 	}
121245785Sbostic 	VATTR_NULL(&vattr);
121345785Sbostic 	vattr.va_uid = uap->uid;
121445785Sbostic 	vattr.va_gid = uap->gid;
121552192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
121648026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
121737741Smckusick out:
121837741Smckusick 	vput(vp);
121947540Skarels 	return (error);
12207701Ssam }
12217439Sroot 
12229167Ssam /*
12239167Ssam  * Set ownership given a file descriptor.
12249167Ssam  */
122542441Smckusick /* ARGSUSED */
122642441Smckusick fchown(p, uap, retval)
122745914Smckusick 	struct proc *p;
122842441Smckusick 	register struct args {
12297701Ssam 		int	fd;
12307701Ssam 		int	uid;
12317701Ssam 		int	gid;
123242441Smckusick 	} *uap;
123342441Smckusick 	int *retval;
123442441Smckusick {
123537741Smckusick 	struct vattr vattr;
123637741Smckusick 	struct vnode *vp;
123737741Smckusick 	struct file *fp;
123837741Smckusick 	int error;
12397701Ssam 
124045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
124147540Skarels 		return (error);
124237741Smckusick 	vp = (struct vnode *)fp->f_data;
124337741Smckusick 	VOP_LOCK(vp);
124441400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
124537741Smckusick 		error = EROFS;
124637741Smckusick 		goto out;
124737741Smckusick 	}
124845785Sbostic 	VATTR_NULL(&vattr);
124945785Sbostic 	vattr.va_uid = uap->uid;
125045785Sbostic 	vattr.va_gid = uap->gid;
125152192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
125248026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
125337741Smckusick out:
125437741Smckusick 	VOP_UNLOCK(vp);
125547540Skarels 	return (error);
12567701Ssam }
12577701Ssam 
125842441Smckusick /*
125942441Smckusick  * Set the access and modification times of a file.
126042441Smckusick  */
126142441Smckusick /* ARGSUSED */
126242441Smckusick utimes(p, uap, retval)
126345914Smckusick 	struct proc *p;
126442441Smckusick 	register struct args {
126511811Ssam 		char	*fname;
126611811Ssam 		struct	timeval *tptr;
126742441Smckusick 	} *uap;
126842441Smckusick 	int *retval;
126942441Smckusick {
127037741Smckusick 	register struct vnode *vp;
127111811Ssam 	struct timeval tv[2];
127237741Smckusick 	struct vattr vattr;
127337741Smckusick 	int error;
127447540Skarels 	struct nameidata nd;
127511811Ssam 
127637741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
127747540Skarels 		return (error);
127852322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
127952322Smckusick 	if (error = namei(&nd))
128047540Skarels 		return (error);
128152322Smckusick 	vp = nd.ni_vp;
128241400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
128337741Smckusick 		error = EROFS;
128437741Smckusick 		goto out;
128521015Smckusick 	}
128645785Sbostic 	VATTR_NULL(&vattr);
128745785Sbostic 	vattr.va_atime = tv[0];
128845785Sbostic 	vattr.va_mtime = tv[1];
128952192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
129048026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
129137741Smckusick out:
129237741Smckusick 	vput(vp);
129347540Skarels 	return (error);
129411811Ssam }
129511811Ssam 
12969167Ssam /*
12979167Ssam  * Truncate a file given its path name.
12989167Ssam  */
129942441Smckusick /* ARGSUSED */
130042441Smckusick truncate(p, uap, retval)
130145914Smckusick 	struct proc *p;
130242441Smckusick 	register struct args {
13037701Ssam 		char	*fname;
130426473Skarels 		off_t	length;
130542441Smckusick 	} *uap;
130642441Smckusick 	int *retval;
130742441Smckusick {
130837741Smckusick 	register struct vnode *vp;
130937741Smckusick 	struct vattr vattr;
131037741Smckusick 	int error;
131147540Skarels 	struct nameidata nd;
13127701Ssam 
131352322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
131452322Smckusick 	if (error = namei(&nd))
131547540Skarels 		return (error);
131652322Smckusick 	vp = nd.ni_vp;
131737741Smckusick 	if (vp->v_type == VDIR) {
131837741Smckusick 		error = EISDIR;
131937741Smckusick 		goto out;
13207701Ssam 	}
132138399Smckusick 	if ((error = vn_writechk(vp)) ||
132248026Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)))
132337741Smckusick 		goto out;
132445785Sbostic 	VATTR_NULL(&vattr);
132545785Sbostic 	vattr.va_size = uap->length;
132652192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
132748026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
132837741Smckusick out:
132937741Smckusick 	vput(vp);
133047540Skarels 	return (error);
13317701Ssam }
13327701Ssam 
13339167Ssam /*
13349167Ssam  * Truncate a file given a file descriptor.
13359167Ssam  */
133642441Smckusick /* ARGSUSED */
133742441Smckusick ftruncate(p, uap, retval)
133845914Smckusick 	struct proc *p;
133942441Smckusick 	register struct args {
13407701Ssam 		int	fd;
134126473Skarels 		off_t	length;
134242441Smckusick 	} *uap;
134342441Smckusick 	int *retval;
134442441Smckusick {
134537741Smckusick 	struct vattr vattr;
134637741Smckusick 	struct vnode *vp;
13477701Ssam 	struct file *fp;
134837741Smckusick 	int error;
13497701Ssam 
135045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
135147540Skarels 		return (error);
135237741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
135347540Skarels 		return (EINVAL);
135437741Smckusick 	vp = (struct vnode *)fp->f_data;
135537741Smckusick 	VOP_LOCK(vp);
135637741Smckusick 	if (vp->v_type == VDIR) {
135737741Smckusick 		error = EISDIR;
135837741Smckusick 		goto out;
13597701Ssam 	}
136038399Smckusick 	if (error = vn_writechk(vp))
136137741Smckusick 		goto out;
136245785Sbostic 	VATTR_NULL(&vattr);
136345785Sbostic 	vattr.va_size = uap->length;
136452192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
136548026Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
136637741Smckusick out:
136737741Smckusick 	VOP_UNLOCK(vp);
136847540Skarels 	return (error);
13697701Ssam }
13707701Ssam 
13719167Ssam /*
13729167Ssam  * Synch an open file.
13739167Ssam  */
137442441Smckusick /* ARGSUSED */
137542441Smckusick fsync(p, uap, retval)
137645914Smckusick 	struct proc *p;
137742441Smckusick 	struct args {
137842441Smckusick 		int	fd;
137942441Smckusick 	} *uap;
138042441Smckusick 	int *retval;
13819167Ssam {
138239592Smckusick 	register struct vnode *vp;
13839167Ssam 	struct file *fp;
138437741Smckusick 	int error;
13859167Ssam 
138645914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
138747540Skarels 		return (error);
138839592Smckusick 	vp = (struct vnode *)fp->f_data;
138939592Smckusick 	VOP_LOCK(vp);
139048026Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT, p);
139139592Smckusick 	VOP_UNLOCK(vp);
139247540Skarels 	return (error);
13939167Ssam }
13949167Ssam 
13959167Ssam /*
13969167Ssam  * Rename system call.
13979167Ssam  *
13989167Ssam  * Source and destination must either both be directories, or both
13999167Ssam  * not be directories.  If target is a directory, it must be empty.
14009167Ssam  */
140142441Smckusick /* ARGSUSED */
140242441Smckusick rename(p, uap, retval)
140345914Smckusick 	struct proc *p;
140442441Smckusick 	register struct args {
14057701Ssam 		char	*from;
14067701Ssam 		char	*to;
140742441Smckusick 	} *uap;
140842441Smckusick 	int *retval;
140942441Smckusick {
141037741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
141149735Smckusick 	struct nameidata fromnd, tond;
141237741Smckusick 	int error;
14137701Ssam 
141452322Smckusick 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
141552322Smckusick 		uap->from, p);
141652322Smckusick 	if (error = namei(&fromnd))
141747540Skarels 		return (error);
141849735Smckusick 	fvp = fromnd.ni_vp;
141952322Smckusick 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
142052322Smckusick 		UIO_USERSPACE, uap->to, p);
142152322Smckusick 	if (error = namei(&tond)) {
142252230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
142349735Smckusick 		vrele(fromnd.ni_dvp);
142442465Smckusick 		vrele(fvp);
142542465Smckusick 		goto out1;
142642465Smckusick 	}
142737741Smckusick 	tdvp = tond.ni_dvp;
142837741Smckusick 	tvp = tond.ni_vp;
142937741Smckusick 	if (tvp != NULL) {
143037741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
143139242Sbostic 			error = ENOTDIR;
143237741Smckusick 			goto out;
143337741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
143439242Sbostic 			error = EISDIR;
143537741Smckusick 			goto out;
14369167Ssam 		}
143745240Smckusick 		if (fvp->v_mount != tvp->v_mount) {
143845240Smckusick 			error = EXDEV;
143945240Smckusick 			goto out;
144045240Smckusick 		}
14419167Ssam 	}
144237741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
144337741Smckusick 		error = EXDEV;
14449167Ssam 		goto out;
144510051Ssam 	}
144639286Smckusick 	if (fvp == tdvp)
144737741Smckusick 		error = EINVAL;
144839286Smckusick 	/*
144949735Smckusick 	 * If source is the same as the destination (that is the
145049735Smckusick 	 * same inode number with the same name in the same directory),
145139286Smckusick 	 * then there is nothing to do.
145239286Smckusick 	 */
145349735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
145452322Smckusick 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
145552322Smckusick 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
145652322Smckusick 	      fromnd.ni_cnd.cn_namelen))
145739286Smckusick 		error = -1;
145837741Smckusick out:
145942465Smckusick 	if (!error) {
146052192Smckusick 		LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE);
146152192Smckusick 		if (fromnd.ni_dvp != tdvp)
146252192Smckusick 			LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
146352192Smckusick 		if (tvp)
146452192Smckusick 			LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE);
146552230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
146652230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
146742465Smckusick 	} else {
146852230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
146943344Smckusick 		if (tdvp == tvp)
147043344Smckusick 			vrele(tdvp);
147143344Smckusick 		else
147243344Smckusick 			vput(tdvp);
147342465Smckusick 		if (tvp)
147442465Smckusick 			vput(tvp);
147552230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
147649735Smckusick 		vrele(fromnd.ni_dvp);
147742465Smckusick 		vrele(fvp);
14789167Ssam 	}
147949735Smckusick 	vrele(tond.ni_startdir);
148052322Smckusick 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
148137741Smckusick out1:
148249735Smckusick 	vrele(fromnd.ni_startdir);
148352322Smckusick 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
148439286Smckusick 	if (error == -1)
148547540Skarels 		return (0);
148647540Skarels 	return (error);
14877701Ssam }
14887701Ssam 
14897535Sroot /*
149049365Smckusick  * Mkdir system call.
149112756Ssam  */
149242441Smckusick /* ARGSUSED */
149342441Smckusick mkdir(p, uap, retval)
149445914Smckusick 	struct proc *p;
149542441Smckusick 	register struct args {
149612756Ssam 		char	*name;
149712756Ssam 		int	dmode;
149842441Smckusick 	} *uap;
149942441Smckusick 	int *retval;
150042441Smckusick {
150137741Smckusick 	register struct vnode *vp;
150237741Smckusick 	struct vattr vattr;
150337741Smckusick 	int error;
150447540Skarels 	struct nameidata nd;
150512756Ssam 
150652322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p);
150752322Smckusick 	if (error = namei(&nd))
150847540Skarels 		return (error);
150952322Smckusick 	vp = nd.ni_vp;
151037741Smckusick 	if (vp != NULL) {
151152322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
151252322Smckusick 		if (nd.ni_dvp == vp)
151352322Smckusick 			vrele(nd.ni_dvp);
151443344Smckusick 		else
151552322Smckusick 			vput(nd.ni_dvp);
151642465Smckusick 		vrele(vp);
151747540Skarels 		return (EEXIST);
151812756Ssam 	}
151941362Smckusick 	VATTR_NULL(&vattr);
152037741Smckusick 	vattr.va_type = VDIR;
152145914Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask;
152252322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
152352322Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
152438145Smckusick 	if (!error)
152552322Smckusick 		vput(nd.ni_vp);
152647540Skarels 	return (error);
152712756Ssam }
152812756Ssam 
152912756Ssam /*
153012756Ssam  * Rmdir system call.
153112756Ssam  */
153242441Smckusick /* ARGSUSED */
153342441Smckusick rmdir(p, uap, retval)
153445914Smckusick 	struct proc *p;
153542441Smckusick 	struct args {
153642441Smckusick 		char	*name;
153742441Smckusick 	} *uap;
153842441Smckusick 	int *retval;
153912756Ssam {
154037741Smckusick 	register struct vnode *vp;
154137741Smckusick 	int error;
154247540Skarels 	struct nameidata nd;
154312756Ssam 
154452322Smckusick 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p);
154552322Smckusick 	if (error = namei(&nd))
154647540Skarels 		return (error);
154752322Smckusick 	vp = nd.ni_vp;
154837741Smckusick 	if (vp->v_type != VDIR) {
154937741Smckusick 		error = ENOTDIR;
155012756Ssam 		goto out;
155112756Ssam 	}
155212756Ssam 	/*
155337741Smckusick 	 * No rmdir "." please.
155412756Ssam 	 */
155552322Smckusick 	if (nd.ni_dvp == vp) {
155637741Smckusick 		error = EINVAL;
155712756Ssam 		goto out;
155812756Ssam 	}
155912756Ssam 	/*
156049365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
156112756Ssam 	 */
156237741Smckusick 	if (vp->v_flag & VROOT)
156337741Smckusick 		error = EBUSY;
156412756Ssam out:
156542465Smckusick 	if (!error) {
156652322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
156752192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
156852322Smckusick 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
156942465Smckusick 	} else {
157052322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
157152322Smckusick 		if (nd.ni_dvp == vp)
157252322Smckusick 			vrele(nd.ni_dvp);
157343344Smckusick 		else
157452322Smckusick 			vput(nd.ni_dvp);
157542465Smckusick 		vput(vp);
157642465Smckusick 	}
157747540Skarels 	return (error);
157812756Ssam }
157912756Ssam 
158037741Smckusick /*
158149365Smckusick  * Read a block of directory entries in a file system independent format.
158237741Smckusick  */
158342441Smckusick getdirentries(p, uap, retval)
158445914Smckusick 	struct proc *p;
158542441Smckusick 	register struct args {
158637741Smckusick 		int	fd;
158737741Smckusick 		char	*buf;
158837741Smckusick 		unsigned count;
158937741Smckusick 		long	*basep;
159042441Smckusick 	} *uap;
159142441Smckusick 	int *retval;
159242441Smckusick {
159339592Smckusick 	register struct vnode *vp;
159416540Ssam 	struct file *fp;
159537741Smckusick 	struct uio auio;
159637741Smckusick 	struct iovec aiov;
159738129Smckusick 	off_t off;
159840321Smckusick 	int error, eofflag;
159912756Ssam 
160045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
160147540Skarels 		return (error);
160237741Smckusick 	if ((fp->f_flag & FREAD) == 0)
160347540Skarels 		return (EBADF);
160439592Smckusick 	vp = (struct vnode *)fp->f_data;
160539592Smckusick 	if (vp->v_type != VDIR)
160647540Skarels 		return (EINVAL);
160737741Smckusick 	aiov.iov_base = uap->buf;
160837741Smckusick 	aiov.iov_len = uap->count;
160937741Smckusick 	auio.uio_iov = &aiov;
161037741Smckusick 	auio.uio_iovcnt = 1;
161137741Smckusick 	auio.uio_rw = UIO_READ;
161237741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
161348026Smckusick 	auio.uio_procp = p;
161437741Smckusick 	auio.uio_resid = uap->count;
161539592Smckusick 	VOP_LOCK(vp);
161639592Smckusick 	auio.uio_offset = off = fp->f_offset;
161740321Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
161839592Smckusick 	fp->f_offset = auio.uio_offset;
161939592Smckusick 	VOP_UNLOCK(vp);
162039592Smckusick 	if (error)
162147540Skarels 		return (error);
162239592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
162342441Smckusick 	*retval = uap->count - auio.uio_resid;
162447540Skarels 	return (error);
162512756Ssam }
162612756Ssam 
162712756Ssam /*
162849365Smckusick  * Set the mode mask for creation of filesystem nodes.
162912756Ssam  */
163042441Smckusick mode_t
163142441Smckusick umask(p, uap, retval)
163245914Smckusick 	struct proc *p;
163342441Smckusick 	struct args {
163442441Smckusick 		int	mask;
163542441Smckusick 	} *uap;
163642441Smckusick 	int *retval;
163712756Ssam {
163845914Smckusick 	register struct filedesc *fdp = p->p_fd;
163912756Ssam 
164045914Smckusick 	*retval = fdp->fd_cmask;
164145914Smckusick 	fdp->fd_cmask = uap->mask & 07777;
164247540Skarels 	return (0);
164312756Ssam }
164437741Smckusick 
164539566Smarc /*
164639566Smarc  * Void all references to file by ripping underlying filesystem
164739566Smarc  * away from vnode.
164839566Smarc  */
164942441Smckusick /* ARGSUSED */
165042441Smckusick revoke(p, uap, retval)
165145914Smckusick 	struct proc *p;
165242441Smckusick 	register struct args {
165339566Smarc 		char	*fname;
165442441Smckusick 	} *uap;
165542441Smckusick 	int *retval;
165642441Smckusick {
165739566Smarc 	register struct vnode *vp;
165839566Smarc 	struct vattr vattr;
165939566Smarc 	int error;
166047540Skarels 	struct nameidata nd;
166139566Smarc 
166252322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
166352322Smckusick 	if (error = namei(&nd))
166447540Skarels 		return (error);
166552322Smckusick 	vp = nd.ni_vp;
166639566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
166739566Smarc 		error = EINVAL;
166839566Smarc 		goto out;
166939566Smarc 	}
167048026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
167139566Smarc 		goto out;
167247540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
167347540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
167439566Smarc 		goto out;
167539805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
167639632Smckusick 		vgoneall(vp);
167739566Smarc out:
167839566Smarc 	vrele(vp);
167947540Skarels 	return (error);
168039566Smarc }
168139566Smarc 
168249365Smckusick /*
168349365Smckusick  * Convert a user file descriptor to a kernel file entry.
168449365Smckusick  */
168545914Smckusick getvnode(fdp, fdes, fpp)
168645914Smckusick 	struct filedesc *fdp;
168737741Smckusick 	struct file **fpp;
168837741Smckusick 	int fdes;
168937741Smckusick {
169037741Smckusick 	struct file *fp;
169137741Smckusick 
169247540Skarels 	if ((unsigned)fdes >= fdp->fd_nfiles ||
169347688Skarels 	    (fp = fdp->fd_ofiles[fdes]) == NULL)
169437741Smckusick 		return (EBADF);
169537741Smckusick 	if (fp->f_type != DTYPE_VNODE)
169637741Smckusick 		return (EINVAL);
169737741Smckusick 	*fpp = fp;
169837741Smckusick 	return (0);
169937741Smckusick }
1700