xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 53468)
123405Smckusick /*
237741Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337741Smckusick  * All rights reserved.
423405Smckusick  *
544459Sbostic  * %sccs.include.redist.c%
637741Smckusick  *
7*53468Smckusick  *	@(#)vfs_syscalls.c	7.81 (Berkeley) 05/13/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"
22*53468Smckusick #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 {
4239335Smckusick 	register struct vnode *vp;
4339335Smckusick 	register struct mount *mp;
4440111Smckusick 	int error, flag;
4547540Skarels 	struct nameidata nd;
466254Sroot 
4737741Smckusick 	/*
4837741Smckusick 	 * Must be super user
4937741Smckusick 	 */
5047540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
5147540Skarels 		return (error);
5237741Smckusick 	/*
5337741Smckusick 	 * Get vnode to be covered
5437741Smckusick 	 */
5552322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->dir, p);
5652322Smckusick 	if (error = namei(&nd))
5747540Skarels 		return (error);
5852322Smckusick 	vp = nd.ni_vp;
5941400Smckusick 	if (uap->flags & MNT_UPDATE) {
6039335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
6139335Smckusick 			vput(vp);
6247540Skarels 			return (EINVAL);
6339335Smckusick 		}
6439335Smckusick 		mp = vp->v_mount;
6539335Smckusick 		/*
6639335Smckusick 		 * We allow going from read-only to read-write,
6739335Smckusick 		 * but not from read-write to read-only.
6839335Smckusick 		 */
6941400Smckusick 		if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
7041400Smckusick 		    (uap->flags & MNT_RDONLY) != 0) {
7139335Smckusick 			vput(vp);
7247540Skarels 			return (EOPNOTSUPP);	/* Needs translation */
7339335Smckusick 		}
7441400Smckusick 		flag = mp->mnt_flag;
7541400Smckusick 		mp->mnt_flag |= MNT_UPDATE;
7639335Smckusick 		VOP_UNLOCK(vp);
7739335Smckusick 		goto update;
7839335Smckusick 	}
7939665Smckusick 	vinvalbuf(vp, 1);
8039805Smckusick 	if (vp->v_usecount != 1) {
8137741Smckusick 		vput(vp);
8247540Skarels 		return (EBUSY);
8337741Smckusick 	}
8437741Smckusick 	if (vp->v_type != VDIR) {
8537741Smckusick 		vput(vp);
8647540Skarels 		return (ENOTDIR);
8737741Smckusick 	}
8839741Smckusick 	if ((unsigned long)uap->type > MOUNT_MAXTYPE ||
8937741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
9037741Smckusick 		vput(vp);
9147540Skarels 		return (ENODEV);
9237741Smckusick 	}
9337741Smckusick 
9437741Smckusick 	/*
9539335Smckusick 	 * Allocate and initialize the file system.
9637741Smckusick 	 */
9737741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
9837741Smckusick 		M_MOUNT, M_WAITOK);
9941400Smckusick 	mp->mnt_op = vfssw[uap->type];
10041400Smckusick 	mp->mnt_flag = 0;
10141400Smckusick 	mp->mnt_mounth = NULLVP;
10239335Smckusick 	if (error = vfs_lock(mp)) {
10339335Smckusick 		free((caddr_t)mp, M_MOUNT);
10439335Smckusick 		vput(vp);
10547540Skarels 		return (error);
10639335Smckusick 	}
10739335Smckusick 	if (vp->v_mountedhere != (struct mount *)0) {
10839335Smckusick 		vfs_unlock(mp);
10939335Smckusick 		free((caddr_t)mp, M_MOUNT);
11039335Smckusick 		vput(vp);
11147540Skarels 		return (EBUSY);
11239335Smckusick 	}
11339335Smckusick 	vp->v_mountedhere = mp;
11441400Smckusick 	mp->mnt_vnodecovered = vp;
11539335Smckusick update:
11639335Smckusick 	/*
11739335Smckusick 	 * Set the mount level flags.
11839335Smckusick 	 */
11941400Smckusick 	if (uap->flags & MNT_RDONLY)
12041400Smckusick 		mp->mnt_flag |= MNT_RDONLY;
12139335Smckusick 	else
12241400Smckusick 		mp->mnt_flag &= ~MNT_RDONLY;
12341400Smckusick 	if (uap->flags & MNT_NOSUID)
12441400Smckusick 		mp->mnt_flag |= MNT_NOSUID;
12539335Smckusick 	else
12641400Smckusick 		mp->mnt_flag &= ~MNT_NOSUID;
12741400Smckusick 	if (uap->flags & MNT_NOEXEC)
12841400Smckusick 		mp->mnt_flag |= MNT_NOEXEC;
12939335Smckusick 	else
13041400Smckusick 		mp->mnt_flag &= ~MNT_NOEXEC;
13141400Smckusick 	if (uap->flags & MNT_NODEV)
13241400Smckusick 		mp->mnt_flag |= MNT_NODEV;
13339335Smckusick 	else
13441400Smckusick 		mp->mnt_flag &= ~MNT_NODEV;
13541400Smckusick 	if (uap->flags & MNT_SYNCHRONOUS)
13641400Smckusick 		mp->mnt_flag |= MNT_SYNCHRONOUS;
13739335Smckusick 	else
13841400Smckusick 		mp->mnt_flag &= ~MNT_SYNCHRONOUS;
13939335Smckusick 	/*
14039335Smckusick 	 * Mount the filesystem.
14139335Smckusick 	 */
14252322Smckusick 	error = VFS_MOUNT(mp, uap->dir, uap->data, &nd, p);
14341400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
14441400Smckusick 		mp->mnt_flag &= ~MNT_UPDATE;
14539335Smckusick 		vrele(vp);
14640111Smckusick 		if (error)
14741400Smckusick 			mp->mnt_flag = flag;
14847540Skarels 		return (error);
14939335Smckusick 	}
15040110Smckusick 	/*
15140110Smckusick 	 * Put the new filesystem on the mount list after root.
15240110Smckusick 	 */
15341400Smckusick 	mp->mnt_next = rootfs->mnt_next;
15441400Smckusick 	mp->mnt_prev = rootfs;
15541400Smckusick 	rootfs->mnt_next = mp;
15641400Smckusick 	mp->mnt_next->mnt_prev = mp;
15737741Smckusick 	cache_purge(vp);
15837741Smckusick 	if (!error) {
15939335Smckusick 		VOP_UNLOCK(vp);
16037741Smckusick 		vfs_unlock(mp);
16148026Smckusick 		error = VFS_START(mp, 0, p);
16237741Smckusick 	} else {
16337741Smckusick 		vfs_remove(mp);
16437741Smckusick 		free((caddr_t)mp, M_MOUNT);
16539335Smckusick 		vput(vp);
16637741Smckusick 	}
16747540Skarels 	return (error);
1686254Sroot }
1696254Sroot 
1709167Ssam /*
17137741Smckusick  * Unmount system call.
17237741Smckusick  *
17337741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
17437741Smckusick  * not special file (as before).
1759167Ssam  */
17642441Smckusick /* ARGSUSED */
17742441Smckusick unmount(p, uap, retval)
17845914Smckusick 	struct proc *p;
17942441Smckusick 	register struct args {
18037741Smckusick 		char	*pathp;
18137741Smckusick 		int	flags;
18242441Smckusick 	} *uap;
18342441Smckusick 	int *retval;
18442441Smckusick {
18537741Smckusick 	register struct vnode *vp;
18639356Smckusick 	struct mount *mp;
18737741Smckusick 	int error;
18847540Skarels 	struct nameidata nd;
1896254Sroot 
19037741Smckusick 	/*
19137741Smckusick 	 * Must be super user
19237741Smckusick 	 */
19347540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
19447540Skarels 		return (error);
19537741Smckusick 
19652322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->pathp, p);
19752322Smckusick 	if (error = namei(&nd))
19847540Skarels 		return (error);
19952322Smckusick 	vp = nd.ni_vp;
20037741Smckusick 	/*
20137741Smckusick 	 * Must be the root of the filesystem
20237741Smckusick 	 */
20337741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
20437741Smckusick 		vput(vp);
20547540Skarels 		return (EINVAL);
20637741Smckusick 	}
20737741Smckusick 	mp = vp->v_mount;
20837741Smckusick 	vput(vp);
20948026Smckusick 	return (dounmount(mp, uap->flags, p));
21039356Smckusick }
21139356Smckusick 
21239356Smckusick /*
21339356Smckusick  * Do an unmount.
21439356Smckusick  */
21548026Smckusick dounmount(mp, flags, p)
21639356Smckusick 	register struct mount *mp;
21739356Smckusick 	int flags;
21848026Smckusick 	struct proc *p;
21939356Smckusick {
22039356Smckusick 	struct vnode *coveredvp;
22139356Smckusick 	int error;
22239356Smckusick 
22341400Smckusick 	coveredvp = mp->mnt_vnodecovered;
22441298Smckusick 	if (vfs_busy(mp))
22541298Smckusick 		return (EBUSY);
22641400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
22737741Smckusick 	if (error = vfs_lock(mp))
22839356Smckusick 		return (error);
22937741Smckusick 
23045738Smckusick 	vnode_pager_umount(mp);	/* release cached vnodes */
23137741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
23241676Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE))
23348026Smckusick 		error = VFS_UNMOUNT(mp, flags, p);
23441400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
23541298Smckusick 	vfs_unbusy(mp);
23637741Smckusick 	if (error) {
23737741Smckusick 		vfs_unlock(mp);
23837741Smckusick 	} else {
23937741Smckusick 		vrele(coveredvp);
24037741Smckusick 		vfs_remove(mp);
24152287Smckusick 		if (mp->mnt_mounth != NULL)
24252287Smckusick 			panic("unmount: dangling vnode");
24337741Smckusick 		free((caddr_t)mp, M_MOUNT);
24437741Smckusick 	}
24539356Smckusick 	return (error);
2466254Sroot }
2476254Sroot 
2489167Ssam /*
24937741Smckusick  * Sync system call.
25037741Smckusick  * Sync each mounted filesystem.
2519167Ssam  */
25239491Smckusick /* ARGSUSED */
25342441Smckusick sync(p, uap, retval)
25445914Smckusick 	struct proc *p;
25547540Skarels 	void *uap;
25642441Smckusick 	int *retval;
2576254Sroot {
25837741Smckusick 	register struct mount *mp;
25941298Smckusick 	struct mount *omp;
26037741Smckusick 
26137741Smckusick 	mp = rootfs;
26237741Smckusick 	do {
26340343Smckusick 		/*
26440343Smckusick 		 * The lock check below is to avoid races with mount
26540343Smckusick 		 * and unmount.
26640343Smckusick 		 */
26741400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
26841298Smckusick 		    !vfs_busy(mp)) {
26937741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
27041298Smckusick 			omp = mp;
27141400Smckusick 			mp = mp->mnt_next;
27241298Smckusick 			vfs_unbusy(omp);
27341298Smckusick 		} else
27441400Smckusick 			mp = mp->mnt_next;
27537741Smckusick 	} while (mp != rootfs);
27647688Skarels 	return (0);
27737741Smckusick }
27837741Smckusick 
27937741Smckusick /*
28049365Smckusick  * Operate on filesystem quotas.
28141298Smckusick  */
28242441Smckusick /* ARGSUSED */
28342441Smckusick quotactl(p, uap, retval)
28445914Smckusick 	struct proc *p;
28542441Smckusick 	register struct args {
28641298Smckusick 		char *path;
28741298Smckusick 		int cmd;
28841298Smckusick 		int uid;
28941298Smckusick 		caddr_t arg;
29042441Smckusick 	} *uap;
29142441Smckusick 	int *retval;
29242441Smckusick {
29341298Smckusick 	register struct mount *mp;
29441298Smckusick 	int error;
29547540Skarels 	struct nameidata nd;
29641298Smckusick 
29752322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
29852322Smckusick 	if (error = namei(&nd))
29947540Skarels 		return (error);
30052322Smckusick 	mp = nd.ni_vp->v_mount;
30152322Smckusick 	vrele(nd.ni_vp);
30248026Smckusick 	return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p));
30341298Smckusick }
30441298Smckusick 
30541298Smckusick /*
30649365Smckusick  * Get filesystem statistics.
30737741Smckusick  */
30842441Smckusick /* ARGSUSED */
30942441Smckusick statfs(p, uap, retval)
31045914Smckusick 	struct proc *p;
31142441Smckusick 	register struct args {
31237741Smckusick 		char *path;
31337741Smckusick 		struct statfs *buf;
31442441Smckusick 	} *uap;
31542441Smckusick 	int *retval;
31642441Smckusick {
31739464Smckusick 	register struct mount *mp;
31840343Smckusick 	register struct statfs *sp;
31937741Smckusick 	int error;
32047540Skarels 	struct nameidata nd;
32137741Smckusick 
32252322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
32352322Smckusick 	if (error = namei(&nd))
32447540Skarels 		return (error);
32552322Smckusick 	mp = nd.ni_vp->v_mount;
32641400Smckusick 	sp = &mp->mnt_stat;
32752322Smckusick 	vrele(nd.ni_vp);
32848026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
32947540Skarels 		return (error);
33041400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
33147540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
33237741Smckusick }
33337741Smckusick 
33442441Smckusick /*
33549365Smckusick  * Get filesystem statistics.
33642441Smckusick  */
33742441Smckusick /* ARGSUSED */
33842441Smckusick fstatfs(p, uap, retval)
33945914Smckusick 	struct proc *p;
34042441Smckusick 	register struct args {
34137741Smckusick 		int fd;
34237741Smckusick 		struct statfs *buf;
34342441Smckusick 	} *uap;
34442441Smckusick 	int *retval;
34542441Smckusick {
34637741Smckusick 	struct file *fp;
34739464Smckusick 	struct mount *mp;
34840343Smckusick 	register struct statfs *sp;
34937741Smckusick 	int error;
35037741Smckusick 
35145914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
35247540Skarels 		return (error);
35339464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
35441400Smckusick 	sp = &mp->mnt_stat;
35548026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
35647540Skarels 		return (error);
35741400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
35847540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
35937741Smckusick }
36037741Smckusick 
36137741Smckusick /*
36249365Smckusick  * Get statistics on all filesystems.
36338270Smckusick  */
36442441Smckusick getfsstat(p, uap, retval)
36545914Smckusick 	struct proc *p;
36642441Smckusick 	register struct args {
36738270Smckusick 		struct statfs *buf;
36838270Smckusick 		long bufsize;
36940343Smckusick 		int flags;
37042441Smckusick 	} *uap;
37142441Smckusick 	int *retval;
37242441Smckusick {
37338270Smckusick 	register struct mount *mp;
37440343Smckusick 	register struct statfs *sp;
37539606Smckusick 	caddr_t sfsp;
37638270Smckusick 	long count, maxcount, error;
37738270Smckusick 
37838270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
37939606Smckusick 	sfsp = (caddr_t)uap->buf;
38038270Smckusick 	mp = rootfs;
38138270Smckusick 	count = 0;
38238270Smckusick 	do {
38341400Smckusick 		if (sfsp && count < maxcount &&
38441400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
38541400Smckusick 			sp = &mp->mnt_stat;
38640343Smckusick 			/*
38740343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
38840343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
38940343Smckusick 			 */
39040343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
39140343Smckusick 			    (uap->flags & MNT_WAIT)) &&
39248026Smckusick 			    (error = VFS_STATFS(mp, sp, p))) {
39341400Smckusick 				mp = mp->mnt_prev;
39439607Smckusick 				continue;
39539607Smckusick 			}
39641400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
39740343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
39847540Skarels 				return (error);
39940343Smckusick 			sfsp += sizeof(*sp);
40038270Smckusick 		}
40139606Smckusick 		count++;
40241400Smckusick 		mp = mp->mnt_prev;
40338270Smckusick 	} while (mp != rootfs);
40438270Smckusick 	if (sfsp && count > maxcount)
40542441Smckusick 		*retval = maxcount;
40638270Smckusick 	else
40742441Smckusick 		*retval = count;
40847540Skarels 	return (0);
40938270Smckusick }
41038270Smckusick 
41138270Smckusick /*
41238259Smckusick  * Change current working directory to a given file descriptor.
41338259Smckusick  */
41442441Smckusick /* ARGSUSED */
41542441Smckusick fchdir(p, uap, retval)
41645914Smckusick 	struct proc *p;
41742441Smckusick 	struct args {
41842441Smckusick 		int	fd;
41942441Smckusick 	} *uap;
42042441Smckusick 	int *retval;
42138259Smckusick {
42245914Smckusick 	register struct filedesc *fdp = p->p_fd;
42338259Smckusick 	register struct vnode *vp;
42438259Smckusick 	struct file *fp;
42538259Smckusick 	int error;
42638259Smckusick 
42745914Smckusick 	if (error = getvnode(fdp, uap->fd, &fp))
42847540Skarels 		return (error);
42938259Smckusick 	vp = (struct vnode *)fp->f_data;
43038259Smckusick 	VOP_LOCK(vp);
43138259Smckusick 	if (vp->v_type != VDIR)
43238259Smckusick 		error = ENOTDIR;
43338259Smckusick 	else
43448026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
43538259Smckusick 	VOP_UNLOCK(vp);
43639860Smckusick 	if (error)
43747540Skarels 		return (error);
43839860Smckusick 	VREF(vp);
43945914Smckusick 	vrele(fdp->fd_cdir);
44045914Smckusick 	fdp->fd_cdir = vp;
44147540Skarels 	return (0);
44238259Smckusick }
44338259Smckusick 
44438259Smckusick /*
44537741Smckusick  * Change current working directory (``.'').
44637741Smckusick  */
44742441Smckusick /* ARGSUSED */
44842441Smckusick chdir(p, uap, retval)
44945914Smckusick 	struct proc *p;
45042441Smckusick 	struct args {
45142441Smckusick 		char	*fname;
45242441Smckusick 	} *uap;
45342441Smckusick 	int *retval;
45437741Smckusick {
45545914Smckusick 	register struct filedesc *fdp = p->p_fd;
45637741Smckusick 	int error;
45747540Skarels 	struct nameidata nd;
4586254Sroot 
45952322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
46052781Sralph 	if (error = chdirec(&nd, p))
46147540Skarels 		return (error);
46245914Smckusick 	vrele(fdp->fd_cdir);
46352322Smckusick 	fdp->fd_cdir = nd.ni_vp;
46447540Skarels 	return (0);
46537741Smckusick }
4666254Sroot 
46737741Smckusick /*
46837741Smckusick  * Change notion of root (``/'') directory.
46937741Smckusick  */
47042441Smckusick /* ARGSUSED */
47142441Smckusick chroot(p, uap, retval)
47245914Smckusick 	struct proc *p;
47342441Smckusick 	struct args {
47442441Smckusick 		char	*fname;
47542441Smckusick 	} *uap;
47642441Smckusick 	int *retval;
47737741Smckusick {
47845914Smckusick 	register struct filedesc *fdp = p->p_fd;
47937741Smckusick 	int error;
48047540Skarels 	struct nameidata nd;
48137741Smckusick 
48247540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
48347540Skarels 		return (error);
48452322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
48552781Sralph 	if (error = chdirec(&nd, p))
48647540Skarels 		return (error);
48745914Smckusick 	if (fdp->fd_rdir != NULL)
48845914Smckusick 		vrele(fdp->fd_rdir);
48952322Smckusick 	fdp->fd_rdir = nd.ni_vp;
49047540Skarels 	return (0);
4916254Sroot }
4926254Sroot 
49337Sbill /*
49437741Smckusick  * Common routine for chroot and chdir.
49537741Smckusick  */
49647540Skarels chdirec(ndp, p)
49752322Smckusick 	register struct nameidata *ndp;
49847540Skarels 	struct proc *p;
49937741Smckusick {
50037741Smckusick 	struct vnode *vp;
50137741Smckusick 	int error;
50237741Smckusick 
50352322Smckusick 	if (error = namei(ndp))
50437741Smckusick 		return (error);
50537741Smckusick 	vp = ndp->ni_vp;
50637741Smckusick 	if (vp->v_type != VDIR)
50737741Smckusick 		error = ENOTDIR;
50837741Smckusick 	else
50948026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
51037741Smckusick 	VOP_UNLOCK(vp);
51137741Smckusick 	if (error)
51237741Smckusick 		vrele(vp);
51337741Smckusick 	return (error);
51437741Smckusick }
51537741Smckusick 
51637741Smckusick /*
5176254Sroot  * Open system call.
51842441Smckusick  * Check permissions, allocate an open file structure,
51942441Smckusick  * and call the device open routine if any.
5206254Sroot  */
52142441Smckusick open(p, uap, retval)
52245914Smckusick 	struct proc *p;
52342441Smckusick 	register struct args {
5246254Sroot 		char	*fname;
5257701Ssam 		int	mode;
52612756Ssam 		int	crtmode;
52742441Smckusick 	} *uap;
52842441Smckusick 	int *retval;
5296254Sroot {
53045914Smckusick 	register struct filedesc *fdp = p->p_fd;
53142441Smckusick 	register struct file *fp;
53250111Smckusick 	register struct vnode *vp;
53337741Smckusick 	int fmode, cmode;
53437741Smckusick 	struct file *nfp;
53549945Smckusick 	int type, indx, error;
53649945Smckusick 	struct flock lf;
53747540Skarels 	struct nameidata nd;
53837741Smckusick 	extern struct fileops vnops;
5396254Sroot 
54045914Smckusick 	if (error = falloc(p, &nfp, &indx))
54147540Skarels 		return (error);
54237741Smckusick 	fp = nfp;
54346553Skarels 	fmode = FFLAGS(uap->mode);
54445914Smckusick 	cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX;
54552322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
54645202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
54752322Smckusick 	if (error = vn_open(&nd, fmode, cmode)) {
54849980Smckusick 		ffree(fp);
54943405Smckusick 		if (error == ENODEV &&		/* XXX from fdopen */
55045202Smckusick 		    p->p_dupfd >= 0 &&
55145914Smckusick 		    (error = dupfdopen(fdp, indx, p->p_dupfd, fmode)) == 0) {
55242441Smckusick 			*retval = indx;
55347540Skarels 			return (0);
55442441Smckusick 		}
55540884Smckusick 		if (error == ERESTART)
55640884Smckusick 			error = EINTR;
55747688Skarels 		fdp->fd_ofiles[indx] = NULL;
55847540Skarels 		return (error);
55912756Ssam 	}
56052322Smckusick 	vp = nd.ni_vp;
56149949Smckusick 	fp->f_flag = fmode & FMASK;
56249945Smckusick 	if (fmode & (O_EXLOCK | O_SHLOCK)) {
56349945Smckusick 		lf.l_whence = SEEK_SET;
56449945Smckusick 		lf.l_start = 0;
56549945Smckusick 		lf.l_len = 0;
56649945Smckusick 		if (fmode & O_EXLOCK)
56749945Smckusick 			lf.l_type = F_WRLCK;
56849945Smckusick 		else
56949945Smckusick 			lf.l_type = F_RDLCK;
57049945Smckusick 		type = F_FLOCK;
57149945Smckusick 		if ((fmode & FNONBLOCK) == 0)
57249945Smckusick 			type |= F_WAIT;
57350111Smckusick 		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
57450111Smckusick 			VOP_UNLOCK(vp);
57550111Smckusick 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
57649980Smckusick 			ffree(fp);
57749945Smckusick 			fdp->fd_ofiles[indx] = NULL;
57849945Smckusick 			return (error);
57949945Smckusick 		}
58049949Smckusick 		fp->f_flag |= FHASLOCK;
58149945Smckusick 	}
58250111Smckusick 	VOP_UNLOCK(vp);
58337741Smckusick 	fp->f_type = DTYPE_VNODE;
58437741Smckusick 	fp->f_ops = &vnops;
58550111Smckusick 	fp->f_data = (caddr_t)vp;
58642441Smckusick 	*retval = indx;
58747540Skarels 	return (0);
5886254Sroot }
5896254Sroot 
59042955Smckusick #ifdef COMPAT_43
5916254Sroot /*
59242441Smckusick  * Creat system call.
5936254Sroot  */
59442955Smckusick ocreat(p, uap, retval)
59542441Smckusick 	struct proc *p;
59642441Smckusick 	register struct args {
59742441Smckusick 		char	*fname;
59842441Smckusick 		int	fmode;
59942441Smckusick 	} *uap;
60042441Smckusick 	int *retval;
6016254Sroot {
60242441Smckusick 	struct args {
6036254Sroot 		char	*fname;
60442441Smckusick 		int	mode;
60542441Smckusick 		int	crtmode;
60642441Smckusick 	} openuap;
60742441Smckusick 
60842441Smckusick 	openuap.fname = uap->fname;
60942441Smckusick 	openuap.crtmode = uap->fmode;
61042441Smckusick 	openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
61147540Skarels 	return (open(p, &openuap, retval));
61242441Smckusick }
61342955Smckusick #endif /* COMPAT_43 */
61442441Smckusick 
61542441Smckusick /*
61649365Smckusick  * Mknod system call.
61742441Smckusick  */
61842441Smckusick /* ARGSUSED */
61942441Smckusick mknod(p, uap, retval)
62045914Smckusick 	struct proc *p;
62142441Smckusick 	register struct args {
62242441Smckusick 		char	*fname;
6236254Sroot 		int	fmode;
6246254Sroot 		int	dev;
62542441Smckusick 	} *uap;
62642441Smckusick 	int *retval;
62742441Smckusick {
62837741Smckusick 	register struct vnode *vp;
62937741Smckusick 	struct vattr vattr;
63037741Smckusick 	int error;
63147540Skarels 	struct nameidata nd;
6326254Sroot 
63347540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
63447540Skarels 		return (error);
63552322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p);
63652322Smckusick 	if (error = namei(&nd))
63747540Skarels 		return (error);
63852322Smckusick 	vp = nd.ni_vp;
63937741Smckusick 	if (vp != NULL) {
64037741Smckusick 		error = EEXIST;
64112756Ssam 		goto out;
6426254Sroot 	}
64341362Smckusick 	VATTR_NULL(&vattr);
64440635Smckusick 	switch (uap->fmode & S_IFMT) {
64512756Ssam 
64640635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
64737741Smckusick 		vattr.va_type = VBAD;
64837741Smckusick 		break;
64940635Smckusick 	case S_IFCHR:
65037741Smckusick 		vattr.va_type = VCHR;
65137741Smckusick 		break;
65240635Smckusick 	case S_IFBLK:
65337741Smckusick 		vattr.va_type = VBLK;
65437741Smckusick 		break;
65537741Smckusick 	default:
65637741Smckusick 		error = EINVAL;
65737741Smckusick 		goto out;
6586254Sroot 	}
65945914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
66037741Smckusick 	vattr.va_rdev = uap->dev;
6616254Sroot out:
66242465Smckusick 	if (!error) {
66352322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
66452322Smckusick 		error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
66542465Smckusick 	} else {
66652322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
66752322Smckusick 		if (nd.ni_dvp == vp)
66852322Smckusick 			vrele(nd.ni_dvp);
66943344Smckusick 		else
67052322Smckusick 			vput(nd.ni_dvp);
67142465Smckusick 		if (vp)
67242465Smckusick 			vrele(vp);
67342465Smckusick 	}
67447540Skarels 	return (error);
6756254Sroot }
6766254Sroot 
6776254Sroot /*
67849365Smckusick  * Mkfifo system call.
67940285Smckusick  */
68042441Smckusick /* ARGSUSED */
68142441Smckusick mkfifo(p, uap, retval)
68245914Smckusick 	struct proc *p;
68342441Smckusick 	register struct args {
68440285Smckusick 		char	*fname;
68540285Smckusick 		int	fmode;
68642441Smckusick 	} *uap;
68742441Smckusick 	int *retval;
68842441Smckusick {
68940285Smckusick 	struct vattr vattr;
69040285Smckusick 	int error;
69147540Skarels 	struct nameidata nd;
69240285Smckusick 
69340285Smckusick #ifndef FIFO
69447540Skarels 	return (EOPNOTSUPP);
69540285Smckusick #else
69652322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p);
69752322Smckusick 	if (error = namei(&nd))
69847540Skarels 		return (error);
69952322Smckusick 	if (nd.ni_vp != NULL) {
70052322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
70152322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
70252322Smckusick 			vrele(nd.ni_dvp);
70343344Smckusick 		else
70452322Smckusick 			vput(nd.ni_dvp);
70552322Smckusick 		vrele(nd.ni_vp);
70647540Skarels 		return (EEXIST);
70740285Smckusick 	}
70845785Sbostic 	VATTR_NULL(&vattr);
70945785Sbostic 	vattr.va_type = VFIFO;
71045914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
71152322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
71252322Smckusick 	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
71340285Smckusick #endif /* FIFO */
71440285Smckusick }
71540285Smckusick 
71640285Smckusick /*
71749365Smckusick  * Link system call.
7186254Sroot  */
71942441Smckusick /* ARGSUSED */
72042441Smckusick link(p, uap, retval)
72145914Smckusick 	struct proc *p;
72242441Smckusick 	register struct args {
7236254Sroot 		char	*target;
7246254Sroot 		char	*linkname;
72542441Smckusick 	} *uap;
72642441Smckusick 	int *retval;
72742441Smckusick {
72837741Smckusick 	register struct vnode *vp, *xp;
72937741Smckusick 	int error;
73047540Skarels 	struct nameidata nd;
7316254Sroot 
73252322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->target, p);
73352322Smckusick 	if (error = namei(&nd))
73447540Skarels 		return (error);
73552322Smckusick 	vp = nd.ni_vp;
73637741Smckusick 	if (vp->v_type == VDIR &&
73747540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
73837741Smckusick 		goto out1;
73952322Smckusick 	nd.ni_cnd.cn_nameiop = CREATE;
74052322Smckusick 	nd.ni_cnd.cn_flags = LOCKPARENT;
74152322Smckusick 	nd.ni_dirp = (caddr_t)uap->linkname;
74252322Smckusick 	if (error = namei(&nd))
74337741Smckusick 		goto out1;
74452322Smckusick 	xp = nd.ni_vp;
7456254Sroot 	if (xp != NULL) {
74637741Smckusick 		error = EEXIST;
7476254Sroot 		goto out;
7486254Sroot 	}
74952322Smckusick 	xp = nd.ni_dvp;
75037741Smckusick 	if (vp->v_mount != xp->v_mount)
75137741Smckusick 		error = EXDEV;
7526254Sroot out:
75342465Smckusick 	if (!error) {
75452192Smckusick 		LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE);
75552192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
75652821Smckusick 		error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
75742465Smckusick 	} else {
75852322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
75952322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
76052322Smckusick 			vrele(nd.ni_dvp);
76143344Smckusick 		else
76252322Smckusick 			vput(nd.ni_dvp);
76352322Smckusick 		if (nd.ni_vp)
76452322Smckusick 			vrele(nd.ni_vp);
76542465Smckusick 	}
76637741Smckusick out1:
76737741Smckusick 	vrele(vp);
76847540Skarels 	return (error);
7696254Sroot }
7706254Sroot 
7716254Sroot /*
77249365Smckusick  * Make a symbolic link.
7736254Sroot  */
77442441Smckusick /* ARGSUSED */
77542441Smckusick symlink(p, uap, retval)
77645914Smckusick 	struct proc *p;
77742441Smckusick 	register struct args {
7786254Sroot 		char	*target;
7796254Sroot 		char	*linkname;
78042441Smckusick 	} *uap;
78142441Smckusick 	int *retval;
78242441Smckusick {
78337741Smckusick 	struct vattr vattr;
78437741Smckusick 	char *target;
78537741Smckusick 	int error;
78647540Skarels 	struct nameidata nd;
7876254Sroot 
78837741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
78937741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
79042465Smckusick 		goto out;
79152322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->linkname, p);
79252322Smckusick 	if (error = namei(&nd))
79342465Smckusick 		goto out;
79452322Smckusick 	if (nd.ni_vp) {
79552322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
79652322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
79752322Smckusick 			vrele(nd.ni_dvp);
79843344Smckusick 		else
79952322Smckusick 			vput(nd.ni_dvp);
80052322Smckusick 		vrele(nd.ni_vp);
80137741Smckusick 		error = EEXIST;
80237741Smckusick 		goto out;
8036254Sroot 	}
80441362Smckusick 	VATTR_NULL(&vattr);
80545914Smckusick 	vattr.va_mode = 0777 &~ p->p_fd->fd_cmask;
80652322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
80752322Smckusick 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, target);
80837741Smckusick out:
80937741Smckusick 	FREE(target, M_NAMEI);
81047540Skarels 	return (error);
8116254Sroot }
8126254Sroot 
8136254Sroot /*
81449365Smckusick  * Delete a name from the filesystem.
8156254Sroot  */
81642441Smckusick /* ARGSUSED */
81742441Smckusick unlink(p, uap, retval)
81845914Smckusick 	struct proc *p;
81942441Smckusick 	struct args {
82052322Smckusick 		char	*name;
82142441Smckusick 	} *uap;
82242441Smckusick 	int *retval;
8236254Sroot {
82437741Smckusick 	register struct vnode *vp;
82537741Smckusick 	int error;
82647540Skarels 	struct nameidata nd;
8276254Sroot 
82852322Smckusick 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p);
82952322Smckusick 	if (error = namei(&nd))
83047540Skarels 		return (error);
83152322Smckusick 	vp = nd.ni_vp;
83237741Smckusick 	if (vp->v_type == VDIR &&
83347540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
8346254Sroot 		goto out;
8356254Sroot 	/*
83649365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
8376254Sroot 	 */
83837741Smckusick 	if (vp->v_flag & VROOT) {
83937741Smckusick 		error = EBUSY;
8406254Sroot 		goto out;
8416254Sroot 	}
84245738Smckusick 	(void) vnode_pager_uncache(vp);
8436254Sroot out:
84442465Smckusick 	if (!error) {
84552322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
84652192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
84752322Smckusick 		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
84842465Smckusick 	} else {
84952322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
85052322Smckusick 		if (nd.ni_dvp == vp)
85152322Smckusick 			vrele(nd.ni_dvp);
85243344Smckusick 		else
85352322Smckusick 			vput(nd.ni_dvp);
85442465Smckusick 		vput(vp);
85542465Smckusick 	}
85647540Skarels 	return (error);
8576254Sroot }
8586254Sroot 
859*53468Smckusick #ifdef COMPAT_43
8606254Sroot /*
86149365Smckusick  * Seek system call.
8626254Sroot  */
86342441Smckusick lseek(p, uap, retval)
86445914Smckusick 	struct proc *p;
86542441Smckusick 	register struct args {
86637741Smckusick 		int	fdes;
867*53468Smckusick 		long	off;
868*53468Smckusick 		int	sbase;
869*53468Smckusick 	} *uap;
870*53468Smckusick 	long *retval;
871*53468Smckusick {
872*53468Smckusick 	struct nargs {
873*53468Smckusick 		int	fdes;
8746254Sroot 		off_t	off;
8756254Sroot 		int	sbase;
876*53468Smckusick 	} nuap;
877*53468Smckusick 	quad_t qret;
878*53468Smckusick 	int error;
879*53468Smckusick 
880*53468Smckusick 	nuap.fdes = uap->fdes;
881*53468Smckusick 	nuap.off = uap->off;
882*53468Smckusick 	nuap.sbase = uap->sbase;
883*53468Smckusick 	error = qseek(p, &nuap, &qret);
884*53468Smckusick 	*retval = qret;
885*53468Smckusick 	return (error);
886*53468Smckusick }
887*53468Smckusick #endif /* COMPAT_43 */
888*53468Smckusick 
889*53468Smckusick /*
890*53468Smckusick  * Seek system call.
891*53468Smckusick  */
892*53468Smckusick qseek(p, uap, retval)
893*53468Smckusick 	struct proc *p;
894*53468Smckusick 	register struct args {
895*53468Smckusick 		int	fdes;
896*53468Smckusick 		off_t	off;
897*53468Smckusick 		int	sbase;
89842441Smckusick 	} *uap;
89942441Smckusick 	off_t *retval;
90042441Smckusick {
90147540Skarels 	struct ucred *cred = p->p_ucred;
90245914Smckusick 	register struct filedesc *fdp = p->p_fd;
90342441Smckusick 	register struct file *fp;
90437741Smckusick 	struct vattr vattr;
90537741Smckusick 	int error;
9066254Sroot 
90747540Skarels 	if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
90847688Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL)
90947540Skarels 		return (EBADF);
91037741Smckusick 	if (fp->f_type != DTYPE_VNODE)
91147540Skarels 		return (ESPIPE);
91213878Ssam 	switch (uap->sbase) {
91313878Ssam 
91413878Ssam 	case L_INCR:
91513878Ssam 		fp->f_offset += uap->off;
91613878Ssam 		break;
91713878Ssam 
91813878Ssam 	case L_XTND:
91937741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
92048026Smckusick 		    &vattr, cred, p))
92147540Skarels 			return (error);
92237741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
92313878Ssam 		break;
92413878Ssam 
92513878Ssam 	case L_SET:
92613878Ssam 		fp->f_offset = uap->off;
92713878Ssam 		break;
92813878Ssam 
92913878Ssam 	default:
93047540Skarels 		return (EINVAL);
93113878Ssam 	}
93242441Smckusick 	*retval = fp->f_offset;
93347540Skarels 	return (0);
9346254Sroot }
9356254Sroot 
9366254Sroot /*
93749365Smckusick  * Check access permissions.
9386254Sroot  */
93942441Smckusick /* ARGSUSED */
94042441Smckusick saccess(p, uap, retval)
94145914Smckusick 	struct proc *p;
94242441Smckusick 	register struct args {
9436254Sroot 		char	*fname;
9446254Sroot 		int	fmode;
94542441Smckusick 	} *uap;
94642441Smckusick 	int *retval;
94742441Smckusick {
94847540Skarels 	register struct ucred *cred = p->p_ucred;
94937741Smckusick 	register struct vnode *vp;
95037741Smckusick 	int error, mode, svuid, svgid;
95147540Skarels 	struct nameidata nd;
9526254Sroot 
95342441Smckusick 	svuid = cred->cr_uid;
95442441Smckusick 	svgid = cred->cr_groups[0];
95547540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
95647540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
95752322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
95852322Smckusick 	if (error = namei(&nd))
95937741Smckusick 		goto out1;
96052322Smckusick 	vp = nd.ni_vp;
96137741Smckusick 	/*
96237741Smckusick 	 * fmode == 0 means only check for exist
96337741Smckusick 	 */
96437741Smckusick 	if (uap->fmode) {
96537741Smckusick 		mode = 0;
96637741Smckusick 		if (uap->fmode & R_OK)
96737741Smckusick 			mode |= VREAD;
96837741Smckusick 		if (uap->fmode & W_OK)
96937741Smckusick 			mode |= VWRITE;
97037741Smckusick 		if (uap->fmode & X_OK)
97137741Smckusick 			mode |= VEXEC;
97239543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
97348026Smckusick 			error = VOP_ACCESS(vp, mode, cred, p);
9746254Sroot 	}
97537741Smckusick 	vput(vp);
97637741Smckusick out1:
97742441Smckusick 	cred->cr_uid = svuid;
97842441Smckusick 	cred->cr_groups[0] = svgid;
97947540Skarels 	return (error);
9806254Sroot }
9816254Sroot 
982*53468Smckusick #ifdef COMPAT_43
9836254Sroot /*
98449365Smckusick  * Stat system call.
98549365Smckusick  * This version follows links.
98637Sbill  */
98742441Smckusick /* ARGSUSED */
98842441Smckusick stat(p, uap, retval)
98945914Smckusick 	struct proc *p;
99042441Smckusick 	register struct args {
99142441Smckusick 		char	*fname;
992*53468Smckusick 		struct ostat *ub;
993*53468Smckusick 	} *uap;
994*53468Smckusick 	int *retval;
995*53468Smckusick {
996*53468Smckusick 	struct stat sb;
997*53468Smckusick 	struct ostat osb;
998*53468Smckusick 	int error;
999*53468Smckusick 	struct nameidata nd;
1000*53468Smckusick 
1001*53468Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
1002*53468Smckusick 	if (error = namei(&nd))
1003*53468Smckusick 		return (error);
1004*53468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
1005*53468Smckusick 	vput(nd.ni_vp);
1006*53468Smckusick 	if (error)
1007*53468Smckusick 		return (error);
1008*53468Smckusick 	cvtstat(&sb, &osb);
1009*53468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
1010*53468Smckusick 	return (error);
1011*53468Smckusick }
1012*53468Smckusick 
1013*53468Smckusick /*
1014*53468Smckusick  * Lstat system call.
1015*53468Smckusick  * This version does not follow links.
1016*53468Smckusick  */
1017*53468Smckusick /* ARGSUSED */
1018*53468Smckusick lstat(p, uap, retval)
1019*53468Smckusick 	struct proc *p;
1020*53468Smckusick 	register struct args {
1021*53468Smckusick 		char	*fname;
1022*53468Smckusick 		struct ostat *ub;
1023*53468Smckusick 	} *uap;
1024*53468Smckusick 	int *retval;
1025*53468Smckusick {
1026*53468Smckusick 	struct stat sb;
1027*53468Smckusick 	struct ostat osb;
1028*53468Smckusick 	int error;
1029*53468Smckusick 	struct nameidata nd;
1030*53468Smckusick 
1031*53468Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
1032*53468Smckusick 	if (error = namei(&nd))
1033*53468Smckusick 		return (error);
1034*53468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
1035*53468Smckusick 	vput(nd.ni_vp);
1036*53468Smckusick 	if (error)
1037*53468Smckusick 		return (error);
1038*53468Smckusick 	cvtstat(&sb, &osb);
1039*53468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
1040*53468Smckusick 	return (error);
1041*53468Smckusick }
1042*53468Smckusick 
1043*53468Smckusick /*
1044*53468Smckusick  * convert from an old to a new stat structure.
1045*53468Smckusick  */
1046*53468Smckusick cvtstat(st, ost)
1047*53468Smckusick 	struct stat *st;
1048*53468Smckusick 	struct ostat *ost;
1049*53468Smckusick {
1050*53468Smckusick 
1051*53468Smckusick 	ost->st_dev = st->st_dev;
1052*53468Smckusick 	ost->st_ino = st->st_ino;
1053*53468Smckusick 	ost->st_mode = st->st_mode;
1054*53468Smckusick 	ost->st_nlink = st->st_nlink;
1055*53468Smckusick 	ost->st_uid = st->st_uid;
1056*53468Smckusick 	ost->st_gid = st->st_gid;
1057*53468Smckusick 	ost->st_rdev = st->st_rdev;
1058*53468Smckusick 	if (st->st_size < (quad_t)1 << 32)
1059*53468Smckusick 		ost->st_size = st->st_size;
1060*53468Smckusick 	else
1061*53468Smckusick 		ost->st_size = -2;
1062*53468Smckusick 	ost->st_atime = st->st_atime;
1063*53468Smckusick 	ost->st_mtime = st->st_mtime;
1064*53468Smckusick 	ost->st_ctime = st->st_ctime;
1065*53468Smckusick 	ost->st_blksize = st->st_blksize;
1066*53468Smckusick 	ost->st_blocks = st->st_blocks;
1067*53468Smckusick 	ost->st_flags = st->st_flags;
1068*53468Smckusick 	ost->st_gen = st->st_gen;
1069*53468Smckusick }
1070*53468Smckusick #endif /* COMPAT_43 */
1071*53468Smckusick 
1072*53468Smckusick /*
1073*53468Smckusick  * Stat system call.
1074*53468Smckusick  * This version follows links.
1075*53468Smckusick  */
1076*53468Smckusick /* ARGSUSED */
1077*53468Smckusick qstat(p, uap, retval)
1078*53468Smckusick 	struct proc *p;
1079*53468Smckusick 	register struct args {
1080*53468Smckusick 		char	*fname;
108142441Smckusick 		struct stat *ub;
108242441Smckusick 	} *uap;
108342441Smckusick 	int *retval;
108437Sbill {
108542441Smckusick 	struct stat sb;
108642441Smckusick 	int error;
108747540Skarels 	struct nameidata nd;
108837Sbill 
108952322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
109052322Smckusick 	if (error = namei(&nd))
109147540Skarels 		return (error);
109252322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
109352322Smckusick 	vput(nd.ni_vp);
109442441Smckusick 	if (error)
109547540Skarels 		return (error);
109642441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
109747540Skarels 	return (error);
109837Sbill }
109937Sbill 
110037Sbill /*
110149365Smckusick  * Lstat system call.
110249365Smckusick  * This version does not follow links.
11035992Swnj  */
110442441Smckusick /* ARGSUSED */
1105*53468Smckusick lqstat(p, uap, retval)
110645914Smckusick 	struct proc *p;
110742441Smckusick 	register struct args {
11085992Swnj 		char	*fname;
110912756Ssam 		struct stat *ub;
111042441Smckusick 	} *uap;
111142441Smckusick 	int *retval;
111242441Smckusick {
111312756Ssam 	struct stat sb;
111437741Smckusick 	int error;
111547540Skarels 	struct nameidata nd;
11165992Swnj 
111752322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
111852322Smckusick 	if (error = namei(&nd))
111947540Skarels 		return (error);
112052322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
112152322Smckusick 	vput(nd.ni_vp);
112237741Smckusick 	if (error)
112347540Skarels 		return (error);
112437741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
112547540Skarels 	return (error);
11265992Swnj }
11275992Swnj 
11285992Swnj /*
112949365Smckusick  * Return target name of a symbolic link.
113037Sbill  */
113142441Smckusick /* ARGSUSED */
113242441Smckusick readlink(p, uap, retval)
113345914Smckusick 	struct proc *p;
113442441Smckusick 	register struct args {
11355992Swnj 		char	*name;
11365992Swnj 		char	*buf;
11375992Swnj 		int	count;
113842441Smckusick 	} *uap;
113942441Smckusick 	int *retval;
114042441Smckusick {
114137741Smckusick 	register struct vnode *vp;
114237741Smckusick 	struct iovec aiov;
114337741Smckusick 	struct uio auio;
114437741Smckusick 	int error;
114547540Skarels 	struct nameidata nd;
11465992Swnj 
114752322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p);
114852322Smckusick 	if (error = namei(&nd))
114947540Skarels 		return (error);
115052322Smckusick 	vp = nd.ni_vp;
115137741Smckusick 	if (vp->v_type != VLNK) {
115237741Smckusick 		error = EINVAL;
11535992Swnj 		goto out;
11545992Swnj 	}
115537741Smckusick 	aiov.iov_base = uap->buf;
115637741Smckusick 	aiov.iov_len = uap->count;
115737741Smckusick 	auio.uio_iov = &aiov;
115837741Smckusick 	auio.uio_iovcnt = 1;
115937741Smckusick 	auio.uio_offset = 0;
116037741Smckusick 	auio.uio_rw = UIO_READ;
116137741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
116248026Smckusick 	auio.uio_procp = p;
116337741Smckusick 	auio.uio_resid = uap->count;
116447540Skarels 	error = VOP_READLINK(vp, &auio, p->p_ucred);
11655992Swnj out:
116637741Smckusick 	vput(vp);
116742441Smckusick 	*retval = uap->count - auio.uio_resid;
116847540Skarels 	return (error);
11695992Swnj }
11705992Swnj 
11719167Ssam /*
117238259Smckusick  * Change flags of a file given path name.
117338259Smckusick  */
117442441Smckusick /* ARGSUSED */
117542441Smckusick chflags(p, uap, retval)
117645914Smckusick 	struct proc *p;
117742441Smckusick 	register struct args {
117838259Smckusick 		char	*fname;
117938259Smckusick 		int	flags;
118042441Smckusick 	} *uap;
118142441Smckusick 	int *retval;
118242441Smckusick {
118338259Smckusick 	register struct vnode *vp;
118438259Smckusick 	struct vattr vattr;
118538259Smckusick 	int error;
118647540Skarels 	struct nameidata nd;
118738259Smckusick 
118852322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
118952322Smckusick 	if (error = namei(&nd))
119047540Skarels 		return (error);
119152322Smckusick 	vp = nd.ni_vp;
119241400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
119338259Smckusick 		error = EROFS;
119438259Smckusick 		goto out;
119538259Smckusick 	}
119645785Sbostic 	VATTR_NULL(&vattr);
119745785Sbostic 	vattr.va_flags = uap->flags;
119852192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
119948026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
120038259Smckusick out:
120138259Smckusick 	vput(vp);
120247540Skarels 	return (error);
120338259Smckusick }
120438259Smckusick 
120538259Smckusick /*
120638259Smckusick  * Change flags of a file given a file descriptor.
120738259Smckusick  */
120842441Smckusick /* ARGSUSED */
120942441Smckusick fchflags(p, uap, retval)
121045914Smckusick 	struct proc *p;
121142441Smckusick 	register struct args {
121238259Smckusick 		int	fd;
121338259Smckusick 		int	flags;
121442441Smckusick 	} *uap;
121542441Smckusick 	int *retval;
121642441Smckusick {
121738259Smckusick 	struct vattr vattr;
121838259Smckusick 	struct vnode *vp;
121938259Smckusick 	struct file *fp;
122038259Smckusick 	int error;
122138259Smckusick 
122245914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
122347540Skarels 		return (error);
122438259Smckusick 	vp = (struct vnode *)fp->f_data;
122538259Smckusick 	VOP_LOCK(vp);
122641400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
122738259Smckusick 		error = EROFS;
122838259Smckusick 		goto out;
122938259Smckusick 	}
123045785Sbostic 	VATTR_NULL(&vattr);
123145785Sbostic 	vattr.va_flags = uap->flags;
123252192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
123348026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
123438259Smckusick out:
123538259Smckusick 	VOP_UNLOCK(vp);
123647540Skarels 	return (error);
123738259Smckusick }
123838259Smckusick 
123938259Smckusick /*
12409167Ssam  * Change mode of a file given path name.
12419167Ssam  */
124242441Smckusick /* ARGSUSED */
124342441Smckusick chmod(p, uap, retval)
124445914Smckusick 	struct proc *p;
124542441Smckusick 	register struct args {
12466254Sroot 		char	*fname;
12476254Sroot 		int	fmode;
124842441Smckusick 	} *uap;
124942441Smckusick 	int *retval;
125042441Smckusick {
125137741Smckusick 	register struct vnode *vp;
125237741Smckusick 	struct vattr vattr;
125337741Smckusick 	int error;
125447540Skarels 	struct nameidata nd;
12555992Swnj 
125652322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
125752322Smckusick 	if (error = namei(&nd))
125847540Skarels 		return (error);
125952322Smckusick 	vp = nd.ni_vp;
126041400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
126137741Smckusick 		error = EROFS;
126237741Smckusick 		goto out;
126337741Smckusick 	}
126445785Sbostic 	VATTR_NULL(&vattr);
126545785Sbostic 	vattr.va_mode = uap->fmode & 07777;
126652192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
126748026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
126837741Smckusick out:
126937741Smckusick 	vput(vp);
127047540Skarels 	return (error);
12717701Ssam }
12727439Sroot 
12739167Ssam /*
12749167Ssam  * Change mode of a file given a file descriptor.
12759167Ssam  */
127642441Smckusick /* ARGSUSED */
127742441Smckusick fchmod(p, uap, retval)
127845914Smckusick 	struct proc *p;
127942441Smckusick 	register struct args {
12807701Ssam 		int	fd;
12817701Ssam 		int	fmode;
128242441Smckusick 	} *uap;
128342441Smckusick 	int *retval;
128442441Smckusick {
128537741Smckusick 	struct vattr vattr;
128637741Smckusick 	struct vnode *vp;
128737741Smckusick 	struct file *fp;
128837741Smckusick 	int error;
12897701Ssam 
129045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
129147540Skarels 		return (error);
129237741Smckusick 	vp = (struct vnode *)fp->f_data;
129337741Smckusick 	VOP_LOCK(vp);
129441400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
129537741Smckusick 		error = EROFS;
129637741Smckusick 		goto out;
12977439Sroot 	}
129845785Sbostic 	VATTR_NULL(&vattr);
129945785Sbostic 	vattr.va_mode = uap->fmode & 07777;
130052192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
130148026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
130237741Smckusick out:
130337741Smckusick 	VOP_UNLOCK(vp);
130447540Skarels 	return (error);
13055992Swnj }
13065992Swnj 
13079167Ssam /*
13089167Ssam  * Set ownership given a path name.
13099167Ssam  */
131042441Smckusick /* ARGSUSED */
131142441Smckusick chown(p, uap, retval)
131245914Smckusick 	struct proc *p;
131342441Smckusick 	register struct args {
13146254Sroot 		char	*fname;
13156254Sroot 		int	uid;
13166254Sroot 		int	gid;
131742441Smckusick 	} *uap;
131842441Smckusick 	int *retval;
131942441Smckusick {
132037741Smckusick 	register struct vnode *vp;
132137741Smckusick 	struct vattr vattr;
132237741Smckusick 	int error;
132347540Skarels 	struct nameidata nd;
132437Sbill 
132552322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
132652322Smckusick 	if (error = namei(&nd))
132747540Skarels 		return (error);
132852322Smckusick 	vp = nd.ni_vp;
132941400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
133037741Smckusick 		error = EROFS;
133137741Smckusick 		goto out;
133237741Smckusick 	}
133345785Sbostic 	VATTR_NULL(&vattr);
133445785Sbostic 	vattr.va_uid = uap->uid;
133545785Sbostic 	vattr.va_gid = uap->gid;
133652192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
133748026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
133837741Smckusick out:
133937741Smckusick 	vput(vp);
134047540Skarels 	return (error);
13417701Ssam }
13427439Sroot 
13439167Ssam /*
13449167Ssam  * Set ownership given a file descriptor.
13459167Ssam  */
134642441Smckusick /* ARGSUSED */
134742441Smckusick fchown(p, uap, retval)
134845914Smckusick 	struct proc *p;
134942441Smckusick 	register struct args {
13507701Ssam 		int	fd;
13517701Ssam 		int	uid;
13527701Ssam 		int	gid;
135342441Smckusick 	} *uap;
135442441Smckusick 	int *retval;
135542441Smckusick {
135637741Smckusick 	struct vattr vattr;
135737741Smckusick 	struct vnode *vp;
135837741Smckusick 	struct file *fp;
135937741Smckusick 	int error;
13607701Ssam 
136145914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
136247540Skarels 		return (error);
136337741Smckusick 	vp = (struct vnode *)fp->f_data;
136437741Smckusick 	VOP_LOCK(vp);
136541400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
136637741Smckusick 		error = EROFS;
136737741Smckusick 		goto out;
136837741Smckusick 	}
136945785Sbostic 	VATTR_NULL(&vattr);
137045785Sbostic 	vattr.va_uid = uap->uid;
137145785Sbostic 	vattr.va_gid = uap->gid;
137252192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
137348026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
137437741Smckusick out:
137537741Smckusick 	VOP_UNLOCK(vp);
137647540Skarels 	return (error);
13777701Ssam }
13787701Ssam 
137942441Smckusick /*
138042441Smckusick  * Set the access and modification times of a file.
138142441Smckusick  */
138242441Smckusick /* ARGSUSED */
138342441Smckusick utimes(p, uap, retval)
138445914Smckusick 	struct proc *p;
138542441Smckusick 	register struct args {
138611811Ssam 		char	*fname;
138711811Ssam 		struct	timeval *tptr;
138842441Smckusick 	} *uap;
138942441Smckusick 	int *retval;
139042441Smckusick {
139137741Smckusick 	register struct vnode *vp;
139211811Ssam 	struct timeval tv[2];
139337741Smckusick 	struct vattr vattr;
139437741Smckusick 	int error;
139547540Skarels 	struct nameidata nd;
139611811Ssam 
139737741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
139847540Skarels 		return (error);
139952322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
140052322Smckusick 	if (error = namei(&nd))
140147540Skarels 		return (error);
140252322Smckusick 	vp = nd.ni_vp;
140341400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
140437741Smckusick 		error = EROFS;
140537741Smckusick 		goto out;
140621015Smckusick 	}
140745785Sbostic 	VATTR_NULL(&vattr);
1408*53468Smckusick 	vattr.va_atime.tv_sec = tv[0].tv_sec;
1409*53468Smckusick 	vattr.va_mtime.tv_sec = tv[1].tv_sec;
141052192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
141148026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
141237741Smckusick out:
141337741Smckusick 	vput(vp);
141447540Skarels 	return (error);
141511811Ssam }
141611811Ssam 
1417*53468Smckusick #ifdef COMPAT_43
14189167Ssam /*
14199167Ssam  * Truncate a file given its path name.
14209167Ssam  */
142142441Smckusick /* ARGSUSED */
142242441Smckusick truncate(p, uap, retval)
142345914Smckusick 	struct proc *p;
142442441Smckusick 	register struct args {
14257701Ssam 		char	*fname;
1426*53468Smckusick 		long	length;
1427*53468Smckusick 	} *uap;
1428*53468Smckusick 	int *retval;
1429*53468Smckusick {
1430*53468Smckusick 	struct nargs {
1431*53468Smckusick 		char	*fname;
143226473Skarels 		off_t	length;
1433*53468Smckusick 	} nuap;
1434*53468Smckusick 
1435*53468Smckusick 	nuap.fname = uap->fname;
1436*53468Smckusick 	nuap.length = uap->length;
1437*53468Smckusick 	return (qtruncate(p, &nuap, retval));
1438*53468Smckusick }
1439*53468Smckusick 
1440*53468Smckusick /*
1441*53468Smckusick  * Truncate a file given a file descriptor.
1442*53468Smckusick  */
1443*53468Smckusick /* ARGSUSED */
1444*53468Smckusick ftruncate(p, uap, retval)
1445*53468Smckusick 	struct proc *p;
1446*53468Smckusick 	register struct args {
1447*53468Smckusick 		int	fd;
1448*53468Smckusick 		long	length;
144942441Smckusick 	} *uap;
145042441Smckusick 	int *retval;
145142441Smckusick {
1452*53468Smckusick 	struct nargs {
1453*53468Smckusick 		int	fd;
1454*53468Smckusick 		off_t	length;
1455*53468Smckusick 	} nuap;
1456*53468Smckusick 
1457*53468Smckusick 	nuap.fd = uap->fd;
1458*53468Smckusick 	nuap.length = uap->length;
1459*53468Smckusick 	return (fqtruncate(p, &nuap, retval));
1460*53468Smckusick }
1461*53468Smckusick #endif /* COMPAT_43 */
1462*53468Smckusick 
1463*53468Smckusick /*
1464*53468Smckusick  * Truncate a file given its path name.
1465*53468Smckusick  */
1466*53468Smckusick /* ARGSUSED */
1467*53468Smckusick qtruncate(p, uap, retval)
1468*53468Smckusick 	struct proc *p;
1469*53468Smckusick 	register struct args {
1470*53468Smckusick 		char	*fname;
1471*53468Smckusick 		off_t	length;
1472*53468Smckusick 	} *uap;
1473*53468Smckusick 	int *retval;
1474*53468Smckusick {
147537741Smckusick 	register struct vnode *vp;
147637741Smckusick 	struct vattr vattr;
147737741Smckusick 	int error;
147847540Skarels 	struct nameidata nd;
14797701Ssam 
148052322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
148152322Smckusick 	if (error = namei(&nd))
148247540Skarels 		return (error);
148352322Smckusick 	vp = nd.ni_vp;
148437741Smckusick 	if (vp->v_type == VDIR) {
148537741Smckusick 		error = EISDIR;
148637741Smckusick 		goto out;
14877701Ssam 	}
148838399Smckusick 	if ((error = vn_writechk(vp)) ||
148948026Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)))
149037741Smckusick 		goto out;
149145785Sbostic 	VATTR_NULL(&vattr);
149245785Sbostic 	vattr.va_size = uap->length;
149352192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
149448026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
149537741Smckusick out:
149637741Smckusick 	vput(vp);
149747540Skarels 	return (error);
14987701Ssam }
14997701Ssam 
15009167Ssam /*
15019167Ssam  * Truncate a file given a file descriptor.
15029167Ssam  */
150342441Smckusick /* ARGSUSED */
1504*53468Smckusick fqtruncate(p, uap, retval)
150545914Smckusick 	struct proc *p;
150642441Smckusick 	register struct args {
15077701Ssam 		int	fd;
150826473Skarels 		off_t	length;
150942441Smckusick 	} *uap;
151042441Smckusick 	int *retval;
151142441Smckusick {
151237741Smckusick 	struct vattr vattr;
151337741Smckusick 	struct vnode *vp;
15147701Ssam 	struct file *fp;
151537741Smckusick 	int error;
15167701Ssam 
151745914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
151847540Skarels 		return (error);
151937741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
152047540Skarels 		return (EINVAL);
152137741Smckusick 	vp = (struct vnode *)fp->f_data;
152237741Smckusick 	VOP_LOCK(vp);
152337741Smckusick 	if (vp->v_type == VDIR) {
152437741Smckusick 		error = EISDIR;
152537741Smckusick 		goto out;
15267701Ssam 	}
152738399Smckusick 	if (error = vn_writechk(vp))
152837741Smckusick 		goto out;
152945785Sbostic 	VATTR_NULL(&vattr);
153045785Sbostic 	vattr.va_size = uap->length;
153152192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
153248026Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
153337741Smckusick out:
153437741Smckusick 	VOP_UNLOCK(vp);
153547540Skarels 	return (error);
15367701Ssam }
15377701Ssam 
15389167Ssam /*
15399167Ssam  * Synch an open file.
15409167Ssam  */
154142441Smckusick /* ARGSUSED */
154242441Smckusick fsync(p, uap, retval)
154345914Smckusick 	struct proc *p;
154442441Smckusick 	struct args {
154542441Smckusick 		int	fd;
154642441Smckusick 	} *uap;
154742441Smckusick 	int *retval;
15489167Ssam {
154939592Smckusick 	register struct vnode *vp;
15509167Ssam 	struct file *fp;
155137741Smckusick 	int error;
15529167Ssam 
155345914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
155447540Skarels 		return (error);
155539592Smckusick 	vp = (struct vnode *)fp->f_data;
155639592Smckusick 	VOP_LOCK(vp);
155748026Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT, p);
155839592Smckusick 	VOP_UNLOCK(vp);
155947540Skarels 	return (error);
15609167Ssam }
15619167Ssam 
15629167Ssam /*
15639167Ssam  * Rename system call.
15649167Ssam  *
15659167Ssam  * Source and destination must either both be directories, or both
15669167Ssam  * not be directories.  If target is a directory, it must be empty.
15679167Ssam  */
156842441Smckusick /* ARGSUSED */
156942441Smckusick rename(p, uap, retval)
157045914Smckusick 	struct proc *p;
157142441Smckusick 	register struct args {
15727701Ssam 		char	*from;
15737701Ssam 		char	*to;
157442441Smckusick 	} *uap;
157542441Smckusick 	int *retval;
157642441Smckusick {
157737741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
157849735Smckusick 	struct nameidata fromnd, tond;
157937741Smckusick 	int error;
15807701Ssam 
158152322Smckusick 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
158252322Smckusick 		uap->from, p);
158352322Smckusick 	if (error = namei(&fromnd))
158447540Skarels 		return (error);
158549735Smckusick 	fvp = fromnd.ni_vp;
158652322Smckusick 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
158752322Smckusick 		UIO_USERSPACE, uap->to, p);
158852322Smckusick 	if (error = namei(&tond)) {
158952230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
159049735Smckusick 		vrele(fromnd.ni_dvp);
159142465Smckusick 		vrele(fvp);
159242465Smckusick 		goto out1;
159342465Smckusick 	}
159437741Smckusick 	tdvp = tond.ni_dvp;
159537741Smckusick 	tvp = tond.ni_vp;
159637741Smckusick 	if (tvp != NULL) {
159737741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
159839242Sbostic 			error = ENOTDIR;
159937741Smckusick 			goto out;
160037741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
160139242Sbostic 			error = EISDIR;
160237741Smckusick 			goto out;
16039167Ssam 		}
160445240Smckusick 		if (fvp->v_mount != tvp->v_mount) {
160545240Smckusick 			error = EXDEV;
160645240Smckusick 			goto out;
160745240Smckusick 		}
16089167Ssam 	}
160937741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
161037741Smckusick 		error = EXDEV;
16119167Ssam 		goto out;
161210051Ssam 	}
161339286Smckusick 	if (fvp == tdvp)
161437741Smckusick 		error = EINVAL;
161539286Smckusick 	/*
161649735Smckusick 	 * If source is the same as the destination (that is the
161749735Smckusick 	 * same inode number with the same name in the same directory),
161839286Smckusick 	 * then there is nothing to do.
161939286Smckusick 	 */
162049735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
162152322Smckusick 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
162252322Smckusick 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
162352322Smckusick 	      fromnd.ni_cnd.cn_namelen))
162439286Smckusick 		error = -1;
162537741Smckusick out:
162642465Smckusick 	if (!error) {
162752192Smckusick 		LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE);
162852192Smckusick 		if (fromnd.ni_dvp != tdvp)
162952192Smckusick 			LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
163052192Smckusick 		if (tvp)
163152192Smckusick 			LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE);
163252230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
163352230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
163442465Smckusick 	} else {
163552230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
163643344Smckusick 		if (tdvp == tvp)
163743344Smckusick 			vrele(tdvp);
163843344Smckusick 		else
163943344Smckusick 			vput(tdvp);
164042465Smckusick 		if (tvp)
164142465Smckusick 			vput(tvp);
164252230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
164349735Smckusick 		vrele(fromnd.ni_dvp);
164442465Smckusick 		vrele(fvp);
16459167Ssam 	}
164649735Smckusick 	vrele(tond.ni_startdir);
164752322Smckusick 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
164837741Smckusick out1:
164949735Smckusick 	vrele(fromnd.ni_startdir);
165052322Smckusick 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
165139286Smckusick 	if (error == -1)
165247540Skarels 		return (0);
165347540Skarels 	return (error);
16547701Ssam }
16557701Ssam 
16567535Sroot /*
165749365Smckusick  * Mkdir system call.
165812756Ssam  */
165942441Smckusick /* ARGSUSED */
166042441Smckusick mkdir(p, uap, retval)
166145914Smckusick 	struct proc *p;
166242441Smckusick 	register struct args {
166312756Ssam 		char	*name;
166412756Ssam 		int	dmode;
166542441Smckusick 	} *uap;
166642441Smckusick 	int *retval;
166742441Smckusick {
166837741Smckusick 	register struct vnode *vp;
166937741Smckusick 	struct vattr vattr;
167037741Smckusick 	int error;
167147540Skarels 	struct nameidata nd;
167212756Ssam 
167352322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p);
167452322Smckusick 	if (error = namei(&nd))
167547540Skarels 		return (error);
167652322Smckusick 	vp = nd.ni_vp;
167737741Smckusick 	if (vp != NULL) {
167852322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
167952322Smckusick 		if (nd.ni_dvp == vp)
168052322Smckusick 			vrele(nd.ni_dvp);
168143344Smckusick 		else
168252322Smckusick 			vput(nd.ni_dvp);
168342465Smckusick 		vrele(vp);
168447540Skarels 		return (EEXIST);
168512756Ssam 	}
168641362Smckusick 	VATTR_NULL(&vattr);
168737741Smckusick 	vattr.va_type = VDIR;
168845914Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask;
168952322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
169052322Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
169138145Smckusick 	if (!error)
169252322Smckusick 		vput(nd.ni_vp);
169347540Skarels 	return (error);
169412756Ssam }
169512756Ssam 
169612756Ssam /*
169712756Ssam  * Rmdir system call.
169812756Ssam  */
169942441Smckusick /* ARGSUSED */
170042441Smckusick rmdir(p, uap, retval)
170145914Smckusick 	struct proc *p;
170242441Smckusick 	struct args {
170342441Smckusick 		char	*name;
170442441Smckusick 	} *uap;
170542441Smckusick 	int *retval;
170612756Ssam {
170737741Smckusick 	register struct vnode *vp;
170837741Smckusick 	int error;
170947540Skarels 	struct nameidata nd;
171012756Ssam 
171152322Smckusick 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p);
171252322Smckusick 	if (error = namei(&nd))
171347540Skarels 		return (error);
171452322Smckusick 	vp = nd.ni_vp;
171537741Smckusick 	if (vp->v_type != VDIR) {
171637741Smckusick 		error = ENOTDIR;
171712756Ssam 		goto out;
171812756Ssam 	}
171912756Ssam 	/*
172037741Smckusick 	 * No rmdir "." please.
172112756Ssam 	 */
172252322Smckusick 	if (nd.ni_dvp == vp) {
172337741Smckusick 		error = EINVAL;
172412756Ssam 		goto out;
172512756Ssam 	}
172612756Ssam 	/*
172749365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
172812756Ssam 	 */
172937741Smckusick 	if (vp->v_flag & VROOT)
173037741Smckusick 		error = EBUSY;
173112756Ssam out:
173242465Smckusick 	if (!error) {
173352322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
173452192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
173552322Smckusick 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
173642465Smckusick 	} else {
173752322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
173852322Smckusick 		if (nd.ni_dvp == vp)
173952322Smckusick 			vrele(nd.ni_dvp);
174043344Smckusick 		else
174152322Smckusick 			vput(nd.ni_dvp);
174242465Smckusick 		vput(vp);
174342465Smckusick 	}
174447540Skarels 	return (error);
174512756Ssam }
174612756Ssam 
174737741Smckusick /*
174849365Smckusick  * Read a block of directory entries in a file system independent format.
174937741Smckusick  */
175042441Smckusick getdirentries(p, uap, retval)
175145914Smckusick 	struct proc *p;
175242441Smckusick 	register struct args {
175337741Smckusick 		int	fd;
175437741Smckusick 		char	*buf;
175537741Smckusick 		unsigned count;
175637741Smckusick 		long	*basep;
175742441Smckusick 	} *uap;
175842441Smckusick 	int *retval;
175942441Smckusick {
176039592Smckusick 	register struct vnode *vp;
176116540Ssam 	struct file *fp;
176237741Smckusick 	struct uio auio;
176337741Smckusick 	struct iovec aiov;
176438129Smckusick 	off_t off;
176540321Smckusick 	int error, eofflag;
176612756Ssam 
176745914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
176847540Skarels 		return (error);
176937741Smckusick 	if ((fp->f_flag & FREAD) == 0)
177047540Skarels 		return (EBADF);
177139592Smckusick 	vp = (struct vnode *)fp->f_data;
177239592Smckusick 	if (vp->v_type != VDIR)
177347540Skarels 		return (EINVAL);
177437741Smckusick 	aiov.iov_base = uap->buf;
177537741Smckusick 	aiov.iov_len = uap->count;
177637741Smckusick 	auio.uio_iov = &aiov;
177737741Smckusick 	auio.uio_iovcnt = 1;
177837741Smckusick 	auio.uio_rw = UIO_READ;
177937741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
178048026Smckusick 	auio.uio_procp = p;
178137741Smckusick 	auio.uio_resid = uap->count;
178239592Smckusick 	VOP_LOCK(vp);
178339592Smckusick 	auio.uio_offset = off = fp->f_offset;
178440321Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
178539592Smckusick 	fp->f_offset = auio.uio_offset;
178639592Smckusick 	VOP_UNLOCK(vp);
178739592Smckusick 	if (error)
178847540Skarels 		return (error);
178939592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
179042441Smckusick 	*retval = uap->count - auio.uio_resid;
179147540Skarels 	return (error);
179212756Ssam }
179312756Ssam 
179412756Ssam /*
179549365Smckusick  * Set the mode mask for creation of filesystem nodes.
179612756Ssam  */
179742441Smckusick mode_t
179842441Smckusick umask(p, uap, retval)
179945914Smckusick 	struct proc *p;
180042441Smckusick 	struct args {
180142441Smckusick 		int	mask;
180242441Smckusick 	} *uap;
180342441Smckusick 	int *retval;
180412756Ssam {
180545914Smckusick 	register struct filedesc *fdp = p->p_fd;
180612756Ssam 
180745914Smckusick 	*retval = fdp->fd_cmask;
180845914Smckusick 	fdp->fd_cmask = uap->mask & 07777;
180947540Skarels 	return (0);
181012756Ssam }
181137741Smckusick 
181239566Smarc /*
181339566Smarc  * Void all references to file by ripping underlying filesystem
181439566Smarc  * away from vnode.
181539566Smarc  */
181642441Smckusick /* ARGSUSED */
181742441Smckusick revoke(p, uap, retval)
181845914Smckusick 	struct proc *p;
181942441Smckusick 	register struct args {
182039566Smarc 		char	*fname;
182142441Smckusick 	} *uap;
182242441Smckusick 	int *retval;
182342441Smckusick {
182439566Smarc 	register struct vnode *vp;
182539566Smarc 	struct vattr vattr;
182639566Smarc 	int error;
182747540Skarels 	struct nameidata nd;
182839566Smarc 
182952322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
183052322Smckusick 	if (error = namei(&nd))
183147540Skarels 		return (error);
183252322Smckusick 	vp = nd.ni_vp;
183339566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
183439566Smarc 		error = EINVAL;
183539566Smarc 		goto out;
183639566Smarc 	}
183748026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
183839566Smarc 		goto out;
183947540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
184047540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
184139566Smarc 		goto out;
184239805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
184339632Smckusick 		vgoneall(vp);
184439566Smarc out:
184539566Smarc 	vrele(vp);
184647540Skarels 	return (error);
184739566Smarc }
184839566Smarc 
184949365Smckusick /*
185049365Smckusick  * Convert a user file descriptor to a kernel file entry.
185149365Smckusick  */
185245914Smckusick getvnode(fdp, fdes, fpp)
185345914Smckusick 	struct filedesc *fdp;
185437741Smckusick 	struct file **fpp;
185537741Smckusick 	int fdes;
185637741Smckusick {
185737741Smckusick 	struct file *fp;
185837741Smckusick 
185947540Skarels 	if ((unsigned)fdes >= fdp->fd_nfiles ||
186047688Skarels 	    (fp = fdp->fd_ofiles[fdes]) == NULL)
186137741Smckusick 		return (EBADF);
186237741Smckusick 	if (fp->f_type != DTYPE_VNODE)
186337741Smckusick 		return (EINVAL);
186437741Smckusick 	*fpp = fp;
186537741Smckusick 	return (0);
186637741Smckusick }
1867