xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 54723)
123405Smckusick /*
237741Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337741Smckusick  * All rights reserved.
423405Smckusick  *
544459Sbostic  * %sccs.include.redist.c%
637741Smckusick  *
7*54723Smckusick  *	@(#)vfs_syscalls.c	7.91 (Berkeley) 07/06/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"
2254620Smckusick #include "dirent.h"
2353468Smckusick #include <vm/vm.h>
2437Sbill 
2537741Smckusick /*
2637741Smckusick  * Virtual File System System Calls
2737741Smckusick  */
2812756Ssam 
299167Ssam /*
3049365Smckusick  * Mount system call.
319167Ssam  */
3242441Smckusick /* ARGSUSED */
3342441Smckusick mount(p, uap, retval)
3445914Smckusick 	struct proc *p;
3542441Smckusick 	register struct args {
3637741Smckusick 		int	type;
3737741Smckusick 		char	*dir;
3837741Smckusick 		int	flags;
3937741Smckusick 		caddr_t	data;
4042441Smckusick 	} *uap;
4142441Smckusick 	int *retval;
4242441Smckusick {
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 	}
8454441Smckusick 	if (error = vinvalbuf(vp, 1, p->p_ucred, p))
8554441Smckusick 		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 */
23354441Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 ||
23454441Smckusick 	    (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)) {
27154441Smckusick 			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 {
42445914Smckusick 	register struct filedesc *fdp = p->p_fd;
42538259Smckusick 	register struct vnode *vp;
42638259Smckusick 	struct file *fp;
42738259Smckusick 	int error;
42838259Smckusick 
42945914Smckusick 	if (error = getvnode(fdp, uap->fd, &fp))
43047540Skarels 		return (error);
43138259Smckusick 	vp = (struct vnode *)fp->f_data;
43238259Smckusick 	VOP_LOCK(vp);
43338259Smckusick 	if (vp->v_type != VDIR)
43438259Smckusick 		error = ENOTDIR;
43538259Smckusick 	else
43648026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
43738259Smckusick 	VOP_UNLOCK(vp);
43839860Smckusick 	if (error)
43947540Skarels 		return (error);
44039860Smckusick 	VREF(vp);
44145914Smckusick 	vrele(fdp->fd_cdir);
44245914Smckusick 	fdp->fd_cdir = vp;
44347540Skarels 	return (0);
44438259Smckusick }
44538259Smckusick 
44638259Smckusick /*
44737741Smckusick  * Change current working directory (``.'').
44837741Smckusick  */
44942441Smckusick /* ARGSUSED */
45042441Smckusick chdir(p, uap, retval)
45145914Smckusick 	struct proc *p;
45242441Smckusick 	struct args {
45342441Smckusick 		char	*fname;
45442441Smckusick 	} *uap;
45542441Smckusick 	int *retval;
45637741Smckusick {
45745914Smckusick 	register struct filedesc *fdp = p->p_fd;
45837741Smckusick 	int error;
45947540Skarels 	struct nameidata nd;
4606254Sroot 
46152322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
46252781Sralph 	if (error = chdirec(&nd, p))
46347540Skarels 		return (error);
46445914Smckusick 	vrele(fdp->fd_cdir);
46552322Smckusick 	fdp->fd_cdir = nd.ni_vp;
46647540Skarels 	return (0);
46737741Smckusick }
4686254Sroot 
46937741Smckusick /*
47037741Smckusick  * Change notion of root (``/'') directory.
47137741Smckusick  */
47242441Smckusick /* ARGSUSED */
47342441Smckusick chroot(p, uap, retval)
47445914Smckusick 	struct proc *p;
47542441Smckusick 	struct args {
47642441Smckusick 		char	*fname;
47742441Smckusick 	} *uap;
47842441Smckusick 	int *retval;
47937741Smckusick {
48045914Smckusick 	register struct filedesc *fdp = p->p_fd;
48137741Smckusick 	int error;
48247540Skarels 	struct nameidata nd;
48337741Smckusick 
48447540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
48547540Skarels 		return (error);
48652322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
48752781Sralph 	if (error = chdirec(&nd, p))
48847540Skarels 		return (error);
48945914Smckusick 	if (fdp->fd_rdir != NULL)
49045914Smckusick 		vrele(fdp->fd_rdir);
49152322Smckusick 	fdp->fd_rdir = nd.ni_vp;
49247540Skarels 	return (0);
4936254Sroot }
4946254Sroot 
49537Sbill /*
49637741Smckusick  * Common routine for chroot and chdir.
49737741Smckusick  */
49847540Skarels chdirec(ndp, p)
49952322Smckusick 	register struct nameidata *ndp;
50047540Skarels 	struct proc *p;
50137741Smckusick {
50237741Smckusick 	struct vnode *vp;
50337741Smckusick 	int error;
50437741Smckusick 
50552322Smckusick 	if (error = namei(ndp))
50637741Smckusick 		return (error);
50737741Smckusick 	vp = ndp->ni_vp;
50837741Smckusick 	if (vp->v_type != VDIR)
50937741Smckusick 		error = ENOTDIR;
51037741Smckusick 	else
51148026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
51237741Smckusick 	VOP_UNLOCK(vp);
51337741Smckusick 	if (error)
51437741Smckusick 		vrele(vp);
51537741Smckusick 	return (error);
51637741Smckusick }
51737741Smckusick 
51837741Smckusick /*
5196254Sroot  * Open system call.
52042441Smckusick  * Check permissions, allocate an open file structure,
52142441Smckusick  * and call the device open routine if any.
5226254Sroot  */
52342441Smckusick open(p, uap, retval)
52445914Smckusick 	struct proc *p;
52542441Smckusick 	register struct args {
5266254Sroot 		char	*fname;
5277701Ssam 		int	mode;
52812756Ssam 		int	crtmode;
52942441Smckusick 	} *uap;
53042441Smckusick 	int *retval;
5316254Sroot {
53245914Smckusick 	register struct filedesc *fdp = p->p_fd;
53342441Smckusick 	register struct file *fp;
53450111Smckusick 	register struct vnode *vp;
53537741Smckusick 	int fmode, cmode;
53637741Smckusick 	struct file *nfp;
53749945Smckusick 	int type, indx, error;
53849945Smckusick 	struct flock lf;
53947540Skarels 	struct nameidata nd;
54037741Smckusick 	extern struct fileops vnops;
5416254Sroot 
54245914Smckusick 	if (error = falloc(p, &nfp, &indx))
54347540Skarels 		return (error);
54437741Smckusick 	fp = nfp;
54546553Skarels 	fmode = FFLAGS(uap->mode);
54645914Smckusick 	cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX;
54752322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
54845202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
54952322Smckusick 	if (error = vn_open(&nd, fmode, cmode)) {
55049980Smckusick 		ffree(fp);
551*54723Smckusick 		if ((error == ENODEV || error == ENXIO) &&
552*54723Smckusick 		    p->p_dupfd >= 0 && 			/* XXX from fdopen */
55353828Spendry 		    (error = dupfdopen(fdp, indx, p->p_dupfd,
55453828Spendry 					fmode, error)) == 0) {
55542441Smckusick 			*retval = indx;
55647540Skarels 			return (0);
55742441Smckusick 		}
55840884Smckusick 		if (error == ERESTART)
55940884Smckusick 			error = EINTR;
56047688Skarels 		fdp->fd_ofiles[indx] = NULL;
56147540Skarels 		return (error);
56212756Ssam 	}
56353828Spendry 	p->p_dupfd = 0;
56452322Smckusick 	vp = nd.ni_vp;
56549949Smckusick 	fp->f_flag = fmode & FMASK;
56654348Smckusick 	fp->f_type = DTYPE_VNODE;
56754348Smckusick 	fp->f_ops = &vnops;
56854348Smckusick 	fp->f_data = (caddr_t)vp;
56949945Smckusick 	if (fmode & (O_EXLOCK | O_SHLOCK)) {
57049945Smckusick 		lf.l_whence = SEEK_SET;
57149945Smckusick 		lf.l_start = 0;
57249945Smckusick 		lf.l_len = 0;
57349945Smckusick 		if (fmode & O_EXLOCK)
57449945Smckusick 			lf.l_type = F_WRLCK;
57549945Smckusick 		else
57649945Smckusick 			lf.l_type = F_RDLCK;
57749945Smckusick 		type = F_FLOCK;
57849945Smckusick 		if ((fmode & FNONBLOCK) == 0)
57949945Smckusick 			type |= F_WAIT;
58050111Smckusick 		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
58150111Smckusick 			VOP_UNLOCK(vp);
58250111Smckusick 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
58349980Smckusick 			ffree(fp);
58449945Smckusick 			fdp->fd_ofiles[indx] = NULL;
58549945Smckusick 			return (error);
58649945Smckusick 		}
58749949Smckusick 		fp->f_flag |= FHASLOCK;
58849945Smckusick 	}
58950111Smckusick 	VOP_UNLOCK(vp);
59042441Smckusick 	*retval = indx;
59147540Skarels 	return (0);
5926254Sroot }
5936254Sroot 
59442955Smckusick #ifdef COMPAT_43
5956254Sroot /*
59642441Smckusick  * Creat system call.
5976254Sroot  */
59842955Smckusick ocreat(p, uap, retval)
59942441Smckusick 	struct proc *p;
60042441Smckusick 	register struct args {
60142441Smckusick 		char	*fname;
60242441Smckusick 		int	fmode;
60342441Smckusick 	} *uap;
60442441Smckusick 	int *retval;
6056254Sroot {
60654620Smckusick 	struct nargs {
6076254Sroot 		char	*fname;
60842441Smckusick 		int	mode;
60942441Smckusick 		int	crtmode;
61042441Smckusick 	} openuap;
61142441Smckusick 
61242441Smckusick 	openuap.fname = uap->fname;
61342441Smckusick 	openuap.crtmode = uap->fmode;
61442441Smckusick 	openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
61547540Skarels 	return (open(p, &openuap, retval));
61642441Smckusick }
61742955Smckusick #endif /* COMPAT_43 */
61842441Smckusick 
61942441Smckusick /*
62049365Smckusick  * Mknod system call.
62142441Smckusick  */
62242441Smckusick /* ARGSUSED */
62342441Smckusick mknod(p, uap, retval)
62445914Smckusick 	struct proc *p;
62542441Smckusick 	register struct args {
62642441Smckusick 		char	*fname;
6276254Sroot 		int	fmode;
6286254Sroot 		int	dev;
62942441Smckusick 	} *uap;
63042441Smckusick 	int *retval;
63142441Smckusick {
63237741Smckusick 	register struct vnode *vp;
63337741Smckusick 	struct vattr vattr;
63437741Smckusick 	int error;
63547540Skarels 	struct nameidata nd;
6366254Sroot 
63747540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
63847540Skarels 		return (error);
63952322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p);
64052322Smckusick 	if (error = namei(&nd))
64147540Skarels 		return (error);
64252322Smckusick 	vp = nd.ni_vp;
64337741Smckusick 	if (vp != NULL) {
64437741Smckusick 		error = EEXIST;
64512756Ssam 		goto out;
6466254Sroot 	}
64741362Smckusick 	VATTR_NULL(&vattr);
64840635Smckusick 	switch (uap->fmode & S_IFMT) {
64912756Ssam 
65040635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
65137741Smckusick 		vattr.va_type = VBAD;
65237741Smckusick 		break;
65340635Smckusick 	case S_IFCHR:
65437741Smckusick 		vattr.va_type = VCHR;
65537741Smckusick 		break;
65640635Smckusick 	case S_IFBLK:
65737741Smckusick 		vattr.va_type = VBLK;
65837741Smckusick 		break;
65937741Smckusick 	default:
66037741Smckusick 		error = EINVAL;
66137741Smckusick 		goto out;
6626254Sroot 	}
66345914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
66437741Smckusick 	vattr.va_rdev = uap->dev;
6656254Sroot out:
66642465Smckusick 	if (!error) {
66752322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
66852322Smckusick 		error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
66942465Smckusick 	} else {
67052322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
67152322Smckusick 		if (nd.ni_dvp == vp)
67252322Smckusick 			vrele(nd.ni_dvp);
67343344Smckusick 		else
67452322Smckusick 			vput(nd.ni_dvp);
67542465Smckusick 		if (vp)
67642465Smckusick 			vrele(vp);
67742465Smckusick 	}
67847540Skarels 	return (error);
6796254Sroot }
6806254Sroot 
6816254Sroot /*
68249365Smckusick  * Mkfifo system call.
68340285Smckusick  */
68442441Smckusick /* ARGSUSED */
68542441Smckusick mkfifo(p, uap, retval)
68645914Smckusick 	struct proc *p;
68742441Smckusick 	register struct args {
68840285Smckusick 		char	*fname;
68940285Smckusick 		int	fmode;
69042441Smckusick 	} *uap;
69142441Smckusick 	int *retval;
69242441Smckusick {
69340285Smckusick 	struct vattr vattr;
69440285Smckusick 	int error;
69547540Skarels 	struct nameidata nd;
69640285Smckusick 
69740285Smckusick #ifndef FIFO
69847540Skarels 	return (EOPNOTSUPP);
69940285Smckusick #else
70052322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p);
70152322Smckusick 	if (error = namei(&nd))
70247540Skarels 		return (error);
70352322Smckusick 	if (nd.ni_vp != NULL) {
70452322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
70552322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
70652322Smckusick 			vrele(nd.ni_dvp);
70743344Smckusick 		else
70852322Smckusick 			vput(nd.ni_dvp);
70952322Smckusick 		vrele(nd.ni_vp);
71047540Skarels 		return (EEXIST);
71140285Smckusick 	}
71245785Sbostic 	VATTR_NULL(&vattr);
71345785Sbostic 	vattr.va_type = VFIFO;
71445914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
71552322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
71652322Smckusick 	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
71740285Smckusick #endif /* FIFO */
71840285Smckusick }
71940285Smckusick 
72040285Smckusick /*
72149365Smckusick  * Link system call.
7226254Sroot  */
72342441Smckusick /* ARGSUSED */
72442441Smckusick link(p, uap, retval)
72545914Smckusick 	struct proc *p;
72642441Smckusick 	register struct args {
7276254Sroot 		char	*target;
7286254Sroot 		char	*linkname;
72942441Smckusick 	} *uap;
73042441Smckusick 	int *retval;
73142441Smckusick {
73237741Smckusick 	register struct vnode *vp, *xp;
73337741Smckusick 	int error;
73447540Skarels 	struct nameidata nd;
7356254Sroot 
73652322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->target, p);
73752322Smckusick 	if (error = namei(&nd))
73847540Skarels 		return (error);
73952322Smckusick 	vp = nd.ni_vp;
74037741Smckusick 	if (vp->v_type == VDIR &&
74147540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
74237741Smckusick 		goto out1;
74352322Smckusick 	nd.ni_cnd.cn_nameiop = CREATE;
74452322Smckusick 	nd.ni_cnd.cn_flags = LOCKPARENT;
74552322Smckusick 	nd.ni_dirp = (caddr_t)uap->linkname;
74652322Smckusick 	if (error = namei(&nd))
74737741Smckusick 		goto out1;
74852322Smckusick 	xp = nd.ni_vp;
7496254Sroot 	if (xp != NULL) {
75037741Smckusick 		error = EEXIST;
7516254Sroot 		goto out;
7526254Sroot 	}
75352322Smckusick 	xp = nd.ni_dvp;
7546254Sroot out:
75542465Smckusick 	if (!error) {
75652192Smckusick 		LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE);
75752192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
75852821Smckusick 		error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
75942465Smckusick 	} else {
76052322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
76152322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
76252322Smckusick 			vrele(nd.ni_dvp);
76343344Smckusick 		else
76452322Smckusick 			vput(nd.ni_dvp);
76552322Smckusick 		if (nd.ni_vp)
76652322Smckusick 			vrele(nd.ni_vp);
76742465Smckusick 	}
76837741Smckusick out1:
76937741Smckusick 	vrele(vp);
77047540Skarels 	return (error);
7716254Sroot }
7726254Sroot 
7736254Sroot /*
77449365Smckusick  * Make a symbolic link.
7756254Sroot  */
77642441Smckusick /* ARGSUSED */
77742441Smckusick symlink(p, uap, retval)
77845914Smckusick 	struct proc *p;
77942441Smckusick 	register struct args {
7806254Sroot 		char	*target;
7816254Sroot 		char	*linkname;
78242441Smckusick 	} *uap;
78342441Smckusick 	int *retval;
78442441Smckusick {
78537741Smckusick 	struct vattr vattr;
78637741Smckusick 	char *target;
78737741Smckusick 	int error;
78847540Skarels 	struct nameidata nd;
7896254Sroot 
79037741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
79137741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
79242465Smckusick 		goto out;
79352322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->linkname, p);
79452322Smckusick 	if (error = namei(&nd))
79542465Smckusick 		goto out;
79652322Smckusick 	if (nd.ni_vp) {
79752322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
79852322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
79952322Smckusick 			vrele(nd.ni_dvp);
80043344Smckusick 		else
80152322Smckusick 			vput(nd.ni_dvp);
80252322Smckusick 		vrele(nd.ni_vp);
80337741Smckusick 		error = EEXIST;
80437741Smckusick 		goto out;
8056254Sroot 	}
80641362Smckusick 	VATTR_NULL(&vattr);
80745914Smckusick 	vattr.va_mode = 0777 &~ p->p_fd->fd_cmask;
80852322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
80952322Smckusick 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, target);
81037741Smckusick out:
81137741Smckusick 	FREE(target, M_NAMEI);
81247540Skarels 	return (error);
8136254Sroot }
8146254Sroot 
8156254Sroot /*
81649365Smckusick  * Delete a name from the filesystem.
8176254Sroot  */
81842441Smckusick /* ARGSUSED */
81942441Smckusick unlink(p, uap, retval)
82045914Smckusick 	struct proc *p;
82142441Smckusick 	struct args {
82252322Smckusick 		char	*name;
82342441Smckusick 	} *uap;
82442441Smckusick 	int *retval;
8256254Sroot {
82637741Smckusick 	register struct vnode *vp;
82737741Smckusick 	int error;
82847540Skarels 	struct nameidata nd;
8296254Sroot 
83052322Smckusick 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p);
83152322Smckusick 	if (error = namei(&nd))
83247540Skarels 		return (error);
83352322Smckusick 	vp = nd.ni_vp;
83437741Smckusick 	if (vp->v_type == VDIR &&
83547540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
8366254Sroot 		goto out;
8376254Sroot 	/*
83849365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
8396254Sroot 	 */
84037741Smckusick 	if (vp->v_flag & VROOT) {
84137741Smckusick 		error = EBUSY;
8426254Sroot 		goto out;
8436254Sroot 	}
84445738Smckusick 	(void) vnode_pager_uncache(vp);
8456254Sroot out:
84642465Smckusick 	if (!error) {
84752322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
84852192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
84952322Smckusick 		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
85042465Smckusick 	} else {
85152322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
85252322Smckusick 		if (nd.ni_dvp == vp)
85352322Smckusick 			vrele(nd.ni_dvp);
85443344Smckusick 		else
85552322Smckusick 			vput(nd.ni_dvp);
85642465Smckusick 		vput(vp);
85742465Smckusick 	}
85847540Skarels 	return (error);
8596254Sroot }
8606254Sroot 
86154348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
8626254Sroot /*
86349365Smckusick  * Seek system call.
8646254Sroot  */
86542441Smckusick lseek(p, uap, retval)
86645914Smckusick 	struct proc *p;
86742441Smckusick 	register struct args {
86837741Smckusick 		int	fdes;
86953468Smckusick 		long	off;
87053468Smckusick 		int	sbase;
87153468Smckusick 	} *uap;
87253468Smckusick 	long *retval;
87353468Smckusick {
87453468Smckusick 	struct nargs {
87553468Smckusick 		int	fdes;
8766254Sroot 		off_t	off;
8776254Sroot 		int	sbase;
87853468Smckusick 	} nuap;
87953468Smckusick 	quad_t qret;
88053468Smckusick 	int error;
88153468Smckusick 
88253468Smckusick 	nuap.fdes = uap->fdes;
88353468Smckusick 	nuap.off = uap->off;
88453468Smckusick 	nuap.sbase = uap->sbase;
88553759Smckusick 	error = __lseek(p, &nuap, &qret);
88653468Smckusick 	*retval = qret;
88753468Smckusick 	return (error);
88853468Smckusick }
88954348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
89053468Smckusick 
89153468Smckusick /*
89253468Smckusick  * Seek system call.
89353468Smckusick  */
89453759Smckusick __lseek(p, uap, retval)
89553468Smckusick 	struct proc *p;
89653468Smckusick 	register struct args {
89753468Smckusick 		int	fdes;
89853468Smckusick 		off_t	off;
89953468Smckusick 		int	sbase;
90042441Smckusick 	} *uap;
90142441Smckusick 	off_t *retval;
90242441Smckusick {
90347540Skarels 	struct ucred *cred = p->p_ucred;
90445914Smckusick 	register struct filedesc *fdp = p->p_fd;
90542441Smckusick 	register struct file *fp;
90637741Smckusick 	struct vattr vattr;
90737741Smckusick 	int error;
9086254Sroot 
90947540Skarels 	if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
91047688Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL)
91147540Skarels 		return (EBADF);
91237741Smckusick 	if (fp->f_type != DTYPE_VNODE)
91347540Skarels 		return (ESPIPE);
91413878Ssam 	switch (uap->sbase) {
91513878Ssam 
91613878Ssam 	case L_INCR:
91713878Ssam 		fp->f_offset += uap->off;
91813878Ssam 		break;
91913878Ssam 
92013878Ssam 	case L_XTND:
92137741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
92248026Smckusick 		    &vattr, cred, p))
92347540Skarels 			return (error);
92437741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
92513878Ssam 		break;
92613878Ssam 
92713878Ssam 	case L_SET:
92813878Ssam 		fp->f_offset = uap->off;
92913878Ssam 		break;
93013878Ssam 
93113878Ssam 	default:
93247540Skarels 		return (EINVAL);
93313878Ssam 	}
93442441Smckusick 	*retval = fp->f_offset;
93547540Skarels 	return (0);
9366254Sroot }
9376254Sroot 
9386254Sroot /*
93949365Smckusick  * Check access permissions.
9406254Sroot  */
94142441Smckusick /* ARGSUSED */
94242441Smckusick saccess(p, uap, retval)
94345914Smckusick 	struct proc *p;
94442441Smckusick 	register struct args {
9456254Sroot 		char	*fname;
9466254Sroot 		int	fmode;
94742441Smckusick 	} *uap;
94842441Smckusick 	int *retval;
94942441Smckusick {
95047540Skarels 	register struct ucred *cred = p->p_ucred;
95137741Smckusick 	register struct vnode *vp;
95237741Smckusick 	int error, mode, svuid, svgid;
95347540Skarels 	struct nameidata nd;
9546254Sroot 
95542441Smckusick 	svuid = cred->cr_uid;
95642441Smckusick 	svgid = cred->cr_groups[0];
95747540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
95847540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
95952322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
96052322Smckusick 	if (error = namei(&nd))
96137741Smckusick 		goto out1;
96252322Smckusick 	vp = nd.ni_vp;
96337741Smckusick 	/*
96437741Smckusick 	 * fmode == 0 means only check for exist
96537741Smckusick 	 */
96637741Smckusick 	if (uap->fmode) {
96737741Smckusick 		mode = 0;
96837741Smckusick 		if (uap->fmode & R_OK)
96937741Smckusick 			mode |= VREAD;
97037741Smckusick 		if (uap->fmode & W_OK)
97137741Smckusick 			mode |= VWRITE;
97237741Smckusick 		if (uap->fmode & X_OK)
97337741Smckusick 			mode |= VEXEC;
97439543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
97548026Smckusick 			error = VOP_ACCESS(vp, mode, cred, p);
9766254Sroot 	}
97737741Smckusick 	vput(vp);
97837741Smckusick out1:
97942441Smckusick 	cred->cr_uid = svuid;
98042441Smckusick 	cred->cr_groups[0] = svgid;
98147540Skarels 	return (error);
9826254Sroot }
9836254Sroot 
98454348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
9856254Sroot /*
98649365Smckusick  * Stat system call.
98749365Smckusick  * This version follows links.
98837Sbill  */
98942441Smckusick /* ARGSUSED */
99053759Smckusick ostat(p, uap, retval)
99145914Smckusick 	struct proc *p;
99242441Smckusick 	register struct args {
99342441Smckusick 		char	*fname;
99453468Smckusick 		struct ostat *ub;
99553468Smckusick 	} *uap;
99653468Smckusick 	int *retval;
99753468Smckusick {
99853468Smckusick 	struct stat sb;
99953468Smckusick 	struct ostat osb;
100053468Smckusick 	int error;
100153468Smckusick 	struct nameidata nd;
100253468Smckusick 
100353468Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
100453468Smckusick 	if (error = namei(&nd))
100553468Smckusick 		return (error);
100653468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
100753468Smckusick 	vput(nd.ni_vp);
100853468Smckusick 	if (error)
100953468Smckusick 		return (error);
101053468Smckusick 	cvtstat(&sb, &osb);
101153468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
101253468Smckusick 	return (error);
101353468Smckusick }
101453468Smckusick 
101553468Smckusick /*
101653468Smckusick  * Lstat system call.
101753468Smckusick  * This version does not follow links.
101853468Smckusick  */
101953468Smckusick /* ARGSUSED */
102053759Smckusick olstat(p, uap, retval)
102153468Smckusick 	struct proc *p;
102253468Smckusick 	register struct args {
102353468Smckusick 		char	*fname;
102453468Smckusick 		struct ostat *ub;
102553468Smckusick 	} *uap;
102653468Smckusick 	int *retval;
102753468Smckusick {
102853468Smckusick 	struct stat sb;
102953468Smckusick 	struct ostat osb;
103053468Smckusick 	int error;
103153468Smckusick 	struct nameidata nd;
103253468Smckusick 
103353468Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
103453468Smckusick 	if (error = namei(&nd))
103553468Smckusick 		return (error);
103653468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
103753468Smckusick 	vput(nd.ni_vp);
103853468Smckusick 	if (error)
103953468Smckusick 		return (error);
104053468Smckusick 	cvtstat(&sb, &osb);
104153468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
104253468Smckusick 	return (error);
104353468Smckusick }
104453468Smckusick 
104553468Smckusick /*
104653468Smckusick  * convert from an old to a new stat structure.
104753468Smckusick  */
104853468Smckusick cvtstat(st, ost)
104953468Smckusick 	struct stat *st;
105053468Smckusick 	struct ostat *ost;
105153468Smckusick {
105253468Smckusick 
105353468Smckusick 	ost->st_dev = st->st_dev;
105453468Smckusick 	ost->st_ino = st->st_ino;
105553468Smckusick 	ost->st_mode = st->st_mode;
105653468Smckusick 	ost->st_nlink = st->st_nlink;
105753468Smckusick 	ost->st_uid = st->st_uid;
105853468Smckusick 	ost->st_gid = st->st_gid;
105953468Smckusick 	ost->st_rdev = st->st_rdev;
106053468Smckusick 	if (st->st_size < (quad_t)1 << 32)
106153468Smckusick 		ost->st_size = st->st_size;
106253468Smckusick 	else
106353468Smckusick 		ost->st_size = -2;
106453468Smckusick 	ost->st_atime = st->st_atime;
106553468Smckusick 	ost->st_mtime = st->st_mtime;
106653468Smckusick 	ost->st_ctime = st->st_ctime;
106753468Smckusick 	ost->st_blksize = st->st_blksize;
106853468Smckusick 	ost->st_blocks = st->st_blocks;
106953468Smckusick 	ost->st_flags = st->st_flags;
107053468Smckusick 	ost->st_gen = st->st_gen;
107153468Smckusick }
107254348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
107353468Smckusick 
107453468Smckusick /*
107553468Smckusick  * Stat system call.
107653468Smckusick  * This version follows links.
107753468Smckusick  */
107853468Smckusick /* ARGSUSED */
107953759Smckusick stat(p, uap, retval)
108053468Smckusick 	struct proc *p;
108153468Smckusick 	register struct args {
108253468Smckusick 		char	*fname;
108342441Smckusick 		struct stat *ub;
108442441Smckusick 	} *uap;
108542441Smckusick 	int *retval;
108637Sbill {
108742441Smckusick 	struct stat sb;
108842441Smckusick 	int error;
108947540Skarels 	struct nameidata nd;
109037Sbill 
109152322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
109252322Smckusick 	if (error = namei(&nd))
109347540Skarels 		return (error);
109452322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
109552322Smckusick 	vput(nd.ni_vp);
109642441Smckusick 	if (error)
109747540Skarels 		return (error);
109842441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
109947540Skarels 	return (error);
110037Sbill }
110137Sbill 
110237Sbill /*
110349365Smckusick  * Lstat system call.
110449365Smckusick  * This version does not follow links.
11055992Swnj  */
110642441Smckusick /* ARGSUSED */
110753759Smckusick lstat(p, uap, retval)
110845914Smckusick 	struct proc *p;
110942441Smckusick 	register struct args {
11105992Swnj 		char	*fname;
111112756Ssam 		struct stat *ub;
111242441Smckusick 	} *uap;
111342441Smckusick 	int *retval;
111442441Smckusick {
111512756Ssam 	struct stat sb;
111637741Smckusick 	int error;
111747540Skarels 	struct nameidata nd;
11185992Swnj 
111952322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
112052322Smckusick 	if (error = namei(&nd))
112147540Skarels 		return (error);
112252322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
112352322Smckusick 	vput(nd.ni_vp);
112437741Smckusick 	if (error)
112547540Skarels 		return (error);
112637741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
112747540Skarels 	return (error);
11285992Swnj }
11295992Swnj 
11305992Swnj /*
113149365Smckusick  * Return target name of a symbolic link.
113237Sbill  */
113342441Smckusick /* ARGSUSED */
113442441Smckusick readlink(p, uap, retval)
113545914Smckusick 	struct proc *p;
113642441Smckusick 	register struct args {
11375992Swnj 		char	*name;
11385992Swnj 		char	*buf;
11395992Swnj 		int	count;
114042441Smckusick 	} *uap;
114142441Smckusick 	int *retval;
114242441Smckusick {
114337741Smckusick 	register struct vnode *vp;
114437741Smckusick 	struct iovec aiov;
114537741Smckusick 	struct uio auio;
114637741Smckusick 	int error;
114747540Skarels 	struct nameidata nd;
11485992Swnj 
114952322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p);
115052322Smckusick 	if (error = namei(&nd))
115147540Skarels 		return (error);
115252322Smckusick 	vp = nd.ni_vp;
115337741Smckusick 	if (vp->v_type != VLNK) {
115437741Smckusick 		error = EINVAL;
11555992Swnj 		goto out;
11565992Swnj 	}
115737741Smckusick 	aiov.iov_base = uap->buf;
115837741Smckusick 	aiov.iov_len = uap->count;
115937741Smckusick 	auio.uio_iov = &aiov;
116037741Smckusick 	auio.uio_iovcnt = 1;
116137741Smckusick 	auio.uio_offset = 0;
116237741Smckusick 	auio.uio_rw = UIO_READ;
116337741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
116448026Smckusick 	auio.uio_procp = p;
116537741Smckusick 	auio.uio_resid = uap->count;
116647540Skarels 	error = VOP_READLINK(vp, &auio, p->p_ucred);
11675992Swnj out:
116837741Smckusick 	vput(vp);
116942441Smckusick 	*retval = uap->count - auio.uio_resid;
117047540Skarels 	return (error);
11715992Swnj }
11725992Swnj 
11739167Ssam /*
117438259Smckusick  * Change flags of a file given path name.
117538259Smckusick  */
117642441Smckusick /* ARGSUSED */
117742441Smckusick chflags(p, uap, retval)
117845914Smckusick 	struct proc *p;
117942441Smckusick 	register struct args {
118038259Smckusick 		char	*fname;
118138259Smckusick 		int	flags;
118242441Smckusick 	} *uap;
118342441Smckusick 	int *retval;
118442441Smckusick {
118538259Smckusick 	register struct vnode *vp;
118638259Smckusick 	struct vattr vattr;
118738259Smckusick 	int error;
118847540Skarels 	struct nameidata nd;
118938259Smckusick 
119052322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
119152322Smckusick 	if (error = namei(&nd))
119247540Skarels 		return (error);
119352322Smckusick 	vp = nd.ni_vp;
119441400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
119538259Smckusick 		error = EROFS;
119638259Smckusick 		goto out;
119738259Smckusick 	}
119845785Sbostic 	VATTR_NULL(&vattr);
119945785Sbostic 	vattr.va_flags = uap->flags;
120052192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
120148026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
120238259Smckusick out:
120338259Smckusick 	vput(vp);
120447540Skarels 	return (error);
120538259Smckusick }
120638259Smckusick 
120738259Smckusick /*
120838259Smckusick  * Change flags of a file given a file descriptor.
120938259Smckusick  */
121042441Smckusick /* ARGSUSED */
121142441Smckusick fchflags(p, uap, retval)
121245914Smckusick 	struct proc *p;
121342441Smckusick 	register struct args {
121438259Smckusick 		int	fd;
121538259Smckusick 		int	flags;
121642441Smckusick 	} *uap;
121742441Smckusick 	int *retval;
121842441Smckusick {
121938259Smckusick 	struct vattr vattr;
122038259Smckusick 	struct vnode *vp;
122138259Smckusick 	struct file *fp;
122238259Smckusick 	int error;
122338259Smckusick 
122445914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
122547540Skarels 		return (error);
122638259Smckusick 	vp = (struct vnode *)fp->f_data;
122738259Smckusick 	VOP_LOCK(vp);
122841400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
122938259Smckusick 		error = EROFS;
123038259Smckusick 		goto out;
123138259Smckusick 	}
123245785Sbostic 	VATTR_NULL(&vattr);
123345785Sbostic 	vattr.va_flags = uap->flags;
123452192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
123548026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
123638259Smckusick out:
123738259Smckusick 	VOP_UNLOCK(vp);
123847540Skarels 	return (error);
123938259Smckusick }
124038259Smckusick 
124138259Smckusick /*
12429167Ssam  * Change mode of a file given path name.
12439167Ssam  */
124442441Smckusick /* ARGSUSED */
124542441Smckusick chmod(p, uap, retval)
124645914Smckusick 	struct proc *p;
124742441Smckusick 	register struct args {
12486254Sroot 		char	*fname;
12496254Sroot 		int	fmode;
125042441Smckusick 	} *uap;
125142441Smckusick 	int *retval;
125242441Smckusick {
125337741Smckusick 	register struct vnode *vp;
125437741Smckusick 	struct vattr vattr;
125537741Smckusick 	int error;
125647540Skarels 	struct nameidata nd;
12575992Swnj 
125852322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
125952322Smckusick 	if (error = namei(&nd))
126047540Skarels 		return (error);
126152322Smckusick 	vp = nd.ni_vp;
126241400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
126337741Smckusick 		error = EROFS;
126437741Smckusick 		goto out;
126537741Smckusick 	}
126645785Sbostic 	VATTR_NULL(&vattr);
126745785Sbostic 	vattr.va_mode = uap->fmode & 07777;
126852192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
126948026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
127037741Smckusick out:
127137741Smckusick 	vput(vp);
127247540Skarels 	return (error);
12737701Ssam }
12747439Sroot 
12759167Ssam /*
12769167Ssam  * Change mode of a file given a file descriptor.
12779167Ssam  */
127842441Smckusick /* ARGSUSED */
127942441Smckusick fchmod(p, uap, retval)
128045914Smckusick 	struct proc *p;
128142441Smckusick 	register struct args {
12827701Ssam 		int	fd;
12837701Ssam 		int	fmode;
128442441Smckusick 	} *uap;
128542441Smckusick 	int *retval;
128642441Smckusick {
128737741Smckusick 	struct vattr vattr;
128837741Smckusick 	struct vnode *vp;
128937741Smckusick 	struct file *fp;
129037741Smckusick 	int error;
12917701Ssam 
129245914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
129347540Skarels 		return (error);
129437741Smckusick 	vp = (struct vnode *)fp->f_data;
129537741Smckusick 	VOP_LOCK(vp);
129641400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
129737741Smckusick 		error = EROFS;
129837741Smckusick 		goto out;
12997439Sroot 	}
130045785Sbostic 	VATTR_NULL(&vattr);
130145785Sbostic 	vattr.va_mode = uap->fmode & 07777;
130252192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
130348026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
130437741Smckusick out:
130537741Smckusick 	VOP_UNLOCK(vp);
130647540Skarels 	return (error);
13075992Swnj }
13085992Swnj 
13099167Ssam /*
13109167Ssam  * Set ownership given a path name.
13119167Ssam  */
131242441Smckusick /* ARGSUSED */
131342441Smckusick chown(p, uap, retval)
131445914Smckusick 	struct proc *p;
131542441Smckusick 	register struct args {
13166254Sroot 		char	*fname;
13176254Sroot 		int	uid;
13186254Sroot 		int	gid;
131942441Smckusick 	} *uap;
132042441Smckusick 	int *retval;
132142441Smckusick {
132237741Smckusick 	register struct vnode *vp;
132337741Smckusick 	struct vattr vattr;
132437741Smckusick 	int error;
132547540Skarels 	struct nameidata nd;
132637Sbill 
132752322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
132852322Smckusick 	if (error = namei(&nd))
132947540Skarels 		return (error);
133052322Smckusick 	vp = nd.ni_vp;
133141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
133237741Smckusick 		error = EROFS;
133337741Smckusick 		goto out;
133437741Smckusick 	}
133545785Sbostic 	VATTR_NULL(&vattr);
133645785Sbostic 	vattr.va_uid = uap->uid;
133745785Sbostic 	vattr.va_gid = uap->gid;
133852192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
133948026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
134037741Smckusick out:
134137741Smckusick 	vput(vp);
134247540Skarels 	return (error);
13437701Ssam }
13447439Sroot 
13459167Ssam /*
13469167Ssam  * Set ownership given a file descriptor.
13479167Ssam  */
134842441Smckusick /* ARGSUSED */
134942441Smckusick fchown(p, uap, retval)
135045914Smckusick 	struct proc *p;
135142441Smckusick 	register struct args {
13527701Ssam 		int	fd;
13537701Ssam 		int	uid;
13547701Ssam 		int	gid;
135542441Smckusick 	} *uap;
135642441Smckusick 	int *retval;
135742441Smckusick {
135837741Smckusick 	struct vattr vattr;
135937741Smckusick 	struct vnode *vp;
136037741Smckusick 	struct file *fp;
136137741Smckusick 	int error;
13627701Ssam 
136345914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
136447540Skarels 		return (error);
136537741Smckusick 	vp = (struct vnode *)fp->f_data;
136637741Smckusick 	VOP_LOCK(vp);
136741400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
136837741Smckusick 		error = EROFS;
136937741Smckusick 		goto out;
137037741Smckusick 	}
137145785Sbostic 	VATTR_NULL(&vattr);
137245785Sbostic 	vattr.va_uid = uap->uid;
137345785Sbostic 	vattr.va_gid = uap->gid;
137452192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
137548026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
137637741Smckusick out:
137737741Smckusick 	VOP_UNLOCK(vp);
137847540Skarels 	return (error);
13797701Ssam }
13807701Ssam 
138142441Smckusick /*
138242441Smckusick  * Set the access and modification times of a file.
138342441Smckusick  */
138442441Smckusick /* ARGSUSED */
138542441Smckusick utimes(p, uap, retval)
138645914Smckusick 	struct proc *p;
138742441Smckusick 	register struct args {
138811811Ssam 		char	*fname;
138911811Ssam 		struct	timeval *tptr;
139042441Smckusick 	} *uap;
139142441Smckusick 	int *retval;
139242441Smckusick {
139337741Smckusick 	register struct vnode *vp;
139411811Ssam 	struct timeval tv[2];
139537741Smckusick 	struct vattr vattr;
139637741Smckusick 	int error;
139747540Skarels 	struct nameidata nd;
139811811Ssam 
139937741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
140047540Skarels 		return (error);
140152322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
140252322Smckusick 	if (error = namei(&nd))
140347540Skarels 		return (error);
140452322Smckusick 	vp = nd.ni_vp;
140541400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
140637741Smckusick 		error = EROFS;
140737741Smckusick 		goto out;
140821015Smckusick 	}
140945785Sbostic 	VATTR_NULL(&vattr);
141054100Smckusick 	vattr.va_atime.ts_sec = tv[0].tv_sec;
141154100Smckusick 	vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
141254100Smckusick 	vattr.va_mtime.ts_sec = tv[1].tv_sec;
141354100Smckusick 	vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
141452192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
141548026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
141637741Smckusick out:
141737741Smckusick 	vput(vp);
141847540Skarels 	return (error);
141911811Ssam }
142011811Ssam 
142154348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
14229167Ssam /*
14239167Ssam  * Truncate a file given its path name.
14249167Ssam  */
142542441Smckusick /* ARGSUSED */
142642441Smckusick truncate(p, uap, retval)
142745914Smckusick 	struct proc *p;
142842441Smckusick 	register struct args {
14297701Ssam 		char	*fname;
143053468Smckusick 		long	length;
143153468Smckusick 	} *uap;
143253468Smckusick 	int *retval;
143353468Smckusick {
143453468Smckusick 	struct nargs {
143553468Smckusick 		char	*fname;
143626473Skarels 		off_t	length;
143753468Smckusick 	} nuap;
143853468Smckusick 
143953468Smckusick 	nuap.fname = uap->fname;
144053468Smckusick 	nuap.length = uap->length;
144153759Smckusick 	return (__truncate(p, &nuap, retval));
144253468Smckusick }
144353468Smckusick 
144453468Smckusick /*
144553468Smckusick  * Truncate a file given a file descriptor.
144653468Smckusick  */
144753468Smckusick /* ARGSUSED */
144853468Smckusick ftruncate(p, uap, retval)
144953468Smckusick 	struct proc *p;
145053468Smckusick 	register struct args {
145153468Smckusick 		int	fd;
145253468Smckusick 		long	length;
145342441Smckusick 	} *uap;
145442441Smckusick 	int *retval;
145542441Smckusick {
145653468Smckusick 	struct nargs {
145753468Smckusick 		int	fd;
145853468Smckusick 		off_t	length;
145953468Smckusick 	} nuap;
146053468Smckusick 
146153468Smckusick 	nuap.fd = uap->fd;
146253468Smckusick 	nuap.length = uap->length;
146353759Smckusick 	return (__ftruncate(p, &nuap, retval));
146453468Smckusick }
146554348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
146653468Smckusick 
146753468Smckusick /*
146853468Smckusick  * Truncate a file given its path name.
146953468Smckusick  */
147053468Smckusick /* ARGSUSED */
147153759Smckusick __truncate(p, uap, retval)
147253468Smckusick 	struct proc *p;
147353468Smckusick 	register struct args {
147453468Smckusick 		char	*fname;
147553468Smckusick 		off_t	length;
147653468Smckusick 	} *uap;
147753468Smckusick 	int *retval;
147853468Smckusick {
147937741Smckusick 	register struct vnode *vp;
148037741Smckusick 	struct vattr vattr;
148137741Smckusick 	int error;
148247540Skarels 	struct nameidata nd;
14837701Ssam 
148452322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
148552322Smckusick 	if (error = namei(&nd))
148647540Skarels 		return (error);
148752322Smckusick 	vp = nd.ni_vp;
148837741Smckusick 	if (vp->v_type == VDIR) {
148937741Smckusick 		error = EISDIR;
149037741Smckusick 		goto out;
14917701Ssam 	}
149238399Smckusick 	if ((error = vn_writechk(vp)) ||
149348026Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)))
149437741Smckusick 		goto out;
149545785Sbostic 	VATTR_NULL(&vattr);
149645785Sbostic 	vattr.va_size = uap->length;
149752192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
149848026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
149937741Smckusick out:
150037741Smckusick 	vput(vp);
150147540Skarels 	return (error);
15027701Ssam }
15037701Ssam 
15049167Ssam /*
15059167Ssam  * Truncate a file given a file descriptor.
15069167Ssam  */
150742441Smckusick /* ARGSUSED */
150853759Smckusick __ftruncate(p, uap, retval)
150945914Smckusick 	struct proc *p;
151042441Smckusick 	register struct args {
15117701Ssam 		int	fd;
151226473Skarels 		off_t	length;
151342441Smckusick 	} *uap;
151442441Smckusick 	int *retval;
151542441Smckusick {
151637741Smckusick 	struct vattr vattr;
151737741Smckusick 	struct vnode *vp;
15187701Ssam 	struct file *fp;
151937741Smckusick 	int error;
15207701Ssam 
152145914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
152247540Skarels 		return (error);
152337741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
152447540Skarels 		return (EINVAL);
152537741Smckusick 	vp = (struct vnode *)fp->f_data;
152637741Smckusick 	VOP_LOCK(vp);
152737741Smckusick 	if (vp->v_type == VDIR) {
152837741Smckusick 		error = EISDIR;
152937741Smckusick 		goto out;
15307701Ssam 	}
153138399Smckusick 	if (error = vn_writechk(vp))
153237741Smckusick 		goto out;
153345785Sbostic 	VATTR_NULL(&vattr);
153445785Sbostic 	vattr.va_size = uap->length;
153552192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
153648026Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
153737741Smckusick out:
153837741Smckusick 	VOP_UNLOCK(vp);
153947540Skarels 	return (error);
15407701Ssam }
15417701Ssam 
15429167Ssam /*
15439167Ssam  * Synch an open file.
15449167Ssam  */
154542441Smckusick /* ARGSUSED */
154642441Smckusick fsync(p, uap, retval)
154745914Smckusick 	struct proc *p;
154842441Smckusick 	struct args {
154942441Smckusick 		int	fd;
155042441Smckusick 	} *uap;
155142441Smckusick 	int *retval;
15529167Ssam {
155339592Smckusick 	register struct vnode *vp;
15549167Ssam 	struct file *fp;
155537741Smckusick 	int error;
15569167Ssam 
155745914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
155847540Skarels 		return (error);
155939592Smckusick 	vp = (struct vnode *)fp->f_data;
156039592Smckusick 	VOP_LOCK(vp);
156154441Smckusick 	error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
156239592Smckusick 	VOP_UNLOCK(vp);
156347540Skarels 	return (error);
15649167Ssam }
15659167Ssam 
15669167Ssam /*
15679167Ssam  * Rename system call.
15689167Ssam  *
15699167Ssam  * Source and destination must either both be directories, or both
15709167Ssam  * not be directories.  If target is a directory, it must be empty.
15719167Ssam  */
157242441Smckusick /* ARGSUSED */
157342441Smckusick rename(p, uap, retval)
157445914Smckusick 	struct proc *p;
157542441Smckusick 	register struct args {
15767701Ssam 		char	*from;
15777701Ssam 		char	*to;
157842441Smckusick 	} *uap;
157942441Smckusick 	int *retval;
158042441Smckusick {
158137741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
158249735Smckusick 	struct nameidata fromnd, tond;
158337741Smckusick 	int error;
15847701Ssam 
158552322Smckusick 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
158652322Smckusick 		uap->from, p);
158752322Smckusick 	if (error = namei(&fromnd))
158847540Skarels 		return (error);
158949735Smckusick 	fvp = fromnd.ni_vp;
159052322Smckusick 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
159152322Smckusick 		UIO_USERSPACE, uap->to, p);
159252322Smckusick 	if (error = namei(&tond)) {
159352230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
159449735Smckusick 		vrele(fromnd.ni_dvp);
159542465Smckusick 		vrele(fvp);
159642465Smckusick 		goto out1;
159742465Smckusick 	}
159837741Smckusick 	tdvp = tond.ni_dvp;
159937741Smckusick 	tvp = tond.ni_vp;
160037741Smckusick 	if (tvp != NULL) {
160137741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
160239242Sbostic 			error = ENOTDIR;
160337741Smckusick 			goto out;
160437741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
160539242Sbostic 			error = EISDIR;
160637741Smckusick 			goto out;
16079167Ssam 		}
16089167Ssam 	}
160939286Smckusick 	if (fvp == tdvp)
161037741Smckusick 		error = EINVAL;
161139286Smckusick 	/*
161249735Smckusick 	 * If source is the same as the destination (that is the
161349735Smckusick 	 * same inode number with the same name in the same directory),
161439286Smckusick 	 * then there is nothing to do.
161539286Smckusick 	 */
161649735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
161752322Smckusick 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
161852322Smckusick 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
161952322Smckusick 	      fromnd.ni_cnd.cn_namelen))
162039286Smckusick 		error = -1;
162137741Smckusick out:
162242465Smckusick 	if (!error) {
162352192Smckusick 		LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE);
162452192Smckusick 		if (fromnd.ni_dvp != tdvp)
162552192Smckusick 			LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
162652192Smckusick 		if (tvp)
162752192Smckusick 			LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE);
162852230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
162952230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
163042465Smckusick 	} else {
163152230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
163243344Smckusick 		if (tdvp == tvp)
163343344Smckusick 			vrele(tdvp);
163443344Smckusick 		else
163543344Smckusick 			vput(tdvp);
163642465Smckusick 		if (tvp)
163742465Smckusick 			vput(tvp);
163852230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
163949735Smckusick 		vrele(fromnd.ni_dvp);
164042465Smckusick 		vrele(fvp);
16419167Ssam 	}
164249735Smckusick 	vrele(tond.ni_startdir);
164352322Smckusick 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
164437741Smckusick out1:
164549735Smckusick 	vrele(fromnd.ni_startdir);
164652322Smckusick 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
164739286Smckusick 	if (error == -1)
164847540Skarels 		return (0);
164947540Skarels 	return (error);
16507701Ssam }
16517701Ssam 
16527535Sroot /*
165349365Smckusick  * Mkdir system call.
165412756Ssam  */
165542441Smckusick /* ARGSUSED */
165642441Smckusick mkdir(p, uap, retval)
165745914Smckusick 	struct proc *p;
165842441Smckusick 	register struct args {
165912756Ssam 		char	*name;
166012756Ssam 		int	dmode;
166142441Smckusick 	} *uap;
166242441Smckusick 	int *retval;
166342441Smckusick {
166437741Smckusick 	register struct vnode *vp;
166537741Smckusick 	struct vattr vattr;
166637741Smckusick 	int error;
166747540Skarels 	struct nameidata nd;
166812756Ssam 
166952322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p);
167052322Smckusick 	if (error = namei(&nd))
167147540Skarels 		return (error);
167252322Smckusick 	vp = nd.ni_vp;
167337741Smckusick 	if (vp != NULL) {
167452322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
167552322Smckusick 		if (nd.ni_dvp == vp)
167652322Smckusick 			vrele(nd.ni_dvp);
167743344Smckusick 		else
167852322Smckusick 			vput(nd.ni_dvp);
167942465Smckusick 		vrele(vp);
168047540Skarels 		return (EEXIST);
168112756Ssam 	}
168241362Smckusick 	VATTR_NULL(&vattr);
168337741Smckusick 	vattr.va_type = VDIR;
168445914Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask;
168552322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
168652322Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
168738145Smckusick 	if (!error)
168852322Smckusick 		vput(nd.ni_vp);
168947540Skarels 	return (error);
169012756Ssam }
169112756Ssam 
169212756Ssam /*
169312756Ssam  * Rmdir system call.
169412756Ssam  */
169542441Smckusick /* ARGSUSED */
169642441Smckusick rmdir(p, uap, retval)
169745914Smckusick 	struct proc *p;
169842441Smckusick 	struct args {
169942441Smckusick 		char	*name;
170042441Smckusick 	} *uap;
170142441Smckusick 	int *retval;
170212756Ssam {
170337741Smckusick 	register struct vnode *vp;
170437741Smckusick 	int error;
170547540Skarels 	struct nameidata nd;
170612756Ssam 
170752322Smckusick 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p);
170852322Smckusick 	if (error = namei(&nd))
170947540Skarels 		return (error);
171052322Smckusick 	vp = nd.ni_vp;
171137741Smckusick 	if (vp->v_type != VDIR) {
171237741Smckusick 		error = ENOTDIR;
171312756Ssam 		goto out;
171412756Ssam 	}
171512756Ssam 	/*
171637741Smckusick 	 * No rmdir "." please.
171712756Ssam 	 */
171852322Smckusick 	if (nd.ni_dvp == vp) {
171937741Smckusick 		error = EINVAL;
172012756Ssam 		goto out;
172112756Ssam 	}
172212756Ssam 	/*
172349365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
172412756Ssam 	 */
172537741Smckusick 	if (vp->v_flag & VROOT)
172637741Smckusick 		error = EBUSY;
172712756Ssam out:
172842465Smckusick 	if (!error) {
172952322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
173052192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
173152322Smckusick 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
173242465Smckusick 	} else {
173352322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
173452322Smckusick 		if (nd.ni_dvp == vp)
173552322Smckusick 			vrele(nd.ni_dvp);
173643344Smckusick 		else
173752322Smckusick 			vput(nd.ni_dvp);
173842465Smckusick 		vput(vp);
173942465Smckusick 	}
174047540Skarels 	return (error);
174112756Ssam }
174212756Ssam 
174354620Smckusick #ifdef COMPAT_43
174437741Smckusick /*
174549365Smckusick  * Read a block of directory entries in a file system independent format.
174637741Smckusick  */
174754620Smckusick ogetdirentries(p, uap, retval)
174854620Smckusick 	struct proc *p;
174954620Smckusick 	register struct args {
175054620Smckusick 		int	fd;
175154620Smckusick 		char	*buf;
175254620Smckusick 		unsigned count;
175354620Smckusick 		long	*basep;
175454620Smckusick 	} *uap;
175554620Smckusick 	int *retval;
175654620Smckusick {
175754620Smckusick 	register struct vnode *vp;
175854620Smckusick 	struct file *fp;
175954620Smckusick 	struct uio auio, kuio;
176054620Smckusick 	struct iovec aiov, kiov;
176154620Smckusick 	struct dirent *dp, *edp;
176254620Smckusick 	caddr_t dirbuf;
176354620Smckusick 	int error, readcnt;
176454620Smckusick 	off_t off;
176554620Smckusick 
176654620Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
176754620Smckusick 		return (error);
176854620Smckusick 	if ((fp->f_flag & FREAD) == 0)
176954620Smckusick 		return (EBADF);
177054620Smckusick 	vp = (struct vnode *)fp->f_data;
177154620Smckusick 	if (vp->v_type != VDIR)
177254620Smckusick 		return (EINVAL);
177354620Smckusick 	aiov.iov_base = uap->buf;
177454620Smckusick 	aiov.iov_len = uap->count;
177554620Smckusick 	auio.uio_iov = &aiov;
177654620Smckusick 	auio.uio_iovcnt = 1;
177754620Smckusick 	auio.uio_rw = UIO_READ;
177854620Smckusick 	auio.uio_segflg = UIO_USERSPACE;
177954620Smckusick 	auio.uio_procp = p;
178054620Smckusick 	auio.uio_resid = uap->count;
178154620Smckusick 	VOP_LOCK(vp);
178254620Smckusick 	auio.uio_offset = off = fp->f_offset;
178354620Smckusick #	if (BYTE_ORDER != LITTLE_ENDIAN)
178454620Smckusick 		if (vp->v_mount->mnt_maxsymlinklen <= 0)
178554620Smckusick 			error = VOP_READDIR(vp, &auio, fp->f_cred);
178654620Smckusick 		else
178754620Smckusick #	endif
178854620Smckusick 	{
178954620Smckusick 		kuio = auio;
179054620Smckusick 		kuio.uio_iov = &kiov;
179154620Smckusick 		kuio.uio_segflg = UIO_SYSSPACE;
179254620Smckusick 		kiov.iov_len = uap->count;
179354620Smckusick 		MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK);
179454620Smckusick 		kiov.iov_base = dirbuf;
179554620Smckusick 		error = VOP_READDIR(vp, &kuio, fp->f_cred);
179654620Smckusick 		if (error == 0) {
179754620Smckusick 			readcnt = uap->count - kuio.uio_resid;
179854620Smckusick 			edp = (struct dirent *)&dirbuf[readcnt];
179954620Smckusick 			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
180054620Smckusick 				dp->d_type = 0;
180154620Smckusick #				if (BYTE_ORDER == LITTLE_ENDIAN)
180254620Smckusick 					{ u_char tmp = dp->d_namlen;
180354620Smckusick 					dp->d_namlen = dp->d_type;
180454620Smckusick 					dp->d_type = tmp; }
180554620Smckusick #				endif
180654620Smckusick 				if (dp->d_reclen > 0) {
180754620Smckusick 					dp = (struct dirent *)
180854620Smckusick 					    ((char *)dp + dp->d_reclen);
180954620Smckusick 				} else {
181054620Smckusick 					error = EIO;
181154620Smckusick 					break;
181254620Smckusick 				}
181354620Smckusick 			}
181454620Smckusick 			if (dp >= edp)
181554620Smckusick 				error = uiomove(dirbuf, readcnt, &auio);
181654620Smckusick 		}
181754620Smckusick 		FREE(dirbuf, M_TEMP);
181854620Smckusick 	}
181954620Smckusick 	fp->f_offset = auio.uio_offset;
182054620Smckusick 	VOP_UNLOCK(vp);
182154620Smckusick 	if (error)
182254620Smckusick 		return (error);
182354620Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
182454620Smckusick 	*retval = uap->count - auio.uio_resid;
182554620Smckusick 	return (error);
182654620Smckusick }
182754620Smckusick #endif
182854620Smckusick 
182954620Smckusick /*
183054620Smckusick  * Read a block of directory entries in a file system independent format.
183154620Smckusick  */
183242441Smckusick getdirentries(p, uap, retval)
183345914Smckusick 	struct proc *p;
183442441Smckusick 	register struct args {
183537741Smckusick 		int	fd;
183637741Smckusick 		char	*buf;
183737741Smckusick 		unsigned count;
183837741Smckusick 		long	*basep;
183942441Smckusick 	} *uap;
184042441Smckusick 	int *retval;
184142441Smckusick {
184239592Smckusick 	register struct vnode *vp;
184316540Ssam 	struct file *fp;
184437741Smckusick 	struct uio auio;
184537741Smckusick 	struct iovec aiov;
184638129Smckusick 	off_t off;
184754441Smckusick 	int error;
184812756Ssam 
184945914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
185047540Skarels 		return (error);
185137741Smckusick 	if ((fp->f_flag & FREAD) == 0)
185247540Skarels 		return (EBADF);
185339592Smckusick 	vp = (struct vnode *)fp->f_data;
185439592Smckusick 	if (vp->v_type != VDIR)
185547540Skarels 		return (EINVAL);
185637741Smckusick 	aiov.iov_base = uap->buf;
185737741Smckusick 	aiov.iov_len = uap->count;
185837741Smckusick 	auio.uio_iov = &aiov;
185937741Smckusick 	auio.uio_iovcnt = 1;
186037741Smckusick 	auio.uio_rw = UIO_READ;
186137741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
186248026Smckusick 	auio.uio_procp = p;
186337741Smckusick 	auio.uio_resid = uap->count;
186439592Smckusick 	VOP_LOCK(vp);
186539592Smckusick 	auio.uio_offset = off = fp->f_offset;
186654441Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred);
186739592Smckusick 	fp->f_offset = auio.uio_offset;
186839592Smckusick 	VOP_UNLOCK(vp);
186939592Smckusick 	if (error)
187047540Skarels 		return (error);
187139592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
187242441Smckusick 	*retval = uap->count - auio.uio_resid;
187347540Skarels 	return (error);
187412756Ssam }
187512756Ssam 
187612756Ssam /*
187749365Smckusick  * Set the mode mask for creation of filesystem nodes.
187812756Ssam  */
187942441Smckusick mode_t
188042441Smckusick umask(p, uap, retval)
188145914Smckusick 	struct proc *p;
188242441Smckusick 	struct args {
188342441Smckusick 		int	mask;
188442441Smckusick 	} *uap;
188542441Smckusick 	int *retval;
188612756Ssam {
188745914Smckusick 	register struct filedesc *fdp = p->p_fd;
188812756Ssam 
188945914Smckusick 	*retval = fdp->fd_cmask;
189045914Smckusick 	fdp->fd_cmask = uap->mask & 07777;
189147540Skarels 	return (0);
189212756Ssam }
189337741Smckusick 
189439566Smarc /*
189539566Smarc  * Void all references to file by ripping underlying filesystem
189639566Smarc  * away from vnode.
189739566Smarc  */
189842441Smckusick /* ARGSUSED */
189942441Smckusick revoke(p, uap, retval)
190045914Smckusick 	struct proc *p;
190142441Smckusick 	register struct args {
190239566Smarc 		char	*fname;
190342441Smckusick 	} *uap;
190442441Smckusick 	int *retval;
190542441Smckusick {
190639566Smarc 	register struct vnode *vp;
190739566Smarc 	struct vattr vattr;
190839566Smarc 	int error;
190947540Skarels 	struct nameidata nd;
191039566Smarc 
191152322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
191252322Smckusick 	if (error = namei(&nd))
191347540Skarels 		return (error);
191452322Smckusick 	vp = nd.ni_vp;
191539566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
191639566Smarc 		error = EINVAL;
191739566Smarc 		goto out;
191839566Smarc 	}
191948026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
192039566Smarc 		goto out;
192147540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
192247540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
192339566Smarc 		goto out;
192439805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
192539632Smckusick 		vgoneall(vp);
192639566Smarc out:
192739566Smarc 	vrele(vp);
192847540Skarels 	return (error);
192939566Smarc }
193039566Smarc 
193149365Smckusick /*
193249365Smckusick  * Convert a user file descriptor to a kernel file entry.
193349365Smckusick  */
193445914Smckusick getvnode(fdp, fdes, fpp)
193545914Smckusick 	struct filedesc *fdp;
193637741Smckusick 	struct file **fpp;
193737741Smckusick 	int fdes;
193837741Smckusick {
193937741Smckusick 	struct file *fp;
194037741Smckusick 
194147540Skarels 	if ((unsigned)fdes >= fdp->fd_nfiles ||
194247688Skarels 	    (fp = fdp->fd_ofiles[fdes]) == NULL)
194337741Smckusick 		return (EBADF);
194437741Smckusick 	if (fp->f_type != DTYPE_VNODE)
194537741Smckusick 		return (EINVAL);
194637741Smckusick 	*fpp = fp;
194737741Smckusick 	return (0);
194837741Smckusick }
1949