xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 52230)
123405Smckusick /*
237741Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337741Smckusick  * All rights reserved.
423405Smckusick  *
544459Sbostic  * %sccs.include.redist.c%
637741Smckusick  *
7*52230Sheideman  *	@(#)vfs_syscalls.c	7.76 (Berkeley) 01/22/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 
23*52230Sheideman /* NEEDSWORK: debugging */
24*52230Sheideman #define CURCOUNT (curproc?curproc->p_spare[2]:0)
25*52230Sheideman #define CHECKPOINT int oldrefcount=CURCOUNT;
26*52230Sheideman #define CHECKCHECK(F) if (oldrefcount!=CURCOUNT) { printf("REFCOUNT: %s, old=%d, new=%d\n", (F), oldrefcount, CURCOUNT); }
27*52230Sheideman 
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);
25337741Smckusick 		free((caddr_t)mp, M_MOUNT);
25437741Smckusick 	}
25539356Smckusick 	return (error);
2566254Sroot }
2576254Sroot 
2589167Ssam /*
25937741Smckusick  * Sync system call.
26037741Smckusick  * Sync each mounted filesystem.
2619167Ssam  */
26239491Smckusick /* ARGSUSED */
26342441Smckusick sync(p, uap, retval)
26445914Smckusick 	struct proc *p;
26547540Skarels 	void *uap;
26642441Smckusick 	int *retval;
2676254Sroot {
26837741Smckusick 	register struct mount *mp;
26941298Smckusick 	struct mount *omp;
27037741Smckusick 
27137741Smckusick 	mp = rootfs;
27237741Smckusick 	do {
27340343Smckusick 		/*
27440343Smckusick 		 * The lock check below is to avoid races with mount
27540343Smckusick 		 * and unmount.
27640343Smckusick 		 */
27741400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
27841298Smckusick 		    !vfs_busy(mp)) {
27937741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
28041298Smckusick 			omp = mp;
28141400Smckusick 			mp = mp->mnt_next;
28241298Smckusick 			vfs_unbusy(omp);
28341298Smckusick 		} else
28441400Smckusick 			mp = mp->mnt_next;
28537741Smckusick 	} while (mp != rootfs);
28647688Skarels 	return (0);
28737741Smckusick }
28837741Smckusick 
28937741Smckusick /*
29049365Smckusick  * Operate on filesystem quotas.
29141298Smckusick  */
29242441Smckusick /* ARGSUSED */
29342441Smckusick quotactl(p, uap, retval)
29445914Smckusick 	struct proc *p;
29542441Smckusick 	register struct args {
29641298Smckusick 		char *path;
29741298Smckusick 		int cmd;
29841298Smckusick 		int uid;
29941298Smckusick 		caddr_t arg;
30042441Smckusick 	} *uap;
30142441Smckusick 	int *retval;
30242441Smckusick {
30341298Smckusick 	register struct mount *mp;
30447540Skarels 	register struct nameidata *ndp;
30541298Smckusick 	int error;
30647540Skarels 	struct nameidata nd;
30741298Smckusick 
30847540Skarels 	ndp = &nd;
30941298Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
31041298Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
31141298Smckusick 	ndp->ni_dirp = uap->path;
31247540Skarels 	if (error = namei(ndp, p))
31347540Skarels 		return (error);
31441298Smckusick 	mp = ndp->ni_vp->v_mount;
31541298Smckusick 	vrele(ndp->ni_vp);
31648026Smckusick 	return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p));
31741298Smckusick }
31841298Smckusick 
31941298Smckusick /*
32049365Smckusick  * Get filesystem statistics.
32137741Smckusick  */
32242441Smckusick /* ARGSUSED */
32342441Smckusick statfs(p, uap, retval)
32445914Smckusick 	struct proc *p;
32542441Smckusick 	register struct args {
32637741Smckusick 		char *path;
32737741Smckusick 		struct statfs *buf;
32842441Smckusick 	} *uap;
32942441Smckusick 	int *retval;
33042441Smckusick {
33139464Smckusick 	register struct mount *mp;
33247540Skarels 	register struct nameidata *ndp;
33340343Smckusick 	register struct statfs *sp;
33437741Smckusick 	int error;
33547540Skarels 	struct nameidata nd;
33637741Smckusick 
33747540Skarels 	ndp = &nd;
33839544Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
33937741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
34037741Smckusick 	ndp->ni_dirp = uap->path;
34147540Skarels 	if (error = namei(ndp, p))
34247540Skarels 		return (error);
34339544Smckusick 	mp = ndp->ni_vp->v_mount;
34441400Smckusick 	sp = &mp->mnt_stat;
34539544Smckusick 	vrele(ndp->ni_vp);
34648026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
34747540Skarels 		return (error);
34841400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
34947540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
35037741Smckusick }
35137741Smckusick 
35242441Smckusick /*
35349365Smckusick  * Get filesystem statistics.
35442441Smckusick  */
35542441Smckusick /* ARGSUSED */
35642441Smckusick fstatfs(p, uap, retval)
35745914Smckusick 	struct proc *p;
35842441Smckusick 	register struct args {
35937741Smckusick 		int fd;
36037741Smckusick 		struct statfs *buf;
36142441Smckusick 	} *uap;
36242441Smckusick 	int *retval;
36342441Smckusick {
36437741Smckusick 	struct file *fp;
36539464Smckusick 	struct mount *mp;
36640343Smckusick 	register struct statfs *sp;
36737741Smckusick 	int error;
36837741Smckusick 
36945914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
37047540Skarels 		return (error);
37139464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
37241400Smckusick 	sp = &mp->mnt_stat;
37348026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
37447540Skarels 		return (error);
37541400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
37647540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
37737741Smckusick }
37837741Smckusick 
37937741Smckusick /*
38049365Smckusick  * Get statistics on all filesystems.
38138270Smckusick  */
38242441Smckusick getfsstat(p, uap, retval)
38345914Smckusick 	struct proc *p;
38442441Smckusick 	register struct args {
38538270Smckusick 		struct statfs *buf;
38638270Smckusick 		long bufsize;
38740343Smckusick 		int flags;
38842441Smckusick 	} *uap;
38942441Smckusick 	int *retval;
39042441Smckusick {
39138270Smckusick 	register struct mount *mp;
39240343Smckusick 	register struct statfs *sp;
39339606Smckusick 	caddr_t sfsp;
39438270Smckusick 	long count, maxcount, error;
39538270Smckusick 
39638270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
39739606Smckusick 	sfsp = (caddr_t)uap->buf;
39838270Smckusick 	mp = rootfs;
39938270Smckusick 	count = 0;
40038270Smckusick 	do {
40141400Smckusick 		if (sfsp && count < maxcount &&
40241400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
40341400Smckusick 			sp = &mp->mnt_stat;
40440343Smckusick 			/*
40540343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
40640343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
40740343Smckusick 			 */
40840343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
40940343Smckusick 			    (uap->flags & MNT_WAIT)) &&
41048026Smckusick 			    (error = VFS_STATFS(mp, sp, p))) {
41141400Smckusick 				mp = mp->mnt_prev;
41239607Smckusick 				continue;
41339607Smckusick 			}
41441400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
41540343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
41647540Skarels 				return (error);
41740343Smckusick 			sfsp += sizeof(*sp);
41838270Smckusick 		}
41939606Smckusick 		count++;
42041400Smckusick 		mp = mp->mnt_prev;
42138270Smckusick 	} while (mp != rootfs);
42238270Smckusick 	if (sfsp && count > maxcount)
42342441Smckusick 		*retval = maxcount;
42438270Smckusick 	else
42542441Smckusick 		*retval = count;
42647540Skarels 	return (0);
42738270Smckusick }
42838270Smckusick 
42938270Smckusick /*
43038259Smckusick  * Change current working directory to a given file descriptor.
43138259Smckusick  */
43242441Smckusick /* ARGSUSED */
43342441Smckusick fchdir(p, uap, retval)
43445914Smckusick 	struct proc *p;
43542441Smckusick 	struct args {
43642441Smckusick 		int	fd;
43742441Smckusick 	} *uap;
43842441Smckusick 	int *retval;
43938259Smckusick {
44045914Smckusick 	register struct filedesc *fdp = p->p_fd;
44138259Smckusick 	register struct vnode *vp;
44238259Smckusick 	struct file *fp;
44338259Smckusick 	int error;
44438259Smckusick 
44545914Smckusick 	if (error = getvnode(fdp, uap->fd, &fp))
44647540Skarels 		return (error);
44738259Smckusick 	vp = (struct vnode *)fp->f_data;
44838259Smckusick 	VOP_LOCK(vp);
44938259Smckusick 	if (vp->v_type != VDIR)
45038259Smckusick 		error = ENOTDIR;
45138259Smckusick 	else
45248026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
45338259Smckusick 	VOP_UNLOCK(vp);
45439860Smckusick 	if (error)
45547540Skarels 		return (error);
45639860Smckusick 	VREF(vp);
45745914Smckusick 	vrele(fdp->fd_cdir);
45845914Smckusick 	fdp->fd_cdir = vp;
45947540Skarels 	return (0);
46038259Smckusick }
46138259Smckusick 
46238259Smckusick /*
46337741Smckusick  * Change current working directory (``.'').
46437741Smckusick  */
46542441Smckusick /* ARGSUSED */
46642441Smckusick chdir(p, uap, retval)
46745914Smckusick 	struct proc *p;
46842441Smckusick 	struct args {
46942441Smckusick 		char	*fname;
47042441Smckusick 	} *uap;
47142441Smckusick 	int *retval;
47237741Smckusick {
47347540Skarels 	register struct nameidata *ndp;
47445914Smckusick 	register struct filedesc *fdp = p->p_fd;
47537741Smckusick 	int error;
47647540Skarels 	struct nameidata nd;
4776254Sroot 
47847540Skarels 	ndp = &nd;
47937741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
48016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
48116694Smckusick 	ndp->ni_dirp = uap->fname;
48247540Skarels 	if (error = chdirec(ndp, p))
48347540Skarels 		return (error);
48445914Smckusick 	vrele(fdp->fd_cdir);
48545914Smckusick 	fdp->fd_cdir = ndp->ni_vp;
48647540Skarels 	return (0);
48737741Smckusick }
4886254Sroot 
48937741Smckusick /*
49037741Smckusick  * Change notion of root (``/'') directory.
49137741Smckusick  */
49242441Smckusick /* ARGSUSED */
49342441Smckusick chroot(p, uap, retval)
49445914Smckusick 	struct proc *p;
49542441Smckusick 	struct args {
49642441Smckusick 		char	*fname;
49742441Smckusick 	} *uap;
49842441Smckusick 	int *retval;
49937741Smckusick {
50047540Skarels 	register struct nameidata *ndp;
50145914Smckusick 	register struct filedesc *fdp = p->p_fd;
50237741Smckusick 	int error;
50347540Skarels 	struct nameidata nd;
50437741Smckusick 
50547540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
50647540Skarels 		return (error);
50747540Skarels 	ndp = &nd;
50837741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
50937741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
51037741Smckusick 	ndp->ni_dirp = uap->fname;
51147540Skarels 	if (error = chdirec(ndp, p))
51247540Skarels 		return (error);
51345914Smckusick 	if (fdp->fd_rdir != NULL)
51445914Smckusick 		vrele(fdp->fd_rdir);
51545914Smckusick 	fdp->fd_rdir = ndp->ni_vp;
51647540Skarels 	return (0);
5176254Sroot }
5186254Sroot 
51937Sbill /*
52037741Smckusick  * Common routine for chroot and chdir.
52137741Smckusick  */
52247540Skarels chdirec(ndp, p)
52347540Skarels 	struct nameidata *ndp;
52447540Skarels 	struct proc *p;
52537741Smckusick {
52637741Smckusick 	struct vnode *vp;
52737741Smckusick 	int error;
52837741Smckusick 
52947540Skarels 	if (error = namei(ndp, p))
53037741Smckusick 		return (error);
53137741Smckusick 	vp = ndp->ni_vp;
53237741Smckusick 	if (vp->v_type != VDIR)
53337741Smckusick 		error = ENOTDIR;
53437741Smckusick 	else
53548026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
53637741Smckusick 	VOP_UNLOCK(vp);
53737741Smckusick 	if (error)
53837741Smckusick 		vrele(vp);
53937741Smckusick 	return (error);
54037741Smckusick }
54137741Smckusick 
54237741Smckusick /*
5436254Sroot  * Open system call.
54442441Smckusick  * Check permissions, allocate an open file structure,
54542441Smckusick  * and call the device open routine if any.
5466254Sroot  */
54742441Smckusick open(p, uap, retval)
54845914Smckusick 	struct proc *p;
54942441Smckusick 	register struct args {
5506254Sroot 		char	*fname;
5517701Ssam 		int	mode;
55212756Ssam 		int	crtmode;
55342441Smckusick 	} *uap;
55442441Smckusick 	int *retval;
5556254Sroot {
55647540Skarels 	struct nameidata *ndp;
55745914Smckusick 	register struct filedesc *fdp = p->p_fd;
55842441Smckusick 	register struct file *fp;
55950111Smckusick 	register struct vnode *vp;
56037741Smckusick 	int fmode, cmode;
56137741Smckusick 	struct file *nfp;
56249945Smckusick 	int type, indx, error;
56349945Smckusick 	struct flock lf;
56447540Skarels 	struct nameidata nd;
56537741Smckusick 	extern struct fileops vnops;
5666254Sroot 
56745914Smckusick 	if (error = falloc(p, &nfp, &indx))
56847540Skarels 		return (error);
56937741Smckusick 	fp = nfp;
57046553Skarels 	fmode = FFLAGS(uap->mode);
57145914Smckusick 	cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX;
57247540Skarels 	ndp = &nd;
57342441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
57442441Smckusick 	ndp->ni_dirp = uap->fname;
57545202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
57647540Skarels 	if (error = vn_open(ndp, p, fmode, cmode)) {
57749980Smckusick 		ffree(fp);
57843405Smckusick 		if (error == ENODEV &&		/* XXX from fdopen */
57945202Smckusick 		    p->p_dupfd >= 0 &&
58045914Smckusick 		    (error = dupfdopen(fdp, indx, p->p_dupfd, fmode)) == 0) {
58142441Smckusick 			*retval = indx;
58247540Skarels 			return (0);
58342441Smckusick 		}
58440884Smckusick 		if (error == ERESTART)
58540884Smckusick 			error = EINTR;
58647688Skarels 		fdp->fd_ofiles[indx] = NULL;
58747540Skarels 		return (error);
58812756Ssam 	}
58950111Smckusick 	vp = ndp->ni_vp;
59049949Smckusick 	fp->f_flag = fmode & FMASK;
59149945Smckusick 	if (fmode & (O_EXLOCK | O_SHLOCK)) {
59249945Smckusick 		lf.l_whence = SEEK_SET;
59349945Smckusick 		lf.l_start = 0;
59449945Smckusick 		lf.l_len = 0;
59549945Smckusick 		if (fmode & O_EXLOCK)
59649945Smckusick 			lf.l_type = F_WRLCK;
59749945Smckusick 		else
59849945Smckusick 			lf.l_type = F_RDLCK;
59949945Smckusick 		type = F_FLOCK;
60049945Smckusick 		if ((fmode & FNONBLOCK) == 0)
60149945Smckusick 			type |= F_WAIT;
60250111Smckusick 		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
60350111Smckusick 			VOP_UNLOCK(vp);
60450111Smckusick 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
60549980Smckusick 			ffree(fp);
60649945Smckusick 			fdp->fd_ofiles[indx] = NULL;
60749945Smckusick 			return (error);
60849945Smckusick 		}
60949949Smckusick 		fp->f_flag |= FHASLOCK;
61049945Smckusick 	}
61150111Smckusick 	VOP_UNLOCK(vp);
61237741Smckusick 	fp->f_type = DTYPE_VNODE;
61337741Smckusick 	fp->f_ops = &vnops;
61450111Smckusick 	fp->f_data = (caddr_t)vp;
61542441Smckusick 	*retval = indx;
61647540Skarels 	return (0);
6176254Sroot }
6186254Sroot 
61942955Smckusick #ifdef COMPAT_43
6206254Sroot /*
62142441Smckusick  * Creat system call.
6226254Sroot  */
62342955Smckusick ocreat(p, uap, retval)
62442441Smckusick 	struct proc *p;
62542441Smckusick 	register struct args {
62642441Smckusick 		char	*fname;
62742441Smckusick 		int	fmode;
62842441Smckusick 	} *uap;
62942441Smckusick 	int *retval;
6306254Sroot {
63142441Smckusick 	struct args {
6326254Sroot 		char	*fname;
63342441Smckusick 		int	mode;
63442441Smckusick 		int	crtmode;
63542441Smckusick 	} openuap;
63642441Smckusick 
63742441Smckusick 	openuap.fname = uap->fname;
63842441Smckusick 	openuap.crtmode = uap->fmode;
63942441Smckusick 	openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
64047540Skarels 	return (open(p, &openuap, retval));
64142441Smckusick }
64242955Smckusick #endif /* COMPAT_43 */
64342441Smckusick 
64442441Smckusick /*
64549365Smckusick  * Mknod system call.
64642441Smckusick  */
64742441Smckusick /* ARGSUSED */
64842441Smckusick mknod(p, uap, retval)
64945914Smckusick 	struct proc *p;
65042441Smckusick 	register struct args {
65142441Smckusick 		char	*fname;
6526254Sroot 		int	fmode;
6536254Sroot 		int	dev;
65442441Smckusick 	} *uap;
65542441Smckusick 	int *retval;
65642441Smckusick {
65747540Skarels 	register struct nameidata *ndp;
65837741Smckusick 	register struct vnode *vp;
65937741Smckusick 	struct vattr vattr;
66037741Smckusick 	int error;
66147540Skarels 	struct nameidata nd;
6626254Sroot 
663*52230Sheideman 	CHECKPOINT;
66447540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
66547540Skarels 		return (error);
66647540Skarels 	ndp = &nd;
66737741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
66816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
66916694Smckusick 	ndp->ni_dirp = uap->fname;
67047540Skarels 	if (error = namei(ndp, p))
67147540Skarels 		return (error);
67237741Smckusick 	vp = ndp->ni_vp;
67337741Smckusick 	if (vp != NULL) {
67437741Smckusick 		error = EEXIST;
67512756Ssam 		goto out;
6766254Sroot 	}
67741362Smckusick 	VATTR_NULL(&vattr);
67840635Smckusick 	switch (uap->fmode & S_IFMT) {
67912756Ssam 
68040635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
68137741Smckusick 		vattr.va_type = VBAD;
68237741Smckusick 		break;
68340635Smckusick 	case S_IFCHR:
68437741Smckusick 		vattr.va_type = VCHR;
68537741Smckusick 		break;
68640635Smckusick 	case S_IFBLK:
68737741Smckusick 		vattr.va_type = VBLK;
68837741Smckusick 		break;
68937741Smckusick 	default:
69037741Smckusick 		error = EINVAL;
69137741Smckusick 		goto out;
6926254Sroot 	}
69345914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
69437741Smckusick 	vattr.va_rdev = uap->dev;
6956254Sroot out:
69642465Smckusick 	if (!error) {
69752192Smckusick 		LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE);
698*52230Sheideman 		error = VOP_MKNOD(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &vattr);
69942465Smckusick 	} else {
700*52230Sheideman 		VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
70143344Smckusick 		if (ndp->ni_dvp == vp)
70243344Smckusick 			vrele(ndp->ni_dvp);
70343344Smckusick 		else
70443344Smckusick 			vput(ndp->ni_dvp);
70542465Smckusick 		if (vp)
70642465Smckusick 			vrele(vp);
70742465Smckusick 	}
708*52230Sheideman 	CHECKCHECK("mknod");
70947540Skarels 	return (error);
7106254Sroot }
7116254Sroot 
7126254Sroot /*
71349365Smckusick  * Mkfifo system call.
71440285Smckusick  */
71542441Smckusick /* ARGSUSED */
71642441Smckusick mkfifo(p, uap, retval)
71745914Smckusick 	struct proc *p;
71842441Smckusick 	register struct args {
71940285Smckusick 		char	*fname;
72040285Smckusick 		int	fmode;
72142441Smckusick 	} *uap;
72242441Smckusick 	int *retval;
72342441Smckusick {
72447540Skarels 	register struct nameidata *ndp;
72540285Smckusick 	struct vattr vattr;
72640285Smckusick 	int error;
72747540Skarels 	struct nameidata nd;
72840285Smckusick 
72940285Smckusick #ifndef FIFO
73047540Skarels 	return (EOPNOTSUPP);
73140285Smckusick #else
73247540Skarels 	ndp = &nd;
73340285Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
73440285Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
73540285Smckusick 	ndp->ni_dirp = uap->fname;
73647540Skarels 	if (error = namei(ndp, p))
73747540Skarels 		return (error);
73840285Smckusick 	if (ndp->ni_vp != NULL) {
739*52230Sheideman 		VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
74043344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
74143344Smckusick 			vrele(ndp->ni_dvp);
74243344Smckusick 		else
74343344Smckusick 			vput(ndp->ni_dvp);
74442465Smckusick 		vrele(ndp->ni_vp);
74547540Skarels 		return (EEXIST);
74640285Smckusick 	}
74745785Sbostic 	VATTR_NULL(&vattr);
74845785Sbostic 	vattr.va_type = VFIFO;
74945914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
75052192Smckusick 	LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE);
751*52230Sheideman 	return (VOP_MKNOD(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &vattr));
75240285Smckusick #endif /* FIFO */
75340285Smckusick }
75440285Smckusick 
75540285Smckusick /*
75649365Smckusick  * Link system call.
7576254Sroot  */
75842441Smckusick /* ARGSUSED */
75942441Smckusick link(p, uap, retval)
76045914Smckusick 	struct proc *p;
76142441Smckusick 	register struct args {
7626254Sroot 		char	*target;
7636254Sroot 		char	*linkname;
76442441Smckusick 	} *uap;
76542441Smckusick 	int *retval;
76642441Smckusick {
76747540Skarels 	register struct nameidata *ndp;
76837741Smckusick 	register struct vnode *vp, *xp;
76937741Smckusick 	int error;
77047540Skarels 	struct nameidata nd;
7716254Sroot 
772*52230Sheideman 	CHECKPOINT;
77347540Skarels 	ndp = &nd;
77416694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
77516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
77616694Smckusick 	ndp->ni_dirp = uap->target;
77747540Skarels 	if (error = namei(ndp, p))
77847540Skarels 		return (error);
77937741Smckusick 	vp = ndp->ni_vp;
78037741Smckusick 	if (vp->v_type == VDIR &&
78147540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
78237741Smckusick 		goto out1;
78337741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
78416694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
78547540Skarels 	if (error = namei(ndp, p))
78637741Smckusick 		goto out1;
78737741Smckusick 	xp = ndp->ni_vp;
7886254Sroot 	if (xp != NULL) {
78937741Smckusick 		error = EEXIST;
7906254Sroot 		goto out;
7916254Sroot 	}
79237741Smckusick 	xp = ndp->ni_dvp;
79337741Smckusick 	if (vp->v_mount != xp->v_mount)
79437741Smckusick 		error = EXDEV;
7956254Sroot out:
79642465Smckusick 	if (!error) {
79752192Smckusick 		LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE);
79852192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
799*52230Sheideman 		error = VOP_LINK(vp, ndp->ni_dvp, &ndp->ni_cnd);
80042465Smckusick 	} else {
801*52230Sheideman 		VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
80243344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
80343344Smckusick 			vrele(ndp->ni_dvp);
80443344Smckusick 		else
80543344Smckusick 			vput(ndp->ni_dvp);
80642465Smckusick 		if (ndp->ni_vp)
80742465Smckusick 			vrele(ndp->ni_vp);
80842465Smckusick 	}
80937741Smckusick out1:
81037741Smckusick 	vrele(vp);
811*52230Sheideman 	CHECKCHECK("link");
81247540Skarels 	return (error);
8136254Sroot }
8146254Sroot 
8156254Sroot /*
81649365Smckusick  * Make a symbolic link.
8176254Sroot  */
81842441Smckusick /* ARGSUSED */
81942441Smckusick symlink(p, uap, retval)
82045914Smckusick 	struct proc *p;
82142441Smckusick 	register struct args {
8226254Sroot 		char	*target;
8236254Sroot 		char	*linkname;
82442441Smckusick 	} *uap;
82542441Smckusick 	int *retval;
82642441Smckusick {
82747540Skarels 	register struct nameidata *ndp;
82837741Smckusick 	struct vattr vattr;
82937741Smckusick 	char *target;
83037741Smckusick 	int error;
83147540Skarels 	struct nameidata nd;
8326254Sroot 
833*52230Sheideman 	CHECKPOINT;
83447540Skarels 	ndp = &nd;
83516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
83616694Smckusick 	ndp->ni_dirp = uap->linkname;
83737741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
83837741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
83942465Smckusick 		goto out;
84037741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
84147540Skarels 	if (error = namei(ndp, p))
84242465Smckusick 		goto out;
84342465Smckusick 	if (ndp->ni_vp) {
844*52230Sheideman 		VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
84543344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
84643344Smckusick 			vrele(ndp->ni_dvp);
84743344Smckusick 		else
84843344Smckusick 			vput(ndp->ni_dvp);
84942465Smckusick 		vrele(ndp->ni_vp);
85037741Smckusick 		error = EEXIST;
85137741Smckusick 		goto out;
8526254Sroot 	}
85341362Smckusick 	VATTR_NULL(&vattr);
85445914Smckusick 	vattr.va_mode = 0777 &~ p->p_fd->fd_cmask;
85552192Smckusick 	LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE);
856*52230Sheideman 	error = VOP_SYMLINK(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &vattr, target);
85737741Smckusick out:
85837741Smckusick 	FREE(target, M_NAMEI);
859*52230Sheideman 	CHECKCHECK("symlink");
86047540Skarels 	return (error);
8616254Sroot }
8626254Sroot 
8636254Sroot /*
86449365Smckusick  * Delete a name from the filesystem.
8656254Sroot  */
86642441Smckusick /* ARGSUSED */
86742441Smckusick unlink(p, uap, retval)
86845914Smckusick 	struct proc *p;
86942441Smckusick 	struct args {
87042441Smckusick 		char	*fname;
87142441Smckusick 	} *uap;
87242441Smckusick 	int *retval;
8736254Sroot {
87447540Skarels 	register struct nameidata *ndp;
87537741Smckusick 	register struct vnode *vp;
87637741Smckusick 	int error;
87747540Skarels 	struct nameidata nd;
8786254Sroot 
879*52230Sheideman 	CHECKPOINT;
88047540Skarels 	ndp = &nd;
88137741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
88216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
88316694Smckusick 	ndp->ni_dirp = uap->fname;
88447540Skarels 	if (error = namei(ndp, p))
88547540Skarels 		return (error);
88637741Smckusick 	vp = ndp->ni_vp;
88737741Smckusick 	if (vp->v_type == VDIR &&
88847540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
8896254Sroot 		goto out;
8906254Sroot 	/*
89149365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
8926254Sroot 	 */
89337741Smckusick 	if (vp->v_flag & VROOT) {
89437741Smckusick 		error = EBUSY;
8956254Sroot 		goto out;
8966254Sroot 	}
89745738Smckusick 	(void) vnode_pager_uncache(vp);
8986254Sroot out:
89942465Smckusick 	if (!error) {
90052192Smckusick 		LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE);
90152192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
902*52230Sheideman 		error = VOP_REMOVE(ndp->ni_dvp, ndp->ni_vp, &ndp->ni_cnd);
90342465Smckusick 	} else {
904*52230Sheideman 		VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
90543344Smckusick 		if (ndp->ni_dvp == vp)
90643344Smckusick 			vrele(ndp->ni_dvp);
90743344Smckusick 		else
90843344Smckusick 			vput(ndp->ni_dvp);
90942465Smckusick 		vput(vp);
91042465Smckusick 	}
911*52230Sheideman 	CHECKCHECK("unlink");
91247540Skarels 	return (error);
9136254Sroot }
9146254Sroot 
9156254Sroot /*
91649365Smckusick  * Seek system call.
9176254Sroot  */
91842441Smckusick lseek(p, uap, retval)
91945914Smckusick 	struct proc *p;
92042441Smckusick 	register struct args {
92137741Smckusick 		int	fdes;
9226254Sroot 		off_t	off;
9236254Sroot 		int	sbase;
92442441Smckusick 	} *uap;
92542441Smckusick 	off_t *retval;
92642441Smckusick {
92747540Skarels 	struct ucred *cred = p->p_ucred;
92845914Smckusick 	register struct filedesc *fdp = p->p_fd;
92942441Smckusick 	register struct file *fp;
93037741Smckusick 	struct vattr vattr;
93137741Smckusick 	int error;
9326254Sroot 
93347540Skarels 	if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
93447688Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL)
93547540Skarels 		return (EBADF);
93637741Smckusick 	if (fp->f_type != DTYPE_VNODE)
93747540Skarels 		return (ESPIPE);
93813878Ssam 	switch (uap->sbase) {
93913878Ssam 
94013878Ssam 	case L_INCR:
94113878Ssam 		fp->f_offset += uap->off;
94213878Ssam 		break;
94313878Ssam 
94413878Ssam 	case L_XTND:
94537741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
94648026Smckusick 		    &vattr, cred, p))
94747540Skarels 			return (error);
94837741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
94913878Ssam 		break;
95013878Ssam 
95113878Ssam 	case L_SET:
95213878Ssam 		fp->f_offset = uap->off;
95313878Ssam 		break;
95413878Ssam 
95513878Ssam 	default:
95647540Skarels 		return (EINVAL);
95713878Ssam 	}
95842441Smckusick 	*retval = fp->f_offset;
95947540Skarels 	return (0);
9606254Sroot }
9616254Sroot 
9626254Sroot /*
96349365Smckusick  * Check access permissions.
9646254Sroot  */
96542441Smckusick /* ARGSUSED */
96642441Smckusick saccess(p, uap, retval)
96745914Smckusick 	struct proc *p;
96842441Smckusick 	register struct args {
9696254Sroot 		char	*fname;
9706254Sroot 		int	fmode;
97142441Smckusick 	} *uap;
97242441Smckusick 	int *retval;
97342441Smckusick {
97447540Skarels 	register struct nameidata *ndp;
97547540Skarels 	register struct ucred *cred = p->p_ucred;
97637741Smckusick 	register struct vnode *vp;
97737741Smckusick 	int error, mode, svuid, svgid;
97847540Skarels 	struct nameidata nd;
9796254Sroot 
98047540Skarels 	ndp = &nd;
98142441Smckusick 	svuid = cred->cr_uid;
98242441Smckusick 	svgid = cred->cr_groups[0];
98347540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
98447540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
98537741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
98616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
98716694Smckusick 	ndp->ni_dirp = uap->fname;
98847540Skarels 	if (error = namei(ndp, p))
98937741Smckusick 		goto out1;
99037741Smckusick 	vp = ndp->ni_vp;
99137741Smckusick 	/*
99237741Smckusick 	 * fmode == 0 means only check for exist
99337741Smckusick 	 */
99437741Smckusick 	if (uap->fmode) {
99537741Smckusick 		mode = 0;
99637741Smckusick 		if (uap->fmode & R_OK)
99737741Smckusick 			mode |= VREAD;
99837741Smckusick 		if (uap->fmode & W_OK)
99937741Smckusick 			mode |= VWRITE;
100037741Smckusick 		if (uap->fmode & X_OK)
100137741Smckusick 			mode |= VEXEC;
100239543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
100348026Smckusick 			error = VOP_ACCESS(vp, mode, cred, p);
10046254Sroot 	}
100537741Smckusick 	vput(vp);
100637741Smckusick out1:
100742441Smckusick 	cred->cr_uid = svuid;
100842441Smckusick 	cred->cr_groups[0] = svgid;
100947540Skarels 	return (error);
10106254Sroot }
10116254Sroot 
10126254Sroot /*
101349365Smckusick  * Stat system call.
101449365Smckusick  * This version follows links.
101537Sbill  */
101642441Smckusick /* ARGSUSED */
101742441Smckusick stat(p, uap, retval)
101845914Smckusick 	struct proc *p;
101942441Smckusick 	register struct args {
102042441Smckusick 		char	*fname;
102142441Smckusick 		struct stat *ub;
102242441Smckusick 	} *uap;
102342441Smckusick 	int *retval;
102437Sbill {
102547540Skarels 	register struct nameidata *ndp;
102642441Smckusick 	struct stat sb;
102742441Smckusick 	int error;
102847540Skarels 	struct nameidata nd;
102937Sbill 
103047540Skarels 	ndp = &nd;
103142441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
103242441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
103342441Smckusick 	ndp->ni_dirp = uap->fname;
103447540Skarels 	if (error = namei(ndp, p))
103547540Skarels 		return (error);
103648026Smckusick 	error = vn_stat(ndp->ni_vp, &sb, p);
103742441Smckusick 	vput(ndp->ni_vp);
103842441Smckusick 	if (error)
103947540Skarels 		return (error);
104042441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
104147540Skarels 	return (error);
104237Sbill }
104337Sbill 
104437Sbill /*
104549365Smckusick  * Lstat system call.
104649365Smckusick  * This version does not follow links.
10475992Swnj  */
104842441Smckusick /* ARGSUSED */
104942441Smckusick lstat(p, uap, retval)
105045914Smckusick 	struct proc *p;
105142441Smckusick 	register struct args {
10525992Swnj 		char	*fname;
105312756Ssam 		struct stat *ub;
105442441Smckusick 	} *uap;
105542441Smckusick 	int *retval;
105642441Smckusick {
105747540Skarels 	register struct nameidata *ndp;
105812756Ssam 	struct stat sb;
105937741Smckusick 	int error;
106047540Skarels 	struct nameidata nd;
10615992Swnj 
106247540Skarels 	ndp = &nd;
106342441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW;
106416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
106516694Smckusick 	ndp->ni_dirp = uap->fname;
106647540Skarels 	if (error = namei(ndp, p))
106747540Skarels 		return (error);
106848026Smckusick 	error = vn_stat(ndp->ni_vp, &sb, p);
106937741Smckusick 	vput(ndp->ni_vp);
107037741Smckusick 	if (error)
107147540Skarels 		return (error);
107237741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
107347540Skarels 	return (error);
10745992Swnj }
10755992Swnj 
10765992Swnj /*
107749365Smckusick  * Return target name of a symbolic link.
107837Sbill  */
107942441Smckusick /* ARGSUSED */
108042441Smckusick readlink(p, uap, retval)
108145914Smckusick 	struct proc *p;
108242441Smckusick 	register struct args {
10835992Swnj 		char	*name;
10845992Swnj 		char	*buf;
10855992Swnj 		int	count;
108642441Smckusick 	} *uap;
108742441Smckusick 	int *retval;
108842441Smckusick {
108947540Skarels 	register struct nameidata *ndp;
109037741Smckusick 	register struct vnode *vp;
109137741Smckusick 	struct iovec aiov;
109237741Smckusick 	struct uio auio;
109337741Smckusick 	int error;
109447540Skarels 	struct nameidata nd;
10955992Swnj 
1096*52230Sheideman 	CHECKPOINT;
109747540Skarels 	ndp = &nd;
109837741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
109916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
110016694Smckusick 	ndp->ni_dirp = uap->name;
110147540Skarels 	if (error = namei(ndp, p))
110247540Skarels 		return (error);
110337741Smckusick 	vp = ndp->ni_vp;
110437741Smckusick 	if (vp->v_type != VLNK) {
110537741Smckusick 		error = EINVAL;
11065992Swnj 		goto out;
11075992Swnj 	}
110837741Smckusick 	aiov.iov_base = uap->buf;
110937741Smckusick 	aiov.iov_len = uap->count;
111037741Smckusick 	auio.uio_iov = &aiov;
111137741Smckusick 	auio.uio_iovcnt = 1;
111237741Smckusick 	auio.uio_offset = 0;
111337741Smckusick 	auio.uio_rw = UIO_READ;
111437741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
111548026Smckusick 	auio.uio_procp = p;
111637741Smckusick 	auio.uio_resid = uap->count;
111747540Skarels 	error = VOP_READLINK(vp, &auio, p->p_ucred);
11185992Swnj out:
111937741Smckusick 	vput(vp);
112042441Smckusick 	*retval = uap->count - auio.uio_resid;
1121*52230Sheideman 	CHECKCHECK("readlink");
112247540Skarels 	return (error);
11235992Swnj }
11245992Swnj 
11259167Ssam /*
112638259Smckusick  * Change flags of a file given path name.
112738259Smckusick  */
112842441Smckusick /* ARGSUSED */
112942441Smckusick chflags(p, uap, retval)
113045914Smckusick 	struct proc *p;
113142441Smckusick 	register struct args {
113238259Smckusick 		char	*fname;
113338259Smckusick 		int	flags;
113442441Smckusick 	} *uap;
113542441Smckusick 	int *retval;
113642441Smckusick {
113747540Skarels 	register struct nameidata *ndp;
113838259Smckusick 	register struct vnode *vp;
113938259Smckusick 	struct vattr vattr;
114038259Smckusick 	int error;
114147540Skarels 	struct nameidata nd;
114238259Smckusick 
114347540Skarels 	ndp = &nd;
114438259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
114538259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
114638259Smckusick 	ndp->ni_dirp = uap->fname;
114747540Skarels 	if (error = namei(ndp, p))
114847540Skarels 		return (error);
114938259Smckusick 	vp = ndp->ni_vp;
115041400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
115138259Smckusick 		error = EROFS;
115238259Smckusick 		goto out;
115338259Smckusick 	}
115445785Sbostic 	VATTR_NULL(&vattr);
115545785Sbostic 	vattr.va_flags = uap->flags;
115652192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
115748026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
115838259Smckusick out:
115938259Smckusick 	vput(vp);
116047540Skarels 	return (error);
116138259Smckusick }
116238259Smckusick 
116338259Smckusick /*
116438259Smckusick  * Change flags of a file given a file descriptor.
116538259Smckusick  */
116642441Smckusick /* ARGSUSED */
116742441Smckusick fchflags(p, uap, retval)
116845914Smckusick 	struct proc *p;
116942441Smckusick 	register struct args {
117038259Smckusick 		int	fd;
117138259Smckusick 		int	flags;
117242441Smckusick 	} *uap;
117342441Smckusick 	int *retval;
117442441Smckusick {
117538259Smckusick 	struct vattr vattr;
117638259Smckusick 	struct vnode *vp;
117738259Smckusick 	struct file *fp;
117838259Smckusick 	int error;
117938259Smckusick 
118045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
118147540Skarels 		return (error);
118238259Smckusick 	vp = (struct vnode *)fp->f_data;
118338259Smckusick 	VOP_LOCK(vp);
118441400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
118538259Smckusick 		error = EROFS;
118638259Smckusick 		goto out;
118738259Smckusick 	}
118845785Sbostic 	VATTR_NULL(&vattr);
118945785Sbostic 	vattr.va_flags = uap->flags;
119052192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
119148026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
119238259Smckusick out:
119338259Smckusick 	VOP_UNLOCK(vp);
119447540Skarels 	return (error);
119538259Smckusick }
119638259Smckusick 
119738259Smckusick /*
11989167Ssam  * Change mode of a file given path name.
11999167Ssam  */
120042441Smckusick /* ARGSUSED */
120142441Smckusick chmod(p, uap, retval)
120245914Smckusick 	struct proc *p;
120342441Smckusick 	register struct args {
12046254Sroot 		char	*fname;
12056254Sroot 		int	fmode;
120642441Smckusick 	} *uap;
120742441Smckusick 	int *retval;
120842441Smckusick {
120947540Skarels 	register struct nameidata *ndp;
121037741Smckusick 	register struct vnode *vp;
121137741Smckusick 	struct vattr vattr;
121237741Smckusick 	int error;
121347540Skarels 	struct nameidata nd;
12145992Swnj 
121547540Skarels 	ndp = &nd;
121637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
121737741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
121837741Smckusick 	ndp->ni_dirp = uap->fname;
121947540Skarels 	if (error = namei(ndp, p))
122047540Skarels 		return (error);
122137741Smckusick 	vp = ndp->ni_vp;
122241400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
122337741Smckusick 		error = EROFS;
122437741Smckusick 		goto out;
122537741Smckusick 	}
122645785Sbostic 	VATTR_NULL(&vattr);
122745785Sbostic 	vattr.va_mode = uap->fmode & 07777;
122852192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
122948026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
123037741Smckusick out:
123137741Smckusick 	vput(vp);
123247540Skarels 	return (error);
12337701Ssam }
12347439Sroot 
12359167Ssam /*
12369167Ssam  * Change mode of a file given a file descriptor.
12379167Ssam  */
123842441Smckusick /* ARGSUSED */
123942441Smckusick fchmod(p, uap, retval)
124045914Smckusick 	struct proc *p;
124142441Smckusick 	register struct args {
12427701Ssam 		int	fd;
12437701Ssam 		int	fmode;
124442441Smckusick 	} *uap;
124542441Smckusick 	int *retval;
124642441Smckusick {
124737741Smckusick 	struct vattr vattr;
124837741Smckusick 	struct vnode *vp;
124937741Smckusick 	struct file *fp;
125037741Smckusick 	int error;
12517701Ssam 
125245914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
125347540Skarels 		return (error);
125437741Smckusick 	vp = (struct vnode *)fp->f_data;
125537741Smckusick 	VOP_LOCK(vp);
125641400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
125737741Smckusick 		error = EROFS;
125837741Smckusick 		goto out;
12597439Sroot 	}
126045785Sbostic 	VATTR_NULL(&vattr);
126145785Sbostic 	vattr.va_mode = uap->fmode & 07777;
126252192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
126348026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
126437741Smckusick out:
126537741Smckusick 	VOP_UNLOCK(vp);
126647540Skarels 	return (error);
12675992Swnj }
12685992Swnj 
12699167Ssam /*
12709167Ssam  * Set ownership given a path name.
12719167Ssam  */
127242441Smckusick /* ARGSUSED */
127342441Smckusick chown(p, uap, retval)
127445914Smckusick 	struct proc *p;
127542441Smckusick 	register struct args {
12766254Sroot 		char	*fname;
12776254Sroot 		int	uid;
12786254Sroot 		int	gid;
127942441Smckusick 	} *uap;
128042441Smckusick 	int *retval;
128142441Smckusick {
128247540Skarels 	register struct nameidata *ndp;
128337741Smckusick 	register struct vnode *vp;
128437741Smckusick 	struct vattr vattr;
128537741Smckusick 	int error;
128647540Skarels 	struct nameidata nd;
128737Sbill 
128847540Skarels 	ndp = &nd;
128937741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
129036614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
129136614Sbostic 	ndp->ni_dirp = uap->fname;
129247540Skarels 	if (error = namei(ndp, p))
129347540Skarels 		return (error);
129437741Smckusick 	vp = ndp->ni_vp;
129541400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
129637741Smckusick 		error = EROFS;
129737741Smckusick 		goto out;
129837741Smckusick 	}
129945785Sbostic 	VATTR_NULL(&vattr);
130045785Sbostic 	vattr.va_uid = uap->uid;
130145785Sbostic 	vattr.va_gid = uap->gid;
130252192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
130348026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
130437741Smckusick out:
130537741Smckusick 	vput(vp);
130647540Skarels 	return (error);
13077701Ssam }
13087439Sroot 
13099167Ssam /*
13109167Ssam  * Set ownership given a file descriptor.
13119167Ssam  */
131242441Smckusick /* ARGSUSED */
131342441Smckusick fchown(p, uap, retval)
131445914Smckusick 	struct proc *p;
131542441Smckusick 	register struct args {
13167701Ssam 		int	fd;
13177701Ssam 		int	uid;
13187701Ssam 		int	gid;
131942441Smckusick 	} *uap;
132042441Smckusick 	int *retval;
132142441Smckusick {
132237741Smckusick 	struct vattr vattr;
132337741Smckusick 	struct vnode *vp;
132437741Smckusick 	struct file *fp;
132537741Smckusick 	int error;
13267701Ssam 
132745914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
132847540Skarels 		return (error);
132937741Smckusick 	vp = (struct vnode *)fp->f_data;
133037741Smckusick 	VOP_LOCK(vp);
133141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
133237741Smckusick 		error = EROFS;
133337741Smckusick 		goto out;
133437741Smckusick 	}
133545785Sbostic 	VATTR_NULL(&vattr);
133645785Sbostic 	vattr.va_uid = uap->uid;
133745785Sbostic 	vattr.va_gid = uap->gid;
133852192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
133948026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
134037741Smckusick out:
134137741Smckusick 	VOP_UNLOCK(vp);
134247540Skarels 	return (error);
13437701Ssam }
13447701Ssam 
134542441Smckusick /*
134642441Smckusick  * Set the access and modification times of a file.
134742441Smckusick  */
134842441Smckusick /* ARGSUSED */
134942441Smckusick utimes(p, uap, retval)
135045914Smckusick 	struct proc *p;
135142441Smckusick 	register struct args {
135211811Ssam 		char	*fname;
135311811Ssam 		struct	timeval *tptr;
135442441Smckusick 	} *uap;
135542441Smckusick 	int *retval;
135642441Smckusick {
135747540Skarels 	register struct nameidata *ndp;
135837741Smckusick 	register struct vnode *vp;
135911811Ssam 	struct timeval tv[2];
136037741Smckusick 	struct vattr vattr;
136137741Smckusick 	int error;
136247540Skarels 	struct nameidata nd;
136311811Ssam 
136437741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
136547540Skarels 		return (error);
136647540Skarels 	ndp = &nd;
136737741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
136837741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
136937741Smckusick 	ndp->ni_dirp = uap->fname;
137047540Skarels 	if (error = namei(ndp, p))
137147540Skarels 		return (error);
137237741Smckusick 	vp = ndp->ni_vp;
137341400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
137437741Smckusick 		error = EROFS;
137537741Smckusick 		goto out;
137621015Smckusick 	}
137745785Sbostic 	VATTR_NULL(&vattr);
137845785Sbostic 	vattr.va_atime = tv[0];
137945785Sbostic 	vattr.va_mtime = tv[1];
138052192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
138148026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
138237741Smckusick out:
138337741Smckusick 	vput(vp);
138447540Skarels 	return (error);
138511811Ssam }
138611811Ssam 
13879167Ssam /*
13889167Ssam  * Truncate a file given its path name.
13899167Ssam  */
139042441Smckusick /* ARGSUSED */
139142441Smckusick truncate(p, uap, retval)
139245914Smckusick 	struct proc *p;
139342441Smckusick 	register struct args {
13947701Ssam 		char	*fname;
139526473Skarels 		off_t	length;
139642441Smckusick 	} *uap;
139742441Smckusick 	int *retval;
139842441Smckusick {
139947540Skarels 	register struct nameidata *ndp;
140037741Smckusick 	register struct vnode *vp;
140137741Smckusick 	struct vattr vattr;
140237741Smckusick 	int error;
140347540Skarels 	struct nameidata nd;
14047701Ssam 
140547540Skarels 	ndp = &nd;
140637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
140716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
140816694Smckusick 	ndp->ni_dirp = uap->fname;
140947540Skarels 	if (error = namei(ndp, p))
141047540Skarels 		return (error);
141137741Smckusick 	vp = ndp->ni_vp;
141237741Smckusick 	if (vp->v_type == VDIR) {
141337741Smckusick 		error = EISDIR;
141437741Smckusick 		goto out;
14157701Ssam 	}
141638399Smckusick 	if ((error = vn_writechk(vp)) ||
141748026Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)))
141837741Smckusick 		goto out;
141945785Sbostic 	VATTR_NULL(&vattr);
142045785Sbostic 	vattr.va_size = uap->length;
142152192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
142248026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
142337741Smckusick out:
142437741Smckusick 	vput(vp);
142547540Skarels 	return (error);
14267701Ssam }
14277701Ssam 
14289167Ssam /*
14299167Ssam  * Truncate a file given a file descriptor.
14309167Ssam  */
143142441Smckusick /* ARGSUSED */
143242441Smckusick ftruncate(p, uap, retval)
143345914Smckusick 	struct proc *p;
143442441Smckusick 	register struct args {
14357701Ssam 		int	fd;
143626473Skarels 		off_t	length;
143742441Smckusick 	} *uap;
143842441Smckusick 	int *retval;
143942441Smckusick {
144037741Smckusick 	struct vattr vattr;
144137741Smckusick 	struct vnode *vp;
14427701Ssam 	struct file *fp;
144337741Smckusick 	int error;
14447701Ssam 
144545914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
144647540Skarels 		return (error);
144737741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
144847540Skarels 		return (EINVAL);
144937741Smckusick 	vp = (struct vnode *)fp->f_data;
145037741Smckusick 	VOP_LOCK(vp);
145137741Smckusick 	if (vp->v_type == VDIR) {
145237741Smckusick 		error = EISDIR;
145337741Smckusick 		goto out;
14547701Ssam 	}
145538399Smckusick 	if (error = vn_writechk(vp))
145637741Smckusick 		goto out;
145745785Sbostic 	VATTR_NULL(&vattr);
145845785Sbostic 	vattr.va_size = uap->length;
145952192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
146048026Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
146137741Smckusick out:
146237741Smckusick 	VOP_UNLOCK(vp);
146347540Skarels 	return (error);
14647701Ssam }
14657701Ssam 
14669167Ssam /*
14679167Ssam  * Synch an open file.
14689167Ssam  */
146942441Smckusick /* ARGSUSED */
147042441Smckusick fsync(p, uap, retval)
147145914Smckusick 	struct proc *p;
147242441Smckusick 	struct args {
147342441Smckusick 		int	fd;
147442441Smckusick 	} *uap;
147542441Smckusick 	int *retval;
14769167Ssam {
147739592Smckusick 	register struct vnode *vp;
14789167Ssam 	struct file *fp;
147937741Smckusick 	int error;
14809167Ssam 
148145914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
148247540Skarels 		return (error);
148339592Smckusick 	vp = (struct vnode *)fp->f_data;
148439592Smckusick 	VOP_LOCK(vp);
148548026Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT, p);
148639592Smckusick 	VOP_UNLOCK(vp);
148747540Skarels 	return (error);
14889167Ssam }
14899167Ssam 
14909167Ssam /*
14919167Ssam  * Rename system call.
14929167Ssam  *
14939167Ssam  * Source and destination must either both be directories, or both
14949167Ssam  * not be directories.  If target is a directory, it must be empty.
14959167Ssam  */
149642441Smckusick /* ARGSUSED */
149742441Smckusick rename(p, uap, retval)
149845914Smckusick 	struct proc *p;
149942441Smckusick 	register struct args {
15007701Ssam 		char	*from;
15017701Ssam 		char	*to;
150242441Smckusick 	} *uap;
150342441Smckusick 	int *retval;
150442441Smckusick {
150537741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
150649735Smckusick 	struct nameidata fromnd, tond;
150737741Smckusick 	int error;
15087701Ssam 
1509*52230Sheideman 	CHECKPOINT;
151049735Smckusick 	fromnd.ni_nameiop = DELETE | WANTPARENT | SAVESTART;
151149735Smckusick 	fromnd.ni_segflg = UIO_USERSPACE;
151249735Smckusick 	fromnd.ni_dirp = uap->from;
151349735Smckusick 	if (error = namei(&fromnd, p))
151447540Skarels 		return (error);
151549735Smckusick 	fvp = fromnd.ni_vp;
151649735Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
151737741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
151837741Smckusick 	tond.ni_dirp = uap->to;
151947540Skarels 	if (error = namei(&tond, p)) {
1520*52230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
152149735Smckusick 		vrele(fromnd.ni_dvp);
152242465Smckusick 		vrele(fvp);
152342465Smckusick 		goto out1;
152442465Smckusick 	}
152537741Smckusick 	tdvp = tond.ni_dvp;
152637741Smckusick 	tvp = tond.ni_vp;
152737741Smckusick 	if (tvp != NULL) {
152837741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
152939242Sbostic 			error = ENOTDIR;
153037741Smckusick 			goto out;
153137741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
153239242Sbostic 			error = EISDIR;
153337741Smckusick 			goto out;
15349167Ssam 		}
153545240Smckusick 		if (fvp->v_mount != tvp->v_mount) {
153645240Smckusick 			error = EXDEV;
153745240Smckusick 			goto out;
153845240Smckusick 		}
15399167Ssam 	}
154037741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
154137741Smckusick 		error = EXDEV;
15429167Ssam 		goto out;
154310051Ssam 	}
154439286Smckusick 	if (fvp == tdvp)
154537741Smckusick 		error = EINVAL;
154639286Smckusick 	/*
154749735Smckusick 	 * If source is the same as the destination (that is the
154849735Smckusick 	 * same inode number with the same name in the same directory),
154939286Smckusick 	 * then there is nothing to do.
155039286Smckusick 	 */
155149735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
155249735Smckusick 	    fromnd.ni_namelen == tond.ni_namelen &&
155349735Smckusick 	    !bcmp(fromnd.ni_ptr, tond.ni_ptr, fromnd.ni_namelen))
155439286Smckusick 		error = -1;
155537741Smckusick out:
155642465Smckusick 	if (!error) {
155752192Smckusick 		LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE);
155852192Smckusick 		if (fromnd.ni_dvp != tdvp)
155952192Smckusick 			LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
156052192Smckusick 		if (tvp)
156152192Smckusick 			LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE);
1562*52230Sheideman 		if (fromnd.ni_startdir != fromnd.ni_dvp ||
1563*52230Sheideman 		    tond.ni_startdir != tond.ni_dvp)   /* NEEDSWORK: debug */
1564*52230Sheideman 			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);
1565*52230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
1566*52230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
1567*52230Sheideman 		if (fromnd.ni_startdir != fromnd.ni_dvp ||
1568*52230Sheideman 		    tond.ni_startdir != tond.ni_dvp)   /* NEEDSWORK: debug */
1569*52230Sheideman 			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);
157042465Smckusick 	} else {
1571*52230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
157243344Smckusick 		if (tdvp == tvp)
157343344Smckusick 			vrele(tdvp);
157443344Smckusick 		else
157543344Smckusick 			vput(tdvp);
157642465Smckusick 		if (tvp)
157742465Smckusick 			vput(tvp);
1578*52230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
157949735Smckusick 		vrele(fromnd.ni_dvp);
158042465Smckusick 		vrele(fvp);
15819167Ssam 	}
158249735Smckusick 	vrele(tond.ni_startdir);
158349735Smckusick 	FREE(tond.ni_pnbuf, M_NAMEI);
158437741Smckusick out1:
158549735Smckusick 	vrele(fromnd.ni_startdir);
158649735Smckusick 	FREE(fromnd.ni_pnbuf, M_NAMEI);
1587*52230Sheideman 	CHECKCHECK("rename");
158839286Smckusick 	if (error == -1)
158947540Skarels 		return (0);
159047540Skarels 	return (error);
15917701Ssam }
15927701Ssam 
15937535Sroot /*
159449365Smckusick  * Mkdir system call.
159512756Ssam  */
159642441Smckusick /* ARGSUSED */
159742441Smckusick mkdir(p, uap, retval)
159845914Smckusick 	struct proc *p;
159942441Smckusick 	register struct args {
160012756Ssam 		char	*name;
160112756Ssam 		int	dmode;
160242441Smckusick 	} *uap;
160342441Smckusick 	int *retval;
160442441Smckusick {
160547540Skarels 	register struct nameidata *ndp;
160637741Smckusick 	register struct vnode *vp;
160737741Smckusick 	struct vattr vattr;
160837741Smckusick 	int error;
160947540Skarels 	struct nameidata nd;
161012756Ssam 
1611*52230Sheideman 	CHECKPOINT;
161247540Skarels 	ndp = &nd;
161337741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
161416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
161516694Smckusick 	ndp->ni_dirp = uap->name;
161647540Skarels 	if (error = namei(ndp, p))
161747540Skarels 		return (error);
161837741Smckusick 	vp = ndp->ni_vp;
161937741Smckusick 	if (vp != NULL) {
1620*52230Sheideman 		VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
162143344Smckusick 		if (ndp->ni_dvp == vp)
162243344Smckusick 			vrele(ndp->ni_dvp);
162343344Smckusick 		else
162443344Smckusick 			vput(ndp->ni_dvp);
162542465Smckusick 		vrele(vp);
1626*52230Sheideman 		CHECKCHECK("mkdir1");
162747540Skarels 		return (EEXIST);
162812756Ssam 	}
162941362Smckusick 	VATTR_NULL(&vattr);
163037741Smckusick 	vattr.va_type = VDIR;
163145914Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask;
163252192Smckusick 	LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE);
1633*52230Sheideman 	error = VOP_MKDIR(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd, &vattr);
163438145Smckusick 	if (!error)
163538145Smckusick 		vput(ndp->ni_vp);
1636*52230Sheideman 	CHECKCHECK("mkdir2");
163747540Skarels 	return (error);
163812756Ssam }
163912756Ssam 
164012756Ssam /*
164112756Ssam  * Rmdir system call.
164212756Ssam  */
164342441Smckusick /* ARGSUSED */
164442441Smckusick rmdir(p, uap, retval)
164545914Smckusick 	struct proc *p;
164642441Smckusick 	struct args {
164742441Smckusick 		char	*name;
164842441Smckusick 	} *uap;
164942441Smckusick 	int *retval;
165012756Ssam {
165147540Skarels 	register struct nameidata *ndp;
165237741Smckusick 	register struct vnode *vp;
165337741Smckusick 	int error;
165447540Skarels 	struct nameidata nd;
165512756Ssam 
1656*52230Sheideman 	CHECKPOINT;
165747540Skarels 	ndp = &nd;
165837741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
165916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
166016694Smckusick 	ndp->ni_dirp = uap->name;
166147540Skarels 	if (error = namei(ndp, p))
166247540Skarels 		return (error);
166337741Smckusick 	vp = ndp->ni_vp;
166437741Smckusick 	if (vp->v_type != VDIR) {
166537741Smckusick 		error = ENOTDIR;
166612756Ssam 		goto out;
166712756Ssam 	}
166812756Ssam 	/*
166937741Smckusick 	 * No rmdir "." please.
167012756Ssam 	 */
167137741Smckusick 	if (ndp->ni_dvp == vp) {
167237741Smckusick 		error = EINVAL;
167312756Ssam 		goto out;
167412756Ssam 	}
167512756Ssam 	/*
167649365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
167712756Ssam 	 */
167837741Smckusick 	if (vp->v_flag & VROOT)
167937741Smckusick 		error = EBUSY;
168012756Ssam out:
168142465Smckusick 	if (!error) {
168252192Smckusick 		LEASE_CHECK(ndp->ni_dvp, p, p->p_ucred, LEASE_WRITE);
168352192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
1684*52230Sheideman 		error = VOP_RMDIR(ndp->ni_dvp, ndp->ni_vp, &ndp->ni_cnd);
168542465Smckusick 	} else {
1686*52230Sheideman 		VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
168743344Smckusick 		if (ndp->ni_dvp == vp)
168843344Smckusick 			vrele(ndp->ni_dvp);
168943344Smckusick 		else
169043344Smckusick 			vput(ndp->ni_dvp);
169142465Smckusick 		vput(vp);
169242465Smckusick 	}
1693*52230Sheideman 	CHECKCHECK("rmdir");
169447540Skarels 	return (error);
169512756Ssam }
169612756Ssam 
169737741Smckusick /*
169849365Smckusick  * Read a block of directory entries in a file system independent format.
169937741Smckusick  */
170042441Smckusick getdirentries(p, uap, retval)
170145914Smckusick 	struct proc *p;
170242441Smckusick 	register struct args {
170337741Smckusick 		int	fd;
170437741Smckusick 		char	*buf;
170537741Smckusick 		unsigned count;
170637741Smckusick 		long	*basep;
170742441Smckusick 	} *uap;
170842441Smckusick 	int *retval;
170942441Smckusick {
171039592Smckusick 	register struct vnode *vp;
171116540Ssam 	struct file *fp;
171237741Smckusick 	struct uio auio;
171337741Smckusick 	struct iovec aiov;
171438129Smckusick 	off_t off;
171540321Smckusick 	int error, eofflag;
171612756Ssam 
171745914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
171847540Skarels 		return (error);
171937741Smckusick 	if ((fp->f_flag & FREAD) == 0)
172047540Skarels 		return (EBADF);
172139592Smckusick 	vp = (struct vnode *)fp->f_data;
172239592Smckusick 	if (vp->v_type != VDIR)
172347540Skarels 		return (EINVAL);
172437741Smckusick 	aiov.iov_base = uap->buf;
172537741Smckusick 	aiov.iov_len = uap->count;
172637741Smckusick 	auio.uio_iov = &aiov;
172737741Smckusick 	auio.uio_iovcnt = 1;
172837741Smckusick 	auio.uio_rw = UIO_READ;
172937741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
173048026Smckusick 	auio.uio_procp = p;
173137741Smckusick 	auio.uio_resid = uap->count;
173239592Smckusick 	VOP_LOCK(vp);
173339592Smckusick 	auio.uio_offset = off = fp->f_offset;
173440321Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
173539592Smckusick 	fp->f_offset = auio.uio_offset;
173639592Smckusick 	VOP_UNLOCK(vp);
173739592Smckusick 	if (error)
173847540Skarels 		return (error);
173939592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
174042441Smckusick 	*retval = uap->count - auio.uio_resid;
174147540Skarels 	return (error);
174212756Ssam }
174312756Ssam 
174412756Ssam /*
174549365Smckusick  * Set the mode mask for creation of filesystem nodes.
174612756Ssam  */
174742441Smckusick mode_t
174842441Smckusick umask(p, uap, retval)
174945914Smckusick 	struct proc *p;
175042441Smckusick 	struct args {
175142441Smckusick 		int	mask;
175242441Smckusick 	} *uap;
175342441Smckusick 	int *retval;
175412756Ssam {
175545914Smckusick 	register struct filedesc *fdp = p->p_fd;
175612756Ssam 
175745914Smckusick 	*retval = fdp->fd_cmask;
175845914Smckusick 	fdp->fd_cmask = uap->mask & 07777;
175947540Skarels 	return (0);
176012756Ssam }
176137741Smckusick 
176239566Smarc /*
176339566Smarc  * Void all references to file by ripping underlying filesystem
176439566Smarc  * away from vnode.
176539566Smarc  */
176642441Smckusick /* ARGSUSED */
176742441Smckusick revoke(p, uap, retval)
176845914Smckusick 	struct proc *p;
176942441Smckusick 	register struct args {
177039566Smarc 		char	*fname;
177142441Smckusick 	} *uap;
177242441Smckusick 	int *retval;
177342441Smckusick {
177447540Skarels 	register struct nameidata *ndp;
177539566Smarc 	register struct vnode *vp;
177639566Smarc 	struct vattr vattr;
177739566Smarc 	int error;
177847540Skarels 	struct nameidata nd;
177939566Smarc 
178047540Skarels 	ndp = &nd;
178139566Smarc 	ndp->ni_nameiop = LOOKUP | FOLLOW;
178239566Smarc 	ndp->ni_segflg = UIO_USERSPACE;
178339566Smarc 	ndp->ni_dirp = uap->fname;
178447540Skarels 	if (error = namei(ndp, p))
178547540Skarels 		return (error);
178639566Smarc 	vp = ndp->ni_vp;
178739566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
178839566Smarc 		error = EINVAL;
178939566Smarc 		goto out;
179039566Smarc 	}
179148026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
179239566Smarc 		goto out;
179347540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
179447540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
179539566Smarc 		goto out;
179639805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
179739632Smckusick 		vgoneall(vp);
179839566Smarc out:
179939566Smarc 	vrele(vp);
180047540Skarels 	return (error);
180139566Smarc }
180239566Smarc 
180349365Smckusick /*
180449365Smckusick  * Convert a user file descriptor to a kernel file entry.
180549365Smckusick  */
180645914Smckusick getvnode(fdp, fdes, fpp)
180745914Smckusick 	struct filedesc *fdp;
180837741Smckusick 	struct file **fpp;
180937741Smckusick 	int fdes;
181037741Smckusick {
181137741Smckusick 	struct file *fp;
181237741Smckusick 
181347540Skarels 	if ((unsigned)fdes >= fdp->fd_nfiles ||
181447688Skarels 	    (fp = fdp->fd_ofiles[fdes]) == NULL)
181537741Smckusick 		return (EBADF);
181637741Smckusick 	if (fp->f_type != DTYPE_VNODE)
181737741Smckusick 		return (EINVAL);
181837741Smckusick 	*fpp = fp;
181937741Smckusick 	return (0);
182037741Smckusick }
1821