xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 52287)
123405Smckusick /*
237741Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337741Smckusick  * All rights reserved.
423405Smckusick  *
544459Sbostic  * %sccs.include.redist.c%
637741Smckusick  *
7*52287Smckusick  *	@(#)vfs_syscalls.c	7.77 (Berkeley) 02/03/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 
2352230Sheideman /* NEEDSWORK: debugging */
2452230Sheideman #define CURCOUNT (curproc?curproc->p_spare[2]:0)
2552230Sheideman #define CHECKPOINT int oldrefcount=CURCOUNT;
2652230Sheideman #define CHECKCHECK(F) if (oldrefcount!=CURCOUNT) { printf("REFCOUNT: %s, old=%d, new=%d\n", (F), oldrefcount, CURCOUNT); }
2752230Sheideman 
2837741Smckusick /*
2937741Smckusick  * Virtual File System System Calls
3037741Smckusick  */
3112756Ssam 
329167Ssam /*
3349365Smckusick  * Mount system call.
349167Ssam  */
3542441Smckusick /* ARGSUSED */
3642441Smckusick mount(p, uap, retval)
3745914Smckusick 	struct proc *p;
3842441Smckusick 	register struct args {
3937741Smckusick 		int	type;
4037741Smckusick 		char	*dir;
4137741Smckusick 		int	flags;
4237741Smckusick 		caddr_t	data;
4342441Smckusick 	} *uap;
4442441Smckusick 	int *retval;
4542441Smckusick {
4647540Skarels 	register struct nameidata *ndp;
4739335Smckusick 	register struct vnode *vp;
4839335Smckusick 	register struct mount *mp;
4940111Smckusick 	int error, flag;
5047540Skarels 	struct nameidata nd;
516254Sroot 
5237741Smckusick 	/*
5337741Smckusick 	 * Must be super user
5437741Smckusick 	 */
5547540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
5647540Skarels 		return (error);
5737741Smckusick 	/*
5837741Smckusick 	 * Get vnode to be covered
5937741Smckusick 	 */
6047540Skarels 	ndp = &nd;
6137741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
6237741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
6337741Smckusick 	ndp->ni_dirp = uap->dir;
6447540Skarels 	if (error = namei(ndp, p))
6547540Skarels 		return (error);
6637741Smckusick 	vp = ndp->ni_vp;
6741400Smckusick 	if (uap->flags & MNT_UPDATE) {
6839335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
6939335Smckusick 			vput(vp);
7047540Skarels 			return (EINVAL);
7139335Smckusick 		}
7239335Smckusick 		mp = vp->v_mount;
7339335Smckusick 		/*
7439335Smckusick 		 * We allow going from read-only to read-write,
7539335Smckusick 		 * but not from read-write to read-only.
7639335Smckusick 		 */
7741400Smckusick 		if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
7841400Smckusick 		    (uap->flags & MNT_RDONLY) != 0) {
7939335Smckusick 			vput(vp);
8047540Skarels 			return (EOPNOTSUPP);	/* Needs translation */
8139335Smckusick 		}
8241400Smckusick 		flag = mp->mnt_flag;
8341400Smckusick 		mp->mnt_flag |= MNT_UPDATE;
8439335Smckusick 		VOP_UNLOCK(vp);
8539335Smckusick 		goto update;
8639335Smckusick 	}
8739665Smckusick 	vinvalbuf(vp, 1);
8839805Smckusick 	if (vp->v_usecount != 1) {
8937741Smckusick 		vput(vp);
9047540Skarels 		return (EBUSY);
9137741Smckusick 	}
9237741Smckusick 	if (vp->v_type != VDIR) {
9337741Smckusick 		vput(vp);
9447540Skarels 		return (ENOTDIR);
9537741Smckusick 	}
9639741Smckusick 	if ((unsigned long)uap->type > MOUNT_MAXTYPE ||
9737741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
9837741Smckusick 		vput(vp);
9947540Skarels 		return (ENODEV);
10037741Smckusick 	}
10137741Smckusick 
10237741Smckusick 	/*
10339335Smckusick 	 * Allocate and initialize the file system.
10437741Smckusick 	 */
10537741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
10637741Smckusick 		M_MOUNT, M_WAITOK);
10741400Smckusick 	mp->mnt_op = vfssw[uap->type];
10841400Smckusick 	mp->mnt_flag = 0;
10941400Smckusick 	mp->mnt_mounth = NULLVP;
11039335Smckusick 	if (error = vfs_lock(mp)) {
11139335Smckusick 		free((caddr_t)mp, M_MOUNT);
11239335Smckusick 		vput(vp);
11347540Skarels 		return (error);
11439335Smckusick 	}
11539335Smckusick 	if (vp->v_mountedhere != (struct mount *)0) {
11639335Smckusick 		vfs_unlock(mp);
11739335Smckusick 		free((caddr_t)mp, M_MOUNT);
11839335Smckusick 		vput(vp);
11947540Skarels 		return (EBUSY);
12039335Smckusick 	}
12139335Smckusick 	vp->v_mountedhere = mp;
12241400Smckusick 	mp->mnt_vnodecovered = vp;
12339335Smckusick update:
12439335Smckusick 	/*
12539335Smckusick 	 * Set the mount level flags.
12639335Smckusick 	 */
12741400Smckusick 	if (uap->flags & MNT_RDONLY)
12841400Smckusick 		mp->mnt_flag |= MNT_RDONLY;
12939335Smckusick 	else
13041400Smckusick 		mp->mnt_flag &= ~MNT_RDONLY;
13141400Smckusick 	if (uap->flags & MNT_NOSUID)
13241400Smckusick 		mp->mnt_flag |= MNT_NOSUID;
13339335Smckusick 	else
13441400Smckusick 		mp->mnt_flag &= ~MNT_NOSUID;
13541400Smckusick 	if (uap->flags & MNT_NOEXEC)
13641400Smckusick 		mp->mnt_flag |= MNT_NOEXEC;
13739335Smckusick 	else
13841400Smckusick 		mp->mnt_flag &= ~MNT_NOEXEC;
13941400Smckusick 	if (uap->flags & MNT_NODEV)
14041400Smckusick 		mp->mnt_flag |= MNT_NODEV;
14139335Smckusick 	else
14241400Smckusick 		mp->mnt_flag &= ~MNT_NODEV;
14341400Smckusick 	if (uap->flags & MNT_SYNCHRONOUS)
14441400Smckusick 		mp->mnt_flag |= MNT_SYNCHRONOUS;
14539335Smckusick 	else
14641400Smckusick 		mp->mnt_flag &= ~MNT_SYNCHRONOUS;
14739335Smckusick 	/*
14839335Smckusick 	 * Mount the filesystem.
14939335Smckusick 	 */
15048026Smckusick 	error = VFS_MOUNT(mp, uap->dir, uap->data, ndp, p);
15141400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
15241400Smckusick 		mp->mnt_flag &= ~MNT_UPDATE;
15339335Smckusick 		vrele(vp);
15440111Smckusick 		if (error)
15541400Smckusick 			mp->mnt_flag = flag;
15647540Skarels 		return (error);
15739335Smckusick 	}
15840110Smckusick 	/*
15940110Smckusick 	 * Put the new filesystem on the mount list after root.
16040110Smckusick 	 */
16141400Smckusick 	mp->mnt_next = rootfs->mnt_next;
16241400Smckusick 	mp->mnt_prev = rootfs;
16341400Smckusick 	rootfs->mnt_next = mp;
16441400Smckusick 	mp->mnt_next->mnt_prev = mp;
16537741Smckusick 	cache_purge(vp);
16637741Smckusick 	if (!error) {
16739335Smckusick 		VOP_UNLOCK(vp);
16837741Smckusick 		vfs_unlock(mp);
16948026Smckusick 		error = VFS_START(mp, 0, p);
17037741Smckusick 	} else {
17137741Smckusick 		vfs_remove(mp);
17237741Smckusick 		free((caddr_t)mp, M_MOUNT);
17339335Smckusick 		vput(vp);
17437741Smckusick 	}
17547540Skarels 	return (error);
1766254Sroot }
1776254Sroot 
1789167Ssam /*
17937741Smckusick  * Unmount system call.
18037741Smckusick  *
18137741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
18237741Smckusick  * not special file (as before).
1839167Ssam  */
18442441Smckusick /* ARGSUSED */
18542441Smckusick unmount(p, uap, retval)
18645914Smckusick 	struct proc *p;
18742441Smckusick 	register struct args {
18837741Smckusick 		char	*pathp;
18937741Smckusick 		int	flags;
19042441Smckusick 	} *uap;
19142441Smckusick 	int *retval;
19242441Smckusick {
19337741Smckusick 	register struct vnode *vp;
19447540Skarels 	register struct nameidata *ndp;
19539356Smckusick 	struct mount *mp;
19637741Smckusick 	int error;
19747540Skarels 	struct nameidata nd;
1986254Sroot 
19937741Smckusick 	/*
20037741Smckusick 	 * Must be super user
20137741Smckusick 	 */
20247540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
20347540Skarels 		return (error);
20437741Smckusick 
20547540Skarels 	ndp = &nd;
20637741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
20737741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
20837741Smckusick 	ndp->ni_dirp = uap->pathp;
20947540Skarels 	if (error = namei(ndp, p))
21047540Skarels 		return (error);
21137741Smckusick 	vp = ndp->ni_vp;
21237741Smckusick 	/*
21337741Smckusick 	 * Must be the root of the filesystem
21437741Smckusick 	 */
21537741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
21637741Smckusick 		vput(vp);
21747540Skarels 		return (EINVAL);
21837741Smckusick 	}
21937741Smckusick 	mp = vp->v_mount;
22037741Smckusick 	vput(vp);
22148026Smckusick 	return (dounmount(mp, uap->flags, p));
22239356Smckusick }
22339356Smckusick 
22439356Smckusick /*
22539356Smckusick  * Do an unmount.
22639356Smckusick  */
22748026Smckusick dounmount(mp, flags, p)
22839356Smckusick 	register struct mount *mp;
22939356Smckusick 	int flags;
23048026Smckusick 	struct proc *p;
23139356Smckusick {
23239356Smckusick 	struct vnode *coveredvp;
23339356Smckusick 	int error;
23439356Smckusick 
23541400Smckusick 	coveredvp = mp->mnt_vnodecovered;
23641298Smckusick 	if (vfs_busy(mp))
23741298Smckusick 		return (EBUSY);
23841400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
23937741Smckusick 	if (error = vfs_lock(mp))
24039356Smckusick 		return (error);
24137741Smckusick 
24245738Smckusick 	vnode_pager_umount(mp);	/* release cached vnodes */
24337741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
24441676Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE))
24548026Smckusick 		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);
253*52287Smckusick 		if (mp->mnt_mounth != NULL)
254*52287Smckusick 			panic("unmount: dangling vnode");
25537741Smckusick 		free((caddr_t)mp, M_MOUNT);
25637741Smckusick 	}
25739356Smckusick 	return (error);
2586254Sroot }
2596254Sroot 
2609167Ssam /*
26137741Smckusick  * Sync system call.
26237741Smckusick  * Sync each mounted filesystem.
2639167Ssam  */
26439491Smckusick /* ARGSUSED */
26542441Smckusick sync(p, uap, retval)
26645914Smckusick 	struct proc *p;
26747540Skarels 	void *uap;
26842441Smckusick 	int *retval;
2696254Sroot {
27037741Smckusick 	register struct mount *mp;
27141298Smckusick 	struct mount *omp;
27237741Smckusick 
27337741Smckusick 	mp = rootfs;
27437741Smckusick 	do {
27540343Smckusick 		/*
27640343Smckusick 		 * The lock check below is to avoid races with mount
27740343Smckusick 		 * and unmount.
27840343Smckusick 		 */
27941400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
28041298Smckusick 		    !vfs_busy(mp)) {
28137741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
28241298Smckusick 			omp = mp;
28341400Smckusick 			mp = mp->mnt_next;
28441298Smckusick 			vfs_unbusy(omp);
28541298Smckusick 		} else
28641400Smckusick 			mp = mp->mnt_next;
28737741Smckusick 	} while (mp != rootfs);
28847688Skarels 	return (0);
28937741Smckusick }
29037741Smckusick 
29137741Smckusick /*
29249365Smckusick  * Operate on filesystem quotas.
29341298Smckusick  */
29442441Smckusick /* ARGSUSED */
29542441Smckusick quotactl(p, uap, retval)
29645914Smckusick 	struct proc *p;
29742441Smckusick 	register struct args {
29841298Smckusick 		char *path;
29941298Smckusick 		int cmd;
30041298Smckusick 		int uid;
30141298Smckusick 		caddr_t arg;
30242441Smckusick 	} *uap;
30342441Smckusick 	int *retval;
30442441Smckusick {
30541298Smckusick 	register struct mount *mp;
30647540Skarels 	register struct nameidata *ndp;
30741298Smckusick 	int error;
30847540Skarels 	struct nameidata nd;
30941298Smckusick 
31047540Skarels 	ndp = &nd;
31141298Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
31241298Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
31341298Smckusick 	ndp->ni_dirp = uap->path;
31447540Skarels 	if (error = namei(ndp, p))
31547540Skarels 		return (error);
31641298Smckusick 	mp = ndp->ni_vp->v_mount;
31741298Smckusick 	vrele(ndp->ni_vp);
31848026Smckusick 	return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p));
31941298Smckusick }
32041298Smckusick 
32141298Smckusick /*
32249365Smckusick  * Get filesystem statistics.
32337741Smckusick  */
32442441Smckusick /* ARGSUSED */
32542441Smckusick statfs(p, uap, retval)
32645914Smckusick 	struct proc *p;
32742441Smckusick 	register struct args {
32837741Smckusick 		char *path;
32937741Smckusick 		struct statfs *buf;
33042441Smckusick 	} *uap;
33142441Smckusick 	int *retval;
33242441Smckusick {
33339464Smckusick 	register struct mount *mp;
33447540Skarels 	register struct nameidata *ndp;
33540343Smckusick 	register struct statfs *sp;
33637741Smckusick 	int error;
33747540Skarels 	struct nameidata nd;
33837741Smckusick 
33947540Skarels 	ndp = &nd;
34039544Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
34137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
34237741Smckusick 	ndp->ni_dirp = uap->path;
34347540Skarels 	if (error = namei(ndp, p))
34447540Skarels 		return (error);
34539544Smckusick 	mp = ndp->ni_vp->v_mount;
34641400Smckusick 	sp = &mp->mnt_stat;
34739544Smckusick 	vrele(ndp->ni_vp);
34848026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
34947540Skarels 		return (error);
35041400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
35147540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
35237741Smckusick }
35337741Smckusick 
35442441Smckusick /*
35549365Smckusick  * Get filesystem statistics.
35642441Smckusick  */
35742441Smckusick /* ARGSUSED */
35842441Smckusick fstatfs(p, uap, retval)
35945914Smckusick 	struct proc *p;
36042441Smckusick 	register struct args {
36137741Smckusick 		int fd;
36237741Smckusick 		struct statfs *buf;
36342441Smckusick 	} *uap;
36442441Smckusick 	int *retval;
36542441Smckusick {
36637741Smckusick 	struct file *fp;
36739464Smckusick 	struct mount *mp;
36840343Smckusick 	register struct statfs *sp;
36937741Smckusick 	int error;
37037741Smckusick 
37145914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
37247540Skarels 		return (error);
37339464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
37441400Smckusick 	sp = &mp->mnt_stat;
37548026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
37647540Skarels 		return (error);
37741400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
37847540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
37937741Smckusick }
38037741Smckusick 
38137741Smckusick /*
38249365Smckusick  * Get statistics on all filesystems.
38338270Smckusick  */
38442441Smckusick getfsstat(p, uap, retval)
38545914Smckusick 	struct proc *p;
38642441Smckusick 	register struct args {
38738270Smckusick 		struct statfs *buf;
38838270Smckusick 		long bufsize;
38940343Smckusick 		int flags;
39042441Smckusick 	} *uap;
39142441Smckusick 	int *retval;
39242441Smckusick {
39338270Smckusick 	register struct mount *mp;
39440343Smckusick 	register struct statfs *sp;
39539606Smckusick 	caddr_t sfsp;
39638270Smckusick 	long count, maxcount, error;
39738270Smckusick 
39838270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
39939606Smckusick 	sfsp = (caddr_t)uap->buf;
40038270Smckusick 	mp = rootfs;
40138270Smckusick 	count = 0;
40238270Smckusick 	do {
40341400Smckusick 		if (sfsp && count < maxcount &&
40441400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
40541400Smckusick 			sp = &mp->mnt_stat;
40640343Smckusick 			/*
40740343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
40840343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
40940343Smckusick 			 */
41040343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
41140343Smckusick 			    (uap->flags & MNT_WAIT)) &&
41248026Smckusick 			    (error = VFS_STATFS(mp, sp, p))) {
41341400Smckusick 				mp = mp->mnt_prev;
41439607Smckusick 				continue;
41539607Smckusick 			}
41641400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
41740343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
41847540Skarels 				return (error);
41940343Smckusick 			sfsp += sizeof(*sp);
42038270Smckusick 		}
42139606Smckusick 		count++;
42241400Smckusick 		mp = mp->mnt_prev;
42338270Smckusick 	} while (mp != rootfs);
42438270Smckusick 	if (sfsp && count > maxcount)
42542441Smckusick 		*retval = maxcount;
42638270Smckusick 	else
42742441Smckusick 		*retval = count;
42847540Skarels 	return (0);
42938270Smckusick }
43038270Smckusick 
43138270Smckusick /*
43238259Smckusick  * Change current working directory to a given file descriptor.
43338259Smckusick  */
43442441Smckusick /* ARGSUSED */
43542441Smckusick fchdir(p, uap, retval)
43645914Smckusick 	struct proc *p;
43742441Smckusick 	struct args {
43842441Smckusick 		int	fd;
43942441Smckusick 	} *uap;
44042441Smckusick 	int *retval;
44138259Smckusick {
44245914Smckusick 	register struct filedesc *fdp = p->p_fd;
44338259Smckusick 	register struct vnode *vp;
44438259Smckusick 	struct file *fp;
44538259Smckusick 	int error;
44638259Smckusick 
44745914Smckusick 	if (error = getvnode(fdp, uap->fd, &fp))
44847540Skarels 		return (error);
44938259Smckusick 	vp = (struct vnode *)fp->f_data;
45038259Smckusick 	VOP_LOCK(vp);
45138259Smckusick 	if (vp->v_type != VDIR)
45238259Smckusick 		error = ENOTDIR;
45338259Smckusick 	else
45448026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
45538259Smckusick 	VOP_UNLOCK(vp);
45639860Smckusick 	if (error)
45747540Skarels 		return (error);
45839860Smckusick 	VREF(vp);
45945914Smckusick 	vrele(fdp->fd_cdir);
46045914Smckusick 	fdp->fd_cdir = vp;
46147540Skarels 	return (0);
46238259Smckusick }
46338259Smckusick 
46438259Smckusick /*
46537741Smckusick  * Change current working directory (``.'').
46637741Smckusick  */
46742441Smckusick /* ARGSUSED */
46842441Smckusick chdir(p, uap, retval)
46945914Smckusick 	struct proc *p;
47042441Smckusick 	struct args {
47142441Smckusick 		char	*fname;
47242441Smckusick 	} *uap;
47342441Smckusick 	int *retval;
47437741Smckusick {
47547540Skarels 	register struct nameidata *ndp;
47645914Smckusick 	register struct filedesc *fdp = p->p_fd;
47737741Smckusick 	int error;
47847540Skarels 	struct nameidata nd;
4796254Sroot 
48047540Skarels 	ndp = &nd;
48137741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
48216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
48316694Smckusick 	ndp->ni_dirp = uap->fname;
48447540Skarels 	if (error = chdirec(ndp, p))
48547540Skarels 		return (error);
48645914Smckusick 	vrele(fdp->fd_cdir);
48745914Smckusick 	fdp->fd_cdir = ndp->ni_vp;
48847540Skarels 	return (0);
48937741Smckusick }
4906254Sroot 
49137741Smckusick /*
49237741Smckusick  * Change notion of root (``/'') directory.
49337741Smckusick  */
49442441Smckusick /* ARGSUSED */
49542441Smckusick chroot(p, uap, retval)
49645914Smckusick 	struct proc *p;
49742441Smckusick 	struct args {
49842441Smckusick 		char	*fname;
49942441Smckusick 	} *uap;
50042441Smckusick 	int *retval;
50137741Smckusick {
50247540Skarels 	register struct nameidata *ndp;
50345914Smckusick 	register struct filedesc *fdp = p->p_fd;
50437741Smckusick 	int error;
50547540Skarels 	struct nameidata nd;
50637741Smckusick 
50747540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
50847540Skarels 		return (error);
50947540Skarels 	ndp = &nd;
51037741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
51137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
51237741Smckusick 	ndp->ni_dirp = uap->fname;
51347540Skarels 	if (error = chdirec(ndp, p))
51447540Skarels 		return (error);
51545914Smckusick 	if (fdp->fd_rdir != NULL)
51645914Smckusick 		vrele(fdp->fd_rdir);
51745914Smckusick 	fdp->fd_rdir = ndp->ni_vp;
51847540Skarels 	return (0);
5196254Sroot }
5206254Sroot 
52137Sbill /*
52237741Smckusick  * Common routine for chroot and chdir.
52337741Smckusick  */
52447540Skarels chdirec(ndp, p)
52547540Skarels 	struct nameidata *ndp;
52647540Skarels 	struct proc *p;
52737741Smckusick {
52837741Smckusick 	struct vnode *vp;
52937741Smckusick 	int error;
53037741Smckusick 
53147540Skarels 	if (error = namei(ndp, p))
53237741Smckusick 		return (error);
53337741Smckusick 	vp = ndp->ni_vp;
53437741Smckusick 	if (vp->v_type != VDIR)
53537741Smckusick 		error = ENOTDIR;
53637741Smckusick 	else
53748026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
53837741Smckusick 	VOP_UNLOCK(vp);
53937741Smckusick 	if (error)
54037741Smckusick 		vrele(vp);
54137741Smckusick 	return (error);
54237741Smckusick }
54337741Smckusick 
54437741Smckusick /*
5456254Sroot  * Open system call.
54642441Smckusick  * Check permissions, allocate an open file structure,
54742441Smckusick  * and call the device open routine if any.
5486254Sroot  */
54942441Smckusick open(p, uap, retval)
55045914Smckusick 	struct proc *p;
55142441Smckusick 	register struct args {
5526254Sroot 		char	*fname;
5537701Ssam 		int	mode;
55412756Ssam 		int	crtmode;
55542441Smckusick 	} *uap;
55642441Smckusick 	int *retval;
5576254Sroot {
55847540Skarels 	struct nameidata *ndp;
55945914Smckusick 	register struct filedesc *fdp = p->p_fd;
56042441Smckusick 	register struct file *fp;
56150111Smckusick 	register struct vnode *vp;
56237741Smckusick 	int fmode, cmode;
56337741Smckusick 	struct file *nfp;
56449945Smckusick 	int type, indx, error;
56549945Smckusick 	struct flock lf;
56647540Skarels 	struct nameidata nd;
56737741Smckusick 	extern struct fileops vnops;
5686254Sroot 
56945914Smckusick 	if (error = falloc(p, &nfp, &indx))
57047540Skarels 		return (error);
57137741Smckusick 	fp = nfp;
57246553Skarels 	fmode = FFLAGS(uap->mode);
57345914Smckusick 	cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX;
57447540Skarels 	ndp = &nd;
57542441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
57642441Smckusick 	ndp->ni_dirp = uap->fname;
57745202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
57847540Skarels 	if (error = vn_open(ndp, p, fmode, cmode)) {
57949980Smckusick 		ffree(fp);
58043405Smckusick 		if (error == ENODEV &&		/* XXX from fdopen */
58145202Smckusick 		    p->p_dupfd >= 0 &&
58245914Smckusick 		    (error = dupfdopen(fdp, indx, p->p_dupfd, fmode)) == 0) {
58342441Smckusick 			*retval = indx;
58447540Skarels 			return (0);
58542441Smckusick 		}
58640884Smckusick 		if (error == ERESTART)
58740884Smckusick 			error = EINTR;
58847688Skarels 		fdp->fd_ofiles[indx] = NULL;
58947540Skarels 		return (error);
59012756Ssam 	}
59150111Smckusick 	vp = ndp->ni_vp;
59249949Smckusick 	fp->f_flag = fmode & FMASK;
59349945Smckusick 	if (fmode & (O_EXLOCK | O_SHLOCK)) {
59449945Smckusick 		lf.l_whence = SEEK_SET;
59549945Smckusick 		lf.l_start = 0;
59649945Smckusick 		lf.l_len = 0;
59749945Smckusick 		if (fmode & O_EXLOCK)
59849945Smckusick 			lf.l_type = F_WRLCK;
59949945Smckusick 		else
60049945Smckusick 			lf.l_type = F_RDLCK;
60149945Smckusick 		type = F_FLOCK;
60249945Smckusick 		if ((fmode & FNONBLOCK) == 0)
60349945Smckusick 			type |= F_WAIT;
60450111Smckusick 		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
60550111Smckusick 			VOP_UNLOCK(vp);
60650111Smckusick 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
60749980Smckusick 			ffree(fp);
60849945Smckusick 			fdp->fd_ofiles[indx] = NULL;
60949945Smckusick 			return (error);
61049945Smckusick 		}
61149949Smckusick 		fp->f_flag |= FHASLOCK;
61249945Smckusick 	}
61350111Smckusick 	VOP_UNLOCK(vp);
61437741Smckusick 	fp->f_type = DTYPE_VNODE;
61537741Smckusick 	fp->f_ops = &vnops;
61650111Smckusick 	fp->f_data = (caddr_t)vp;
61742441Smckusick 	*retval = indx;
61847540Skarels 	return (0);
6196254Sroot }
6206254Sroot 
62142955Smckusick #ifdef COMPAT_43
6226254Sroot /*
62342441Smckusick  * Creat system call.
6246254Sroot  */
62542955Smckusick ocreat(p, uap, retval)
62642441Smckusick 	struct proc *p;
62742441Smckusick 	register struct args {
62842441Smckusick 		char	*fname;
62942441Smckusick 		int	fmode;
63042441Smckusick 	} *uap;
63142441Smckusick 	int *retval;
6326254Sroot {
63342441Smckusick 	struct args {
6346254Sroot 		char	*fname;
63542441Smckusick 		int	mode;
63642441Smckusick 		int	crtmode;
63742441Smckusick 	} openuap;
63842441Smckusick 
63942441Smckusick 	openuap.fname = uap->fname;
64042441Smckusick 	openuap.crtmode = uap->fmode;
64142441Smckusick 	openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
64247540Skarels 	return (open(p, &openuap, retval));
64342441Smckusick }
64442955Smckusick #endif /* COMPAT_43 */
64542441Smckusick 
64642441Smckusick /*
64749365Smckusick  * Mknod system call.
64842441Smckusick  */
64942441Smckusick /* ARGSUSED */
65042441Smckusick mknod(p, uap, retval)
65145914Smckusick 	struct proc *p;
65242441Smckusick 	register struct args {
65342441Smckusick 		char	*fname;
6546254Sroot 		int	fmode;
6556254Sroot 		int	dev;
65642441Smckusick 	} *uap;
65742441Smckusick 	int *retval;
65842441Smckusick {
65947540Skarels 	register struct nameidata *ndp;
66037741Smckusick 	register struct vnode *vp;
66137741Smckusick 	struct vattr vattr;
66237741Smckusick 	int error;
66347540Skarels 	struct nameidata nd;
6646254Sroot 
66552230Sheideman 	CHECKPOINT;
66647540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
66747540Skarels 		return (error);
66847540Skarels 	ndp = &nd;
66937741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
67016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
67116694Smckusick 	ndp->ni_dirp = uap->fname;
67247540Skarels 	if (error = namei(ndp, p))
67347540Skarels 		return (error);
67437741Smckusick 	vp = ndp->ni_vp;
67537741Smckusick 	if (vp != NULL) {
67637741Smckusick 		error = EEXIST;
67712756Ssam 		goto out;
6786254Sroot 	}
67941362Smckusick 	VATTR_NULL(&vattr);
68040635Smckusick 	switch (uap->fmode & S_IFMT) {
68112756Ssam 
68240635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
68337741Smckusick 		vattr.va_type = VBAD;
68437741Smckusick 		break;
68540635Smckusick 	case S_IFCHR:
68637741Smckusick 		vattr.va_type = VCHR;
68737741Smckusick 		break;
68840635Smckusick 	case S_IFBLK:
68937741Smckusick 		vattr.va_type = VBLK;
69037741Smckusick 		break;
69137741Smckusick 	default:
69237741Smckusick 		error = EINVAL;
69337741Smckusick 		goto out;
6946254Sroot 	}
69545914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
69637741Smckusick 	vattr.va_rdev = uap->dev;
6976254Sroot out:
69842465Smckusick 	if (!error) {
69952192Smckusick 		LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE);
70052230Sheideman 		error = VOP_MKNOD(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &vattr);
70142465Smckusick 	} else {
70252230Sheideman 		VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
70343344Smckusick 		if (ndp->ni_dvp == vp)
70443344Smckusick 			vrele(ndp->ni_dvp);
70543344Smckusick 		else
70643344Smckusick 			vput(ndp->ni_dvp);
70742465Smckusick 		if (vp)
70842465Smckusick 			vrele(vp);
70942465Smckusick 	}
71052230Sheideman 	CHECKCHECK("mknod");
71147540Skarels 	return (error);
7126254Sroot }
7136254Sroot 
7146254Sroot /*
71549365Smckusick  * Mkfifo system call.
71640285Smckusick  */
71742441Smckusick /* ARGSUSED */
71842441Smckusick mkfifo(p, uap, retval)
71945914Smckusick 	struct proc *p;
72042441Smckusick 	register struct args {
72140285Smckusick 		char	*fname;
72240285Smckusick 		int	fmode;
72342441Smckusick 	} *uap;
72442441Smckusick 	int *retval;
72542441Smckusick {
72647540Skarels 	register struct nameidata *ndp;
72740285Smckusick 	struct vattr vattr;
72840285Smckusick 	int error;
72947540Skarels 	struct nameidata nd;
73040285Smckusick 
73140285Smckusick #ifndef FIFO
73247540Skarels 	return (EOPNOTSUPP);
73340285Smckusick #else
73447540Skarels 	ndp = &nd;
73540285Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
73640285Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
73740285Smckusick 	ndp->ni_dirp = uap->fname;
73847540Skarels 	if (error = namei(ndp, p))
73947540Skarels 		return (error);
74040285Smckusick 	if (ndp->ni_vp != NULL) {
74152230Sheideman 		VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
74243344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
74343344Smckusick 			vrele(ndp->ni_dvp);
74443344Smckusick 		else
74543344Smckusick 			vput(ndp->ni_dvp);
74642465Smckusick 		vrele(ndp->ni_vp);
74747540Skarels 		return (EEXIST);
74840285Smckusick 	}
74945785Sbostic 	VATTR_NULL(&vattr);
75045785Sbostic 	vattr.va_type = VFIFO;
75145914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
75252192Smckusick 	LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE);
75352230Sheideman 	return (VOP_MKNOD(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &vattr));
75440285Smckusick #endif /* FIFO */
75540285Smckusick }
75640285Smckusick 
75740285Smckusick /*
75849365Smckusick  * Link system call.
7596254Sroot  */
76042441Smckusick /* ARGSUSED */
76142441Smckusick link(p, uap, retval)
76245914Smckusick 	struct proc *p;
76342441Smckusick 	register struct args {
7646254Sroot 		char	*target;
7656254Sroot 		char	*linkname;
76642441Smckusick 	} *uap;
76742441Smckusick 	int *retval;
76842441Smckusick {
76947540Skarels 	register struct nameidata *ndp;
77037741Smckusick 	register struct vnode *vp, *xp;
77137741Smckusick 	int error;
77247540Skarels 	struct nameidata nd;
7736254Sroot 
77452230Sheideman 	CHECKPOINT;
77547540Skarels 	ndp = &nd;
77616694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
77716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
77816694Smckusick 	ndp->ni_dirp = uap->target;
77947540Skarels 	if (error = namei(ndp, p))
78047540Skarels 		return (error);
78137741Smckusick 	vp = ndp->ni_vp;
78237741Smckusick 	if (vp->v_type == VDIR &&
78347540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
78437741Smckusick 		goto out1;
78537741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
78616694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
78747540Skarels 	if (error = namei(ndp, p))
78837741Smckusick 		goto out1;
78937741Smckusick 	xp = ndp->ni_vp;
7906254Sroot 	if (xp != NULL) {
79137741Smckusick 		error = EEXIST;
7926254Sroot 		goto out;
7936254Sroot 	}
79437741Smckusick 	xp = ndp->ni_dvp;
79537741Smckusick 	if (vp->v_mount != xp->v_mount)
79637741Smckusick 		error = EXDEV;
7976254Sroot out:
79842465Smckusick 	if (!error) {
79952192Smckusick 		LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE);
80052192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
80152230Sheideman 		error = VOP_LINK(vp, ndp->ni_dvp, &ndp->ni_cnd);
80242465Smckusick 	} else {
80352230Sheideman 		VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
80443344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
80543344Smckusick 			vrele(ndp->ni_dvp);
80643344Smckusick 		else
80743344Smckusick 			vput(ndp->ni_dvp);
80842465Smckusick 		if (ndp->ni_vp)
80942465Smckusick 			vrele(ndp->ni_vp);
81042465Smckusick 	}
81137741Smckusick out1:
81237741Smckusick 	vrele(vp);
81352230Sheideman 	CHECKCHECK("link");
81447540Skarels 	return (error);
8156254Sroot }
8166254Sroot 
8176254Sroot /*
81849365Smckusick  * Make a symbolic link.
8196254Sroot  */
82042441Smckusick /* ARGSUSED */
82142441Smckusick symlink(p, uap, retval)
82245914Smckusick 	struct proc *p;
82342441Smckusick 	register struct args {
8246254Sroot 		char	*target;
8256254Sroot 		char	*linkname;
82642441Smckusick 	} *uap;
82742441Smckusick 	int *retval;
82842441Smckusick {
82947540Skarels 	register struct nameidata *ndp;
83037741Smckusick 	struct vattr vattr;
83137741Smckusick 	char *target;
83237741Smckusick 	int error;
83347540Skarels 	struct nameidata nd;
8346254Sroot 
83552230Sheideman 	CHECKPOINT;
83647540Skarels 	ndp = &nd;
83716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
83816694Smckusick 	ndp->ni_dirp = uap->linkname;
83937741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
84037741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
84142465Smckusick 		goto out;
84237741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
84347540Skarels 	if (error = namei(ndp, p))
84442465Smckusick 		goto out;
84542465Smckusick 	if (ndp->ni_vp) {
84652230Sheideman 		VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
84743344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
84843344Smckusick 			vrele(ndp->ni_dvp);
84943344Smckusick 		else
85043344Smckusick 			vput(ndp->ni_dvp);
85142465Smckusick 		vrele(ndp->ni_vp);
85237741Smckusick 		error = EEXIST;
85337741Smckusick 		goto out;
8546254Sroot 	}
85541362Smckusick 	VATTR_NULL(&vattr);
85645914Smckusick 	vattr.va_mode = 0777 &~ p->p_fd->fd_cmask;
85752192Smckusick 	LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE);
85852230Sheideman 	error = VOP_SYMLINK(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &vattr, target);
85937741Smckusick out:
86037741Smckusick 	FREE(target, M_NAMEI);
86152230Sheideman 	CHECKCHECK("symlink");
86247540Skarels 	return (error);
8636254Sroot }
8646254Sroot 
8656254Sroot /*
86649365Smckusick  * Delete a name from the filesystem.
8676254Sroot  */
86842441Smckusick /* ARGSUSED */
86942441Smckusick unlink(p, uap, retval)
87045914Smckusick 	struct proc *p;
87142441Smckusick 	struct args {
87242441Smckusick 		char	*fname;
87342441Smckusick 	} *uap;
87442441Smckusick 	int *retval;
8756254Sroot {
87647540Skarels 	register struct nameidata *ndp;
87737741Smckusick 	register struct vnode *vp;
87837741Smckusick 	int error;
87947540Skarels 	struct nameidata nd;
8806254Sroot 
88152230Sheideman 	CHECKPOINT;
88247540Skarels 	ndp = &nd;
88337741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
88416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
88516694Smckusick 	ndp->ni_dirp = uap->fname;
88647540Skarels 	if (error = namei(ndp, p))
88747540Skarels 		return (error);
88837741Smckusick 	vp = ndp->ni_vp;
88937741Smckusick 	if (vp->v_type == VDIR &&
89047540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
8916254Sroot 		goto out;
8926254Sroot 	/*
89349365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
8946254Sroot 	 */
89537741Smckusick 	if (vp->v_flag & VROOT) {
89637741Smckusick 		error = EBUSY;
8976254Sroot 		goto out;
8986254Sroot 	}
89945738Smckusick 	(void) vnode_pager_uncache(vp);
9006254Sroot out:
90142465Smckusick 	if (!error) {
90252192Smckusick 		LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE);
90352192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
90452230Sheideman 		error = VOP_REMOVE(ndp->ni_dvp, ndp->ni_vp, &ndp->ni_cnd);
90542465Smckusick 	} else {
90652230Sheideman 		VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
90743344Smckusick 		if (ndp->ni_dvp == vp)
90843344Smckusick 			vrele(ndp->ni_dvp);
90943344Smckusick 		else
91043344Smckusick 			vput(ndp->ni_dvp);
91142465Smckusick 		vput(vp);
91242465Smckusick 	}
91352230Sheideman 	CHECKCHECK("unlink");
91447540Skarels 	return (error);
9156254Sroot }
9166254Sroot 
9176254Sroot /*
91849365Smckusick  * Seek system call.
9196254Sroot  */
92042441Smckusick lseek(p, uap, retval)
92145914Smckusick 	struct proc *p;
92242441Smckusick 	register struct args {
92337741Smckusick 		int	fdes;
9246254Sroot 		off_t	off;
9256254Sroot 		int	sbase;
92642441Smckusick 	} *uap;
92742441Smckusick 	off_t *retval;
92842441Smckusick {
92947540Skarels 	struct ucred *cred = p->p_ucred;
93045914Smckusick 	register struct filedesc *fdp = p->p_fd;
93142441Smckusick 	register struct file *fp;
93237741Smckusick 	struct vattr vattr;
93337741Smckusick 	int error;
9346254Sroot 
93547540Skarels 	if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
93647688Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL)
93747540Skarels 		return (EBADF);
93837741Smckusick 	if (fp->f_type != DTYPE_VNODE)
93947540Skarels 		return (ESPIPE);
94013878Ssam 	switch (uap->sbase) {
94113878Ssam 
94213878Ssam 	case L_INCR:
94313878Ssam 		fp->f_offset += uap->off;
94413878Ssam 		break;
94513878Ssam 
94613878Ssam 	case L_XTND:
94737741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
94848026Smckusick 		    &vattr, cred, p))
94947540Skarels 			return (error);
95037741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
95113878Ssam 		break;
95213878Ssam 
95313878Ssam 	case L_SET:
95413878Ssam 		fp->f_offset = uap->off;
95513878Ssam 		break;
95613878Ssam 
95713878Ssam 	default:
95847540Skarels 		return (EINVAL);
95913878Ssam 	}
96042441Smckusick 	*retval = fp->f_offset;
96147540Skarels 	return (0);
9626254Sroot }
9636254Sroot 
9646254Sroot /*
96549365Smckusick  * Check access permissions.
9666254Sroot  */
96742441Smckusick /* ARGSUSED */
96842441Smckusick saccess(p, uap, retval)
96945914Smckusick 	struct proc *p;
97042441Smckusick 	register struct args {
9716254Sroot 		char	*fname;
9726254Sroot 		int	fmode;
97342441Smckusick 	} *uap;
97442441Smckusick 	int *retval;
97542441Smckusick {
97647540Skarels 	register struct nameidata *ndp;
97747540Skarels 	register struct ucred *cred = p->p_ucred;
97837741Smckusick 	register struct vnode *vp;
97937741Smckusick 	int error, mode, svuid, svgid;
98047540Skarels 	struct nameidata nd;
9816254Sroot 
98247540Skarels 	ndp = &nd;
98342441Smckusick 	svuid = cred->cr_uid;
98442441Smckusick 	svgid = cred->cr_groups[0];
98547540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
98647540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
98737741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
98816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
98916694Smckusick 	ndp->ni_dirp = uap->fname;
99047540Skarels 	if (error = namei(ndp, p))
99137741Smckusick 		goto out1;
99237741Smckusick 	vp = ndp->ni_vp;
99337741Smckusick 	/*
99437741Smckusick 	 * fmode == 0 means only check for exist
99537741Smckusick 	 */
99637741Smckusick 	if (uap->fmode) {
99737741Smckusick 		mode = 0;
99837741Smckusick 		if (uap->fmode & R_OK)
99937741Smckusick 			mode |= VREAD;
100037741Smckusick 		if (uap->fmode & W_OK)
100137741Smckusick 			mode |= VWRITE;
100237741Smckusick 		if (uap->fmode & X_OK)
100337741Smckusick 			mode |= VEXEC;
100439543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
100548026Smckusick 			error = VOP_ACCESS(vp, mode, cred, p);
10066254Sroot 	}
100737741Smckusick 	vput(vp);
100837741Smckusick out1:
100942441Smckusick 	cred->cr_uid = svuid;
101042441Smckusick 	cred->cr_groups[0] = svgid;
101147540Skarels 	return (error);
10126254Sroot }
10136254Sroot 
10146254Sroot /*
101549365Smckusick  * Stat system call.
101649365Smckusick  * This version follows links.
101737Sbill  */
101842441Smckusick /* ARGSUSED */
101942441Smckusick stat(p, uap, retval)
102045914Smckusick 	struct proc *p;
102142441Smckusick 	register struct args {
102242441Smckusick 		char	*fname;
102342441Smckusick 		struct stat *ub;
102442441Smckusick 	} *uap;
102542441Smckusick 	int *retval;
102637Sbill {
102747540Skarels 	register struct nameidata *ndp;
102842441Smckusick 	struct stat sb;
102942441Smckusick 	int error;
103047540Skarels 	struct nameidata nd;
103137Sbill 
103247540Skarels 	ndp = &nd;
103342441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
103442441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
103542441Smckusick 	ndp->ni_dirp = uap->fname;
103647540Skarels 	if (error = namei(ndp, p))
103747540Skarels 		return (error);
103848026Smckusick 	error = vn_stat(ndp->ni_vp, &sb, p);
103942441Smckusick 	vput(ndp->ni_vp);
104042441Smckusick 	if (error)
104147540Skarels 		return (error);
104242441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
104347540Skarels 	return (error);
104437Sbill }
104537Sbill 
104637Sbill /*
104749365Smckusick  * Lstat system call.
104849365Smckusick  * This version does not follow links.
10495992Swnj  */
105042441Smckusick /* ARGSUSED */
105142441Smckusick lstat(p, uap, retval)
105245914Smckusick 	struct proc *p;
105342441Smckusick 	register struct args {
10545992Swnj 		char	*fname;
105512756Ssam 		struct stat *ub;
105642441Smckusick 	} *uap;
105742441Smckusick 	int *retval;
105842441Smckusick {
105947540Skarels 	register struct nameidata *ndp;
106012756Ssam 	struct stat sb;
106137741Smckusick 	int error;
106247540Skarels 	struct nameidata nd;
10635992Swnj 
106447540Skarels 	ndp = &nd;
106542441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW;
106616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
106716694Smckusick 	ndp->ni_dirp = uap->fname;
106847540Skarels 	if (error = namei(ndp, p))
106947540Skarels 		return (error);
107048026Smckusick 	error = vn_stat(ndp->ni_vp, &sb, p);
107137741Smckusick 	vput(ndp->ni_vp);
107237741Smckusick 	if (error)
107347540Skarels 		return (error);
107437741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
107547540Skarels 	return (error);
10765992Swnj }
10775992Swnj 
10785992Swnj /*
107949365Smckusick  * Return target name of a symbolic link.
108037Sbill  */
108142441Smckusick /* ARGSUSED */
108242441Smckusick readlink(p, uap, retval)
108345914Smckusick 	struct proc *p;
108442441Smckusick 	register struct args {
10855992Swnj 		char	*name;
10865992Swnj 		char	*buf;
10875992Swnj 		int	count;
108842441Smckusick 	} *uap;
108942441Smckusick 	int *retval;
109042441Smckusick {
109147540Skarels 	register struct nameidata *ndp;
109237741Smckusick 	register struct vnode *vp;
109337741Smckusick 	struct iovec aiov;
109437741Smckusick 	struct uio auio;
109537741Smckusick 	int error;
109647540Skarels 	struct nameidata nd;
10975992Swnj 
109852230Sheideman 	CHECKPOINT;
109947540Skarels 	ndp = &nd;
110037741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
110116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
110216694Smckusick 	ndp->ni_dirp = uap->name;
110347540Skarels 	if (error = namei(ndp, p))
110447540Skarels 		return (error);
110537741Smckusick 	vp = ndp->ni_vp;
110637741Smckusick 	if (vp->v_type != VLNK) {
110737741Smckusick 		error = EINVAL;
11085992Swnj 		goto out;
11095992Swnj 	}
111037741Smckusick 	aiov.iov_base = uap->buf;
111137741Smckusick 	aiov.iov_len = uap->count;
111237741Smckusick 	auio.uio_iov = &aiov;
111337741Smckusick 	auio.uio_iovcnt = 1;
111437741Smckusick 	auio.uio_offset = 0;
111537741Smckusick 	auio.uio_rw = UIO_READ;
111637741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
111748026Smckusick 	auio.uio_procp = p;
111837741Smckusick 	auio.uio_resid = uap->count;
111947540Skarels 	error = VOP_READLINK(vp, &auio, p->p_ucred);
11205992Swnj out:
112137741Smckusick 	vput(vp);
112242441Smckusick 	*retval = uap->count - auio.uio_resid;
112352230Sheideman 	CHECKCHECK("readlink");
112447540Skarels 	return (error);
11255992Swnj }
11265992Swnj 
11279167Ssam /*
112838259Smckusick  * Change flags of a file given path name.
112938259Smckusick  */
113042441Smckusick /* ARGSUSED */
113142441Smckusick chflags(p, uap, retval)
113245914Smckusick 	struct proc *p;
113342441Smckusick 	register struct args {
113438259Smckusick 		char	*fname;
113538259Smckusick 		int	flags;
113642441Smckusick 	} *uap;
113742441Smckusick 	int *retval;
113842441Smckusick {
113947540Skarels 	register struct nameidata *ndp;
114038259Smckusick 	register struct vnode *vp;
114138259Smckusick 	struct vattr vattr;
114238259Smckusick 	int error;
114347540Skarels 	struct nameidata nd;
114438259Smckusick 
114547540Skarels 	ndp = &nd;
114638259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
114738259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
114838259Smckusick 	ndp->ni_dirp = uap->fname;
114947540Skarels 	if (error = namei(ndp, p))
115047540Skarels 		return (error);
115138259Smckusick 	vp = ndp->ni_vp;
115241400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
115338259Smckusick 		error = EROFS;
115438259Smckusick 		goto out;
115538259Smckusick 	}
115645785Sbostic 	VATTR_NULL(&vattr);
115745785Sbostic 	vattr.va_flags = uap->flags;
115852192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
115948026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
116038259Smckusick out:
116138259Smckusick 	vput(vp);
116247540Skarels 	return (error);
116338259Smckusick }
116438259Smckusick 
116538259Smckusick /*
116638259Smckusick  * Change flags of a file given a file descriptor.
116738259Smckusick  */
116842441Smckusick /* ARGSUSED */
116942441Smckusick fchflags(p, uap, retval)
117045914Smckusick 	struct proc *p;
117142441Smckusick 	register struct args {
117238259Smckusick 		int	fd;
117338259Smckusick 		int	flags;
117442441Smckusick 	} *uap;
117542441Smckusick 	int *retval;
117642441Smckusick {
117738259Smckusick 	struct vattr vattr;
117838259Smckusick 	struct vnode *vp;
117938259Smckusick 	struct file *fp;
118038259Smckusick 	int error;
118138259Smckusick 
118245914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
118347540Skarels 		return (error);
118438259Smckusick 	vp = (struct vnode *)fp->f_data;
118538259Smckusick 	VOP_LOCK(vp);
118641400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
118738259Smckusick 		error = EROFS;
118838259Smckusick 		goto out;
118938259Smckusick 	}
119045785Sbostic 	VATTR_NULL(&vattr);
119145785Sbostic 	vattr.va_flags = uap->flags;
119252192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
119348026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
119438259Smckusick out:
119538259Smckusick 	VOP_UNLOCK(vp);
119647540Skarels 	return (error);
119738259Smckusick }
119838259Smckusick 
119938259Smckusick /*
12009167Ssam  * Change mode of a file given path name.
12019167Ssam  */
120242441Smckusick /* ARGSUSED */
120342441Smckusick chmod(p, uap, retval)
120445914Smckusick 	struct proc *p;
120542441Smckusick 	register struct args {
12066254Sroot 		char	*fname;
12076254Sroot 		int	fmode;
120842441Smckusick 	} *uap;
120942441Smckusick 	int *retval;
121042441Smckusick {
121147540Skarels 	register struct nameidata *ndp;
121237741Smckusick 	register struct vnode *vp;
121337741Smckusick 	struct vattr vattr;
121437741Smckusick 	int error;
121547540Skarels 	struct nameidata nd;
12165992Swnj 
121747540Skarels 	ndp = &nd;
121837741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
121937741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
122037741Smckusick 	ndp->ni_dirp = uap->fname;
122147540Skarels 	if (error = namei(ndp, p))
122247540Skarels 		return (error);
122337741Smckusick 	vp = ndp->ni_vp;
122441400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
122537741Smckusick 		error = EROFS;
122637741Smckusick 		goto out;
122737741Smckusick 	}
122845785Sbostic 	VATTR_NULL(&vattr);
122945785Sbostic 	vattr.va_mode = uap->fmode & 07777;
123052192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
123148026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
123237741Smckusick out:
123337741Smckusick 	vput(vp);
123447540Skarels 	return (error);
12357701Ssam }
12367439Sroot 
12379167Ssam /*
12389167Ssam  * Change mode of a file given a file descriptor.
12399167Ssam  */
124042441Smckusick /* ARGSUSED */
124142441Smckusick fchmod(p, uap, retval)
124245914Smckusick 	struct proc *p;
124342441Smckusick 	register struct args {
12447701Ssam 		int	fd;
12457701Ssam 		int	fmode;
124642441Smckusick 	} *uap;
124742441Smckusick 	int *retval;
124842441Smckusick {
124937741Smckusick 	struct vattr vattr;
125037741Smckusick 	struct vnode *vp;
125137741Smckusick 	struct file *fp;
125237741Smckusick 	int error;
12537701Ssam 
125445914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
125547540Skarels 		return (error);
125637741Smckusick 	vp = (struct vnode *)fp->f_data;
125737741Smckusick 	VOP_LOCK(vp);
125841400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
125937741Smckusick 		error = EROFS;
126037741Smckusick 		goto out;
12617439Sroot 	}
126245785Sbostic 	VATTR_NULL(&vattr);
126345785Sbostic 	vattr.va_mode = uap->fmode & 07777;
126452192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
126548026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
126637741Smckusick out:
126737741Smckusick 	VOP_UNLOCK(vp);
126847540Skarels 	return (error);
12695992Swnj }
12705992Swnj 
12719167Ssam /*
12729167Ssam  * Set ownership given a path name.
12739167Ssam  */
127442441Smckusick /* ARGSUSED */
127542441Smckusick chown(p, uap, retval)
127645914Smckusick 	struct proc *p;
127742441Smckusick 	register struct args {
12786254Sroot 		char	*fname;
12796254Sroot 		int	uid;
12806254Sroot 		int	gid;
128142441Smckusick 	} *uap;
128242441Smckusick 	int *retval;
128342441Smckusick {
128447540Skarels 	register struct nameidata *ndp;
128537741Smckusick 	register struct vnode *vp;
128637741Smckusick 	struct vattr vattr;
128737741Smckusick 	int error;
128847540Skarels 	struct nameidata nd;
128937Sbill 
129047540Skarels 	ndp = &nd;
129137741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
129236614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
129336614Sbostic 	ndp->ni_dirp = uap->fname;
129447540Skarels 	if (error = namei(ndp, p))
129547540Skarels 		return (error);
129637741Smckusick 	vp = ndp->ni_vp;
129741400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
129837741Smckusick 		error = EROFS;
129937741Smckusick 		goto out;
130037741Smckusick 	}
130145785Sbostic 	VATTR_NULL(&vattr);
130245785Sbostic 	vattr.va_uid = uap->uid;
130345785Sbostic 	vattr.va_gid = uap->gid;
130452192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
130548026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
130637741Smckusick out:
130737741Smckusick 	vput(vp);
130847540Skarels 	return (error);
13097701Ssam }
13107439Sroot 
13119167Ssam /*
13129167Ssam  * Set ownership given a file descriptor.
13139167Ssam  */
131442441Smckusick /* ARGSUSED */
131542441Smckusick fchown(p, uap, retval)
131645914Smckusick 	struct proc *p;
131742441Smckusick 	register struct args {
13187701Ssam 		int	fd;
13197701Ssam 		int	uid;
13207701Ssam 		int	gid;
132142441Smckusick 	} *uap;
132242441Smckusick 	int *retval;
132342441Smckusick {
132437741Smckusick 	struct vattr vattr;
132537741Smckusick 	struct vnode *vp;
132637741Smckusick 	struct file *fp;
132737741Smckusick 	int error;
13287701Ssam 
132945914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
133047540Skarels 		return (error);
133137741Smckusick 	vp = (struct vnode *)fp->f_data;
133237741Smckusick 	VOP_LOCK(vp);
133341400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
133437741Smckusick 		error = EROFS;
133537741Smckusick 		goto out;
133637741Smckusick 	}
133745785Sbostic 	VATTR_NULL(&vattr);
133845785Sbostic 	vattr.va_uid = uap->uid;
133945785Sbostic 	vattr.va_gid = uap->gid;
134052192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
134148026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
134237741Smckusick out:
134337741Smckusick 	VOP_UNLOCK(vp);
134447540Skarels 	return (error);
13457701Ssam }
13467701Ssam 
134742441Smckusick /*
134842441Smckusick  * Set the access and modification times of a file.
134942441Smckusick  */
135042441Smckusick /* ARGSUSED */
135142441Smckusick utimes(p, uap, retval)
135245914Smckusick 	struct proc *p;
135342441Smckusick 	register struct args {
135411811Ssam 		char	*fname;
135511811Ssam 		struct	timeval *tptr;
135642441Smckusick 	} *uap;
135742441Smckusick 	int *retval;
135842441Smckusick {
135947540Skarels 	register struct nameidata *ndp;
136037741Smckusick 	register struct vnode *vp;
136111811Ssam 	struct timeval tv[2];
136237741Smckusick 	struct vattr vattr;
136337741Smckusick 	int error;
136447540Skarels 	struct nameidata nd;
136511811Ssam 
136637741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
136747540Skarels 		return (error);
136847540Skarels 	ndp = &nd;
136937741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
137037741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
137137741Smckusick 	ndp->ni_dirp = uap->fname;
137247540Skarels 	if (error = namei(ndp, p))
137347540Skarels 		return (error);
137437741Smckusick 	vp = ndp->ni_vp;
137541400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
137637741Smckusick 		error = EROFS;
137737741Smckusick 		goto out;
137821015Smckusick 	}
137945785Sbostic 	VATTR_NULL(&vattr);
138045785Sbostic 	vattr.va_atime = tv[0];
138145785Sbostic 	vattr.va_mtime = tv[1];
138252192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
138348026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
138437741Smckusick out:
138537741Smckusick 	vput(vp);
138647540Skarels 	return (error);
138711811Ssam }
138811811Ssam 
13899167Ssam /*
13909167Ssam  * Truncate a file given its path name.
13919167Ssam  */
139242441Smckusick /* ARGSUSED */
139342441Smckusick truncate(p, uap, retval)
139445914Smckusick 	struct proc *p;
139542441Smckusick 	register struct args {
13967701Ssam 		char	*fname;
139726473Skarels 		off_t	length;
139842441Smckusick 	} *uap;
139942441Smckusick 	int *retval;
140042441Smckusick {
140147540Skarels 	register struct nameidata *ndp;
140237741Smckusick 	register struct vnode *vp;
140337741Smckusick 	struct vattr vattr;
140437741Smckusick 	int error;
140547540Skarels 	struct nameidata nd;
14067701Ssam 
140747540Skarels 	ndp = &nd;
140837741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
140916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
141016694Smckusick 	ndp->ni_dirp = uap->fname;
141147540Skarels 	if (error = namei(ndp, p))
141247540Skarels 		return (error);
141337741Smckusick 	vp = ndp->ni_vp;
141437741Smckusick 	if (vp->v_type == VDIR) {
141537741Smckusick 		error = EISDIR;
141637741Smckusick 		goto out;
14177701Ssam 	}
141838399Smckusick 	if ((error = vn_writechk(vp)) ||
141948026Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)))
142037741Smckusick 		goto out;
142145785Sbostic 	VATTR_NULL(&vattr);
142245785Sbostic 	vattr.va_size = uap->length;
142352192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
142448026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
142537741Smckusick out:
142637741Smckusick 	vput(vp);
142747540Skarels 	return (error);
14287701Ssam }
14297701Ssam 
14309167Ssam /*
14319167Ssam  * Truncate a file given a file descriptor.
14329167Ssam  */
143342441Smckusick /* ARGSUSED */
143442441Smckusick ftruncate(p, uap, retval)
143545914Smckusick 	struct proc *p;
143642441Smckusick 	register struct args {
14377701Ssam 		int	fd;
143826473Skarels 		off_t	length;
143942441Smckusick 	} *uap;
144042441Smckusick 	int *retval;
144142441Smckusick {
144237741Smckusick 	struct vattr vattr;
144337741Smckusick 	struct vnode *vp;
14447701Ssam 	struct file *fp;
144537741Smckusick 	int error;
14467701Ssam 
144745914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
144847540Skarels 		return (error);
144937741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
145047540Skarels 		return (EINVAL);
145137741Smckusick 	vp = (struct vnode *)fp->f_data;
145237741Smckusick 	VOP_LOCK(vp);
145337741Smckusick 	if (vp->v_type == VDIR) {
145437741Smckusick 		error = EISDIR;
145537741Smckusick 		goto out;
14567701Ssam 	}
145738399Smckusick 	if (error = vn_writechk(vp))
145837741Smckusick 		goto out;
145945785Sbostic 	VATTR_NULL(&vattr);
146045785Sbostic 	vattr.va_size = uap->length;
146152192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
146248026Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
146337741Smckusick out:
146437741Smckusick 	VOP_UNLOCK(vp);
146547540Skarels 	return (error);
14667701Ssam }
14677701Ssam 
14689167Ssam /*
14699167Ssam  * Synch an open file.
14709167Ssam  */
147142441Smckusick /* ARGSUSED */
147242441Smckusick fsync(p, uap, retval)
147345914Smckusick 	struct proc *p;
147442441Smckusick 	struct args {
147542441Smckusick 		int	fd;
147642441Smckusick 	} *uap;
147742441Smckusick 	int *retval;
14789167Ssam {
147939592Smckusick 	register struct vnode *vp;
14809167Ssam 	struct file *fp;
148137741Smckusick 	int error;
14829167Ssam 
148345914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
148447540Skarels 		return (error);
148539592Smckusick 	vp = (struct vnode *)fp->f_data;
148639592Smckusick 	VOP_LOCK(vp);
148748026Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT, p);
148839592Smckusick 	VOP_UNLOCK(vp);
148947540Skarels 	return (error);
14909167Ssam }
14919167Ssam 
14929167Ssam /*
14939167Ssam  * Rename system call.
14949167Ssam  *
14959167Ssam  * Source and destination must either both be directories, or both
14969167Ssam  * not be directories.  If target is a directory, it must be empty.
14979167Ssam  */
149842441Smckusick /* ARGSUSED */
149942441Smckusick rename(p, uap, retval)
150045914Smckusick 	struct proc *p;
150142441Smckusick 	register struct args {
15027701Ssam 		char	*from;
15037701Ssam 		char	*to;
150442441Smckusick 	} *uap;
150542441Smckusick 	int *retval;
150642441Smckusick {
150737741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
150849735Smckusick 	struct nameidata fromnd, tond;
150937741Smckusick 	int error;
15107701Ssam 
151152230Sheideman 	CHECKPOINT;
151249735Smckusick 	fromnd.ni_nameiop = DELETE | WANTPARENT | SAVESTART;
151349735Smckusick 	fromnd.ni_segflg = UIO_USERSPACE;
151449735Smckusick 	fromnd.ni_dirp = uap->from;
151549735Smckusick 	if (error = namei(&fromnd, p))
151647540Skarels 		return (error);
151749735Smckusick 	fvp = fromnd.ni_vp;
151849735Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
151937741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
152037741Smckusick 	tond.ni_dirp = uap->to;
152147540Skarels 	if (error = namei(&tond, p)) {
152252230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
152349735Smckusick 		vrele(fromnd.ni_dvp);
152442465Smckusick 		vrele(fvp);
152542465Smckusick 		goto out1;
152642465Smckusick 	}
152737741Smckusick 	tdvp = tond.ni_dvp;
152837741Smckusick 	tvp = tond.ni_vp;
152937741Smckusick 	if (tvp != NULL) {
153037741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
153139242Sbostic 			error = ENOTDIR;
153237741Smckusick 			goto out;
153337741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
153439242Sbostic 			error = EISDIR;
153537741Smckusick 			goto out;
15369167Ssam 		}
153745240Smckusick 		if (fvp->v_mount != tvp->v_mount) {
153845240Smckusick 			error = EXDEV;
153945240Smckusick 			goto out;
154045240Smckusick 		}
15419167Ssam 	}
154237741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
154337741Smckusick 		error = EXDEV;
15449167Ssam 		goto out;
154510051Ssam 	}
154639286Smckusick 	if (fvp == tdvp)
154737741Smckusick 		error = EINVAL;
154839286Smckusick 	/*
154949735Smckusick 	 * If source is the same as the destination (that is the
155049735Smckusick 	 * same inode number with the same name in the same directory),
155139286Smckusick 	 * then there is nothing to do.
155239286Smckusick 	 */
155349735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
155449735Smckusick 	    fromnd.ni_namelen == tond.ni_namelen &&
155549735Smckusick 	    !bcmp(fromnd.ni_ptr, tond.ni_ptr, fromnd.ni_namelen))
155639286Smckusick 		error = -1;
155737741Smckusick out:
155842465Smckusick 	if (!error) {
155952192Smckusick 		LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE);
156052192Smckusick 		if (fromnd.ni_dvp != tdvp)
156152192Smckusick 			LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
156252192Smckusick 		if (tvp)
156352192Smckusick 			LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE);
156452230Sheideman 		if (fromnd.ni_startdir != fromnd.ni_dvp ||
156552230Sheideman 		    tond.ni_startdir != tond.ni_dvp)   /* NEEDSWORK: debug */
156652230Sheideman 			printf ("rename: f.startdir=%x, dvp=%x; t.startdir=%x, dvp=%x\n", fromnd.ni_startdir, fromnd.ni_dvp, tond.ni_startdir, tond.ni_dvp);
156752230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
156852230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
156952230Sheideman 		if (fromnd.ni_startdir != fromnd.ni_dvp ||
157052230Sheideman 		    tond.ni_startdir != tond.ni_dvp)   /* NEEDSWORK: debug */
157152230Sheideman 			printf ("rename: f.startdir=%x, dvp=%x; t.startdir=%x, dvp=%x\n", fromnd.ni_startdir, fromnd.ni_dvp, tond.ni_startdir, tond.ni_dvp);
157242465Smckusick 	} else {
157352230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
157443344Smckusick 		if (tdvp == tvp)
157543344Smckusick 			vrele(tdvp);
157643344Smckusick 		else
157743344Smckusick 			vput(tdvp);
157842465Smckusick 		if (tvp)
157942465Smckusick 			vput(tvp);
158052230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
158149735Smckusick 		vrele(fromnd.ni_dvp);
158242465Smckusick 		vrele(fvp);
15839167Ssam 	}
158449735Smckusick 	vrele(tond.ni_startdir);
158549735Smckusick 	FREE(tond.ni_pnbuf, M_NAMEI);
158637741Smckusick out1:
158749735Smckusick 	vrele(fromnd.ni_startdir);
158849735Smckusick 	FREE(fromnd.ni_pnbuf, M_NAMEI);
158952230Sheideman 	CHECKCHECK("rename");
159039286Smckusick 	if (error == -1)
159147540Skarels 		return (0);
159247540Skarels 	return (error);
15937701Ssam }
15947701Ssam 
15957535Sroot /*
159649365Smckusick  * Mkdir system call.
159712756Ssam  */
159842441Smckusick /* ARGSUSED */
159942441Smckusick mkdir(p, uap, retval)
160045914Smckusick 	struct proc *p;
160142441Smckusick 	register struct args {
160212756Ssam 		char	*name;
160312756Ssam 		int	dmode;
160442441Smckusick 	} *uap;
160542441Smckusick 	int *retval;
160642441Smckusick {
160747540Skarels 	register struct nameidata *ndp;
160837741Smckusick 	register struct vnode *vp;
160937741Smckusick 	struct vattr vattr;
161037741Smckusick 	int error;
161147540Skarels 	struct nameidata nd;
161212756Ssam 
161352230Sheideman 	CHECKPOINT;
161447540Skarels 	ndp = &nd;
161537741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
161616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
161716694Smckusick 	ndp->ni_dirp = uap->name;
161847540Skarels 	if (error = namei(ndp, p))
161947540Skarels 		return (error);
162037741Smckusick 	vp = ndp->ni_vp;
162137741Smckusick 	if (vp != NULL) {
162252230Sheideman 		VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
162343344Smckusick 		if (ndp->ni_dvp == vp)
162443344Smckusick 			vrele(ndp->ni_dvp);
162543344Smckusick 		else
162643344Smckusick 			vput(ndp->ni_dvp);
162742465Smckusick 		vrele(vp);
162852230Sheideman 		CHECKCHECK("mkdir1");
162947540Skarels 		return (EEXIST);
163012756Ssam 	}
163141362Smckusick 	VATTR_NULL(&vattr);
163237741Smckusick 	vattr.va_type = VDIR;
163345914Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask;
163452192Smckusick 	LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE);
163552230Sheideman 	error = VOP_MKDIR(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &vattr);
163638145Smckusick 	if (!error)
163738145Smckusick 		vput(ndp->ni_vp);
163852230Sheideman 	CHECKCHECK("mkdir2");
163947540Skarels 	return (error);
164012756Ssam }
164112756Ssam 
164212756Ssam /*
164312756Ssam  * Rmdir system call.
164412756Ssam  */
164542441Smckusick /* ARGSUSED */
164642441Smckusick rmdir(p, uap, retval)
164745914Smckusick 	struct proc *p;
164842441Smckusick 	struct args {
164942441Smckusick 		char	*name;
165042441Smckusick 	} *uap;
165142441Smckusick 	int *retval;
165212756Ssam {
165347540Skarels 	register struct nameidata *ndp;
165437741Smckusick 	register struct vnode *vp;
165537741Smckusick 	int error;
165647540Skarels 	struct nameidata nd;
165712756Ssam 
165852230Sheideman 	CHECKPOINT;
165947540Skarels 	ndp = &nd;
166037741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
166116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
166216694Smckusick 	ndp->ni_dirp = uap->name;
166347540Skarels 	if (error = namei(ndp, p))
166447540Skarels 		return (error);
166537741Smckusick 	vp = ndp->ni_vp;
166637741Smckusick 	if (vp->v_type != VDIR) {
166737741Smckusick 		error = ENOTDIR;
166812756Ssam 		goto out;
166912756Ssam 	}
167012756Ssam 	/*
167137741Smckusick 	 * No rmdir "." please.
167212756Ssam 	 */
167337741Smckusick 	if (ndp->ni_dvp == vp) {
167437741Smckusick 		error = EINVAL;
167512756Ssam 		goto out;
167612756Ssam 	}
167712756Ssam 	/*
167849365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
167912756Ssam 	 */
168037741Smckusick 	if (vp->v_flag & VROOT)
168137741Smckusick 		error = EBUSY;
168212756Ssam out:
168342465Smckusick 	if (!error) {
168452192Smckusick 		LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE);
168552192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
168652230Sheideman 		error = VOP_RMDIR(ndp->ni_dvp, ndp->ni_vp, &ndp->ni_cnd);
168742465Smckusick 	} else {
168852230Sheideman 		VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
168943344Smckusick 		if (ndp->ni_dvp == vp)
169043344Smckusick 			vrele(ndp->ni_dvp);
169143344Smckusick 		else
169243344Smckusick 			vput(ndp->ni_dvp);
169342465Smckusick 		vput(vp);
169442465Smckusick 	}
169552230Sheideman 	CHECKCHECK("rmdir");
169647540Skarels 	return (error);
169712756Ssam }
169812756Ssam 
169937741Smckusick /*
170049365Smckusick  * Read a block of directory entries in a file system independent format.
170137741Smckusick  */
170242441Smckusick getdirentries(p, uap, retval)
170345914Smckusick 	struct proc *p;
170442441Smckusick 	register struct args {
170537741Smckusick 		int	fd;
170637741Smckusick 		char	*buf;
170737741Smckusick 		unsigned count;
170837741Smckusick 		long	*basep;
170942441Smckusick 	} *uap;
171042441Smckusick 	int *retval;
171142441Smckusick {
171239592Smckusick 	register struct vnode *vp;
171316540Ssam 	struct file *fp;
171437741Smckusick 	struct uio auio;
171537741Smckusick 	struct iovec aiov;
171638129Smckusick 	off_t off;
171740321Smckusick 	int error, eofflag;
171812756Ssam 
171945914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
172047540Skarels 		return (error);
172137741Smckusick 	if ((fp->f_flag & FREAD) == 0)
172247540Skarels 		return (EBADF);
172339592Smckusick 	vp = (struct vnode *)fp->f_data;
172439592Smckusick 	if (vp->v_type != VDIR)
172547540Skarels 		return (EINVAL);
172637741Smckusick 	aiov.iov_base = uap->buf;
172737741Smckusick 	aiov.iov_len = uap->count;
172837741Smckusick 	auio.uio_iov = &aiov;
172937741Smckusick 	auio.uio_iovcnt = 1;
173037741Smckusick 	auio.uio_rw = UIO_READ;
173137741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
173248026Smckusick 	auio.uio_procp = p;
173337741Smckusick 	auio.uio_resid = uap->count;
173439592Smckusick 	VOP_LOCK(vp);
173539592Smckusick 	auio.uio_offset = off = fp->f_offset;
173640321Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
173739592Smckusick 	fp->f_offset = auio.uio_offset;
173839592Smckusick 	VOP_UNLOCK(vp);
173939592Smckusick 	if (error)
174047540Skarels 		return (error);
174139592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
174242441Smckusick 	*retval = uap->count - auio.uio_resid;
174347540Skarels 	return (error);
174412756Ssam }
174512756Ssam 
174612756Ssam /*
174749365Smckusick  * Set the mode mask for creation of filesystem nodes.
174812756Ssam  */
174942441Smckusick mode_t
175042441Smckusick umask(p, uap, retval)
175145914Smckusick 	struct proc *p;
175242441Smckusick 	struct args {
175342441Smckusick 		int	mask;
175442441Smckusick 	} *uap;
175542441Smckusick 	int *retval;
175612756Ssam {
175745914Smckusick 	register struct filedesc *fdp = p->p_fd;
175812756Ssam 
175945914Smckusick 	*retval = fdp->fd_cmask;
176045914Smckusick 	fdp->fd_cmask = uap->mask & 07777;
176147540Skarels 	return (0);
176212756Ssam }
176337741Smckusick 
176439566Smarc /*
176539566Smarc  * Void all references to file by ripping underlying filesystem
176639566Smarc  * away from vnode.
176739566Smarc  */
176842441Smckusick /* ARGSUSED */
176942441Smckusick revoke(p, uap, retval)
177045914Smckusick 	struct proc *p;
177142441Smckusick 	register struct args {
177239566Smarc 		char	*fname;
177342441Smckusick 	} *uap;
177442441Smckusick 	int *retval;
177542441Smckusick {
177647540Skarels 	register struct nameidata *ndp;
177739566Smarc 	register struct vnode *vp;
177839566Smarc 	struct vattr vattr;
177939566Smarc 	int error;
178047540Skarels 	struct nameidata nd;
178139566Smarc 
178247540Skarels 	ndp = &nd;
178339566Smarc 	ndp->ni_nameiop = LOOKUP | FOLLOW;
178439566Smarc 	ndp->ni_segflg = UIO_USERSPACE;
178539566Smarc 	ndp->ni_dirp = uap->fname;
178647540Skarels 	if (error = namei(ndp, p))
178747540Skarels 		return (error);
178839566Smarc 	vp = ndp->ni_vp;
178939566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
179039566Smarc 		error = EINVAL;
179139566Smarc 		goto out;
179239566Smarc 	}
179348026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
179439566Smarc 		goto out;
179547540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
179647540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
179739566Smarc 		goto out;
179839805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
179939632Smckusick 		vgoneall(vp);
180039566Smarc out:
180139566Smarc 	vrele(vp);
180247540Skarels 	return (error);
180339566Smarc }
180439566Smarc 
180549365Smckusick /*
180649365Smckusick  * Convert a user file descriptor to a kernel file entry.
180749365Smckusick  */
180845914Smckusick getvnode(fdp, fdes, fpp)
180945914Smckusick 	struct filedesc *fdp;
181037741Smckusick 	struct file **fpp;
181137741Smckusick 	int fdes;
181237741Smckusick {
181337741Smckusick 	struct file *fp;
181437741Smckusick 
181547540Skarels 	if ((unsigned)fdes >= fdp->fd_nfiles ||
181647688Skarels 	    (fp = fdp->fd_ofiles[fdes]) == NULL)
181737741Smckusick 		return (EBADF);
181837741Smckusick 	if (fp->f_type != DTYPE_VNODE)
181937741Smckusick 		return (EINVAL);
182037741Smckusick 	*fpp = fp;
182137741Smckusick 	return (0);
182237741Smckusick }
1823