xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 54100)
123405Smckusick /*
237741Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337741Smckusick  * All rights reserved.
423405Smckusick  *
544459Sbostic  * %sccs.include.redist.c%
637741Smckusick  *
7*54100Smckusick  *	@(#)vfs_syscalls.c	7.85 (Berkeley) 06/19/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 	}
8039665Smckusick 	vinvalbuf(vp, 1);
8139805Smckusick 	if (vp->v_usecount != 1) {
8237741Smckusick 		vput(vp);
8347540Skarels 		return (EBUSY);
8437741Smckusick 	}
8537741Smckusick 	if (vp->v_type != VDIR) {
8637741Smckusick 		vput(vp);
8747540Skarels 		return (ENOTDIR);
8837741Smckusick 	}
8939741Smckusick 	if ((unsigned long)uap->type > MOUNT_MAXTYPE ||
9037741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
9137741Smckusick 		vput(vp);
9247540Skarels 		return (ENODEV);
9337741Smckusick 	}
9437741Smckusick 
9537741Smckusick 	/*
9639335Smckusick 	 * Allocate and initialize the file system.
9737741Smckusick 	 */
9837741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
9937741Smckusick 		M_MOUNT, M_WAITOK);
10041400Smckusick 	mp->mnt_op = vfssw[uap->type];
10141400Smckusick 	mp->mnt_flag = 0;
10241400Smckusick 	mp->mnt_mounth = NULLVP;
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 */
23341676Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE))
23448026Smckusick 		error = VFS_UNMOUNT(mp, flags, p);
23541400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
23641298Smckusick 	vfs_unbusy(mp);
23737741Smckusick 	if (error) {
23837741Smckusick 		vfs_unlock(mp);
23937741Smckusick 	} else {
24037741Smckusick 		vrele(coveredvp);
24137741Smckusick 		vfs_remove(mp);
24252287Smckusick 		if (mp->mnt_mounth != NULL)
24352287Smckusick 			panic("unmount: dangling vnode");
24437741Smckusick 		free((caddr_t)mp, M_MOUNT);
24537741Smckusick 	}
24639356Smckusick 	return (error);
2476254Sroot }
2486254Sroot 
2499167Ssam /*
25037741Smckusick  * Sync system call.
25137741Smckusick  * Sync each mounted filesystem.
2529167Ssam  */
25339491Smckusick /* ARGSUSED */
25442441Smckusick sync(p, uap, retval)
25545914Smckusick 	struct proc *p;
25647540Skarels 	void *uap;
25742441Smckusick 	int *retval;
2586254Sroot {
25937741Smckusick 	register struct mount *mp;
26041298Smckusick 	struct mount *omp;
26137741Smckusick 
26237741Smckusick 	mp = rootfs;
26337741Smckusick 	do {
26440343Smckusick 		/*
26540343Smckusick 		 * The lock check below is to avoid races with mount
26640343Smckusick 		 * and unmount.
26740343Smckusick 		 */
26841400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
26941298Smckusick 		    !vfs_busy(mp)) {
27037741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
27141298Smckusick 			omp = mp;
27241400Smckusick 			mp = mp->mnt_next;
27341298Smckusick 			vfs_unbusy(omp);
27441298Smckusick 		} else
27541400Smckusick 			mp = mp->mnt_next;
27637741Smckusick 	} while (mp != rootfs);
27747688Skarels 	return (0);
27837741Smckusick }
27937741Smckusick 
28037741Smckusick /*
28149365Smckusick  * Operate on filesystem quotas.
28241298Smckusick  */
28342441Smckusick /* ARGSUSED */
28442441Smckusick quotactl(p, uap, retval)
28545914Smckusick 	struct proc *p;
28642441Smckusick 	register struct args {
28741298Smckusick 		char *path;
28841298Smckusick 		int cmd;
28941298Smckusick 		int uid;
29041298Smckusick 		caddr_t arg;
29142441Smckusick 	} *uap;
29242441Smckusick 	int *retval;
29342441Smckusick {
29441298Smckusick 	register struct mount *mp;
29541298Smckusick 	int error;
29647540Skarels 	struct nameidata nd;
29741298Smckusick 
29852322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
29952322Smckusick 	if (error = namei(&nd))
30047540Skarels 		return (error);
30152322Smckusick 	mp = nd.ni_vp->v_mount;
30252322Smckusick 	vrele(nd.ni_vp);
30348026Smckusick 	return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p));
30441298Smckusick }
30541298Smckusick 
30641298Smckusick /*
30749365Smckusick  * Get filesystem statistics.
30837741Smckusick  */
30942441Smckusick /* ARGSUSED */
31042441Smckusick statfs(p, uap, retval)
31145914Smckusick 	struct proc *p;
31242441Smckusick 	register struct args {
31337741Smckusick 		char *path;
31437741Smckusick 		struct statfs *buf;
31542441Smckusick 	} *uap;
31642441Smckusick 	int *retval;
31742441Smckusick {
31839464Smckusick 	register struct mount *mp;
31940343Smckusick 	register struct statfs *sp;
32037741Smckusick 	int error;
32147540Skarels 	struct nameidata nd;
32237741Smckusick 
32352322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
32452322Smckusick 	if (error = namei(&nd))
32547540Skarels 		return (error);
32652322Smckusick 	mp = nd.ni_vp->v_mount;
32741400Smckusick 	sp = &mp->mnt_stat;
32852322Smckusick 	vrele(nd.ni_vp);
32948026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
33047540Skarels 		return (error);
33141400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
33247540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
33337741Smckusick }
33437741Smckusick 
33542441Smckusick /*
33649365Smckusick  * Get filesystem statistics.
33742441Smckusick  */
33842441Smckusick /* ARGSUSED */
33942441Smckusick fstatfs(p, uap, retval)
34045914Smckusick 	struct proc *p;
34142441Smckusick 	register struct args {
34237741Smckusick 		int fd;
34337741Smckusick 		struct statfs *buf;
34442441Smckusick 	} *uap;
34542441Smckusick 	int *retval;
34642441Smckusick {
34737741Smckusick 	struct file *fp;
34839464Smckusick 	struct mount *mp;
34940343Smckusick 	register struct statfs *sp;
35037741Smckusick 	int error;
35137741Smckusick 
35245914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
35347540Skarels 		return (error);
35439464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
35541400Smckusick 	sp = &mp->mnt_stat;
35648026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
35747540Skarels 		return (error);
35841400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
35947540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
36037741Smckusick }
36137741Smckusick 
36237741Smckusick /*
36349365Smckusick  * Get statistics on all filesystems.
36438270Smckusick  */
36542441Smckusick getfsstat(p, uap, retval)
36645914Smckusick 	struct proc *p;
36742441Smckusick 	register struct args {
36838270Smckusick 		struct statfs *buf;
36938270Smckusick 		long bufsize;
37040343Smckusick 		int flags;
37142441Smckusick 	} *uap;
37242441Smckusick 	int *retval;
37342441Smckusick {
37438270Smckusick 	register struct mount *mp;
37540343Smckusick 	register struct statfs *sp;
37639606Smckusick 	caddr_t sfsp;
37738270Smckusick 	long count, maxcount, error;
37838270Smckusick 
37938270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
38039606Smckusick 	sfsp = (caddr_t)uap->buf;
38138270Smckusick 	mp = rootfs;
38238270Smckusick 	count = 0;
38338270Smckusick 	do {
38441400Smckusick 		if (sfsp && count < maxcount &&
38541400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
38641400Smckusick 			sp = &mp->mnt_stat;
38740343Smckusick 			/*
38840343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
38940343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
39040343Smckusick 			 */
39140343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
39240343Smckusick 			    (uap->flags & MNT_WAIT)) &&
39348026Smckusick 			    (error = VFS_STATFS(mp, sp, p))) {
39441400Smckusick 				mp = mp->mnt_prev;
39539607Smckusick 				continue;
39639607Smckusick 			}
39741400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
39840343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
39947540Skarels 				return (error);
40040343Smckusick 			sfsp += sizeof(*sp);
40138270Smckusick 		}
40239606Smckusick 		count++;
40341400Smckusick 		mp = mp->mnt_prev;
40438270Smckusick 	} while (mp != rootfs);
40538270Smckusick 	if (sfsp && count > maxcount)
40642441Smckusick 		*retval = maxcount;
40738270Smckusick 	else
40842441Smckusick 		*retval = count;
40947540Skarels 	return (0);
41038270Smckusick }
41138270Smckusick 
41238270Smckusick /*
41338259Smckusick  * Change current working directory to a given file descriptor.
41438259Smckusick  */
41542441Smckusick /* ARGSUSED */
41642441Smckusick fchdir(p, uap, retval)
41745914Smckusick 	struct proc *p;
41842441Smckusick 	struct args {
41942441Smckusick 		int	fd;
42042441Smckusick 	} *uap;
42142441Smckusick 	int *retval;
42238259Smckusick {
42353548Sheideman 	USES_VOP_ACCESS;
42453548Sheideman 	USES_VOP_LOCK;
42553548Sheideman 	USES_VOP_UNLOCK;
42645914Smckusick 	register struct filedesc *fdp = p->p_fd;
42738259Smckusick 	register struct vnode *vp;
42838259Smckusick 	struct file *fp;
42938259Smckusick 	int error;
43038259Smckusick 
43145914Smckusick 	if (error = getvnode(fdp, uap->fd, &fp))
43247540Skarels 		return (error);
43338259Smckusick 	vp = (struct vnode *)fp->f_data;
43438259Smckusick 	VOP_LOCK(vp);
43538259Smckusick 	if (vp->v_type != VDIR)
43638259Smckusick 		error = ENOTDIR;
43738259Smckusick 	else
43848026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
43938259Smckusick 	VOP_UNLOCK(vp);
44039860Smckusick 	if (error)
44147540Skarels 		return (error);
44239860Smckusick 	VREF(vp);
44345914Smckusick 	vrele(fdp->fd_cdir);
44445914Smckusick 	fdp->fd_cdir = vp;
44547540Skarels 	return (0);
44638259Smckusick }
44738259Smckusick 
44838259Smckusick /*
44937741Smckusick  * Change current working directory (``.'').
45037741Smckusick  */
45142441Smckusick /* ARGSUSED */
45242441Smckusick chdir(p, uap, retval)
45345914Smckusick 	struct proc *p;
45442441Smckusick 	struct args {
45542441Smckusick 		char	*fname;
45642441Smckusick 	} *uap;
45742441Smckusick 	int *retval;
45837741Smckusick {
45945914Smckusick 	register struct filedesc *fdp = p->p_fd;
46037741Smckusick 	int error;
46147540Skarels 	struct nameidata nd;
4626254Sroot 
46352322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
46452781Sralph 	if (error = chdirec(&nd, p))
46547540Skarels 		return (error);
46645914Smckusick 	vrele(fdp->fd_cdir);
46752322Smckusick 	fdp->fd_cdir = nd.ni_vp;
46847540Skarels 	return (0);
46937741Smckusick }
4706254Sroot 
47137741Smckusick /*
47237741Smckusick  * Change notion of root (``/'') directory.
47337741Smckusick  */
47442441Smckusick /* ARGSUSED */
47542441Smckusick chroot(p, uap, retval)
47645914Smckusick 	struct proc *p;
47742441Smckusick 	struct args {
47842441Smckusick 		char	*fname;
47942441Smckusick 	} *uap;
48042441Smckusick 	int *retval;
48137741Smckusick {
48245914Smckusick 	register struct filedesc *fdp = p->p_fd;
48337741Smckusick 	int error;
48447540Skarels 	struct nameidata nd;
48537741Smckusick 
48647540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
48747540Skarels 		return (error);
48852322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
48952781Sralph 	if (error = chdirec(&nd, p))
49047540Skarels 		return (error);
49145914Smckusick 	if (fdp->fd_rdir != NULL)
49245914Smckusick 		vrele(fdp->fd_rdir);
49352322Smckusick 	fdp->fd_rdir = nd.ni_vp;
49447540Skarels 	return (0);
4956254Sroot }
4966254Sroot 
49737Sbill /*
49837741Smckusick  * Common routine for chroot and chdir.
49937741Smckusick  */
50047540Skarels chdirec(ndp, p)
50152322Smckusick 	register struct nameidata *ndp;
50247540Skarels 	struct proc *p;
50337741Smckusick {
50453548Sheideman 	USES_VOP_ACCESS;
50553548Sheideman 	USES_VOP_UNLOCK;
50637741Smckusick 	struct vnode *vp;
50737741Smckusick 	int error;
50837741Smckusick 
50952322Smckusick 	if (error = namei(ndp))
51037741Smckusick 		return (error);
51137741Smckusick 	vp = ndp->ni_vp;
51237741Smckusick 	if (vp->v_type != VDIR)
51337741Smckusick 		error = ENOTDIR;
51437741Smckusick 	else
51548026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
51637741Smckusick 	VOP_UNLOCK(vp);
51737741Smckusick 	if (error)
51837741Smckusick 		vrele(vp);
51937741Smckusick 	return (error);
52037741Smckusick }
52137741Smckusick 
52237741Smckusick /*
5236254Sroot  * Open system call.
52442441Smckusick  * Check permissions, allocate an open file structure,
52542441Smckusick  * and call the device open routine if any.
5266254Sroot  */
52742441Smckusick open(p, uap, retval)
52845914Smckusick 	struct proc *p;
52942441Smckusick 	register struct args {
5306254Sroot 		char	*fname;
5317701Ssam 		int	mode;
53212756Ssam 		int	crtmode;
53342441Smckusick 	} *uap;
53442441Smckusick 	int *retval;
5356254Sroot {
53653548Sheideman 	USES_VOP_ADVLOCK;
53753548Sheideman 	USES_VOP_UNLOCK;
53845914Smckusick 	register struct filedesc *fdp = p->p_fd;
53942441Smckusick 	register struct file *fp;
54050111Smckusick 	register struct vnode *vp;
54137741Smckusick 	int fmode, cmode;
54237741Smckusick 	struct file *nfp;
54349945Smckusick 	int type, indx, error;
54449945Smckusick 	struct flock lf;
54547540Skarels 	struct nameidata nd;
54637741Smckusick 	extern struct fileops vnops;
5476254Sroot 
54845914Smckusick 	if (error = falloc(p, &nfp, &indx))
54947540Skarels 		return (error);
55037741Smckusick 	fp = nfp;
55146553Skarels 	fmode = FFLAGS(uap->mode);
55245914Smckusick 	cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX;
55352322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
55445202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
55552322Smckusick 	if (error = vn_open(&nd, fmode, cmode)) {
55653828Spendry 		int dfd = p->p_dupfd;
55753828Spendry 		p->p_dupfd = 0;
55849980Smckusick 		ffree(fp);
55953828Spendry 		if ((error == ENODEV || error == ENXIO) && /* XXX from fdopen */
56053828Spendry 		    dfd >= 0 &&
56153828Spendry 		    (error = dupfdopen(fdp, indx, p->p_dupfd,
56253828Spendry 					fmode, error)) == 0) {
56342441Smckusick 			*retval = indx;
56447540Skarels 			return (0);
56542441Smckusick 		}
56640884Smckusick 		if (error == ERESTART)
56740884Smckusick 			error = EINTR;
56847688Skarels 		fdp->fd_ofiles[indx] = NULL;
56947540Skarels 		return (error);
57012756Ssam 	}
57153828Spendry 	p->p_dupfd = 0;
57252322Smckusick 	vp = nd.ni_vp;
57349949Smckusick 	fp->f_flag = fmode & FMASK;
57449945Smckusick 	if (fmode & (O_EXLOCK | O_SHLOCK)) {
57549945Smckusick 		lf.l_whence = SEEK_SET;
57649945Smckusick 		lf.l_start = 0;
57749945Smckusick 		lf.l_len = 0;
57849945Smckusick 		if (fmode & O_EXLOCK)
57949945Smckusick 			lf.l_type = F_WRLCK;
58049945Smckusick 		else
58149945Smckusick 			lf.l_type = F_RDLCK;
58249945Smckusick 		type = F_FLOCK;
58349945Smckusick 		if ((fmode & FNONBLOCK) == 0)
58449945Smckusick 			type |= F_WAIT;
58550111Smckusick 		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
58650111Smckusick 			VOP_UNLOCK(vp);
58750111Smckusick 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
58849980Smckusick 			ffree(fp);
58949945Smckusick 			fdp->fd_ofiles[indx] = NULL;
59049945Smckusick 			return (error);
59149945Smckusick 		}
59249949Smckusick 		fp->f_flag |= FHASLOCK;
59349945Smckusick 	}
59450111Smckusick 	VOP_UNLOCK(vp);
59537741Smckusick 	fp->f_type = DTYPE_VNODE;
59637741Smckusick 	fp->f_ops = &vnops;
59750111Smckusick 	fp->f_data = (caddr_t)vp;
59842441Smckusick 	*retval = indx;
59947540Skarels 	return (0);
6006254Sroot }
6016254Sroot 
60242955Smckusick #ifdef COMPAT_43
6036254Sroot /*
60442441Smckusick  * Creat system call.
6056254Sroot  */
60642955Smckusick ocreat(p, uap, retval)
60742441Smckusick 	struct proc *p;
60842441Smckusick 	register struct args {
60942441Smckusick 		char	*fname;
61042441Smckusick 		int	fmode;
61142441Smckusick 	} *uap;
61242441Smckusick 	int *retval;
6136254Sroot {
61442441Smckusick 	struct args {
6156254Sroot 		char	*fname;
61642441Smckusick 		int	mode;
61742441Smckusick 		int	crtmode;
61842441Smckusick 	} openuap;
61942441Smckusick 
62042441Smckusick 	openuap.fname = uap->fname;
62142441Smckusick 	openuap.crtmode = uap->fmode;
62242441Smckusick 	openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
62347540Skarels 	return (open(p, &openuap, retval));
62442441Smckusick }
62542955Smckusick #endif /* COMPAT_43 */
62642441Smckusick 
62742441Smckusick /*
62849365Smckusick  * Mknod system call.
62942441Smckusick  */
63042441Smckusick /* ARGSUSED */
63142441Smckusick mknod(p, uap, retval)
63245914Smckusick 	struct proc *p;
63342441Smckusick 	register struct args {
63442441Smckusick 		char	*fname;
6356254Sroot 		int	fmode;
6366254Sroot 		int	dev;
63742441Smckusick 	} *uap;
63842441Smckusick 	int *retval;
63942441Smckusick {
64053548Sheideman 	USES_VOP_ABORTOP;
64153548Sheideman 	USES_VOP_MKNOD;
64237741Smckusick 	register struct vnode *vp;
64337741Smckusick 	struct vattr vattr;
64437741Smckusick 	int error;
64547540Skarels 	struct nameidata nd;
6466254Sroot 
64747540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
64847540Skarels 		return (error);
64952322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p);
65052322Smckusick 	if (error = namei(&nd))
65147540Skarels 		return (error);
65252322Smckusick 	vp = nd.ni_vp;
65337741Smckusick 	if (vp != NULL) {
65437741Smckusick 		error = EEXIST;
65512756Ssam 		goto out;
6566254Sroot 	}
65741362Smckusick 	VATTR_NULL(&vattr);
65840635Smckusick 	switch (uap->fmode & S_IFMT) {
65912756Ssam 
66040635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
66137741Smckusick 		vattr.va_type = VBAD;
66237741Smckusick 		break;
66340635Smckusick 	case S_IFCHR:
66437741Smckusick 		vattr.va_type = VCHR;
66537741Smckusick 		break;
66640635Smckusick 	case S_IFBLK:
66737741Smckusick 		vattr.va_type = VBLK;
66837741Smckusick 		break;
66937741Smckusick 	default:
67037741Smckusick 		error = EINVAL;
67137741Smckusick 		goto out;
6726254Sroot 	}
67345914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
67437741Smckusick 	vattr.va_rdev = uap->dev;
6756254Sroot out:
67642465Smckusick 	if (!error) {
67752322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
67852322Smckusick 		error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
67942465Smckusick 	} else {
68052322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
68152322Smckusick 		if (nd.ni_dvp == vp)
68252322Smckusick 			vrele(nd.ni_dvp);
68343344Smckusick 		else
68452322Smckusick 			vput(nd.ni_dvp);
68542465Smckusick 		if (vp)
68642465Smckusick 			vrele(vp);
68742465Smckusick 	}
68847540Skarels 	return (error);
6896254Sroot }
6906254Sroot 
6916254Sroot /*
69249365Smckusick  * Mkfifo system call.
69340285Smckusick  */
69442441Smckusick /* ARGSUSED */
69542441Smckusick mkfifo(p, uap, retval)
69645914Smckusick 	struct proc *p;
69742441Smckusick 	register struct args {
69840285Smckusick 		char	*fname;
69940285Smckusick 		int	fmode;
70042441Smckusick 	} *uap;
70142441Smckusick 	int *retval;
70242441Smckusick {
70353548Sheideman 	USES_VOP_ABORTOP;
70453548Sheideman 	USES_VOP_MKNOD;
70540285Smckusick 	struct vattr vattr;
70640285Smckusick 	int error;
70747540Skarels 	struct nameidata nd;
70840285Smckusick 
70940285Smckusick #ifndef FIFO
71047540Skarels 	return (EOPNOTSUPP);
71140285Smckusick #else
71252322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p);
71352322Smckusick 	if (error = namei(&nd))
71447540Skarels 		return (error);
71552322Smckusick 	if (nd.ni_vp != NULL) {
71652322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
71752322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
71852322Smckusick 			vrele(nd.ni_dvp);
71943344Smckusick 		else
72052322Smckusick 			vput(nd.ni_dvp);
72152322Smckusick 		vrele(nd.ni_vp);
72247540Skarels 		return (EEXIST);
72340285Smckusick 	}
72445785Sbostic 	VATTR_NULL(&vattr);
72545785Sbostic 	vattr.va_type = VFIFO;
72645914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
72752322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
72852322Smckusick 	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
72940285Smckusick #endif /* FIFO */
73040285Smckusick }
73140285Smckusick 
73240285Smckusick /*
73349365Smckusick  * Link system call.
7346254Sroot  */
73542441Smckusick /* ARGSUSED */
73642441Smckusick link(p, uap, retval)
73745914Smckusick 	struct proc *p;
73842441Smckusick 	register struct args {
7396254Sroot 		char	*target;
7406254Sroot 		char	*linkname;
74142441Smckusick 	} *uap;
74242441Smckusick 	int *retval;
74342441Smckusick {
74453548Sheideman 	USES_VOP_ABORTOP;
74553548Sheideman 	USES_VOP_LINK;
74637741Smckusick 	register struct vnode *vp, *xp;
74737741Smckusick 	int error;
74847540Skarels 	struct nameidata nd;
7496254Sroot 
75052322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->target, p);
75152322Smckusick 	if (error = namei(&nd))
75247540Skarels 		return (error);
75352322Smckusick 	vp = nd.ni_vp;
75437741Smckusick 	if (vp->v_type == VDIR &&
75547540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
75637741Smckusick 		goto out1;
75752322Smckusick 	nd.ni_cnd.cn_nameiop = CREATE;
75852322Smckusick 	nd.ni_cnd.cn_flags = LOCKPARENT;
75952322Smckusick 	nd.ni_dirp = (caddr_t)uap->linkname;
76052322Smckusick 	if (error = namei(&nd))
76137741Smckusick 		goto out1;
76252322Smckusick 	xp = nd.ni_vp;
7636254Sroot 	if (xp != NULL) {
76437741Smckusick 		error = EEXIST;
7656254Sroot 		goto out;
7666254Sroot 	}
76752322Smckusick 	xp = nd.ni_dvp;
7686254Sroot out:
76942465Smckusick 	if (!error) {
77052192Smckusick 		LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE);
77152192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
77252821Smckusick 		error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
77342465Smckusick 	} else {
77452322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
77552322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
77652322Smckusick 			vrele(nd.ni_dvp);
77743344Smckusick 		else
77852322Smckusick 			vput(nd.ni_dvp);
77952322Smckusick 		if (nd.ni_vp)
78052322Smckusick 			vrele(nd.ni_vp);
78142465Smckusick 	}
78237741Smckusick out1:
78337741Smckusick 	vrele(vp);
78447540Skarels 	return (error);
7856254Sroot }
7866254Sroot 
7876254Sroot /*
78849365Smckusick  * Make a symbolic link.
7896254Sroot  */
79042441Smckusick /* ARGSUSED */
79142441Smckusick symlink(p, uap, retval)
79245914Smckusick 	struct proc *p;
79342441Smckusick 	register struct args {
7946254Sroot 		char	*target;
7956254Sroot 		char	*linkname;
79642441Smckusick 	} *uap;
79742441Smckusick 	int *retval;
79842441Smckusick {
79953548Sheideman 	USES_VOP_ABORTOP;
80053548Sheideman 	USES_VOP_SYMLINK;
80137741Smckusick 	struct vattr vattr;
80237741Smckusick 	char *target;
80337741Smckusick 	int error;
80447540Skarels 	struct nameidata nd;
8056254Sroot 
80637741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
80737741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
80842465Smckusick 		goto out;
80952322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->linkname, p);
81052322Smckusick 	if (error = namei(&nd))
81142465Smckusick 		goto out;
81252322Smckusick 	if (nd.ni_vp) {
81352322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
81452322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
81552322Smckusick 			vrele(nd.ni_dvp);
81643344Smckusick 		else
81752322Smckusick 			vput(nd.ni_dvp);
81852322Smckusick 		vrele(nd.ni_vp);
81937741Smckusick 		error = EEXIST;
82037741Smckusick 		goto out;
8216254Sroot 	}
82241362Smckusick 	VATTR_NULL(&vattr);
82345914Smckusick 	vattr.va_mode = 0777 &~ p->p_fd->fd_cmask;
82452322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
82552322Smckusick 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, target);
82637741Smckusick out:
82737741Smckusick 	FREE(target, M_NAMEI);
82847540Skarels 	return (error);
8296254Sroot }
8306254Sroot 
8316254Sroot /*
83249365Smckusick  * Delete a name from the filesystem.
8336254Sroot  */
83442441Smckusick /* ARGSUSED */
83542441Smckusick unlink(p, uap, retval)
83645914Smckusick 	struct proc *p;
83742441Smckusick 	struct args {
83852322Smckusick 		char	*name;
83942441Smckusick 	} *uap;
84042441Smckusick 	int *retval;
8416254Sroot {
84253548Sheideman 	USES_VOP_ABORTOP;
84353548Sheideman 	USES_VOP_REMOVE;
84437741Smckusick 	register struct vnode *vp;
84537741Smckusick 	int error;
84647540Skarels 	struct nameidata nd;
8476254Sroot 
84852322Smckusick 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p);
84952322Smckusick 	if (error = namei(&nd))
85047540Skarels 		return (error);
85152322Smckusick 	vp = nd.ni_vp;
85237741Smckusick 	if (vp->v_type == VDIR &&
85347540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
8546254Sroot 		goto out;
8556254Sroot 	/*
85649365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
8576254Sroot 	 */
85837741Smckusick 	if (vp->v_flag & VROOT) {
85937741Smckusick 		error = EBUSY;
8606254Sroot 		goto out;
8616254Sroot 	}
86245738Smckusick 	(void) vnode_pager_uncache(vp);
8636254Sroot out:
86442465Smckusick 	if (!error) {
86552322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
86652192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
86752322Smckusick 		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
86842465Smckusick 	} else {
86952322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
87052322Smckusick 		if (nd.ni_dvp == vp)
87152322Smckusick 			vrele(nd.ni_dvp);
87243344Smckusick 		else
87352322Smckusick 			vput(nd.ni_dvp);
87442465Smckusick 		vput(vp);
87542465Smckusick 	}
87647540Skarels 	return (error);
8776254Sroot }
8786254Sroot 
87953468Smckusick #ifdef COMPAT_43
8806254Sroot /*
88149365Smckusick  * Seek system call.
8826254Sroot  */
88342441Smckusick lseek(p, uap, retval)
88445914Smckusick 	struct proc *p;
88542441Smckusick 	register struct args {
88637741Smckusick 		int	fdes;
88753468Smckusick 		long	off;
88853468Smckusick 		int	sbase;
88953468Smckusick 	} *uap;
89053468Smckusick 	long *retval;
89153468Smckusick {
89253468Smckusick 	struct nargs {
89353468Smckusick 		int	fdes;
8946254Sroot 		off_t	off;
8956254Sroot 		int	sbase;
89653468Smckusick 	} nuap;
89753468Smckusick 	quad_t qret;
89853468Smckusick 	int error;
89953468Smckusick 
90053468Smckusick 	nuap.fdes = uap->fdes;
90153468Smckusick 	nuap.off = uap->off;
90253468Smckusick 	nuap.sbase = uap->sbase;
90353759Smckusick 	error = __lseek(p, &nuap, &qret);
90453468Smckusick 	*retval = qret;
90553468Smckusick 	return (error);
90653468Smckusick }
90753468Smckusick #endif /* COMPAT_43 */
90853468Smckusick 
90953468Smckusick /*
91053468Smckusick  * Seek system call.
91153468Smckusick  */
91253759Smckusick __lseek(p, uap, retval)
91353468Smckusick 	struct proc *p;
91453468Smckusick 	register struct args {
91553468Smckusick 		int	fdes;
91653468Smckusick 		off_t	off;
91753468Smckusick 		int	sbase;
91842441Smckusick 	} *uap;
91942441Smckusick 	off_t *retval;
92042441Smckusick {
92153548Sheideman 	USES_VOP_GETATTR;
92247540Skarels 	struct ucred *cred = p->p_ucred;
92345914Smckusick 	register struct filedesc *fdp = p->p_fd;
92442441Smckusick 	register struct file *fp;
92537741Smckusick 	struct vattr vattr;
92637741Smckusick 	int error;
9276254Sroot 
92847540Skarels 	if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
92947688Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL)
93047540Skarels 		return (EBADF);
93137741Smckusick 	if (fp->f_type != DTYPE_VNODE)
93247540Skarels 		return (ESPIPE);
93313878Ssam 	switch (uap->sbase) {
93413878Ssam 
93513878Ssam 	case L_INCR:
93613878Ssam 		fp->f_offset += uap->off;
93713878Ssam 		break;
93813878Ssam 
93913878Ssam 	case L_XTND:
94037741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
94148026Smckusick 		    &vattr, cred, p))
94247540Skarels 			return (error);
94337741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
94413878Ssam 		break;
94513878Ssam 
94613878Ssam 	case L_SET:
94713878Ssam 		fp->f_offset = uap->off;
94813878Ssam 		break;
94913878Ssam 
95013878Ssam 	default:
95147540Skarels 		return (EINVAL);
95213878Ssam 	}
95342441Smckusick 	*retval = fp->f_offset;
95447540Skarels 	return (0);
9556254Sroot }
9566254Sroot 
9576254Sroot /*
95849365Smckusick  * Check access permissions.
9596254Sroot  */
96042441Smckusick /* ARGSUSED */
96142441Smckusick saccess(p, uap, retval)
96245914Smckusick 	struct proc *p;
96342441Smckusick 	register struct args {
9646254Sroot 		char	*fname;
9656254Sroot 		int	fmode;
96642441Smckusick 	} *uap;
96742441Smckusick 	int *retval;
96842441Smckusick {
96953548Sheideman 	USES_VOP_ACCESS;
97047540Skarels 	register struct ucred *cred = p->p_ucred;
97137741Smckusick 	register struct vnode *vp;
97237741Smckusick 	int error, mode, svuid, svgid;
97347540Skarels 	struct nameidata nd;
9746254Sroot 
97542441Smckusick 	svuid = cred->cr_uid;
97642441Smckusick 	svgid = cred->cr_groups[0];
97747540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
97847540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
97952322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
98052322Smckusick 	if (error = namei(&nd))
98137741Smckusick 		goto out1;
98252322Smckusick 	vp = nd.ni_vp;
98337741Smckusick 	/*
98437741Smckusick 	 * fmode == 0 means only check for exist
98537741Smckusick 	 */
98637741Smckusick 	if (uap->fmode) {
98737741Smckusick 		mode = 0;
98837741Smckusick 		if (uap->fmode & R_OK)
98937741Smckusick 			mode |= VREAD;
99037741Smckusick 		if (uap->fmode & W_OK)
99137741Smckusick 			mode |= VWRITE;
99237741Smckusick 		if (uap->fmode & X_OK)
99337741Smckusick 			mode |= VEXEC;
99439543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
99548026Smckusick 			error = VOP_ACCESS(vp, mode, cred, p);
9966254Sroot 	}
99737741Smckusick 	vput(vp);
99837741Smckusick out1:
99942441Smckusick 	cred->cr_uid = svuid;
100042441Smckusick 	cred->cr_groups[0] = svgid;
100147540Skarels 	return (error);
10026254Sroot }
10036254Sroot 
100453468Smckusick #ifdef COMPAT_43
10056254Sroot /*
100649365Smckusick  * Stat system call.
100749365Smckusick  * This version follows links.
100837Sbill  */
100942441Smckusick /* ARGSUSED */
101053759Smckusick ostat(p, uap, retval)
101145914Smckusick 	struct proc *p;
101242441Smckusick 	register struct args {
101342441Smckusick 		char	*fname;
101453468Smckusick 		struct ostat *ub;
101553468Smckusick 	} *uap;
101653468Smckusick 	int *retval;
101753468Smckusick {
101853468Smckusick 	struct stat sb;
101953468Smckusick 	struct ostat osb;
102053468Smckusick 	int error;
102153468Smckusick 	struct nameidata nd;
102253468Smckusick 
102353468Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
102453468Smckusick 	if (error = namei(&nd))
102553468Smckusick 		return (error);
102653468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
102753468Smckusick 	vput(nd.ni_vp);
102853468Smckusick 	if (error)
102953468Smckusick 		return (error);
103053468Smckusick 	cvtstat(&sb, &osb);
103153468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
103253468Smckusick 	return (error);
103353468Smckusick }
103453468Smckusick 
103553468Smckusick /*
103653468Smckusick  * Lstat system call.
103753468Smckusick  * This version does not follow links.
103853468Smckusick  */
103953468Smckusick /* ARGSUSED */
104053759Smckusick olstat(p, uap, retval)
104153468Smckusick 	struct proc *p;
104253468Smckusick 	register struct args {
104353468Smckusick 		char	*fname;
104453468Smckusick 		struct ostat *ub;
104553468Smckusick 	} *uap;
104653468Smckusick 	int *retval;
104753468Smckusick {
104853468Smckusick 	struct stat sb;
104953468Smckusick 	struct ostat osb;
105053468Smckusick 	int error;
105153468Smckusick 	struct nameidata nd;
105253468Smckusick 
105353468Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
105453468Smckusick 	if (error = namei(&nd))
105553468Smckusick 		return (error);
105653468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
105753468Smckusick 	vput(nd.ni_vp);
105853468Smckusick 	if (error)
105953468Smckusick 		return (error);
106053468Smckusick 	cvtstat(&sb, &osb);
106153468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
106253468Smckusick 	return (error);
106353468Smckusick }
106453468Smckusick 
106553468Smckusick /*
106653468Smckusick  * convert from an old to a new stat structure.
106753468Smckusick  */
106853468Smckusick cvtstat(st, ost)
106953468Smckusick 	struct stat *st;
107053468Smckusick 	struct ostat *ost;
107153468Smckusick {
107253468Smckusick 
107353468Smckusick 	ost->st_dev = st->st_dev;
107453468Smckusick 	ost->st_ino = st->st_ino;
107553468Smckusick 	ost->st_mode = st->st_mode;
107653468Smckusick 	ost->st_nlink = st->st_nlink;
107753468Smckusick 	ost->st_uid = st->st_uid;
107853468Smckusick 	ost->st_gid = st->st_gid;
107953468Smckusick 	ost->st_rdev = st->st_rdev;
108053468Smckusick 	if (st->st_size < (quad_t)1 << 32)
108153468Smckusick 		ost->st_size = st->st_size;
108253468Smckusick 	else
108353468Smckusick 		ost->st_size = -2;
108453468Smckusick 	ost->st_atime = st->st_atime;
108553468Smckusick 	ost->st_mtime = st->st_mtime;
108653468Smckusick 	ost->st_ctime = st->st_ctime;
108753468Smckusick 	ost->st_blksize = st->st_blksize;
108853468Smckusick 	ost->st_blocks = st->st_blocks;
108953468Smckusick 	ost->st_flags = st->st_flags;
109053468Smckusick 	ost->st_gen = st->st_gen;
109153468Smckusick }
109253468Smckusick #endif /* COMPAT_43 */
109353468Smckusick 
109453468Smckusick /*
109553468Smckusick  * Stat system call.
109653468Smckusick  * This version follows links.
109753468Smckusick  */
109853468Smckusick /* ARGSUSED */
109953759Smckusick stat(p, uap, retval)
110053468Smckusick 	struct proc *p;
110153468Smckusick 	register struct args {
110253468Smckusick 		char	*fname;
110342441Smckusick 		struct stat *ub;
110442441Smckusick 	} *uap;
110542441Smckusick 	int *retval;
110637Sbill {
110742441Smckusick 	struct stat sb;
110842441Smckusick 	int error;
110947540Skarels 	struct nameidata nd;
111037Sbill 
111152322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
111252322Smckusick 	if (error = namei(&nd))
111347540Skarels 		return (error);
111452322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
111552322Smckusick 	vput(nd.ni_vp);
111642441Smckusick 	if (error)
111747540Skarels 		return (error);
111842441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
111947540Skarels 	return (error);
112037Sbill }
112137Sbill 
112237Sbill /*
112349365Smckusick  * Lstat system call.
112449365Smckusick  * This version does not follow links.
11255992Swnj  */
112642441Smckusick /* ARGSUSED */
112753759Smckusick lstat(p, uap, retval)
112845914Smckusick 	struct proc *p;
112942441Smckusick 	register struct args {
11305992Swnj 		char	*fname;
113112756Ssam 		struct stat *ub;
113242441Smckusick 	} *uap;
113342441Smckusick 	int *retval;
113442441Smckusick {
113512756Ssam 	struct stat sb;
113637741Smckusick 	int error;
113747540Skarels 	struct nameidata nd;
11385992Swnj 
113952322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
114052322Smckusick 	if (error = namei(&nd))
114147540Skarels 		return (error);
114252322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
114352322Smckusick 	vput(nd.ni_vp);
114437741Smckusick 	if (error)
114547540Skarels 		return (error);
114637741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
114747540Skarels 	return (error);
11485992Swnj }
11495992Swnj 
11505992Swnj /*
115149365Smckusick  * Return target name of a symbolic link.
115237Sbill  */
115342441Smckusick /* ARGSUSED */
115442441Smckusick readlink(p, uap, retval)
115545914Smckusick 	struct proc *p;
115642441Smckusick 	register struct args {
11575992Swnj 		char	*name;
11585992Swnj 		char	*buf;
11595992Swnj 		int	count;
116042441Smckusick 	} *uap;
116142441Smckusick 	int *retval;
116242441Smckusick {
116353548Sheideman 	USES_VOP_READLINK;
116437741Smckusick 	register struct vnode *vp;
116537741Smckusick 	struct iovec aiov;
116637741Smckusick 	struct uio auio;
116737741Smckusick 	int error;
116847540Skarels 	struct nameidata nd;
11695992Swnj 
117052322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p);
117152322Smckusick 	if (error = namei(&nd))
117247540Skarels 		return (error);
117352322Smckusick 	vp = nd.ni_vp;
117437741Smckusick 	if (vp->v_type != VLNK) {
117537741Smckusick 		error = EINVAL;
11765992Swnj 		goto out;
11775992Swnj 	}
117837741Smckusick 	aiov.iov_base = uap->buf;
117937741Smckusick 	aiov.iov_len = uap->count;
118037741Smckusick 	auio.uio_iov = &aiov;
118137741Smckusick 	auio.uio_iovcnt = 1;
118237741Smckusick 	auio.uio_offset = 0;
118337741Smckusick 	auio.uio_rw = UIO_READ;
118437741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
118548026Smckusick 	auio.uio_procp = p;
118637741Smckusick 	auio.uio_resid = uap->count;
118747540Skarels 	error = VOP_READLINK(vp, &auio, p->p_ucred);
11885992Swnj out:
118937741Smckusick 	vput(vp);
119042441Smckusick 	*retval = uap->count - auio.uio_resid;
119147540Skarels 	return (error);
11925992Swnj }
11935992Swnj 
11949167Ssam /*
119538259Smckusick  * Change flags of a file given path name.
119638259Smckusick  */
119742441Smckusick /* ARGSUSED */
119842441Smckusick chflags(p, uap, retval)
119945914Smckusick 	struct proc *p;
120042441Smckusick 	register struct args {
120138259Smckusick 		char	*fname;
120238259Smckusick 		int	flags;
120342441Smckusick 	} *uap;
120442441Smckusick 	int *retval;
120542441Smckusick {
120653548Sheideman 	USES_VOP_SETATTR;
120738259Smckusick 	register struct vnode *vp;
120838259Smckusick 	struct vattr vattr;
120938259Smckusick 	int error;
121047540Skarels 	struct nameidata nd;
121138259Smckusick 
121252322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
121352322Smckusick 	if (error = namei(&nd))
121447540Skarels 		return (error);
121552322Smckusick 	vp = nd.ni_vp;
121641400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
121738259Smckusick 		error = EROFS;
121838259Smckusick 		goto out;
121938259Smckusick 	}
122045785Sbostic 	VATTR_NULL(&vattr);
122145785Sbostic 	vattr.va_flags = uap->flags;
122252192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
122348026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
122438259Smckusick out:
122538259Smckusick 	vput(vp);
122647540Skarels 	return (error);
122738259Smckusick }
122838259Smckusick 
122938259Smckusick /*
123038259Smckusick  * Change flags of a file given a file descriptor.
123138259Smckusick  */
123242441Smckusick /* ARGSUSED */
123342441Smckusick fchflags(p, uap, retval)
123445914Smckusick 	struct proc *p;
123542441Smckusick 	register struct args {
123638259Smckusick 		int	fd;
123738259Smckusick 		int	flags;
123842441Smckusick 	} *uap;
123942441Smckusick 	int *retval;
124042441Smckusick {
124153548Sheideman 	USES_VOP_LOCK;
124253548Sheideman 	USES_VOP_SETATTR;
124353548Sheideman 	USES_VOP_UNLOCK;
124438259Smckusick 	struct vattr vattr;
124538259Smckusick 	struct vnode *vp;
124638259Smckusick 	struct file *fp;
124738259Smckusick 	int error;
124838259Smckusick 
124945914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
125047540Skarels 		return (error);
125138259Smckusick 	vp = (struct vnode *)fp->f_data;
125238259Smckusick 	VOP_LOCK(vp);
125341400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
125438259Smckusick 		error = EROFS;
125538259Smckusick 		goto out;
125638259Smckusick 	}
125745785Sbostic 	VATTR_NULL(&vattr);
125845785Sbostic 	vattr.va_flags = uap->flags;
125952192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
126048026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
126138259Smckusick out:
126238259Smckusick 	VOP_UNLOCK(vp);
126347540Skarels 	return (error);
126438259Smckusick }
126538259Smckusick 
126638259Smckusick /*
12679167Ssam  * Change mode of a file given path name.
12689167Ssam  */
126942441Smckusick /* ARGSUSED */
127042441Smckusick chmod(p, uap, retval)
127145914Smckusick 	struct proc *p;
127242441Smckusick 	register struct args {
12736254Sroot 		char	*fname;
12746254Sroot 		int	fmode;
127542441Smckusick 	} *uap;
127642441Smckusick 	int *retval;
127742441Smckusick {
127853548Sheideman 	USES_VOP_SETATTR;
127937741Smckusick 	register struct vnode *vp;
128037741Smckusick 	struct vattr vattr;
128137741Smckusick 	int error;
128247540Skarels 	struct nameidata nd;
12835992Swnj 
128452322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
128552322Smckusick 	if (error = namei(&nd))
128647540Skarels 		return (error);
128752322Smckusick 	vp = nd.ni_vp;
128841400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
128937741Smckusick 		error = EROFS;
129037741Smckusick 		goto out;
129137741Smckusick 	}
129245785Sbostic 	VATTR_NULL(&vattr);
129345785Sbostic 	vattr.va_mode = uap->fmode & 07777;
129452192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
129548026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
129637741Smckusick out:
129737741Smckusick 	vput(vp);
129847540Skarels 	return (error);
12997701Ssam }
13007439Sroot 
13019167Ssam /*
13029167Ssam  * Change mode of a file given a file descriptor.
13039167Ssam  */
130442441Smckusick /* ARGSUSED */
130542441Smckusick fchmod(p, uap, retval)
130645914Smckusick 	struct proc *p;
130742441Smckusick 	register struct args {
13087701Ssam 		int	fd;
13097701Ssam 		int	fmode;
131042441Smckusick 	} *uap;
131142441Smckusick 	int *retval;
131242441Smckusick {
131353548Sheideman 	USES_VOP_LOCK;
131453548Sheideman 	USES_VOP_SETATTR;
131553548Sheideman 	USES_VOP_UNLOCK;
131637741Smckusick 	struct vattr vattr;
131737741Smckusick 	struct vnode *vp;
131837741Smckusick 	struct file *fp;
131937741Smckusick 	int error;
13207701Ssam 
132145914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
132247540Skarels 		return (error);
132337741Smckusick 	vp = (struct vnode *)fp->f_data;
132437741Smckusick 	VOP_LOCK(vp);
132541400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
132637741Smckusick 		error = EROFS;
132737741Smckusick 		goto out;
13287439Sroot 	}
132945785Sbostic 	VATTR_NULL(&vattr);
133045785Sbostic 	vattr.va_mode = uap->fmode & 07777;
133152192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
133248026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
133337741Smckusick out:
133437741Smckusick 	VOP_UNLOCK(vp);
133547540Skarels 	return (error);
13365992Swnj }
13375992Swnj 
13389167Ssam /*
13399167Ssam  * Set ownership given a path name.
13409167Ssam  */
134142441Smckusick /* ARGSUSED */
134242441Smckusick chown(p, uap, retval)
134345914Smckusick 	struct proc *p;
134442441Smckusick 	register struct args {
13456254Sroot 		char	*fname;
13466254Sroot 		int	uid;
13476254Sroot 		int	gid;
134842441Smckusick 	} *uap;
134942441Smckusick 	int *retval;
135042441Smckusick {
135153548Sheideman 	USES_VOP_SETATTR;
135237741Smckusick 	register struct vnode *vp;
135337741Smckusick 	struct vattr vattr;
135437741Smckusick 	int error;
135547540Skarels 	struct nameidata nd;
135637Sbill 
135752322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
135852322Smckusick 	if (error = namei(&nd))
135947540Skarels 		return (error);
136052322Smckusick 	vp = nd.ni_vp;
136141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
136237741Smckusick 		error = EROFS;
136337741Smckusick 		goto out;
136437741Smckusick 	}
136545785Sbostic 	VATTR_NULL(&vattr);
136645785Sbostic 	vattr.va_uid = uap->uid;
136745785Sbostic 	vattr.va_gid = uap->gid;
136852192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
136948026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
137037741Smckusick out:
137137741Smckusick 	vput(vp);
137247540Skarels 	return (error);
13737701Ssam }
13747439Sroot 
13759167Ssam /*
13769167Ssam  * Set ownership given a file descriptor.
13779167Ssam  */
137842441Smckusick /* ARGSUSED */
137942441Smckusick fchown(p, uap, retval)
138045914Smckusick 	struct proc *p;
138142441Smckusick 	register struct args {
13827701Ssam 		int	fd;
13837701Ssam 		int	uid;
13847701Ssam 		int	gid;
138542441Smckusick 	} *uap;
138642441Smckusick 	int *retval;
138742441Smckusick {
138853548Sheideman 	USES_VOP_LOCK;
138953548Sheideman 	USES_VOP_SETATTR;
139053548Sheideman 	USES_VOP_UNLOCK;
139137741Smckusick 	struct vattr vattr;
139237741Smckusick 	struct vnode *vp;
139337741Smckusick 	struct file *fp;
139437741Smckusick 	int error;
13957701Ssam 
139645914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
139747540Skarels 		return (error);
139837741Smckusick 	vp = (struct vnode *)fp->f_data;
139937741Smckusick 	VOP_LOCK(vp);
140041400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
140137741Smckusick 		error = EROFS;
140237741Smckusick 		goto out;
140337741Smckusick 	}
140445785Sbostic 	VATTR_NULL(&vattr);
140545785Sbostic 	vattr.va_uid = uap->uid;
140645785Sbostic 	vattr.va_gid = uap->gid;
140752192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
140848026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
140937741Smckusick out:
141037741Smckusick 	VOP_UNLOCK(vp);
141147540Skarels 	return (error);
14127701Ssam }
14137701Ssam 
141442441Smckusick /*
141542441Smckusick  * Set the access and modification times of a file.
141642441Smckusick  */
141742441Smckusick /* ARGSUSED */
141842441Smckusick utimes(p, uap, retval)
141945914Smckusick 	struct proc *p;
142042441Smckusick 	register struct args {
142111811Ssam 		char	*fname;
142211811Ssam 		struct	timeval *tptr;
142342441Smckusick 	} *uap;
142442441Smckusick 	int *retval;
142542441Smckusick {
142653548Sheideman 	USES_VOP_SETATTR;
142737741Smckusick 	register struct vnode *vp;
142811811Ssam 	struct timeval tv[2];
142937741Smckusick 	struct vattr vattr;
143037741Smckusick 	int error;
143147540Skarels 	struct nameidata nd;
143211811Ssam 
143337741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
143447540Skarels 		return (error);
143552322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
143652322Smckusick 	if (error = namei(&nd))
143747540Skarels 		return (error);
143852322Smckusick 	vp = nd.ni_vp;
143941400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
144037741Smckusick 		error = EROFS;
144137741Smckusick 		goto out;
144221015Smckusick 	}
144345785Sbostic 	VATTR_NULL(&vattr);
1444*54100Smckusick 	vattr.va_atime.ts_sec = tv[0].tv_sec;
1445*54100Smckusick 	vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
1446*54100Smckusick 	vattr.va_mtime.ts_sec = tv[1].tv_sec;
1447*54100Smckusick 	vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
144852192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
144948026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
145037741Smckusick out:
145137741Smckusick 	vput(vp);
145247540Skarels 	return (error);
145311811Ssam }
145411811Ssam 
145553468Smckusick #ifdef COMPAT_43
14569167Ssam /*
14579167Ssam  * Truncate a file given its path name.
14589167Ssam  */
145942441Smckusick /* ARGSUSED */
146042441Smckusick truncate(p, uap, retval)
146145914Smckusick 	struct proc *p;
146242441Smckusick 	register struct args {
14637701Ssam 		char	*fname;
146453468Smckusick 		long	length;
146553468Smckusick 	} *uap;
146653468Smckusick 	int *retval;
146753468Smckusick {
146853468Smckusick 	struct nargs {
146953468Smckusick 		char	*fname;
147026473Skarels 		off_t	length;
147153468Smckusick 	} nuap;
147253468Smckusick 
147353468Smckusick 	nuap.fname = uap->fname;
147453468Smckusick 	nuap.length = uap->length;
147553759Smckusick 	return (__truncate(p, &nuap, retval));
147653468Smckusick }
147753468Smckusick 
147853468Smckusick /*
147953468Smckusick  * Truncate a file given a file descriptor.
148053468Smckusick  */
148153468Smckusick /* ARGSUSED */
148253468Smckusick ftruncate(p, uap, retval)
148353468Smckusick 	struct proc *p;
148453468Smckusick 	register struct args {
148553468Smckusick 		int	fd;
148653468Smckusick 		long	length;
148742441Smckusick 	} *uap;
148842441Smckusick 	int *retval;
148942441Smckusick {
149053468Smckusick 	struct nargs {
149153468Smckusick 		int	fd;
149253468Smckusick 		off_t	length;
149353468Smckusick 	} nuap;
149453468Smckusick 
149553468Smckusick 	nuap.fd = uap->fd;
149653468Smckusick 	nuap.length = uap->length;
149753759Smckusick 	return (__ftruncate(p, &nuap, retval));
149853468Smckusick }
149953468Smckusick #endif /* COMPAT_43 */
150053468Smckusick 
150153468Smckusick /*
150253468Smckusick  * Truncate a file given its path name.
150353468Smckusick  */
150453468Smckusick /* ARGSUSED */
150553759Smckusick __truncate(p, uap, retval)
150653468Smckusick 	struct proc *p;
150753468Smckusick 	register struct args {
150853468Smckusick 		char	*fname;
150953468Smckusick 		off_t	length;
151053468Smckusick 	} *uap;
151153468Smckusick 	int *retval;
151253468Smckusick {
151353548Sheideman 	USES_VOP_ACCESS;
151453548Sheideman 	USES_VOP_SETATTR;
151537741Smckusick 	register struct vnode *vp;
151637741Smckusick 	struct vattr vattr;
151737741Smckusick 	int error;
151847540Skarels 	struct nameidata nd;
15197701Ssam 
152052322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
152152322Smckusick 	if (error = namei(&nd))
152247540Skarels 		return (error);
152352322Smckusick 	vp = nd.ni_vp;
152437741Smckusick 	if (vp->v_type == VDIR) {
152537741Smckusick 		error = EISDIR;
152637741Smckusick 		goto out;
15277701Ssam 	}
152838399Smckusick 	if ((error = vn_writechk(vp)) ||
152948026Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)))
153037741Smckusick 		goto out;
153145785Sbostic 	VATTR_NULL(&vattr);
153245785Sbostic 	vattr.va_size = uap->length;
153352192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
153448026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
153537741Smckusick out:
153637741Smckusick 	vput(vp);
153747540Skarels 	return (error);
15387701Ssam }
15397701Ssam 
15409167Ssam /*
15419167Ssam  * Truncate a file given a file descriptor.
15429167Ssam  */
154342441Smckusick /* ARGSUSED */
154453759Smckusick __ftruncate(p, uap, retval)
154545914Smckusick 	struct proc *p;
154642441Smckusick 	register struct args {
15477701Ssam 		int	fd;
154826473Skarels 		off_t	length;
154942441Smckusick 	} *uap;
155042441Smckusick 	int *retval;
155142441Smckusick {
155253548Sheideman 	USES_VOP_LOCK;
155353548Sheideman 	USES_VOP_SETATTR;
155453548Sheideman 	USES_VOP_UNLOCK;
155537741Smckusick 	struct vattr vattr;
155637741Smckusick 	struct vnode *vp;
15577701Ssam 	struct file *fp;
155837741Smckusick 	int error;
15597701Ssam 
156045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
156147540Skarels 		return (error);
156237741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
156347540Skarels 		return (EINVAL);
156437741Smckusick 	vp = (struct vnode *)fp->f_data;
156537741Smckusick 	VOP_LOCK(vp);
156637741Smckusick 	if (vp->v_type == VDIR) {
156737741Smckusick 		error = EISDIR;
156837741Smckusick 		goto out;
15697701Ssam 	}
157038399Smckusick 	if (error = vn_writechk(vp))
157137741Smckusick 		goto out;
157245785Sbostic 	VATTR_NULL(&vattr);
157345785Sbostic 	vattr.va_size = uap->length;
157452192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
157548026Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
157637741Smckusick out:
157737741Smckusick 	VOP_UNLOCK(vp);
157847540Skarels 	return (error);
15797701Ssam }
15807701Ssam 
15819167Ssam /*
15829167Ssam  * Synch an open file.
15839167Ssam  */
158442441Smckusick /* ARGSUSED */
158542441Smckusick fsync(p, uap, retval)
158645914Smckusick 	struct proc *p;
158742441Smckusick 	struct args {
158842441Smckusick 		int	fd;
158942441Smckusick 	} *uap;
159042441Smckusick 	int *retval;
15919167Ssam {
159253548Sheideman 	USES_VOP_FSYNC;
159353548Sheideman 	USES_VOP_LOCK;
159453548Sheideman 	USES_VOP_UNLOCK;
159539592Smckusick 	register struct vnode *vp;
15969167Ssam 	struct file *fp;
159737741Smckusick 	int error;
15989167Ssam 
159945914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
160047540Skarels 		return (error);
160139592Smckusick 	vp = (struct vnode *)fp->f_data;
160239592Smckusick 	VOP_LOCK(vp);
160348026Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT, p);
160439592Smckusick 	VOP_UNLOCK(vp);
160547540Skarels 	return (error);
16069167Ssam }
16079167Ssam 
16089167Ssam /*
16099167Ssam  * Rename system call.
16109167Ssam  *
16119167Ssam  * Source and destination must either both be directories, or both
16129167Ssam  * not be directories.  If target is a directory, it must be empty.
16139167Ssam  */
161442441Smckusick /* ARGSUSED */
161542441Smckusick rename(p, uap, retval)
161645914Smckusick 	struct proc *p;
161742441Smckusick 	register struct args {
16187701Ssam 		char	*from;
16197701Ssam 		char	*to;
162042441Smckusick 	} *uap;
162142441Smckusick 	int *retval;
162242441Smckusick {
162353548Sheideman 	USES_VOP_ABORTOP;
162453548Sheideman 	USES_VOP_RENAME;
162537741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
162649735Smckusick 	struct nameidata fromnd, tond;
162737741Smckusick 	int error;
16287701Ssam 
162952322Smckusick 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
163052322Smckusick 		uap->from, p);
163152322Smckusick 	if (error = namei(&fromnd))
163247540Skarels 		return (error);
163349735Smckusick 	fvp = fromnd.ni_vp;
163452322Smckusick 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
163552322Smckusick 		UIO_USERSPACE, uap->to, p);
163652322Smckusick 	if (error = namei(&tond)) {
163752230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
163849735Smckusick 		vrele(fromnd.ni_dvp);
163942465Smckusick 		vrele(fvp);
164042465Smckusick 		goto out1;
164142465Smckusick 	}
164237741Smckusick 	tdvp = tond.ni_dvp;
164337741Smckusick 	tvp = tond.ni_vp;
164437741Smckusick 	if (tvp != NULL) {
164537741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
164639242Sbostic 			error = ENOTDIR;
164737741Smckusick 			goto out;
164837741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
164939242Sbostic 			error = EISDIR;
165037741Smckusick 			goto out;
16519167Ssam 		}
16529167Ssam 	}
165339286Smckusick 	if (fvp == tdvp)
165437741Smckusick 		error = EINVAL;
165539286Smckusick 	/*
165649735Smckusick 	 * If source is the same as the destination (that is the
165749735Smckusick 	 * same inode number with the same name in the same directory),
165839286Smckusick 	 * then there is nothing to do.
165939286Smckusick 	 */
166049735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
166152322Smckusick 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
166252322Smckusick 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
166352322Smckusick 	      fromnd.ni_cnd.cn_namelen))
166439286Smckusick 		error = -1;
166537741Smckusick out:
166642465Smckusick 	if (!error) {
166752192Smckusick 		LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE);
166852192Smckusick 		if (fromnd.ni_dvp != tdvp)
166952192Smckusick 			LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
167052192Smckusick 		if (tvp)
167152192Smckusick 			LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE);
167252230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
167352230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
167442465Smckusick 	} else {
167552230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
167643344Smckusick 		if (tdvp == tvp)
167743344Smckusick 			vrele(tdvp);
167843344Smckusick 		else
167943344Smckusick 			vput(tdvp);
168042465Smckusick 		if (tvp)
168142465Smckusick 			vput(tvp);
168252230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
168349735Smckusick 		vrele(fromnd.ni_dvp);
168442465Smckusick 		vrele(fvp);
16859167Ssam 	}
168649735Smckusick 	vrele(tond.ni_startdir);
168752322Smckusick 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
168837741Smckusick out1:
168949735Smckusick 	vrele(fromnd.ni_startdir);
169052322Smckusick 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
169139286Smckusick 	if (error == -1)
169247540Skarels 		return (0);
169347540Skarels 	return (error);
16947701Ssam }
16957701Ssam 
16967535Sroot /*
169749365Smckusick  * Mkdir system call.
169812756Ssam  */
169942441Smckusick /* ARGSUSED */
170042441Smckusick mkdir(p, uap, retval)
170145914Smckusick 	struct proc *p;
170242441Smckusick 	register struct args {
170312756Ssam 		char	*name;
170412756Ssam 		int	dmode;
170542441Smckusick 	} *uap;
170642441Smckusick 	int *retval;
170742441Smckusick {
170853548Sheideman 	USES_VOP_ABORTOP;
170953548Sheideman 	USES_VOP_MKDIR;
171037741Smckusick 	register struct vnode *vp;
171137741Smckusick 	struct vattr vattr;
171237741Smckusick 	int error;
171347540Skarels 	struct nameidata nd;
171412756Ssam 
171552322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p);
171652322Smckusick 	if (error = namei(&nd))
171747540Skarels 		return (error);
171852322Smckusick 	vp = nd.ni_vp;
171937741Smckusick 	if (vp != NULL) {
172052322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
172152322Smckusick 		if (nd.ni_dvp == vp)
172252322Smckusick 			vrele(nd.ni_dvp);
172343344Smckusick 		else
172452322Smckusick 			vput(nd.ni_dvp);
172542465Smckusick 		vrele(vp);
172647540Skarels 		return (EEXIST);
172712756Ssam 	}
172841362Smckusick 	VATTR_NULL(&vattr);
172937741Smckusick 	vattr.va_type = VDIR;
173045914Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask;
173152322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
173252322Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
173338145Smckusick 	if (!error)
173452322Smckusick 		vput(nd.ni_vp);
173547540Skarels 	return (error);
173612756Ssam }
173712756Ssam 
173812756Ssam /*
173912756Ssam  * Rmdir system call.
174012756Ssam  */
174142441Smckusick /* ARGSUSED */
174242441Smckusick rmdir(p, uap, retval)
174345914Smckusick 	struct proc *p;
174442441Smckusick 	struct args {
174542441Smckusick 		char	*name;
174642441Smckusick 	} *uap;
174742441Smckusick 	int *retval;
174812756Ssam {
174953548Sheideman 	USES_VOP_ABORTOP;
175053548Sheideman 	USES_VOP_RMDIR;
175137741Smckusick 	register struct vnode *vp;
175237741Smckusick 	int error;
175347540Skarels 	struct nameidata nd;
175412756Ssam 
175552322Smckusick 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p);
175652322Smckusick 	if (error = namei(&nd))
175747540Skarels 		return (error);
175852322Smckusick 	vp = nd.ni_vp;
175937741Smckusick 	if (vp->v_type != VDIR) {
176037741Smckusick 		error = ENOTDIR;
176112756Ssam 		goto out;
176212756Ssam 	}
176312756Ssam 	/*
176437741Smckusick 	 * No rmdir "." please.
176512756Ssam 	 */
176652322Smckusick 	if (nd.ni_dvp == vp) {
176737741Smckusick 		error = EINVAL;
176812756Ssam 		goto out;
176912756Ssam 	}
177012756Ssam 	/*
177149365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
177212756Ssam 	 */
177337741Smckusick 	if (vp->v_flag & VROOT)
177437741Smckusick 		error = EBUSY;
177512756Ssam out:
177642465Smckusick 	if (!error) {
177752322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
177852192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
177952322Smckusick 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
178042465Smckusick 	} else {
178152322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
178252322Smckusick 		if (nd.ni_dvp == vp)
178352322Smckusick 			vrele(nd.ni_dvp);
178443344Smckusick 		else
178552322Smckusick 			vput(nd.ni_dvp);
178642465Smckusick 		vput(vp);
178742465Smckusick 	}
178847540Skarels 	return (error);
178912756Ssam }
179012756Ssam 
179137741Smckusick /*
179249365Smckusick  * Read a block of directory entries in a file system independent format.
179337741Smckusick  */
179442441Smckusick getdirentries(p, uap, retval)
179545914Smckusick 	struct proc *p;
179642441Smckusick 	register struct args {
179737741Smckusick 		int	fd;
179837741Smckusick 		char	*buf;
179937741Smckusick 		unsigned count;
180037741Smckusick 		long	*basep;
180142441Smckusick 	} *uap;
180242441Smckusick 	int *retval;
180342441Smckusick {
180453548Sheideman 	USES_VOP_LOCK;
180553548Sheideman 	USES_VOP_READDIR;
180653548Sheideman 	USES_VOP_UNLOCK;
180739592Smckusick 	register struct vnode *vp;
180816540Ssam 	struct file *fp;
180937741Smckusick 	struct uio auio;
181037741Smckusick 	struct iovec aiov;
181138129Smckusick 	off_t off;
181240321Smckusick 	int error, eofflag;
181312756Ssam 
181445914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
181547540Skarels 		return (error);
181637741Smckusick 	if ((fp->f_flag & FREAD) == 0)
181747540Skarels 		return (EBADF);
181839592Smckusick 	vp = (struct vnode *)fp->f_data;
181939592Smckusick 	if (vp->v_type != VDIR)
182047540Skarels 		return (EINVAL);
182137741Smckusick 	aiov.iov_base = uap->buf;
182237741Smckusick 	aiov.iov_len = uap->count;
182337741Smckusick 	auio.uio_iov = &aiov;
182437741Smckusick 	auio.uio_iovcnt = 1;
182537741Smckusick 	auio.uio_rw = UIO_READ;
182637741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
182748026Smckusick 	auio.uio_procp = p;
182837741Smckusick 	auio.uio_resid = uap->count;
182939592Smckusick 	VOP_LOCK(vp);
183039592Smckusick 	auio.uio_offset = off = fp->f_offset;
183140321Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
183239592Smckusick 	fp->f_offset = auio.uio_offset;
183339592Smckusick 	VOP_UNLOCK(vp);
183439592Smckusick 	if (error)
183547540Skarels 		return (error);
183639592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
183742441Smckusick 	*retval = uap->count - auio.uio_resid;
183847540Skarels 	return (error);
183912756Ssam }
184012756Ssam 
184112756Ssam /*
184249365Smckusick  * Set the mode mask for creation of filesystem nodes.
184312756Ssam  */
184442441Smckusick mode_t
184542441Smckusick umask(p, uap, retval)
184645914Smckusick 	struct proc *p;
184742441Smckusick 	struct args {
184842441Smckusick 		int	mask;
184942441Smckusick 	} *uap;
185042441Smckusick 	int *retval;
185112756Ssam {
185245914Smckusick 	register struct filedesc *fdp = p->p_fd;
185312756Ssam 
185445914Smckusick 	*retval = fdp->fd_cmask;
185545914Smckusick 	fdp->fd_cmask = uap->mask & 07777;
185647540Skarels 	return (0);
185712756Ssam }
185837741Smckusick 
185939566Smarc /*
186039566Smarc  * Void all references to file by ripping underlying filesystem
186139566Smarc  * away from vnode.
186239566Smarc  */
186342441Smckusick /* ARGSUSED */
186442441Smckusick revoke(p, uap, retval)
186545914Smckusick 	struct proc *p;
186642441Smckusick 	register struct args {
186739566Smarc 		char	*fname;
186842441Smckusick 	} *uap;
186942441Smckusick 	int *retval;
187042441Smckusick {
187153548Sheideman 	USES_VOP_GETATTR;
187239566Smarc 	register struct vnode *vp;
187339566Smarc 	struct vattr vattr;
187439566Smarc 	int error;
187547540Skarels 	struct nameidata nd;
187639566Smarc 
187752322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
187852322Smckusick 	if (error = namei(&nd))
187947540Skarels 		return (error);
188052322Smckusick 	vp = nd.ni_vp;
188139566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
188239566Smarc 		error = EINVAL;
188339566Smarc 		goto out;
188439566Smarc 	}
188548026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
188639566Smarc 		goto out;
188747540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
188847540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
188939566Smarc 		goto out;
189039805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
189139632Smckusick 		vgoneall(vp);
189239566Smarc out:
189339566Smarc 	vrele(vp);
189447540Skarels 	return (error);
189539566Smarc }
189639566Smarc 
189749365Smckusick /*
189849365Smckusick  * Convert a user file descriptor to a kernel file entry.
189949365Smckusick  */
190045914Smckusick getvnode(fdp, fdes, fpp)
190145914Smckusick 	struct filedesc *fdp;
190237741Smckusick 	struct file **fpp;
190337741Smckusick 	int fdes;
190437741Smckusick {
190537741Smckusick 	struct file *fp;
190637741Smckusick 
190747540Skarels 	if ((unsigned)fdes >= fdp->fd_nfiles ||
190847688Skarels 	    (fp = fdp->fd_ofiles[fdes]) == NULL)
190937741Smckusick 		return (EBADF);
191037741Smckusick 	if (fp->f_type != DTYPE_VNODE)
191137741Smckusick 		return (EINVAL);
191237741Smckusick 	*fpp = fp;
191337741Smckusick 	return (0);
191437741Smckusick }
1915