xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 54441)
123405Smckusick /*
237741Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337741Smckusick  * All rights reserved.
423405Smckusick  *
544459Sbostic  * %sccs.include.redist.c%
637741Smckusick  *
7*54441Smckusick  *	@(#)vfs_syscalls.c	7.88 (Berkeley) 06/25/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"
2253468Smckusick #include <vm/vm.h>
2337Sbill 
2437741Smckusick /*
2537741Smckusick  * Virtual File System System Calls
2637741Smckusick  */
2712756Ssam 
289167Ssam /*
2949365Smckusick  * Mount system call.
309167Ssam  */
3142441Smckusick /* ARGSUSED */
3242441Smckusick mount(p, uap, retval)
3345914Smckusick 	struct proc *p;
3442441Smckusick 	register struct args {
3537741Smckusick 		int	type;
3637741Smckusick 		char	*dir;
3737741Smckusick 		int	flags;
3837741Smckusick 		caddr_t	data;
3942441Smckusick 	} *uap;
4042441Smckusick 	int *retval;
4142441Smckusick {
4253548Sheideman 	USES_VOP_UNLOCK;
4339335Smckusick 	register struct vnode *vp;
4439335Smckusick 	register struct mount *mp;
4540111Smckusick 	int error, flag;
4647540Skarels 	struct nameidata nd;
476254Sroot 
4837741Smckusick 	/*
4937741Smckusick 	 * Must be super user
5037741Smckusick 	 */
5147540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
5247540Skarels 		return (error);
5337741Smckusick 	/*
5437741Smckusick 	 * Get vnode to be covered
5537741Smckusick 	 */
5652322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->dir, p);
5752322Smckusick 	if (error = namei(&nd))
5847540Skarels 		return (error);
5952322Smckusick 	vp = nd.ni_vp;
6041400Smckusick 	if (uap->flags & MNT_UPDATE) {
6139335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
6239335Smckusick 			vput(vp);
6347540Skarels 			return (EINVAL);
6439335Smckusick 		}
6539335Smckusick 		mp = vp->v_mount;
6639335Smckusick 		/*
6739335Smckusick 		 * We allow going from read-only to read-write,
6839335Smckusick 		 * but not from read-write to read-only.
6939335Smckusick 		 */
7041400Smckusick 		if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
7141400Smckusick 		    (uap->flags & MNT_RDONLY) != 0) {
7239335Smckusick 			vput(vp);
7347540Skarels 			return (EOPNOTSUPP);	/* Needs translation */
7439335Smckusick 		}
7541400Smckusick 		flag = mp->mnt_flag;
7641400Smckusick 		mp->mnt_flag |= MNT_UPDATE;
7739335Smckusick 		VOP_UNLOCK(vp);
7839335Smckusick 		goto update;
7939335Smckusick 	}
8039805Smckusick 	if (vp->v_usecount != 1) {
8137741Smckusick 		vput(vp);
8247540Skarels 		return (EBUSY);
8337741Smckusick 	}
84*54441Smckusick 	if (error = vinvalbuf(vp, 1, p->p_ucred, p))
85*54441Smckusick 		return (error);
8637741Smckusick 	if (vp->v_type != VDIR) {
8737741Smckusick 		vput(vp);
8847540Skarels 		return (ENOTDIR);
8937741Smckusick 	}
9039741Smckusick 	if ((unsigned long)uap->type > MOUNT_MAXTYPE ||
9137741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
9237741Smckusick 		vput(vp);
9347540Skarels 		return (ENODEV);
9437741Smckusick 	}
9537741Smckusick 
9637741Smckusick 	/*
9739335Smckusick 	 * Allocate and initialize the file system.
9837741Smckusick 	 */
9937741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
10037741Smckusick 		M_MOUNT, M_WAITOK);
10154172Smckusick 	bzero((char *)mp, (u_long)sizeof(struct mount));
10241400Smckusick 	mp->mnt_op = vfssw[uap->type];
10339335Smckusick 	if (error = vfs_lock(mp)) {
10439335Smckusick 		free((caddr_t)mp, M_MOUNT);
10539335Smckusick 		vput(vp);
10647540Skarels 		return (error);
10739335Smckusick 	}
10839335Smckusick 	if (vp->v_mountedhere != (struct mount *)0) {
10939335Smckusick 		vfs_unlock(mp);
11039335Smckusick 		free((caddr_t)mp, M_MOUNT);
11139335Smckusick 		vput(vp);
11247540Skarels 		return (EBUSY);
11339335Smckusick 	}
11439335Smckusick 	vp->v_mountedhere = mp;
11541400Smckusick 	mp->mnt_vnodecovered = vp;
11639335Smckusick update:
11739335Smckusick 	/*
11839335Smckusick 	 * Set the mount level flags.
11939335Smckusick 	 */
12041400Smckusick 	if (uap->flags & MNT_RDONLY)
12141400Smckusick 		mp->mnt_flag |= MNT_RDONLY;
12239335Smckusick 	else
12341400Smckusick 		mp->mnt_flag &= ~MNT_RDONLY;
12441400Smckusick 	if (uap->flags & MNT_NOSUID)
12541400Smckusick 		mp->mnt_flag |= MNT_NOSUID;
12639335Smckusick 	else
12741400Smckusick 		mp->mnt_flag &= ~MNT_NOSUID;
12841400Smckusick 	if (uap->flags & MNT_NOEXEC)
12941400Smckusick 		mp->mnt_flag |= MNT_NOEXEC;
13039335Smckusick 	else
13141400Smckusick 		mp->mnt_flag &= ~MNT_NOEXEC;
13241400Smckusick 	if (uap->flags & MNT_NODEV)
13341400Smckusick 		mp->mnt_flag |= MNT_NODEV;
13439335Smckusick 	else
13541400Smckusick 		mp->mnt_flag &= ~MNT_NODEV;
13641400Smckusick 	if (uap->flags & MNT_SYNCHRONOUS)
13741400Smckusick 		mp->mnt_flag |= MNT_SYNCHRONOUS;
13839335Smckusick 	else
13941400Smckusick 		mp->mnt_flag &= ~MNT_SYNCHRONOUS;
14039335Smckusick 	/*
14139335Smckusick 	 * Mount the filesystem.
14239335Smckusick 	 */
14352322Smckusick 	error = VFS_MOUNT(mp, uap->dir, uap->data, &nd, p);
14441400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
14541400Smckusick 		mp->mnt_flag &= ~MNT_UPDATE;
14639335Smckusick 		vrele(vp);
14740111Smckusick 		if (error)
14841400Smckusick 			mp->mnt_flag = flag;
14947540Skarels 		return (error);
15039335Smckusick 	}
15140110Smckusick 	/*
15240110Smckusick 	 * Put the new filesystem on the mount list after root.
15340110Smckusick 	 */
15441400Smckusick 	mp->mnt_next = rootfs->mnt_next;
15541400Smckusick 	mp->mnt_prev = rootfs;
15641400Smckusick 	rootfs->mnt_next = mp;
15741400Smckusick 	mp->mnt_next->mnt_prev = mp;
15837741Smckusick 	cache_purge(vp);
15937741Smckusick 	if (!error) {
16039335Smckusick 		VOP_UNLOCK(vp);
16137741Smckusick 		vfs_unlock(mp);
16248026Smckusick 		error = VFS_START(mp, 0, p);
16337741Smckusick 	} else {
16437741Smckusick 		vfs_remove(mp);
16537741Smckusick 		free((caddr_t)mp, M_MOUNT);
16639335Smckusick 		vput(vp);
16737741Smckusick 	}
16847540Skarels 	return (error);
1696254Sroot }
1706254Sroot 
1719167Ssam /*
17237741Smckusick  * Unmount system call.
17337741Smckusick  *
17437741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
17537741Smckusick  * not special file (as before).
1769167Ssam  */
17742441Smckusick /* ARGSUSED */
17842441Smckusick unmount(p, uap, retval)
17945914Smckusick 	struct proc *p;
18042441Smckusick 	register struct args {
18137741Smckusick 		char	*pathp;
18237741Smckusick 		int	flags;
18342441Smckusick 	} *uap;
18442441Smckusick 	int *retval;
18542441Smckusick {
18637741Smckusick 	register struct vnode *vp;
18739356Smckusick 	struct mount *mp;
18837741Smckusick 	int error;
18947540Skarels 	struct nameidata nd;
1906254Sroot 
19137741Smckusick 	/*
19237741Smckusick 	 * Must be super user
19337741Smckusick 	 */
19447540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
19547540Skarels 		return (error);
19637741Smckusick 
19752322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->pathp, p);
19852322Smckusick 	if (error = namei(&nd))
19947540Skarels 		return (error);
20052322Smckusick 	vp = nd.ni_vp;
20137741Smckusick 	/*
20237741Smckusick 	 * Must be the root of the filesystem
20337741Smckusick 	 */
20437741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
20537741Smckusick 		vput(vp);
20647540Skarels 		return (EINVAL);
20737741Smckusick 	}
20837741Smckusick 	mp = vp->v_mount;
20937741Smckusick 	vput(vp);
21048026Smckusick 	return (dounmount(mp, uap->flags, p));
21139356Smckusick }
21239356Smckusick 
21339356Smckusick /*
21439356Smckusick  * Do an unmount.
21539356Smckusick  */
21648026Smckusick dounmount(mp, flags, p)
21739356Smckusick 	register struct mount *mp;
21839356Smckusick 	int flags;
21948026Smckusick 	struct proc *p;
22039356Smckusick {
22139356Smckusick 	struct vnode *coveredvp;
22239356Smckusick 	int error;
22339356Smckusick 
22441400Smckusick 	coveredvp = mp->mnt_vnodecovered;
22541298Smckusick 	if (vfs_busy(mp))
22641298Smckusick 		return (EBUSY);
22741400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
22837741Smckusick 	if (error = vfs_lock(mp))
22939356Smckusick 		return (error);
23037741Smckusick 
23145738Smckusick 	vnode_pager_umount(mp);	/* release cached vnodes */
23237741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
233*54441Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 ||
234*54441Smckusick 	    (flags & MNT_FORCE))
23548026Smckusick 		error = VFS_UNMOUNT(mp, flags, p);
23641400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
23741298Smckusick 	vfs_unbusy(mp);
23837741Smckusick 	if (error) {
23937741Smckusick 		vfs_unlock(mp);
24037741Smckusick 	} else {
24137741Smckusick 		vrele(coveredvp);
24237741Smckusick 		vfs_remove(mp);
24352287Smckusick 		if (mp->mnt_mounth != NULL)
24452287Smckusick 			panic("unmount: dangling vnode");
24537741Smckusick 		free((caddr_t)mp, M_MOUNT);
24637741Smckusick 	}
24739356Smckusick 	return (error);
2486254Sroot }
2496254Sroot 
2509167Ssam /*
25137741Smckusick  * Sync system call.
25237741Smckusick  * Sync each mounted filesystem.
2539167Ssam  */
25439491Smckusick /* ARGSUSED */
25542441Smckusick sync(p, uap, retval)
25645914Smckusick 	struct proc *p;
25747540Skarels 	void *uap;
25842441Smckusick 	int *retval;
2596254Sroot {
26037741Smckusick 	register struct mount *mp;
26141298Smckusick 	struct mount *omp;
26237741Smckusick 
26337741Smckusick 	mp = rootfs;
26437741Smckusick 	do {
26540343Smckusick 		/*
26640343Smckusick 		 * The lock check below is to avoid races with mount
26740343Smckusick 		 * and unmount.
26840343Smckusick 		 */
26941400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
27041298Smckusick 		    !vfs_busy(mp)) {
271*54441Smckusick 			VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
27241298Smckusick 			omp = mp;
27341400Smckusick 			mp = mp->mnt_next;
27441298Smckusick 			vfs_unbusy(omp);
27541298Smckusick 		} else
27641400Smckusick 			mp = mp->mnt_next;
27737741Smckusick 	} while (mp != rootfs);
27847688Skarels 	return (0);
27937741Smckusick }
28037741Smckusick 
28137741Smckusick /*
28249365Smckusick  * Operate on filesystem quotas.
28341298Smckusick  */
28442441Smckusick /* ARGSUSED */
28542441Smckusick quotactl(p, uap, retval)
28645914Smckusick 	struct proc *p;
28742441Smckusick 	register struct args {
28841298Smckusick 		char *path;
28941298Smckusick 		int cmd;
29041298Smckusick 		int uid;
29141298Smckusick 		caddr_t arg;
29242441Smckusick 	} *uap;
29342441Smckusick 	int *retval;
29442441Smckusick {
29541298Smckusick 	register struct mount *mp;
29641298Smckusick 	int error;
29747540Skarels 	struct nameidata nd;
29841298Smckusick 
29952322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
30052322Smckusick 	if (error = namei(&nd))
30147540Skarels 		return (error);
30252322Smckusick 	mp = nd.ni_vp->v_mount;
30352322Smckusick 	vrele(nd.ni_vp);
30448026Smckusick 	return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p));
30541298Smckusick }
30641298Smckusick 
30741298Smckusick /*
30849365Smckusick  * Get filesystem statistics.
30937741Smckusick  */
31042441Smckusick /* ARGSUSED */
31142441Smckusick statfs(p, uap, retval)
31245914Smckusick 	struct proc *p;
31342441Smckusick 	register struct args {
31437741Smckusick 		char *path;
31537741Smckusick 		struct statfs *buf;
31642441Smckusick 	} *uap;
31742441Smckusick 	int *retval;
31842441Smckusick {
31939464Smckusick 	register struct mount *mp;
32040343Smckusick 	register struct statfs *sp;
32137741Smckusick 	int error;
32247540Skarels 	struct nameidata nd;
32337741Smckusick 
32452322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
32552322Smckusick 	if (error = namei(&nd))
32647540Skarels 		return (error);
32752322Smckusick 	mp = nd.ni_vp->v_mount;
32841400Smckusick 	sp = &mp->mnt_stat;
32952322Smckusick 	vrele(nd.ni_vp);
33048026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
33147540Skarels 		return (error);
33241400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
33347540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
33437741Smckusick }
33537741Smckusick 
33642441Smckusick /*
33749365Smckusick  * Get filesystem statistics.
33842441Smckusick  */
33942441Smckusick /* ARGSUSED */
34042441Smckusick fstatfs(p, uap, retval)
34145914Smckusick 	struct proc *p;
34242441Smckusick 	register struct args {
34337741Smckusick 		int fd;
34437741Smckusick 		struct statfs *buf;
34542441Smckusick 	} *uap;
34642441Smckusick 	int *retval;
34742441Smckusick {
34837741Smckusick 	struct file *fp;
34939464Smckusick 	struct mount *mp;
35040343Smckusick 	register struct statfs *sp;
35137741Smckusick 	int error;
35237741Smckusick 
35345914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
35447540Skarels 		return (error);
35539464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
35641400Smckusick 	sp = &mp->mnt_stat;
35748026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
35847540Skarels 		return (error);
35941400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
36047540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
36137741Smckusick }
36237741Smckusick 
36337741Smckusick /*
36449365Smckusick  * Get statistics on all filesystems.
36538270Smckusick  */
36642441Smckusick getfsstat(p, uap, retval)
36745914Smckusick 	struct proc *p;
36842441Smckusick 	register struct args {
36938270Smckusick 		struct statfs *buf;
37038270Smckusick 		long bufsize;
37140343Smckusick 		int flags;
37242441Smckusick 	} *uap;
37342441Smckusick 	int *retval;
37442441Smckusick {
37538270Smckusick 	register struct mount *mp;
37640343Smckusick 	register struct statfs *sp;
37739606Smckusick 	caddr_t sfsp;
37838270Smckusick 	long count, maxcount, error;
37938270Smckusick 
38038270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
38139606Smckusick 	sfsp = (caddr_t)uap->buf;
38238270Smckusick 	mp = rootfs;
38338270Smckusick 	count = 0;
38438270Smckusick 	do {
38541400Smckusick 		if (sfsp && count < maxcount &&
38641400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
38741400Smckusick 			sp = &mp->mnt_stat;
38840343Smckusick 			/*
38940343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
39040343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
39140343Smckusick 			 */
39240343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
39340343Smckusick 			    (uap->flags & MNT_WAIT)) &&
39448026Smckusick 			    (error = VFS_STATFS(mp, sp, p))) {
39541400Smckusick 				mp = mp->mnt_prev;
39639607Smckusick 				continue;
39739607Smckusick 			}
39841400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
39940343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
40047540Skarels 				return (error);
40140343Smckusick 			sfsp += sizeof(*sp);
40238270Smckusick 		}
40339606Smckusick 		count++;
40441400Smckusick 		mp = mp->mnt_prev;
40538270Smckusick 	} while (mp != rootfs);
40638270Smckusick 	if (sfsp && count > maxcount)
40742441Smckusick 		*retval = maxcount;
40838270Smckusick 	else
40942441Smckusick 		*retval = count;
41047540Skarels 	return (0);
41138270Smckusick }
41238270Smckusick 
41338270Smckusick /*
41438259Smckusick  * Change current working directory to a given file descriptor.
41538259Smckusick  */
41642441Smckusick /* ARGSUSED */
41742441Smckusick fchdir(p, uap, retval)
41845914Smckusick 	struct proc *p;
41942441Smckusick 	struct args {
42042441Smckusick 		int	fd;
42142441Smckusick 	} *uap;
42242441Smckusick 	int *retval;
42338259Smckusick {
42453548Sheideman 	USES_VOP_ACCESS;
42553548Sheideman 	USES_VOP_LOCK;
42653548Sheideman 	USES_VOP_UNLOCK;
42745914Smckusick 	register struct filedesc *fdp = p->p_fd;
42838259Smckusick 	register struct vnode *vp;
42938259Smckusick 	struct file *fp;
43038259Smckusick 	int error;
43138259Smckusick 
43245914Smckusick 	if (error = getvnode(fdp, uap->fd, &fp))
43347540Skarels 		return (error);
43438259Smckusick 	vp = (struct vnode *)fp->f_data;
43538259Smckusick 	VOP_LOCK(vp);
43638259Smckusick 	if (vp->v_type != VDIR)
43738259Smckusick 		error = ENOTDIR;
43838259Smckusick 	else
43948026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
44038259Smckusick 	VOP_UNLOCK(vp);
44139860Smckusick 	if (error)
44247540Skarels 		return (error);
44339860Smckusick 	VREF(vp);
44445914Smckusick 	vrele(fdp->fd_cdir);
44545914Smckusick 	fdp->fd_cdir = vp;
44647540Skarels 	return (0);
44738259Smckusick }
44838259Smckusick 
44938259Smckusick /*
45037741Smckusick  * Change current working directory (``.'').
45137741Smckusick  */
45242441Smckusick /* ARGSUSED */
45342441Smckusick chdir(p, uap, retval)
45445914Smckusick 	struct proc *p;
45542441Smckusick 	struct args {
45642441Smckusick 		char	*fname;
45742441Smckusick 	} *uap;
45842441Smckusick 	int *retval;
45937741Smckusick {
46045914Smckusick 	register struct filedesc *fdp = p->p_fd;
46137741Smckusick 	int error;
46247540Skarels 	struct nameidata nd;
4636254Sroot 
46452322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
46552781Sralph 	if (error = chdirec(&nd, p))
46647540Skarels 		return (error);
46745914Smckusick 	vrele(fdp->fd_cdir);
46852322Smckusick 	fdp->fd_cdir = nd.ni_vp;
46947540Skarels 	return (0);
47037741Smckusick }
4716254Sroot 
47237741Smckusick /*
47337741Smckusick  * Change notion of root (``/'') directory.
47437741Smckusick  */
47542441Smckusick /* ARGSUSED */
47642441Smckusick chroot(p, uap, retval)
47745914Smckusick 	struct proc *p;
47842441Smckusick 	struct args {
47942441Smckusick 		char	*fname;
48042441Smckusick 	} *uap;
48142441Smckusick 	int *retval;
48237741Smckusick {
48345914Smckusick 	register struct filedesc *fdp = p->p_fd;
48437741Smckusick 	int error;
48547540Skarels 	struct nameidata nd;
48637741Smckusick 
48747540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
48847540Skarels 		return (error);
48952322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
49052781Sralph 	if (error = chdirec(&nd, p))
49147540Skarels 		return (error);
49245914Smckusick 	if (fdp->fd_rdir != NULL)
49345914Smckusick 		vrele(fdp->fd_rdir);
49452322Smckusick 	fdp->fd_rdir = nd.ni_vp;
49547540Skarels 	return (0);
4966254Sroot }
4976254Sroot 
49837Sbill /*
49937741Smckusick  * Common routine for chroot and chdir.
50037741Smckusick  */
50147540Skarels chdirec(ndp, p)
50252322Smckusick 	register struct nameidata *ndp;
50347540Skarels 	struct proc *p;
50437741Smckusick {
50553548Sheideman 	USES_VOP_ACCESS;
50653548Sheideman 	USES_VOP_UNLOCK;
50737741Smckusick 	struct vnode *vp;
50837741Smckusick 	int error;
50937741Smckusick 
51052322Smckusick 	if (error = namei(ndp))
51137741Smckusick 		return (error);
51237741Smckusick 	vp = ndp->ni_vp;
51337741Smckusick 	if (vp->v_type != VDIR)
51437741Smckusick 		error = ENOTDIR;
51537741Smckusick 	else
51648026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
51737741Smckusick 	VOP_UNLOCK(vp);
51837741Smckusick 	if (error)
51937741Smckusick 		vrele(vp);
52037741Smckusick 	return (error);
52137741Smckusick }
52237741Smckusick 
52337741Smckusick /*
5246254Sroot  * Open system call.
52542441Smckusick  * Check permissions, allocate an open file structure,
52642441Smckusick  * and call the device open routine if any.
5276254Sroot  */
52842441Smckusick open(p, uap, retval)
52945914Smckusick 	struct proc *p;
53042441Smckusick 	register struct args {
5316254Sroot 		char	*fname;
5327701Ssam 		int	mode;
53312756Ssam 		int	crtmode;
53442441Smckusick 	} *uap;
53542441Smckusick 	int *retval;
5366254Sroot {
53753548Sheideman 	USES_VOP_ADVLOCK;
53853548Sheideman 	USES_VOP_UNLOCK;
53945914Smckusick 	register struct filedesc *fdp = p->p_fd;
54042441Smckusick 	register struct file *fp;
54150111Smckusick 	register struct vnode *vp;
54237741Smckusick 	int fmode, cmode;
54337741Smckusick 	struct file *nfp;
54449945Smckusick 	int type, indx, error;
54549945Smckusick 	struct flock lf;
54647540Skarels 	struct nameidata nd;
54737741Smckusick 	extern struct fileops vnops;
5486254Sroot 
54945914Smckusick 	if (error = falloc(p, &nfp, &indx))
55047540Skarels 		return (error);
55137741Smckusick 	fp = nfp;
55246553Skarels 	fmode = FFLAGS(uap->mode);
55345914Smckusick 	cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX;
55452322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
55545202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
55652322Smckusick 	if (error = vn_open(&nd, fmode, cmode)) {
55753828Spendry 		int dfd = p->p_dupfd;
55853828Spendry 		p->p_dupfd = 0;
55949980Smckusick 		ffree(fp);
56053828Spendry 		if ((error == ENODEV || error == ENXIO) && /* XXX from fdopen */
56153828Spendry 		    dfd >= 0 &&
56253828Spendry 		    (error = dupfdopen(fdp, indx, p->p_dupfd,
56353828Spendry 					fmode, error)) == 0) {
56442441Smckusick 			*retval = indx;
56547540Skarels 			return (0);
56642441Smckusick 		}
56740884Smckusick 		if (error == ERESTART)
56840884Smckusick 			error = EINTR;
56947688Skarels 		fdp->fd_ofiles[indx] = NULL;
57047540Skarels 		return (error);
57112756Ssam 	}
57253828Spendry 	p->p_dupfd = 0;
57352322Smckusick 	vp = nd.ni_vp;
57449949Smckusick 	fp->f_flag = fmode & FMASK;
57554348Smckusick 	fp->f_type = DTYPE_VNODE;
57654348Smckusick 	fp->f_ops = &vnops;
57754348Smckusick 	fp->f_data = (caddr_t)vp;
57849945Smckusick 	if (fmode & (O_EXLOCK | O_SHLOCK)) {
57949945Smckusick 		lf.l_whence = SEEK_SET;
58049945Smckusick 		lf.l_start = 0;
58149945Smckusick 		lf.l_len = 0;
58249945Smckusick 		if (fmode & O_EXLOCK)
58349945Smckusick 			lf.l_type = F_WRLCK;
58449945Smckusick 		else
58549945Smckusick 			lf.l_type = F_RDLCK;
58649945Smckusick 		type = F_FLOCK;
58749945Smckusick 		if ((fmode & FNONBLOCK) == 0)
58849945Smckusick 			type |= F_WAIT;
58950111Smckusick 		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
59050111Smckusick 			VOP_UNLOCK(vp);
59150111Smckusick 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
59249980Smckusick 			ffree(fp);
59349945Smckusick 			fdp->fd_ofiles[indx] = NULL;
59449945Smckusick 			return (error);
59549945Smckusick 		}
59649949Smckusick 		fp->f_flag |= FHASLOCK;
59749945Smckusick 	}
59850111Smckusick 	VOP_UNLOCK(vp);
59942441Smckusick 	*retval = indx;
60047540Skarels 	return (0);
6016254Sroot }
6026254Sroot 
60342955Smckusick #ifdef COMPAT_43
6046254Sroot /*
60542441Smckusick  * Creat system call.
6066254Sroot  */
60742955Smckusick ocreat(p, uap, retval)
60842441Smckusick 	struct proc *p;
60942441Smckusick 	register struct args {
61042441Smckusick 		char	*fname;
61142441Smckusick 		int	fmode;
61242441Smckusick 	} *uap;
61342441Smckusick 	int *retval;
6146254Sroot {
61542441Smckusick 	struct args {
6166254Sroot 		char	*fname;
61742441Smckusick 		int	mode;
61842441Smckusick 		int	crtmode;
61942441Smckusick 	} openuap;
62042441Smckusick 
62142441Smckusick 	openuap.fname = uap->fname;
62242441Smckusick 	openuap.crtmode = uap->fmode;
62342441Smckusick 	openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
62447540Skarels 	return (open(p, &openuap, retval));
62542441Smckusick }
62642955Smckusick #endif /* COMPAT_43 */
62742441Smckusick 
62842441Smckusick /*
62949365Smckusick  * Mknod system call.
63042441Smckusick  */
63142441Smckusick /* ARGSUSED */
63242441Smckusick mknod(p, uap, retval)
63345914Smckusick 	struct proc *p;
63442441Smckusick 	register struct args {
63542441Smckusick 		char	*fname;
6366254Sroot 		int	fmode;
6376254Sroot 		int	dev;
63842441Smckusick 	} *uap;
63942441Smckusick 	int *retval;
64042441Smckusick {
64153548Sheideman 	USES_VOP_ABORTOP;
64253548Sheideman 	USES_VOP_MKNOD;
64337741Smckusick 	register struct vnode *vp;
64437741Smckusick 	struct vattr vattr;
64537741Smckusick 	int error;
64647540Skarels 	struct nameidata nd;
6476254Sroot 
64847540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
64947540Skarels 		return (error);
65052322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p);
65152322Smckusick 	if (error = namei(&nd))
65247540Skarels 		return (error);
65352322Smckusick 	vp = nd.ni_vp;
65437741Smckusick 	if (vp != NULL) {
65537741Smckusick 		error = EEXIST;
65612756Ssam 		goto out;
6576254Sroot 	}
65841362Smckusick 	VATTR_NULL(&vattr);
65940635Smckusick 	switch (uap->fmode & S_IFMT) {
66012756Ssam 
66140635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
66237741Smckusick 		vattr.va_type = VBAD;
66337741Smckusick 		break;
66440635Smckusick 	case S_IFCHR:
66537741Smckusick 		vattr.va_type = VCHR;
66637741Smckusick 		break;
66740635Smckusick 	case S_IFBLK:
66837741Smckusick 		vattr.va_type = VBLK;
66937741Smckusick 		break;
67037741Smckusick 	default:
67137741Smckusick 		error = EINVAL;
67237741Smckusick 		goto out;
6736254Sroot 	}
67445914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
67537741Smckusick 	vattr.va_rdev = uap->dev;
6766254Sroot out:
67742465Smckusick 	if (!error) {
67852322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
67952322Smckusick 		error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
68042465Smckusick 	} else {
68152322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
68252322Smckusick 		if (nd.ni_dvp == vp)
68352322Smckusick 			vrele(nd.ni_dvp);
68443344Smckusick 		else
68552322Smckusick 			vput(nd.ni_dvp);
68642465Smckusick 		if (vp)
68742465Smckusick 			vrele(vp);
68842465Smckusick 	}
68947540Skarels 	return (error);
6906254Sroot }
6916254Sroot 
6926254Sroot /*
69349365Smckusick  * Mkfifo system call.
69440285Smckusick  */
69542441Smckusick /* ARGSUSED */
69642441Smckusick mkfifo(p, uap, retval)
69745914Smckusick 	struct proc *p;
69842441Smckusick 	register struct args {
69940285Smckusick 		char	*fname;
70040285Smckusick 		int	fmode;
70142441Smckusick 	} *uap;
70242441Smckusick 	int *retval;
70342441Smckusick {
70453548Sheideman 	USES_VOP_ABORTOP;
70553548Sheideman 	USES_VOP_MKNOD;
70640285Smckusick 	struct vattr vattr;
70740285Smckusick 	int error;
70847540Skarels 	struct nameidata nd;
70940285Smckusick 
71040285Smckusick #ifndef FIFO
71147540Skarels 	return (EOPNOTSUPP);
71240285Smckusick #else
71352322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p);
71452322Smckusick 	if (error = namei(&nd))
71547540Skarels 		return (error);
71652322Smckusick 	if (nd.ni_vp != NULL) {
71752322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
71852322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
71952322Smckusick 			vrele(nd.ni_dvp);
72043344Smckusick 		else
72152322Smckusick 			vput(nd.ni_dvp);
72252322Smckusick 		vrele(nd.ni_vp);
72347540Skarels 		return (EEXIST);
72440285Smckusick 	}
72545785Sbostic 	VATTR_NULL(&vattr);
72645785Sbostic 	vattr.va_type = VFIFO;
72745914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
72852322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
72952322Smckusick 	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
73040285Smckusick #endif /* FIFO */
73140285Smckusick }
73240285Smckusick 
73340285Smckusick /*
73449365Smckusick  * Link system call.
7356254Sroot  */
73642441Smckusick /* ARGSUSED */
73742441Smckusick link(p, uap, retval)
73845914Smckusick 	struct proc *p;
73942441Smckusick 	register struct args {
7406254Sroot 		char	*target;
7416254Sroot 		char	*linkname;
74242441Smckusick 	} *uap;
74342441Smckusick 	int *retval;
74442441Smckusick {
74553548Sheideman 	USES_VOP_ABORTOP;
74653548Sheideman 	USES_VOP_LINK;
74737741Smckusick 	register struct vnode *vp, *xp;
74837741Smckusick 	int error;
74947540Skarels 	struct nameidata nd;
7506254Sroot 
75152322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->target, p);
75252322Smckusick 	if (error = namei(&nd))
75347540Skarels 		return (error);
75452322Smckusick 	vp = nd.ni_vp;
75537741Smckusick 	if (vp->v_type == VDIR &&
75647540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
75737741Smckusick 		goto out1;
75852322Smckusick 	nd.ni_cnd.cn_nameiop = CREATE;
75952322Smckusick 	nd.ni_cnd.cn_flags = LOCKPARENT;
76052322Smckusick 	nd.ni_dirp = (caddr_t)uap->linkname;
76152322Smckusick 	if (error = namei(&nd))
76237741Smckusick 		goto out1;
76352322Smckusick 	xp = nd.ni_vp;
7646254Sroot 	if (xp != NULL) {
76537741Smckusick 		error = EEXIST;
7666254Sroot 		goto out;
7676254Sroot 	}
76852322Smckusick 	xp = nd.ni_dvp;
7696254Sroot out:
77042465Smckusick 	if (!error) {
77152192Smckusick 		LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE);
77252192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
77352821Smckusick 		error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
77442465Smckusick 	} else {
77552322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
77652322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
77752322Smckusick 			vrele(nd.ni_dvp);
77843344Smckusick 		else
77952322Smckusick 			vput(nd.ni_dvp);
78052322Smckusick 		if (nd.ni_vp)
78152322Smckusick 			vrele(nd.ni_vp);
78242465Smckusick 	}
78337741Smckusick out1:
78437741Smckusick 	vrele(vp);
78547540Skarels 	return (error);
7866254Sroot }
7876254Sroot 
7886254Sroot /*
78949365Smckusick  * Make a symbolic link.
7906254Sroot  */
79142441Smckusick /* ARGSUSED */
79242441Smckusick symlink(p, uap, retval)
79345914Smckusick 	struct proc *p;
79442441Smckusick 	register struct args {
7956254Sroot 		char	*target;
7966254Sroot 		char	*linkname;
79742441Smckusick 	} *uap;
79842441Smckusick 	int *retval;
79942441Smckusick {
80053548Sheideman 	USES_VOP_ABORTOP;
80153548Sheideman 	USES_VOP_SYMLINK;
80237741Smckusick 	struct vattr vattr;
80337741Smckusick 	char *target;
80437741Smckusick 	int error;
80547540Skarels 	struct nameidata nd;
8066254Sroot 
80737741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
80837741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
80942465Smckusick 		goto out;
81052322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->linkname, p);
81152322Smckusick 	if (error = namei(&nd))
81242465Smckusick 		goto out;
81352322Smckusick 	if (nd.ni_vp) {
81452322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
81552322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
81652322Smckusick 			vrele(nd.ni_dvp);
81743344Smckusick 		else
81852322Smckusick 			vput(nd.ni_dvp);
81952322Smckusick 		vrele(nd.ni_vp);
82037741Smckusick 		error = EEXIST;
82137741Smckusick 		goto out;
8226254Sroot 	}
82341362Smckusick 	VATTR_NULL(&vattr);
82445914Smckusick 	vattr.va_mode = 0777 &~ p->p_fd->fd_cmask;
82552322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
82652322Smckusick 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, target);
82737741Smckusick out:
82837741Smckusick 	FREE(target, M_NAMEI);
82947540Skarels 	return (error);
8306254Sroot }
8316254Sroot 
8326254Sroot /*
83349365Smckusick  * Delete a name from the filesystem.
8346254Sroot  */
83542441Smckusick /* ARGSUSED */
83642441Smckusick unlink(p, uap, retval)
83745914Smckusick 	struct proc *p;
83842441Smckusick 	struct args {
83952322Smckusick 		char	*name;
84042441Smckusick 	} *uap;
84142441Smckusick 	int *retval;
8426254Sroot {
84353548Sheideman 	USES_VOP_ABORTOP;
84453548Sheideman 	USES_VOP_REMOVE;
84537741Smckusick 	register struct vnode *vp;
84637741Smckusick 	int error;
84747540Skarels 	struct nameidata nd;
8486254Sroot 
84952322Smckusick 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p);
85052322Smckusick 	if (error = namei(&nd))
85147540Skarels 		return (error);
85252322Smckusick 	vp = nd.ni_vp;
85337741Smckusick 	if (vp->v_type == VDIR &&
85447540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
8556254Sroot 		goto out;
8566254Sroot 	/*
85749365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
8586254Sroot 	 */
85937741Smckusick 	if (vp->v_flag & VROOT) {
86037741Smckusick 		error = EBUSY;
8616254Sroot 		goto out;
8626254Sroot 	}
86345738Smckusick 	(void) vnode_pager_uncache(vp);
8646254Sroot out:
86542465Smckusick 	if (!error) {
86652322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
86752192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
86852322Smckusick 		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
86942465Smckusick 	} else {
87052322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
87152322Smckusick 		if (nd.ni_dvp == vp)
87252322Smckusick 			vrele(nd.ni_dvp);
87343344Smckusick 		else
87452322Smckusick 			vput(nd.ni_dvp);
87542465Smckusick 		vput(vp);
87642465Smckusick 	}
87747540Skarels 	return (error);
8786254Sroot }
8796254Sroot 
88054348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
8816254Sroot /*
88249365Smckusick  * Seek system call.
8836254Sroot  */
88442441Smckusick lseek(p, uap, retval)
88545914Smckusick 	struct proc *p;
88642441Smckusick 	register struct args {
88737741Smckusick 		int	fdes;
88853468Smckusick 		long	off;
88953468Smckusick 		int	sbase;
89053468Smckusick 	} *uap;
89153468Smckusick 	long *retval;
89253468Smckusick {
89353468Smckusick 	struct nargs {
89453468Smckusick 		int	fdes;
8956254Sroot 		off_t	off;
8966254Sroot 		int	sbase;
89753468Smckusick 	} nuap;
89853468Smckusick 	quad_t qret;
89953468Smckusick 	int error;
90053468Smckusick 
90153468Smckusick 	nuap.fdes = uap->fdes;
90253468Smckusick 	nuap.off = uap->off;
90353468Smckusick 	nuap.sbase = uap->sbase;
90453759Smckusick 	error = __lseek(p, &nuap, &qret);
90553468Smckusick 	*retval = qret;
90653468Smckusick 	return (error);
90753468Smckusick }
90854348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
90953468Smckusick 
91053468Smckusick /*
91153468Smckusick  * Seek system call.
91253468Smckusick  */
91353759Smckusick __lseek(p, uap, retval)
91453468Smckusick 	struct proc *p;
91553468Smckusick 	register struct args {
91653468Smckusick 		int	fdes;
91753468Smckusick 		off_t	off;
91853468Smckusick 		int	sbase;
91942441Smckusick 	} *uap;
92042441Smckusick 	off_t *retval;
92142441Smckusick {
92253548Sheideman 	USES_VOP_GETATTR;
92347540Skarels 	struct ucred *cred = p->p_ucred;
92445914Smckusick 	register struct filedesc *fdp = p->p_fd;
92542441Smckusick 	register struct file *fp;
92637741Smckusick 	struct vattr vattr;
92737741Smckusick 	int error;
9286254Sroot 
92947540Skarels 	if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
93047688Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL)
93147540Skarels 		return (EBADF);
93237741Smckusick 	if (fp->f_type != DTYPE_VNODE)
93347540Skarels 		return (ESPIPE);
93413878Ssam 	switch (uap->sbase) {
93513878Ssam 
93613878Ssam 	case L_INCR:
93713878Ssam 		fp->f_offset += uap->off;
93813878Ssam 		break;
93913878Ssam 
94013878Ssam 	case L_XTND:
94137741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
94248026Smckusick 		    &vattr, cred, p))
94347540Skarels 			return (error);
94437741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
94513878Ssam 		break;
94613878Ssam 
94713878Ssam 	case L_SET:
94813878Ssam 		fp->f_offset = uap->off;
94913878Ssam 		break;
95013878Ssam 
95113878Ssam 	default:
95247540Skarels 		return (EINVAL);
95313878Ssam 	}
95442441Smckusick 	*retval = fp->f_offset;
95547540Skarels 	return (0);
9566254Sroot }
9576254Sroot 
9586254Sroot /*
95949365Smckusick  * Check access permissions.
9606254Sroot  */
96142441Smckusick /* ARGSUSED */
96242441Smckusick saccess(p, uap, retval)
96345914Smckusick 	struct proc *p;
96442441Smckusick 	register struct args {
9656254Sroot 		char	*fname;
9666254Sroot 		int	fmode;
96742441Smckusick 	} *uap;
96842441Smckusick 	int *retval;
96942441Smckusick {
97053548Sheideman 	USES_VOP_ACCESS;
97147540Skarels 	register struct ucred *cred = p->p_ucred;
97237741Smckusick 	register struct vnode *vp;
97337741Smckusick 	int error, mode, svuid, svgid;
97447540Skarels 	struct nameidata nd;
9756254Sroot 
97642441Smckusick 	svuid = cred->cr_uid;
97742441Smckusick 	svgid = cred->cr_groups[0];
97847540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
97947540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
98052322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
98152322Smckusick 	if (error = namei(&nd))
98237741Smckusick 		goto out1;
98352322Smckusick 	vp = nd.ni_vp;
98437741Smckusick 	/*
98537741Smckusick 	 * fmode == 0 means only check for exist
98637741Smckusick 	 */
98737741Smckusick 	if (uap->fmode) {
98837741Smckusick 		mode = 0;
98937741Smckusick 		if (uap->fmode & R_OK)
99037741Smckusick 			mode |= VREAD;
99137741Smckusick 		if (uap->fmode & W_OK)
99237741Smckusick 			mode |= VWRITE;
99337741Smckusick 		if (uap->fmode & X_OK)
99437741Smckusick 			mode |= VEXEC;
99539543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
99648026Smckusick 			error = VOP_ACCESS(vp, mode, cred, p);
9976254Sroot 	}
99837741Smckusick 	vput(vp);
99937741Smckusick out1:
100042441Smckusick 	cred->cr_uid = svuid;
100142441Smckusick 	cred->cr_groups[0] = svgid;
100247540Skarels 	return (error);
10036254Sroot }
10046254Sroot 
100554348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
10066254Sroot /*
100749365Smckusick  * Stat system call.
100849365Smckusick  * This version follows links.
100937Sbill  */
101042441Smckusick /* ARGSUSED */
101153759Smckusick ostat(p, uap, retval)
101245914Smckusick 	struct proc *p;
101342441Smckusick 	register struct args {
101442441Smckusick 		char	*fname;
101553468Smckusick 		struct ostat *ub;
101653468Smckusick 	} *uap;
101753468Smckusick 	int *retval;
101853468Smckusick {
101953468Smckusick 	struct stat sb;
102053468Smckusick 	struct ostat osb;
102153468Smckusick 	int error;
102253468Smckusick 	struct nameidata nd;
102353468Smckusick 
102453468Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
102553468Smckusick 	if (error = namei(&nd))
102653468Smckusick 		return (error);
102753468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
102853468Smckusick 	vput(nd.ni_vp);
102953468Smckusick 	if (error)
103053468Smckusick 		return (error);
103153468Smckusick 	cvtstat(&sb, &osb);
103253468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
103353468Smckusick 	return (error);
103453468Smckusick }
103553468Smckusick 
103653468Smckusick /*
103753468Smckusick  * Lstat system call.
103853468Smckusick  * This version does not follow links.
103953468Smckusick  */
104053468Smckusick /* ARGSUSED */
104153759Smckusick olstat(p, uap, retval)
104253468Smckusick 	struct proc *p;
104353468Smckusick 	register struct args {
104453468Smckusick 		char	*fname;
104553468Smckusick 		struct ostat *ub;
104653468Smckusick 	} *uap;
104753468Smckusick 	int *retval;
104853468Smckusick {
104953468Smckusick 	struct stat sb;
105053468Smckusick 	struct ostat osb;
105153468Smckusick 	int error;
105253468Smckusick 	struct nameidata nd;
105353468Smckusick 
105453468Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
105553468Smckusick 	if (error = namei(&nd))
105653468Smckusick 		return (error);
105753468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
105853468Smckusick 	vput(nd.ni_vp);
105953468Smckusick 	if (error)
106053468Smckusick 		return (error);
106153468Smckusick 	cvtstat(&sb, &osb);
106253468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
106353468Smckusick 	return (error);
106453468Smckusick }
106553468Smckusick 
106653468Smckusick /*
106753468Smckusick  * convert from an old to a new stat structure.
106853468Smckusick  */
106953468Smckusick cvtstat(st, ost)
107053468Smckusick 	struct stat *st;
107153468Smckusick 	struct ostat *ost;
107253468Smckusick {
107353468Smckusick 
107453468Smckusick 	ost->st_dev = st->st_dev;
107553468Smckusick 	ost->st_ino = st->st_ino;
107653468Smckusick 	ost->st_mode = st->st_mode;
107753468Smckusick 	ost->st_nlink = st->st_nlink;
107853468Smckusick 	ost->st_uid = st->st_uid;
107953468Smckusick 	ost->st_gid = st->st_gid;
108053468Smckusick 	ost->st_rdev = st->st_rdev;
108153468Smckusick 	if (st->st_size < (quad_t)1 << 32)
108253468Smckusick 		ost->st_size = st->st_size;
108353468Smckusick 	else
108453468Smckusick 		ost->st_size = -2;
108553468Smckusick 	ost->st_atime = st->st_atime;
108653468Smckusick 	ost->st_mtime = st->st_mtime;
108753468Smckusick 	ost->st_ctime = st->st_ctime;
108853468Smckusick 	ost->st_blksize = st->st_blksize;
108953468Smckusick 	ost->st_blocks = st->st_blocks;
109053468Smckusick 	ost->st_flags = st->st_flags;
109153468Smckusick 	ost->st_gen = st->st_gen;
109253468Smckusick }
109354348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
109453468Smckusick 
109553468Smckusick /*
109653468Smckusick  * Stat system call.
109753468Smckusick  * This version follows links.
109853468Smckusick  */
109953468Smckusick /* ARGSUSED */
110053759Smckusick stat(p, uap, retval)
110153468Smckusick 	struct proc *p;
110253468Smckusick 	register struct args {
110353468Smckusick 		char	*fname;
110442441Smckusick 		struct stat *ub;
110542441Smckusick 	} *uap;
110642441Smckusick 	int *retval;
110737Sbill {
110842441Smckusick 	struct stat sb;
110942441Smckusick 	int error;
111047540Skarels 	struct nameidata nd;
111137Sbill 
111252322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
111352322Smckusick 	if (error = namei(&nd))
111447540Skarels 		return (error);
111552322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
111652322Smckusick 	vput(nd.ni_vp);
111742441Smckusick 	if (error)
111847540Skarels 		return (error);
111942441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
112047540Skarels 	return (error);
112137Sbill }
112237Sbill 
112337Sbill /*
112449365Smckusick  * Lstat system call.
112549365Smckusick  * This version does not follow links.
11265992Swnj  */
112742441Smckusick /* ARGSUSED */
112853759Smckusick lstat(p, uap, retval)
112945914Smckusick 	struct proc *p;
113042441Smckusick 	register struct args {
11315992Swnj 		char	*fname;
113212756Ssam 		struct stat *ub;
113342441Smckusick 	} *uap;
113442441Smckusick 	int *retval;
113542441Smckusick {
113612756Ssam 	struct stat sb;
113737741Smckusick 	int error;
113847540Skarels 	struct nameidata nd;
11395992Swnj 
114052322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
114152322Smckusick 	if (error = namei(&nd))
114247540Skarels 		return (error);
114352322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
114452322Smckusick 	vput(nd.ni_vp);
114537741Smckusick 	if (error)
114647540Skarels 		return (error);
114737741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
114847540Skarels 	return (error);
11495992Swnj }
11505992Swnj 
11515992Swnj /*
115249365Smckusick  * Return target name of a symbolic link.
115337Sbill  */
115442441Smckusick /* ARGSUSED */
115542441Smckusick readlink(p, uap, retval)
115645914Smckusick 	struct proc *p;
115742441Smckusick 	register struct args {
11585992Swnj 		char	*name;
11595992Swnj 		char	*buf;
11605992Swnj 		int	count;
116142441Smckusick 	} *uap;
116242441Smckusick 	int *retval;
116342441Smckusick {
116453548Sheideman 	USES_VOP_READLINK;
116537741Smckusick 	register struct vnode *vp;
116637741Smckusick 	struct iovec aiov;
116737741Smckusick 	struct uio auio;
116837741Smckusick 	int error;
116947540Skarels 	struct nameidata nd;
11705992Swnj 
117152322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p);
117252322Smckusick 	if (error = namei(&nd))
117347540Skarels 		return (error);
117452322Smckusick 	vp = nd.ni_vp;
117537741Smckusick 	if (vp->v_type != VLNK) {
117637741Smckusick 		error = EINVAL;
11775992Swnj 		goto out;
11785992Swnj 	}
117937741Smckusick 	aiov.iov_base = uap->buf;
118037741Smckusick 	aiov.iov_len = uap->count;
118137741Smckusick 	auio.uio_iov = &aiov;
118237741Smckusick 	auio.uio_iovcnt = 1;
118337741Smckusick 	auio.uio_offset = 0;
118437741Smckusick 	auio.uio_rw = UIO_READ;
118537741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
118648026Smckusick 	auio.uio_procp = p;
118737741Smckusick 	auio.uio_resid = uap->count;
118847540Skarels 	error = VOP_READLINK(vp, &auio, p->p_ucred);
11895992Swnj out:
119037741Smckusick 	vput(vp);
119142441Smckusick 	*retval = uap->count - auio.uio_resid;
119247540Skarels 	return (error);
11935992Swnj }
11945992Swnj 
11959167Ssam /*
119638259Smckusick  * Change flags of a file given path name.
119738259Smckusick  */
119842441Smckusick /* ARGSUSED */
119942441Smckusick chflags(p, uap, retval)
120045914Smckusick 	struct proc *p;
120142441Smckusick 	register struct args {
120238259Smckusick 		char	*fname;
120338259Smckusick 		int	flags;
120442441Smckusick 	} *uap;
120542441Smckusick 	int *retval;
120642441Smckusick {
120753548Sheideman 	USES_VOP_SETATTR;
120838259Smckusick 	register struct vnode *vp;
120938259Smckusick 	struct vattr vattr;
121038259Smckusick 	int error;
121147540Skarels 	struct nameidata nd;
121238259Smckusick 
121352322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
121452322Smckusick 	if (error = namei(&nd))
121547540Skarels 		return (error);
121652322Smckusick 	vp = nd.ni_vp;
121741400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
121838259Smckusick 		error = EROFS;
121938259Smckusick 		goto out;
122038259Smckusick 	}
122145785Sbostic 	VATTR_NULL(&vattr);
122245785Sbostic 	vattr.va_flags = uap->flags;
122352192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
122448026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
122538259Smckusick out:
122638259Smckusick 	vput(vp);
122747540Skarels 	return (error);
122838259Smckusick }
122938259Smckusick 
123038259Smckusick /*
123138259Smckusick  * Change flags of a file given a file descriptor.
123238259Smckusick  */
123342441Smckusick /* ARGSUSED */
123442441Smckusick fchflags(p, uap, retval)
123545914Smckusick 	struct proc *p;
123642441Smckusick 	register struct args {
123738259Smckusick 		int	fd;
123838259Smckusick 		int	flags;
123942441Smckusick 	} *uap;
124042441Smckusick 	int *retval;
124142441Smckusick {
124253548Sheideman 	USES_VOP_LOCK;
124353548Sheideman 	USES_VOP_SETATTR;
124453548Sheideman 	USES_VOP_UNLOCK;
124538259Smckusick 	struct vattr vattr;
124638259Smckusick 	struct vnode *vp;
124738259Smckusick 	struct file *fp;
124838259Smckusick 	int error;
124938259Smckusick 
125045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
125147540Skarels 		return (error);
125238259Smckusick 	vp = (struct vnode *)fp->f_data;
125338259Smckusick 	VOP_LOCK(vp);
125441400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
125538259Smckusick 		error = EROFS;
125638259Smckusick 		goto out;
125738259Smckusick 	}
125845785Sbostic 	VATTR_NULL(&vattr);
125945785Sbostic 	vattr.va_flags = uap->flags;
126052192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
126148026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
126238259Smckusick out:
126338259Smckusick 	VOP_UNLOCK(vp);
126447540Skarels 	return (error);
126538259Smckusick }
126638259Smckusick 
126738259Smckusick /*
12689167Ssam  * Change mode of a file given path name.
12699167Ssam  */
127042441Smckusick /* ARGSUSED */
127142441Smckusick chmod(p, uap, retval)
127245914Smckusick 	struct proc *p;
127342441Smckusick 	register struct args {
12746254Sroot 		char	*fname;
12756254Sroot 		int	fmode;
127642441Smckusick 	} *uap;
127742441Smckusick 	int *retval;
127842441Smckusick {
127953548Sheideman 	USES_VOP_SETATTR;
128037741Smckusick 	register struct vnode *vp;
128137741Smckusick 	struct vattr vattr;
128237741Smckusick 	int error;
128347540Skarels 	struct nameidata nd;
12845992Swnj 
128552322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
128652322Smckusick 	if (error = namei(&nd))
128747540Skarels 		return (error);
128852322Smckusick 	vp = nd.ni_vp;
128941400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
129037741Smckusick 		error = EROFS;
129137741Smckusick 		goto out;
129237741Smckusick 	}
129345785Sbostic 	VATTR_NULL(&vattr);
129445785Sbostic 	vattr.va_mode = uap->fmode & 07777;
129552192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
129648026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
129737741Smckusick out:
129837741Smckusick 	vput(vp);
129947540Skarels 	return (error);
13007701Ssam }
13017439Sroot 
13029167Ssam /*
13039167Ssam  * Change mode of a file given a file descriptor.
13049167Ssam  */
130542441Smckusick /* ARGSUSED */
130642441Smckusick fchmod(p, uap, retval)
130745914Smckusick 	struct proc *p;
130842441Smckusick 	register struct args {
13097701Ssam 		int	fd;
13107701Ssam 		int	fmode;
131142441Smckusick 	} *uap;
131242441Smckusick 	int *retval;
131342441Smckusick {
131453548Sheideman 	USES_VOP_LOCK;
131553548Sheideman 	USES_VOP_SETATTR;
131653548Sheideman 	USES_VOP_UNLOCK;
131737741Smckusick 	struct vattr vattr;
131837741Smckusick 	struct vnode *vp;
131937741Smckusick 	struct file *fp;
132037741Smckusick 	int error;
13217701Ssam 
132245914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
132347540Skarels 		return (error);
132437741Smckusick 	vp = (struct vnode *)fp->f_data;
132537741Smckusick 	VOP_LOCK(vp);
132641400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
132737741Smckusick 		error = EROFS;
132837741Smckusick 		goto out;
13297439Sroot 	}
133045785Sbostic 	VATTR_NULL(&vattr);
133145785Sbostic 	vattr.va_mode = uap->fmode & 07777;
133252192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
133348026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
133437741Smckusick out:
133537741Smckusick 	VOP_UNLOCK(vp);
133647540Skarels 	return (error);
13375992Swnj }
13385992Swnj 
13399167Ssam /*
13409167Ssam  * Set ownership given a path name.
13419167Ssam  */
134242441Smckusick /* ARGSUSED */
134342441Smckusick chown(p, uap, retval)
134445914Smckusick 	struct proc *p;
134542441Smckusick 	register struct args {
13466254Sroot 		char	*fname;
13476254Sroot 		int	uid;
13486254Sroot 		int	gid;
134942441Smckusick 	} *uap;
135042441Smckusick 	int *retval;
135142441Smckusick {
135253548Sheideman 	USES_VOP_SETATTR;
135337741Smckusick 	register struct vnode *vp;
135437741Smckusick 	struct vattr vattr;
135537741Smckusick 	int error;
135647540Skarels 	struct nameidata nd;
135737Sbill 
135852322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
135952322Smckusick 	if (error = namei(&nd))
136047540Skarels 		return (error);
136152322Smckusick 	vp = nd.ni_vp;
136241400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
136337741Smckusick 		error = EROFS;
136437741Smckusick 		goto out;
136537741Smckusick 	}
136645785Sbostic 	VATTR_NULL(&vattr);
136745785Sbostic 	vattr.va_uid = uap->uid;
136845785Sbostic 	vattr.va_gid = uap->gid;
136952192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
137048026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
137137741Smckusick out:
137237741Smckusick 	vput(vp);
137347540Skarels 	return (error);
13747701Ssam }
13757439Sroot 
13769167Ssam /*
13779167Ssam  * Set ownership given a file descriptor.
13789167Ssam  */
137942441Smckusick /* ARGSUSED */
138042441Smckusick fchown(p, uap, retval)
138145914Smckusick 	struct proc *p;
138242441Smckusick 	register struct args {
13837701Ssam 		int	fd;
13847701Ssam 		int	uid;
13857701Ssam 		int	gid;
138642441Smckusick 	} *uap;
138742441Smckusick 	int *retval;
138842441Smckusick {
138953548Sheideman 	USES_VOP_LOCK;
139053548Sheideman 	USES_VOP_SETATTR;
139153548Sheideman 	USES_VOP_UNLOCK;
139237741Smckusick 	struct vattr vattr;
139337741Smckusick 	struct vnode *vp;
139437741Smckusick 	struct file *fp;
139537741Smckusick 	int error;
13967701Ssam 
139745914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
139847540Skarels 		return (error);
139937741Smckusick 	vp = (struct vnode *)fp->f_data;
140037741Smckusick 	VOP_LOCK(vp);
140141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
140237741Smckusick 		error = EROFS;
140337741Smckusick 		goto out;
140437741Smckusick 	}
140545785Sbostic 	VATTR_NULL(&vattr);
140645785Sbostic 	vattr.va_uid = uap->uid;
140745785Sbostic 	vattr.va_gid = uap->gid;
140852192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
140948026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
141037741Smckusick out:
141137741Smckusick 	VOP_UNLOCK(vp);
141247540Skarels 	return (error);
14137701Ssam }
14147701Ssam 
141542441Smckusick /*
141642441Smckusick  * Set the access and modification times of a file.
141742441Smckusick  */
141842441Smckusick /* ARGSUSED */
141942441Smckusick utimes(p, uap, retval)
142045914Smckusick 	struct proc *p;
142142441Smckusick 	register struct args {
142211811Ssam 		char	*fname;
142311811Ssam 		struct	timeval *tptr;
142442441Smckusick 	} *uap;
142542441Smckusick 	int *retval;
142642441Smckusick {
142753548Sheideman 	USES_VOP_SETATTR;
142837741Smckusick 	register struct vnode *vp;
142911811Ssam 	struct timeval tv[2];
143037741Smckusick 	struct vattr vattr;
143137741Smckusick 	int error;
143247540Skarels 	struct nameidata nd;
143311811Ssam 
143437741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
143547540Skarels 		return (error);
143652322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
143752322Smckusick 	if (error = namei(&nd))
143847540Skarels 		return (error);
143952322Smckusick 	vp = nd.ni_vp;
144041400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
144137741Smckusick 		error = EROFS;
144237741Smckusick 		goto out;
144321015Smckusick 	}
144445785Sbostic 	VATTR_NULL(&vattr);
144554100Smckusick 	vattr.va_atime.ts_sec = tv[0].tv_sec;
144654100Smckusick 	vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
144754100Smckusick 	vattr.va_mtime.ts_sec = tv[1].tv_sec;
144854100Smckusick 	vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
144952192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
145048026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
145137741Smckusick out:
145237741Smckusick 	vput(vp);
145347540Skarels 	return (error);
145411811Ssam }
145511811Ssam 
145654348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
14579167Ssam /*
14589167Ssam  * Truncate a file given its path name.
14599167Ssam  */
146042441Smckusick /* ARGSUSED */
146142441Smckusick truncate(p, uap, retval)
146245914Smckusick 	struct proc *p;
146342441Smckusick 	register struct args {
14647701Ssam 		char	*fname;
146553468Smckusick 		long	length;
146653468Smckusick 	} *uap;
146753468Smckusick 	int *retval;
146853468Smckusick {
146953468Smckusick 	struct nargs {
147053468Smckusick 		char	*fname;
147126473Skarels 		off_t	length;
147253468Smckusick 	} nuap;
147353468Smckusick 
147453468Smckusick 	nuap.fname = uap->fname;
147553468Smckusick 	nuap.length = uap->length;
147653759Smckusick 	return (__truncate(p, &nuap, retval));
147753468Smckusick }
147853468Smckusick 
147953468Smckusick /*
148053468Smckusick  * Truncate a file given a file descriptor.
148153468Smckusick  */
148253468Smckusick /* ARGSUSED */
148353468Smckusick ftruncate(p, uap, retval)
148453468Smckusick 	struct proc *p;
148553468Smckusick 	register struct args {
148653468Smckusick 		int	fd;
148753468Smckusick 		long	length;
148842441Smckusick 	} *uap;
148942441Smckusick 	int *retval;
149042441Smckusick {
149153468Smckusick 	struct nargs {
149253468Smckusick 		int	fd;
149353468Smckusick 		off_t	length;
149453468Smckusick 	} nuap;
149553468Smckusick 
149653468Smckusick 	nuap.fd = uap->fd;
149753468Smckusick 	nuap.length = uap->length;
149853759Smckusick 	return (__ftruncate(p, &nuap, retval));
149953468Smckusick }
150054348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
150153468Smckusick 
150253468Smckusick /*
150353468Smckusick  * Truncate a file given its path name.
150453468Smckusick  */
150553468Smckusick /* ARGSUSED */
150653759Smckusick __truncate(p, uap, retval)
150753468Smckusick 	struct proc *p;
150853468Smckusick 	register struct args {
150953468Smckusick 		char	*fname;
151053468Smckusick 		off_t	length;
151153468Smckusick 	} *uap;
151253468Smckusick 	int *retval;
151353468Smckusick {
151453548Sheideman 	USES_VOP_ACCESS;
151553548Sheideman 	USES_VOP_SETATTR;
151637741Smckusick 	register struct vnode *vp;
151737741Smckusick 	struct vattr vattr;
151837741Smckusick 	int error;
151947540Skarels 	struct nameidata nd;
15207701Ssam 
152152322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
152252322Smckusick 	if (error = namei(&nd))
152347540Skarels 		return (error);
152452322Smckusick 	vp = nd.ni_vp;
152537741Smckusick 	if (vp->v_type == VDIR) {
152637741Smckusick 		error = EISDIR;
152737741Smckusick 		goto out;
15287701Ssam 	}
152938399Smckusick 	if ((error = vn_writechk(vp)) ||
153048026Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)))
153137741Smckusick 		goto out;
153245785Sbostic 	VATTR_NULL(&vattr);
153345785Sbostic 	vattr.va_size = uap->length;
153452192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
153548026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
153637741Smckusick out:
153737741Smckusick 	vput(vp);
153847540Skarels 	return (error);
15397701Ssam }
15407701Ssam 
15419167Ssam /*
15429167Ssam  * Truncate a file given a file descriptor.
15439167Ssam  */
154442441Smckusick /* ARGSUSED */
154553759Smckusick __ftruncate(p, uap, retval)
154645914Smckusick 	struct proc *p;
154742441Smckusick 	register struct args {
15487701Ssam 		int	fd;
154926473Skarels 		off_t	length;
155042441Smckusick 	} *uap;
155142441Smckusick 	int *retval;
155242441Smckusick {
155353548Sheideman 	USES_VOP_LOCK;
155453548Sheideman 	USES_VOP_SETATTR;
155553548Sheideman 	USES_VOP_UNLOCK;
155637741Smckusick 	struct vattr vattr;
155737741Smckusick 	struct vnode *vp;
15587701Ssam 	struct file *fp;
155937741Smckusick 	int error;
15607701Ssam 
156145914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
156247540Skarels 		return (error);
156337741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
156447540Skarels 		return (EINVAL);
156537741Smckusick 	vp = (struct vnode *)fp->f_data;
156637741Smckusick 	VOP_LOCK(vp);
156737741Smckusick 	if (vp->v_type == VDIR) {
156837741Smckusick 		error = EISDIR;
156937741Smckusick 		goto out;
15707701Ssam 	}
157138399Smckusick 	if (error = vn_writechk(vp))
157237741Smckusick 		goto out;
157345785Sbostic 	VATTR_NULL(&vattr);
157445785Sbostic 	vattr.va_size = uap->length;
157552192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
157648026Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
157737741Smckusick out:
157837741Smckusick 	VOP_UNLOCK(vp);
157947540Skarels 	return (error);
15807701Ssam }
15817701Ssam 
15829167Ssam /*
15839167Ssam  * Synch an open file.
15849167Ssam  */
158542441Smckusick /* ARGSUSED */
158642441Smckusick fsync(p, uap, retval)
158745914Smckusick 	struct proc *p;
158842441Smckusick 	struct args {
158942441Smckusick 		int	fd;
159042441Smckusick 	} *uap;
159142441Smckusick 	int *retval;
15929167Ssam {
159353548Sheideman 	USES_VOP_FSYNC;
159453548Sheideman 	USES_VOP_LOCK;
159553548Sheideman 	USES_VOP_UNLOCK;
159639592Smckusick 	register struct vnode *vp;
15979167Ssam 	struct file *fp;
159837741Smckusick 	int error;
15999167Ssam 
160045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
160147540Skarels 		return (error);
160239592Smckusick 	vp = (struct vnode *)fp->f_data;
160339592Smckusick 	VOP_LOCK(vp);
1604*54441Smckusick 	error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
160539592Smckusick 	VOP_UNLOCK(vp);
160647540Skarels 	return (error);
16079167Ssam }
16089167Ssam 
16099167Ssam /*
16109167Ssam  * Rename system call.
16119167Ssam  *
16129167Ssam  * Source and destination must either both be directories, or both
16139167Ssam  * not be directories.  If target is a directory, it must be empty.
16149167Ssam  */
161542441Smckusick /* ARGSUSED */
161642441Smckusick rename(p, uap, retval)
161745914Smckusick 	struct proc *p;
161842441Smckusick 	register struct args {
16197701Ssam 		char	*from;
16207701Ssam 		char	*to;
162142441Smckusick 	} *uap;
162242441Smckusick 	int *retval;
162342441Smckusick {
162453548Sheideman 	USES_VOP_ABORTOP;
162553548Sheideman 	USES_VOP_RENAME;
162637741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
162749735Smckusick 	struct nameidata fromnd, tond;
162837741Smckusick 	int error;
16297701Ssam 
163052322Smckusick 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
163152322Smckusick 		uap->from, p);
163252322Smckusick 	if (error = namei(&fromnd))
163347540Skarels 		return (error);
163449735Smckusick 	fvp = fromnd.ni_vp;
163552322Smckusick 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
163652322Smckusick 		UIO_USERSPACE, uap->to, p);
163752322Smckusick 	if (error = namei(&tond)) {
163852230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
163949735Smckusick 		vrele(fromnd.ni_dvp);
164042465Smckusick 		vrele(fvp);
164142465Smckusick 		goto out1;
164242465Smckusick 	}
164337741Smckusick 	tdvp = tond.ni_dvp;
164437741Smckusick 	tvp = tond.ni_vp;
164537741Smckusick 	if (tvp != NULL) {
164637741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
164739242Sbostic 			error = ENOTDIR;
164837741Smckusick 			goto out;
164937741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
165039242Sbostic 			error = EISDIR;
165137741Smckusick 			goto out;
16529167Ssam 		}
16539167Ssam 	}
165439286Smckusick 	if (fvp == tdvp)
165537741Smckusick 		error = EINVAL;
165639286Smckusick 	/*
165749735Smckusick 	 * If source is the same as the destination (that is the
165849735Smckusick 	 * same inode number with the same name in the same directory),
165939286Smckusick 	 * then there is nothing to do.
166039286Smckusick 	 */
166149735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
166252322Smckusick 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
166352322Smckusick 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
166452322Smckusick 	      fromnd.ni_cnd.cn_namelen))
166539286Smckusick 		error = -1;
166637741Smckusick out:
166742465Smckusick 	if (!error) {
166852192Smckusick 		LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE);
166952192Smckusick 		if (fromnd.ni_dvp != tdvp)
167052192Smckusick 			LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
167152192Smckusick 		if (tvp)
167252192Smckusick 			LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE);
167352230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
167452230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
167542465Smckusick 	} else {
167652230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
167743344Smckusick 		if (tdvp == tvp)
167843344Smckusick 			vrele(tdvp);
167943344Smckusick 		else
168043344Smckusick 			vput(tdvp);
168142465Smckusick 		if (tvp)
168242465Smckusick 			vput(tvp);
168352230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
168449735Smckusick 		vrele(fromnd.ni_dvp);
168542465Smckusick 		vrele(fvp);
16869167Ssam 	}
168749735Smckusick 	vrele(tond.ni_startdir);
168852322Smckusick 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
168937741Smckusick out1:
169049735Smckusick 	vrele(fromnd.ni_startdir);
169152322Smckusick 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
169239286Smckusick 	if (error == -1)
169347540Skarels 		return (0);
169447540Skarels 	return (error);
16957701Ssam }
16967701Ssam 
16977535Sroot /*
169849365Smckusick  * Mkdir system call.
169912756Ssam  */
170042441Smckusick /* ARGSUSED */
170142441Smckusick mkdir(p, uap, retval)
170245914Smckusick 	struct proc *p;
170342441Smckusick 	register struct args {
170412756Ssam 		char	*name;
170512756Ssam 		int	dmode;
170642441Smckusick 	} *uap;
170742441Smckusick 	int *retval;
170842441Smckusick {
170953548Sheideman 	USES_VOP_ABORTOP;
171053548Sheideman 	USES_VOP_MKDIR;
171137741Smckusick 	register struct vnode *vp;
171237741Smckusick 	struct vattr vattr;
171337741Smckusick 	int error;
171447540Skarels 	struct nameidata nd;
171512756Ssam 
171652322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p);
171752322Smckusick 	if (error = namei(&nd))
171847540Skarels 		return (error);
171952322Smckusick 	vp = nd.ni_vp;
172037741Smckusick 	if (vp != NULL) {
172152322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
172252322Smckusick 		if (nd.ni_dvp == vp)
172352322Smckusick 			vrele(nd.ni_dvp);
172443344Smckusick 		else
172552322Smckusick 			vput(nd.ni_dvp);
172642465Smckusick 		vrele(vp);
172747540Skarels 		return (EEXIST);
172812756Ssam 	}
172941362Smckusick 	VATTR_NULL(&vattr);
173037741Smckusick 	vattr.va_type = VDIR;
173145914Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask;
173252322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
173352322Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
173438145Smckusick 	if (!error)
173552322Smckusick 		vput(nd.ni_vp);
173647540Skarels 	return (error);
173712756Ssam }
173812756Ssam 
173912756Ssam /*
174012756Ssam  * Rmdir system call.
174112756Ssam  */
174242441Smckusick /* ARGSUSED */
174342441Smckusick rmdir(p, uap, retval)
174445914Smckusick 	struct proc *p;
174542441Smckusick 	struct args {
174642441Smckusick 		char	*name;
174742441Smckusick 	} *uap;
174842441Smckusick 	int *retval;
174912756Ssam {
175053548Sheideman 	USES_VOP_ABORTOP;
175153548Sheideman 	USES_VOP_RMDIR;
175237741Smckusick 	register struct vnode *vp;
175337741Smckusick 	int error;
175447540Skarels 	struct nameidata nd;
175512756Ssam 
175652322Smckusick 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p);
175752322Smckusick 	if (error = namei(&nd))
175847540Skarels 		return (error);
175952322Smckusick 	vp = nd.ni_vp;
176037741Smckusick 	if (vp->v_type != VDIR) {
176137741Smckusick 		error = ENOTDIR;
176212756Ssam 		goto out;
176312756Ssam 	}
176412756Ssam 	/*
176537741Smckusick 	 * No rmdir "." please.
176612756Ssam 	 */
176752322Smckusick 	if (nd.ni_dvp == vp) {
176837741Smckusick 		error = EINVAL;
176912756Ssam 		goto out;
177012756Ssam 	}
177112756Ssam 	/*
177249365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
177312756Ssam 	 */
177437741Smckusick 	if (vp->v_flag & VROOT)
177537741Smckusick 		error = EBUSY;
177612756Ssam out:
177742465Smckusick 	if (!error) {
177852322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
177952192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
178052322Smckusick 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
178142465Smckusick 	} else {
178252322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
178352322Smckusick 		if (nd.ni_dvp == vp)
178452322Smckusick 			vrele(nd.ni_dvp);
178543344Smckusick 		else
178652322Smckusick 			vput(nd.ni_dvp);
178742465Smckusick 		vput(vp);
178842465Smckusick 	}
178947540Skarels 	return (error);
179012756Ssam }
179112756Ssam 
179237741Smckusick /*
179349365Smckusick  * Read a block of directory entries in a file system independent format.
179437741Smckusick  */
179542441Smckusick getdirentries(p, uap, retval)
179645914Smckusick 	struct proc *p;
179742441Smckusick 	register struct args {
179837741Smckusick 		int	fd;
179937741Smckusick 		char	*buf;
180037741Smckusick 		unsigned count;
180137741Smckusick 		long	*basep;
180242441Smckusick 	} *uap;
180342441Smckusick 	int *retval;
180442441Smckusick {
180553548Sheideman 	USES_VOP_LOCK;
180653548Sheideman 	USES_VOP_READDIR;
180753548Sheideman 	USES_VOP_UNLOCK;
180839592Smckusick 	register struct vnode *vp;
180916540Ssam 	struct file *fp;
181037741Smckusick 	struct uio auio;
181137741Smckusick 	struct iovec aiov;
181238129Smckusick 	off_t off;
1813*54441Smckusick 	int error;
181412756Ssam 
181545914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
181647540Skarels 		return (error);
181737741Smckusick 	if ((fp->f_flag & FREAD) == 0)
181847540Skarels 		return (EBADF);
181939592Smckusick 	vp = (struct vnode *)fp->f_data;
182039592Smckusick 	if (vp->v_type != VDIR)
182147540Skarels 		return (EINVAL);
182237741Smckusick 	aiov.iov_base = uap->buf;
182337741Smckusick 	aiov.iov_len = uap->count;
182437741Smckusick 	auio.uio_iov = &aiov;
182537741Smckusick 	auio.uio_iovcnt = 1;
182637741Smckusick 	auio.uio_rw = UIO_READ;
182737741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
182848026Smckusick 	auio.uio_procp = p;
182937741Smckusick 	auio.uio_resid = uap->count;
183039592Smckusick 	VOP_LOCK(vp);
183139592Smckusick 	auio.uio_offset = off = fp->f_offset;
1832*54441Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred);
183339592Smckusick 	fp->f_offset = auio.uio_offset;
183439592Smckusick 	VOP_UNLOCK(vp);
183539592Smckusick 	if (error)
183647540Skarels 		return (error);
183739592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
183842441Smckusick 	*retval = uap->count - auio.uio_resid;
183947540Skarels 	return (error);
184012756Ssam }
184112756Ssam 
184212756Ssam /*
184349365Smckusick  * Set the mode mask for creation of filesystem nodes.
184412756Ssam  */
184542441Smckusick mode_t
184642441Smckusick umask(p, uap, retval)
184745914Smckusick 	struct proc *p;
184842441Smckusick 	struct args {
184942441Smckusick 		int	mask;
185042441Smckusick 	} *uap;
185142441Smckusick 	int *retval;
185212756Ssam {
185345914Smckusick 	register struct filedesc *fdp = p->p_fd;
185412756Ssam 
185545914Smckusick 	*retval = fdp->fd_cmask;
185645914Smckusick 	fdp->fd_cmask = uap->mask & 07777;
185747540Skarels 	return (0);
185812756Ssam }
185937741Smckusick 
186039566Smarc /*
186139566Smarc  * Void all references to file by ripping underlying filesystem
186239566Smarc  * away from vnode.
186339566Smarc  */
186442441Smckusick /* ARGSUSED */
186542441Smckusick revoke(p, uap, retval)
186645914Smckusick 	struct proc *p;
186742441Smckusick 	register struct args {
186839566Smarc 		char	*fname;
186942441Smckusick 	} *uap;
187042441Smckusick 	int *retval;
187142441Smckusick {
187253548Sheideman 	USES_VOP_GETATTR;
187339566Smarc 	register struct vnode *vp;
187439566Smarc 	struct vattr vattr;
187539566Smarc 	int error;
187647540Skarels 	struct nameidata nd;
187739566Smarc 
187852322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
187952322Smckusick 	if (error = namei(&nd))
188047540Skarels 		return (error);
188152322Smckusick 	vp = nd.ni_vp;
188239566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
188339566Smarc 		error = EINVAL;
188439566Smarc 		goto out;
188539566Smarc 	}
188648026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
188739566Smarc 		goto out;
188847540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
188947540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
189039566Smarc 		goto out;
189139805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
189239632Smckusick 		vgoneall(vp);
189339566Smarc out:
189439566Smarc 	vrele(vp);
189547540Skarels 	return (error);
189639566Smarc }
189739566Smarc 
189849365Smckusick /*
189949365Smckusick  * Convert a user file descriptor to a kernel file entry.
190049365Smckusick  */
190145914Smckusick getvnode(fdp, fdes, fpp)
190245914Smckusick 	struct filedesc *fdp;
190337741Smckusick 	struct file **fpp;
190437741Smckusick 	int fdes;
190537741Smckusick {
190637741Smckusick 	struct file *fp;
190737741Smckusick 
190847540Skarels 	if ((unsigned)fdes >= fdp->fd_nfiles ||
190947688Skarels 	    (fp = fdp->fd_ofiles[fdes]) == NULL)
191037741Smckusick 		return (EBADF);
191137741Smckusick 	if (fp->f_type != DTYPE_VNODE)
191237741Smckusick 		return (EINVAL);
191337741Smckusick 	*fpp = fp;
191437741Smckusick 	return (0);
191537741Smckusick }
1916