xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 54172)
123405Smckusick /*
237741Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337741Smckusick  * All rights reserved.
423405Smckusick  *
544459Sbostic  * %sccs.include.redist.c%
637741Smckusick  *
7*54172Smckusick  *	@(#)vfs_syscalls.c	7.86 (Berkeley) 06/20/92
823405Smckusick  */
937Sbill 
1017101Sbloom #include "param.h"
1117101Sbloom #include "systm.h"
1247540Skarels #include "namei.h"
1345914Smckusick #include "filedesc.h"
1417101Sbloom #include "kernel.h"
1517101Sbloom #include "file.h"
1617101Sbloom #include "stat.h"
1737741Smckusick #include "vnode.h"
1837741Smckusick #include "mount.h"
1917101Sbloom #include "proc.h"
2017101Sbloom #include "uio.h"
2137741Smckusick #include "malloc.h"
2253468Smckusick #include <vm/vm.h>
2337Sbill 
2437741Smckusick /*
2537741Smckusick  * Virtual File System System Calls
2637741Smckusick  */
2712756Ssam 
289167Ssam /*
2949365Smckusick  * Mount system call.
309167Ssam  */
3142441Smckusick /* ARGSUSED */
3242441Smckusick mount(p, uap, retval)
3345914Smckusick 	struct proc *p;
3442441Smckusick 	register struct args {
3537741Smckusick 		int	type;
3637741Smckusick 		char	*dir;
3737741Smckusick 		int	flags;
3837741Smckusick 		caddr_t	data;
3942441Smckusick 	} *uap;
4042441Smckusick 	int *retval;
4142441Smckusick {
4253548Sheideman 	USES_VOP_UNLOCK;
4339335Smckusick 	register struct vnode *vp;
4439335Smckusick 	register struct mount *mp;
4540111Smckusick 	int error, flag;
4647540Skarels 	struct nameidata nd;
476254Sroot 
4837741Smckusick 	/*
4937741Smckusick 	 * Must be super user
5037741Smckusick 	 */
5147540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
5247540Skarels 		return (error);
5337741Smckusick 	/*
5437741Smckusick 	 * Get vnode to be covered
5537741Smckusick 	 */
5652322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->dir, p);
5752322Smckusick 	if (error = namei(&nd))
5847540Skarels 		return (error);
5952322Smckusick 	vp = nd.ni_vp;
6041400Smckusick 	if (uap->flags & MNT_UPDATE) {
6139335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
6239335Smckusick 			vput(vp);
6347540Skarels 			return (EINVAL);
6439335Smckusick 		}
6539335Smckusick 		mp = vp->v_mount;
6639335Smckusick 		/*
6739335Smckusick 		 * We allow going from read-only to read-write,
6839335Smckusick 		 * but not from read-write to read-only.
6939335Smckusick 		 */
7041400Smckusick 		if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
7141400Smckusick 		    (uap->flags & MNT_RDONLY) != 0) {
7239335Smckusick 			vput(vp);
7347540Skarels 			return (EOPNOTSUPP);	/* Needs translation */
7439335Smckusick 		}
7541400Smckusick 		flag = mp->mnt_flag;
7641400Smckusick 		mp->mnt_flag |= MNT_UPDATE;
7739335Smckusick 		VOP_UNLOCK(vp);
7839335Smckusick 		goto update;
7939335Smckusick 	}
8039665Smckusick 	vinvalbuf(vp, 1);
8139805Smckusick 	if (vp->v_usecount != 1) {
8237741Smckusick 		vput(vp);
8347540Skarels 		return (EBUSY);
8437741Smckusick 	}
8537741Smckusick 	if (vp->v_type != VDIR) {
8637741Smckusick 		vput(vp);
8747540Skarels 		return (ENOTDIR);
8837741Smckusick 	}
8939741Smckusick 	if ((unsigned long)uap->type > MOUNT_MAXTYPE ||
9037741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
9137741Smckusick 		vput(vp);
9247540Skarels 		return (ENODEV);
9337741Smckusick 	}
9437741Smckusick 
9537741Smckusick 	/*
9639335Smckusick 	 * Allocate and initialize the file system.
9737741Smckusick 	 */
9837741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
9937741Smckusick 		M_MOUNT, M_WAITOK);
100*54172Smckusick 	bzero((char *)mp, (u_long)sizeof(struct mount));
10141400Smckusick 	mp->mnt_op = vfssw[uap->type];
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 {
42253548Sheideman 	USES_VOP_ACCESS;
42353548Sheideman 	USES_VOP_LOCK;
42453548Sheideman 	USES_VOP_UNLOCK;
42545914Smckusick 	register struct filedesc *fdp = p->p_fd;
42638259Smckusick 	register struct vnode *vp;
42738259Smckusick 	struct file *fp;
42838259Smckusick 	int error;
42938259Smckusick 
43045914Smckusick 	if (error = getvnode(fdp, uap->fd, &fp))
43147540Skarels 		return (error);
43238259Smckusick 	vp = (struct vnode *)fp->f_data;
43338259Smckusick 	VOP_LOCK(vp);
43438259Smckusick 	if (vp->v_type != VDIR)
43538259Smckusick 		error = ENOTDIR;
43638259Smckusick 	else
43748026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
43838259Smckusick 	VOP_UNLOCK(vp);
43939860Smckusick 	if (error)
44047540Skarels 		return (error);
44139860Smckusick 	VREF(vp);
44245914Smckusick 	vrele(fdp->fd_cdir);
44345914Smckusick 	fdp->fd_cdir = vp;
44447540Skarels 	return (0);
44538259Smckusick }
44638259Smckusick 
44738259Smckusick /*
44837741Smckusick  * Change current working directory (``.'').
44937741Smckusick  */
45042441Smckusick /* ARGSUSED */
45142441Smckusick chdir(p, uap, retval)
45245914Smckusick 	struct proc *p;
45342441Smckusick 	struct args {
45442441Smckusick 		char	*fname;
45542441Smckusick 	} *uap;
45642441Smckusick 	int *retval;
45737741Smckusick {
45845914Smckusick 	register struct filedesc *fdp = p->p_fd;
45937741Smckusick 	int error;
46047540Skarels 	struct nameidata nd;
4616254Sroot 
46252322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
46352781Sralph 	if (error = chdirec(&nd, p))
46447540Skarels 		return (error);
46545914Smckusick 	vrele(fdp->fd_cdir);
46652322Smckusick 	fdp->fd_cdir = nd.ni_vp;
46747540Skarels 	return (0);
46837741Smckusick }
4696254Sroot 
47037741Smckusick /*
47137741Smckusick  * Change notion of root (``/'') directory.
47237741Smckusick  */
47342441Smckusick /* ARGSUSED */
47442441Smckusick chroot(p, uap, retval)
47545914Smckusick 	struct proc *p;
47642441Smckusick 	struct args {
47742441Smckusick 		char	*fname;
47842441Smckusick 	} *uap;
47942441Smckusick 	int *retval;
48037741Smckusick {
48145914Smckusick 	register struct filedesc *fdp = p->p_fd;
48237741Smckusick 	int error;
48347540Skarels 	struct nameidata nd;
48437741Smckusick 
48547540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
48647540Skarels 		return (error);
48752322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
48852781Sralph 	if (error = chdirec(&nd, p))
48947540Skarels 		return (error);
49045914Smckusick 	if (fdp->fd_rdir != NULL)
49145914Smckusick 		vrele(fdp->fd_rdir);
49252322Smckusick 	fdp->fd_rdir = nd.ni_vp;
49347540Skarels 	return (0);
4946254Sroot }
4956254Sroot 
49637Sbill /*
49737741Smckusick  * Common routine for chroot and chdir.
49837741Smckusick  */
49947540Skarels chdirec(ndp, p)
50052322Smckusick 	register struct nameidata *ndp;
50147540Skarels 	struct proc *p;
50237741Smckusick {
50353548Sheideman 	USES_VOP_ACCESS;
50453548Sheideman 	USES_VOP_UNLOCK;
50537741Smckusick 	struct vnode *vp;
50637741Smckusick 	int error;
50737741Smckusick 
50852322Smckusick 	if (error = namei(ndp))
50937741Smckusick 		return (error);
51037741Smckusick 	vp = ndp->ni_vp;
51137741Smckusick 	if (vp->v_type != VDIR)
51237741Smckusick 		error = ENOTDIR;
51337741Smckusick 	else
51448026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
51537741Smckusick 	VOP_UNLOCK(vp);
51637741Smckusick 	if (error)
51737741Smckusick 		vrele(vp);
51837741Smckusick 	return (error);
51937741Smckusick }
52037741Smckusick 
52137741Smckusick /*
5226254Sroot  * Open system call.
52342441Smckusick  * Check permissions, allocate an open file structure,
52442441Smckusick  * and call the device open routine if any.
5256254Sroot  */
52642441Smckusick open(p, uap, retval)
52745914Smckusick 	struct proc *p;
52842441Smckusick 	register struct args {
5296254Sroot 		char	*fname;
5307701Ssam 		int	mode;
53112756Ssam 		int	crtmode;
53242441Smckusick 	} *uap;
53342441Smckusick 	int *retval;
5346254Sroot {
53553548Sheideman 	USES_VOP_ADVLOCK;
53653548Sheideman 	USES_VOP_UNLOCK;
53745914Smckusick 	register struct filedesc *fdp = p->p_fd;
53842441Smckusick 	register struct file *fp;
53950111Smckusick 	register struct vnode *vp;
54037741Smckusick 	int fmode, cmode;
54137741Smckusick 	struct file *nfp;
54249945Smckusick 	int type, indx, error;
54349945Smckusick 	struct flock lf;
54447540Skarels 	struct nameidata nd;
54537741Smckusick 	extern struct fileops vnops;
5466254Sroot 
54745914Smckusick 	if (error = falloc(p, &nfp, &indx))
54847540Skarels 		return (error);
54937741Smckusick 	fp = nfp;
55046553Skarels 	fmode = FFLAGS(uap->mode);
55145914Smckusick 	cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX;
55252322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
55345202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
55452322Smckusick 	if (error = vn_open(&nd, fmode, cmode)) {
55553828Spendry 		int dfd = p->p_dupfd;
55653828Spendry 		p->p_dupfd = 0;
55749980Smckusick 		ffree(fp);
55853828Spendry 		if ((error == ENODEV || error == ENXIO) && /* XXX from fdopen */
55953828Spendry 		    dfd >= 0 &&
56053828Spendry 		    (error = dupfdopen(fdp, indx, p->p_dupfd,
56153828Spendry 					fmode, error)) == 0) {
56242441Smckusick 			*retval = indx;
56347540Skarels 			return (0);
56442441Smckusick 		}
56540884Smckusick 		if (error == ERESTART)
56640884Smckusick 			error = EINTR;
56747688Skarels 		fdp->fd_ofiles[indx] = NULL;
56847540Skarels 		return (error);
56912756Ssam 	}
57053828Spendry 	p->p_dupfd = 0;
57152322Smckusick 	vp = nd.ni_vp;
57249949Smckusick 	fp->f_flag = fmode & FMASK;
57349945Smckusick 	if (fmode & (O_EXLOCK | O_SHLOCK)) {
57449945Smckusick 		lf.l_whence = SEEK_SET;
57549945Smckusick 		lf.l_start = 0;
57649945Smckusick 		lf.l_len = 0;
57749945Smckusick 		if (fmode & O_EXLOCK)
57849945Smckusick 			lf.l_type = F_WRLCK;
57949945Smckusick 		else
58049945Smckusick 			lf.l_type = F_RDLCK;
58149945Smckusick 		type = F_FLOCK;
58249945Smckusick 		if ((fmode & FNONBLOCK) == 0)
58349945Smckusick 			type |= F_WAIT;
58450111Smckusick 		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
58550111Smckusick 			VOP_UNLOCK(vp);
58650111Smckusick 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
58749980Smckusick 			ffree(fp);
58849945Smckusick 			fdp->fd_ofiles[indx] = NULL;
58949945Smckusick 			return (error);
59049945Smckusick 		}
59149949Smckusick 		fp->f_flag |= FHASLOCK;
59249945Smckusick 	}
59350111Smckusick 	VOP_UNLOCK(vp);
59437741Smckusick 	fp->f_type = DTYPE_VNODE;
59537741Smckusick 	fp->f_ops = &vnops;
59650111Smckusick 	fp->f_data = (caddr_t)vp;
59742441Smckusick 	*retval = indx;
59847540Skarels 	return (0);
5996254Sroot }
6006254Sroot 
60142955Smckusick #ifdef COMPAT_43
6026254Sroot /*
60342441Smckusick  * Creat system call.
6046254Sroot  */
60542955Smckusick ocreat(p, uap, retval)
60642441Smckusick 	struct proc *p;
60742441Smckusick 	register struct args {
60842441Smckusick 		char	*fname;
60942441Smckusick 		int	fmode;
61042441Smckusick 	} *uap;
61142441Smckusick 	int *retval;
6126254Sroot {
61342441Smckusick 	struct args {
6146254Sroot 		char	*fname;
61542441Smckusick 		int	mode;
61642441Smckusick 		int	crtmode;
61742441Smckusick 	} openuap;
61842441Smckusick 
61942441Smckusick 	openuap.fname = uap->fname;
62042441Smckusick 	openuap.crtmode = uap->fmode;
62142441Smckusick 	openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
62247540Skarels 	return (open(p, &openuap, retval));
62342441Smckusick }
62442955Smckusick #endif /* COMPAT_43 */
62542441Smckusick 
62642441Smckusick /*
62749365Smckusick  * Mknod system call.
62842441Smckusick  */
62942441Smckusick /* ARGSUSED */
63042441Smckusick mknod(p, uap, retval)
63145914Smckusick 	struct proc *p;
63242441Smckusick 	register struct args {
63342441Smckusick 		char	*fname;
6346254Sroot 		int	fmode;
6356254Sroot 		int	dev;
63642441Smckusick 	} *uap;
63742441Smckusick 	int *retval;
63842441Smckusick {
63953548Sheideman 	USES_VOP_ABORTOP;
64053548Sheideman 	USES_VOP_MKNOD;
64137741Smckusick 	register struct vnode *vp;
64237741Smckusick 	struct vattr vattr;
64337741Smckusick 	int error;
64447540Skarels 	struct nameidata nd;
6456254Sroot 
64647540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
64747540Skarels 		return (error);
64852322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p);
64952322Smckusick 	if (error = namei(&nd))
65047540Skarels 		return (error);
65152322Smckusick 	vp = nd.ni_vp;
65237741Smckusick 	if (vp != NULL) {
65337741Smckusick 		error = EEXIST;
65412756Ssam 		goto out;
6556254Sroot 	}
65641362Smckusick 	VATTR_NULL(&vattr);
65740635Smckusick 	switch (uap->fmode & S_IFMT) {
65812756Ssam 
65940635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
66037741Smckusick 		vattr.va_type = VBAD;
66137741Smckusick 		break;
66240635Smckusick 	case S_IFCHR:
66337741Smckusick 		vattr.va_type = VCHR;
66437741Smckusick 		break;
66540635Smckusick 	case S_IFBLK:
66637741Smckusick 		vattr.va_type = VBLK;
66737741Smckusick 		break;
66837741Smckusick 	default:
66937741Smckusick 		error = EINVAL;
67037741Smckusick 		goto out;
6716254Sroot 	}
67245914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
67337741Smckusick 	vattr.va_rdev = uap->dev;
6746254Sroot out:
67542465Smckusick 	if (!error) {
67652322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
67752322Smckusick 		error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
67842465Smckusick 	} else {
67952322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
68052322Smckusick 		if (nd.ni_dvp == vp)
68152322Smckusick 			vrele(nd.ni_dvp);
68243344Smckusick 		else
68352322Smckusick 			vput(nd.ni_dvp);
68442465Smckusick 		if (vp)
68542465Smckusick 			vrele(vp);
68642465Smckusick 	}
68747540Skarels 	return (error);
6886254Sroot }
6896254Sroot 
6906254Sroot /*
69149365Smckusick  * Mkfifo system call.
69240285Smckusick  */
69342441Smckusick /* ARGSUSED */
69442441Smckusick mkfifo(p, uap, retval)
69545914Smckusick 	struct proc *p;
69642441Smckusick 	register struct args {
69740285Smckusick 		char	*fname;
69840285Smckusick 		int	fmode;
69942441Smckusick 	} *uap;
70042441Smckusick 	int *retval;
70142441Smckusick {
70253548Sheideman 	USES_VOP_ABORTOP;
70353548Sheideman 	USES_VOP_MKNOD;
70440285Smckusick 	struct vattr vattr;
70540285Smckusick 	int error;
70647540Skarels 	struct nameidata nd;
70740285Smckusick 
70840285Smckusick #ifndef FIFO
70947540Skarels 	return (EOPNOTSUPP);
71040285Smckusick #else
71152322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p);
71252322Smckusick 	if (error = namei(&nd))
71347540Skarels 		return (error);
71452322Smckusick 	if (nd.ni_vp != NULL) {
71552322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
71652322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
71752322Smckusick 			vrele(nd.ni_dvp);
71843344Smckusick 		else
71952322Smckusick 			vput(nd.ni_dvp);
72052322Smckusick 		vrele(nd.ni_vp);
72147540Skarels 		return (EEXIST);
72240285Smckusick 	}
72345785Sbostic 	VATTR_NULL(&vattr);
72445785Sbostic 	vattr.va_type = VFIFO;
72545914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
72652322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
72752322Smckusick 	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
72840285Smckusick #endif /* FIFO */
72940285Smckusick }
73040285Smckusick 
73140285Smckusick /*
73249365Smckusick  * Link system call.
7336254Sroot  */
73442441Smckusick /* ARGSUSED */
73542441Smckusick link(p, uap, retval)
73645914Smckusick 	struct proc *p;
73742441Smckusick 	register struct args {
7386254Sroot 		char	*target;
7396254Sroot 		char	*linkname;
74042441Smckusick 	} *uap;
74142441Smckusick 	int *retval;
74242441Smckusick {
74353548Sheideman 	USES_VOP_ABORTOP;
74453548Sheideman 	USES_VOP_LINK;
74537741Smckusick 	register struct vnode *vp, *xp;
74637741Smckusick 	int error;
74747540Skarels 	struct nameidata nd;
7486254Sroot 
74952322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->target, p);
75052322Smckusick 	if (error = namei(&nd))
75147540Skarels 		return (error);
75252322Smckusick 	vp = nd.ni_vp;
75337741Smckusick 	if (vp->v_type == VDIR &&
75447540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
75537741Smckusick 		goto out1;
75652322Smckusick 	nd.ni_cnd.cn_nameiop = CREATE;
75752322Smckusick 	nd.ni_cnd.cn_flags = LOCKPARENT;
75852322Smckusick 	nd.ni_dirp = (caddr_t)uap->linkname;
75952322Smckusick 	if (error = namei(&nd))
76037741Smckusick 		goto out1;
76152322Smckusick 	xp = nd.ni_vp;
7626254Sroot 	if (xp != NULL) {
76337741Smckusick 		error = EEXIST;
7646254Sroot 		goto out;
7656254Sroot 	}
76652322Smckusick 	xp = nd.ni_dvp;
7676254Sroot out:
76842465Smckusick 	if (!error) {
76952192Smckusick 		LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE);
77052192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
77152821Smckusick 		error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
77242465Smckusick 	} else {
77352322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
77452322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
77552322Smckusick 			vrele(nd.ni_dvp);
77643344Smckusick 		else
77752322Smckusick 			vput(nd.ni_dvp);
77852322Smckusick 		if (nd.ni_vp)
77952322Smckusick 			vrele(nd.ni_vp);
78042465Smckusick 	}
78137741Smckusick out1:
78237741Smckusick 	vrele(vp);
78347540Skarels 	return (error);
7846254Sroot }
7856254Sroot 
7866254Sroot /*
78749365Smckusick  * Make a symbolic link.
7886254Sroot  */
78942441Smckusick /* ARGSUSED */
79042441Smckusick symlink(p, uap, retval)
79145914Smckusick 	struct proc *p;
79242441Smckusick 	register struct args {
7936254Sroot 		char	*target;
7946254Sroot 		char	*linkname;
79542441Smckusick 	} *uap;
79642441Smckusick 	int *retval;
79742441Smckusick {
79853548Sheideman 	USES_VOP_ABORTOP;
79953548Sheideman 	USES_VOP_SYMLINK;
80037741Smckusick 	struct vattr vattr;
80137741Smckusick 	char *target;
80237741Smckusick 	int error;
80347540Skarels 	struct nameidata nd;
8046254Sroot 
80537741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
80637741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
80742465Smckusick 		goto out;
80852322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->linkname, p);
80952322Smckusick 	if (error = namei(&nd))
81042465Smckusick 		goto out;
81152322Smckusick 	if (nd.ni_vp) {
81252322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
81352322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
81452322Smckusick 			vrele(nd.ni_dvp);
81543344Smckusick 		else
81652322Smckusick 			vput(nd.ni_dvp);
81752322Smckusick 		vrele(nd.ni_vp);
81837741Smckusick 		error = EEXIST;
81937741Smckusick 		goto out;
8206254Sroot 	}
82141362Smckusick 	VATTR_NULL(&vattr);
82245914Smckusick 	vattr.va_mode = 0777 &~ p->p_fd->fd_cmask;
82352322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
82452322Smckusick 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, target);
82537741Smckusick out:
82637741Smckusick 	FREE(target, M_NAMEI);
82747540Skarels 	return (error);
8286254Sroot }
8296254Sroot 
8306254Sroot /*
83149365Smckusick  * Delete a name from the filesystem.
8326254Sroot  */
83342441Smckusick /* ARGSUSED */
83442441Smckusick unlink(p, uap, retval)
83545914Smckusick 	struct proc *p;
83642441Smckusick 	struct args {
83752322Smckusick 		char	*name;
83842441Smckusick 	} *uap;
83942441Smckusick 	int *retval;
8406254Sroot {
84153548Sheideman 	USES_VOP_ABORTOP;
84253548Sheideman 	USES_VOP_REMOVE;
84337741Smckusick 	register struct vnode *vp;
84437741Smckusick 	int error;
84547540Skarels 	struct nameidata nd;
8466254Sroot 
84752322Smckusick 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p);
84852322Smckusick 	if (error = namei(&nd))
84947540Skarels 		return (error);
85052322Smckusick 	vp = nd.ni_vp;
85137741Smckusick 	if (vp->v_type == VDIR &&
85247540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
8536254Sroot 		goto out;
8546254Sroot 	/*
85549365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
8566254Sroot 	 */
85737741Smckusick 	if (vp->v_flag & VROOT) {
85837741Smckusick 		error = EBUSY;
8596254Sroot 		goto out;
8606254Sroot 	}
86145738Smckusick 	(void) vnode_pager_uncache(vp);
8626254Sroot out:
86342465Smckusick 	if (!error) {
86452322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
86552192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
86652322Smckusick 		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
86742465Smckusick 	} else {
86852322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
86952322Smckusick 		if (nd.ni_dvp == vp)
87052322Smckusick 			vrele(nd.ni_dvp);
87143344Smckusick 		else
87252322Smckusick 			vput(nd.ni_dvp);
87342465Smckusick 		vput(vp);
87442465Smckusick 	}
87547540Skarels 	return (error);
8766254Sroot }
8776254Sroot 
87853468Smckusick #ifdef COMPAT_43
8796254Sroot /*
88049365Smckusick  * Seek system call.
8816254Sroot  */
88242441Smckusick lseek(p, uap, retval)
88345914Smckusick 	struct proc *p;
88442441Smckusick 	register struct args {
88537741Smckusick 		int	fdes;
88653468Smckusick 		long	off;
88753468Smckusick 		int	sbase;
88853468Smckusick 	} *uap;
88953468Smckusick 	long *retval;
89053468Smckusick {
89153468Smckusick 	struct nargs {
89253468Smckusick 		int	fdes;
8936254Sroot 		off_t	off;
8946254Sroot 		int	sbase;
89553468Smckusick 	} nuap;
89653468Smckusick 	quad_t qret;
89753468Smckusick 	int error;
89853468Smckusick 
89953468Smckusick 	nuap.fdes = uap->fdes;
90053468Smckusick 	nuap.off = uap->off;
90153468Smckusick 	nuap.sbase = uap->sbase;
90253759Smckusick 	error = __lseek(p, &nuap, &qret);
90353468Smckusick 	*retval = qret;
90453468Smckusick 	return (error);
90553468Smckusick }
90653468Smckusick #endif /* COMPAT_43 */
90753468Smckusick 
90853468Smckusick /*
90953468Smckusick  * Seek system call.
91053468Smckusick  */
91153759Smckusick __lseek(p, uap, retval)
91253468Smckusick 	struct proc *p;
91353468Smckusick 	register struct args {
91453468Smckusick 		int	fdes;
91553468Smckusick 		off_t	off;
91653468Smckusick 		int	sbase;
91742441Smckusick 	} *uap;
91842441Smckusick 	off_t *retval;
91942441Smckusick {
92053548Sheideman 	USES_VOP_GETATTR;
92147540Skarels 	struct ucred *cred = p->p_ucred;
92245914Smckusick 	register struct filedesc *fdp = p->p_fd;
92342441Smckusick 	register struct file *fp;
92437741Smckusick 	struct vattr vattr;
92537741Smckusick 	int error;
9266254Sroot 
92747540Skarels 	if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
92847688Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL)
92947540Skarels 		return (EBADF);
93037741Smckusick 	if (fp->f_type != DTYPE_VNODE)
93147540Skarels 		return (ESPIPE);
93213878Ssam 	switch (uap->sbase) {
93313878Ssam 
93413878Ssam 	case L_INCR:
93513878Ssam 		fp->f_offset += uap->off;
93613878Ssam 		break;
93713878Ssam 
93813878Ssam 	case L_XTND:
93937741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
94048026Smckusick 		    &vattr, cred, p))
94147540Skarels 			return (error);
94237741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
94313878Ssam 		break;
94413878Ssam 
94513878Ssam 	case L_SET:
94613878Ssam 		fp->f_offset = uap->off;
94713878Ssam 		break;
94813878Ssam 
94913878Ssam 	default:
95047540Skarels 		return (EINVAL);
95113878Ssam 	}
95242441Smckusick 	*retval = fp->f_offset;
95347540Skarels 	return (0);
9546254Sroot }
9556254Sroot 
9566254Sroot /*
95749365Smckusick  * Check access permissions.
9586254Sroot  */
95942441Smckusick /* ARGSUSED */
96042441Smckusick saccess(p, uap, retval)
96145914Smckusick 	struct proc *p;
96242441Smckusick 	register struct args {
9636254Sroot 		char	*fname;
9646254Sroot 		int	fmode;
96542441Smckusick 	} *uap;
96642441Smckusick 	int *retval;
96742441Smckusick {
96853548Sheideman 	USES_VOP_ACCESS;
96947540Skarels 	register struct ucred *cred = p->p_ucred;
97037741Smckusick 	register struct vnode *vp;
97137741Smckusick 	int error, mode, svuid, svgid;
97247540Skarels 	struct nameidata nd;
9736254Sroot 
97442441Smckusick 	svuid = cred->cr_uid;
97542441Smckusick 	svgid = cred->cr_groups[0];
97647540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
97747540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
97852322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
97952322Smckusick 	if (error = namei(&nd))
98037741Smckusick 		goto out1;
98152322Smckusick 	vp = nd.ni_vp;
98237741Smckusick 	/*
98337741Smckusick 	 * fmode == 0 means only check for exist
98437741Smckusick 	 */
98537741Smckusick 	if (uap->fmode) {
98637741Smckusick 		mode = 0;
98737741Smckusick 		if (uap->fmode & R_OK)
98837741Smckusick 			mode |= VREAD;
98937741Smckusick 		if (uap->fmode & W_OK)
99037741Smckusick 			mode |= VWRITE;
99137741Smckusick 		if (uap->fmode & X_OK)
99237741Smckusick 			mode |= VEXEC;
99339543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
99448026Smckusick 			error = VOP_ACCESS(vp, mode, cred, p);
9956254Sroot 	}
99637741Smckusick 	vput(vp);
99737741Smckusick out1:
99842441Smckusick 	cred->cr_uid = svuid;
99942441Smckusick 	cred->cr_groups[0] = svgid;
100047540Skarels 	return (error);
10016254Sroot }
10026254Sroot 
100353468Smckusick #ifdef COMPAT_43
10046254Sroot /*
100549365Smckusick  * Stat system call.
100649365Smckusick  * This version follows links.
100737Sbill  */
100842441Smckusick /* ARGSUSED */
100953759Smckusick ostat(p, uap, retval)
101045914Smckusick 	struct proc *p;
101142441Smckusick 	register struct args {
101242441Smckusick 		char	*fname;
101353468Smckusick 		struct ostat *ub;
101453468Smckusick 	} *uap;
101553468Smckusick 	int *retval;
101653468Smckusick {
101753468Smckusick 	struct stat sb;
101853468Smckusick 	struct ostat osb;
101953468Smckusick 	int error;
102053468Smckusick 	struct nameidata nd;
102153468Smckusick 
102253468Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
102353468Smckusick 	if (error = namei(&nd))
102453468Smckusick 		return (error);
102553468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
102653468Smckusick 	vput(nd.ni_vp);
102753468Smckusick 	if (error)
102853468Smckusick 		return (error);
102953468Smckusick 	cvtstat(&sb, &osb);
103053468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
103153468Smckusick 	return (error);
103253468Smckusick }
103353468Smckusick 
103453468Smckusick /*
103553468Smckusick  * Lstat system call.
103653468Smckusick  * This version does not follow links.
103753468Smckusick  */
103853468Smckusick /* ARGSUSED */
103953759Smckusick olstat(p, uap, retval)
104053468Smckusick 	struct proc *p;
104153468Smckusick 	register struct args {
104253468Smckusick 		char	*fname;
104353468Smckusick 		struct ostat *ub;
104453468Smckusick 	} *uap;
104553468Smckusick 	int *retval;
104653468Smckusick {
104753468Smckusick 	struct stat sb;
104853468Smckusick 	struct ostat osb;
104953468Smckusick 	int error;
105053468Smckusick 	struct nameidata nd;
105153468Smckusick 
105253468Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
105353468Smckusick 	if (error = namei(&nd))
105453468Smckusick 		return (error);
105553468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
105653468Smckusick 	vput(nd.ni_vp);
105753468Smckusick 	if (error)
105853468Smckusick 		return (error);
105953468Smckusick 	cvtstat(&sb, &osb);
106053468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
106153468Smckusick 	return (error);
106253468Smckusick }
106353468Smckusick 
106453468Smckusick /*
106553468Smckusick  * convert from an old to a new stat structure.
106653468Smckusick  */
106753468Smckusick cvtstat(st, ost)
106853468Smckusick 	struct stat *st;
106953468Smckusick 	struct ostat *ost;
107053468Smckusick {
107153468Smckusick 
107253468Smckusick 	ost->st_dev = st->st_dev;
107353468Smckusick 	ost->st_ino = st->st_ino;
107453468Smckusick 	ost->st_mode = st->st_mode;
107553468Smckusick 	ost->st_nlink = st->st_nlink;
107653468Smckusick 	ost->st_uid = st->st_uid;
107753468Smckusick 	ost->st_gid = st->st_gid;
107853468Smckusick 	ost->st_rdev = st->st_rdev;
107953468Smckusick 	if (st->st_size < (quad_t)1 << 32)
108053468Smckusick 		ost->st_size = st->st_size;
108153468Smckusick 	else
108253468Smckusick 		ost->st_size = -2;
108353468Smckusick 	ost->st_atime = st->st_atime;
108453468Smckusick 	ost->st_mtime = st->st_mtime;
108553468Smckusick 	ost->st_ctime = st->st_ctime;
108653468Smckusick 	ost->st_blksize = st->st_blksize;
108753468Smckusick 	ost->st_blocks = st->st_blocks;
108853468Smckusick 	ost->st_flags = st->st_flags;
108953468Smckusick 	ost->st_gen = st->st_gen;
109053468Smckusick }
109153468Smckusick #endif /* COMPAT_43 */
109253468Smckusick 
109353468Smckusick /*
109453468Smckusick  * Stat system call.
109553468Smckusick  * This version follows links.
109653468Smckusick  */
109753468Smckusick /* ARGSUSED */
109853759Smckusick stat(p, uap, retval)
109953468Smckusick 	struct proc *p;
110053468Smckusick 	register struct args {
110153468Smckusick 		char	*fname;
110242441Smckusick 		struct stat *ub;
110342441Smckusick 	} *uap;
110442441Smckusick 	int *retval;
110537Sbill {
110642441Smckusick 	struct stat sb;
110742441Smckusick 	int error;
110847540Skarels 	struct nameidata nd;
110937Sbill 
111052322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
111152322Smckusick 	if (error = namei(&nd))
111247540Skarels 		return (error);
111352322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
111452322Smckusick 	vput(nd.ni_vp);
111542441Smckusick 	if (error)
111647540Skarels 		return (error);
111742441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
111847540Skarels 	return (error);
111937Sbill }
112037Sbill 
112137Sbill /*
112249365Smckusick  * Lstat system call.
112349365Smckusick  * This version does not follow links.
11245992Swnj  */
112542441Smckusick /* ARGSUSED */
112653759Smckusick lstat(p, uap, retval)
112745914Smckusick 	struct proc *p;
112842441Smckusick 	register struct args {
11295992Swnj 		char	*fname;
113012756Ssam 		struct stat *ub;
113142441Smckusick 	} *uap;
113242441Smckusick 	int *retval;
113342441Smckusick {
113412756Ssam 	struct stat sb;
113537741Smckusick 	int error;
113647540Skarels 	struct nameidata nd;
11375992Swnj 
113852322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
113952322Smckusick 	if (error = namei(&nd))
114047540Skarels 		return (error);
114152322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
114252322Smckusick 	vput(nd.ni_vp);
114337741Smckusick 	if (error)
114447540Skarels 		return (error);
114537741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
114647540Skarels 	return (error);
11475992Swnj }
11485992Swnj 
11495992Swnj /*
115049365Smckusick  * Return target name of a symbolic link.
115137Sbill  */
115242441Smckusick /* ARGSUSED */
115342441Smckusick readlink(p, uap, retval)
115445914Smckusick 	struct proc *p;
115542441Smckusick 	register struct args {
11565992Swnj 		char	*name;
11575992Swnj 		char	*buf;
11585992Swnj 		int	count;
115942441Smckusick 	} *uap;
116042441Smckusick 	int *retval;
116142441Smckusick {
116253548Sheideman 	USES_VOP_READLINK;
116337741Smckusick 	register struct vnode *vp;
116437741Smckusick 	struct iovec aiov;
116537741Smckusick 	struct uio auio;
116637741Smckusick 	int error;
116747540Skarels 	struct nameidata nd;
11685992Swnj 
116952322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p);
117052322Smckusick 	if (error = namei(&nd))
117147540Skarels 		return (error);
117252322Smckusick 	vp = nd.ni_vp;
117337741Smckusick 	if (vp->v_type != VLNK) {
117437741Smckusick 		error = EINVAL;
11755992Swnj 		goto out;
11765992Swnj 	}
117737741Smckusick 	aiov.iov_base = uap->buf;
117837741Smckusick 	aiov.iov_len = uap->count;
117937741Smckusick 	auio.uio_iov = &aiov;
118037741Smckusick 	auio.uio_iovcnt = 1;
118137741Smckusick 	auio.uio_offset = 0;
118237741Smckusick 	auio.uio_rw = UIO_READ;
118337741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
118448026Smckusick 	auio.uio_procp = p;
118537741Smckusick 	auio.uio_resid = uap->count;
118647540Skarels 	error = VOP_READLINK(vp, &auio, p->p_ucred);
11875992Swnj out:
118837741Smckusick 	vput(vp);
118942441Smckusick 	*retval = uap->count - auio.uio_resid;
119047540Skarels 	return (error);
11915992Swnj }
11925992Swnj 
11939167Ssam /*
119438259Smckusick  * Change flags of a file given path name.
119538259Smckusick  */
119642441Smckusick /* ARGSUSED */
119742441Smckusick chflags(p, uap, retval)
119845914Smckusick 	struct proc *p;
119942441Smckusick 	register struct args {
120038259Smckusick 		char	*fname;
120138259Smckusick 		int	flags;
120242441Smckusick 	} *uap;
120342441Smckusick 	int *retval;
120442441Smckusick {
120553548Sheideman 	USES_VOP_SETATTR;
120638259Smckusick 	register struct vnode *vp;
120738259Smckusick 	struct vattr vattr;
120838259Smckusick 	int error;
120947540Skarels 	struct nameidata nd;
121038259Smckusick 
121152322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
121252322Smckusick 	if (error = namei(&nd))
121347540Skarels 		return (error);
121452322Smckusick 	vp = nd.ni_vp;
121541400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
121638259Smckusick 		error = EROFS;
121738259Smckusick 		goto out;
121838259Smckusick 	}
121945785Sbostic 	VATTR_NULL(&vattr);
122045785Sbostic 	vattr.va_flags = uap->flags;
122152192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
122248026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
122338259Smckusick out:
122438259Smckusick 	vput(vp);
122547540Skarels 	return (error);
122638259Smckusick }
122738259Smckusick 
122838259Smckusick /*
122938259Smckusick  * Change flags of a file given a file descriptor.
123038259Smckusick  */
123142441Smckusick /* ARGSUSED */
123242441Smckusick fchflags(p, uap, retval)
123345914Smckusick 	struct proc *p;
123442441Smckusick 	register struct args {
123538259Smckusick 		int	fd;
123638259Smckusick 		int	flags;
123742441Smckusick 	} *uap;
123842441Smckusick 	int *retval;
123942441Smckusick {
124053548Sheideman 	USES_VOP_LOCK;
124153548Sheideman 	USES_VOP_SETATTR;
124253548Sheideman 	USES_VOP_UNLOCK;
124338259Smckusick 	struct vattr vattr;
124438259Smckusick 	struct vnode *vp;
124538259Smckusick 	struct file *fp;
124638259Smckusick 	int error;
124738259Smckusick 
124845914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
124947540Skarels 		return (error);
125038259Smckusick 	vp = (struct vnode *)fp->f_data;
125138259Smckusick 	VOP_LOCK(vp);
125241400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
125338259Smckusick 		error = EROFS;
125438259Smckusick 		goto out;
125538259Smckusick 	}
125645785Sbostic 	VATTR_NULL(&vattr);
125745785Sbostic 	vattr.va_flags = uap->flags;
125852192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
125948026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
126038259Smckusick out:
126138259Smckusick 	VOP_UNLOCK(vp);
126247540Skarels 	return (error);
126338259Smckusick }
126438259Smckusick 
126538259Smckusick /*
12669167Ssam  * Change mode of a file given path name.
12679167Ssam  */
126842441Smckusick /* ARGSUSED */
126942441Smckusick chmod(p, uap, retval)
127045914Smckusick 	struct proc *p;
127142441Smckusick 	register struct args {
12726254Sroot 		char	*fname;
12736254Sroot 		int	fmode;
127442441Smckusick 	} *uap;
127542441Smckusick 	int *retval;
127642441Smckusick {
127753548Sheideman 	USES_VOP_SETATTR;
127837741Smckusick 	register struct vnode *vp;
127937741Smckusick 	struct vattr vattr;
128037741Smckusick 	int error;
128147540Skarels 	struct nameidata nd;
12825992Swnj 
128352322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
128452322Smckusick 	if (error = namei(&nd))
128547540Skarels 		return (error);
128652322Smckusick 	vp = nd.ni_vp;
128741400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
128837741Smckusick 		error = EROFS;
128937741Smckusick 		goto out;
129037741Smckusick 	}
129145785Sbostic 	VATTR_NULL(&vattr);
129245785Sbostic 	vattr.va_mode = uap->fmode & 07777;
129352192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
129448026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
129537741Smckusick out:
129637741Smckusick 	vput(vp);
129747540Skarels 	return (error);
12987701Ssam }
12997439Sroot 
13009167Ssam /*
13019167Ssam  * Change mode of a file given a file descriptor.
13029167Ssam  */
130342441Smckusick /* ARGSUSED */
130442441Smckusick fchmod(p, uap, retval)
130545914Smckusick 	struct proc *p;
130642441Smckusick 	register struct args {
13077701Ssam 		int	fd;
13087701Ssam 		int	fmode;
130942441Smckusick 	} *uap;
131042441Smckusick 	int *retval;
131142441Smckusick {
131253548Sheideman 	USES_VOP_LOCK;
131353548Sheideman 	USES_VOP_SETATTR;
131453548Sheideman 	USES_VOP_UNLOCK;
131537741Smckusick 	struct vattr vattr;
131637741Smckusick 	struct vnode *vp;
131737741Smckusick 	struct file *fp;
131837741Smckusick 	int error;
13197701Ssam 
132045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
132147540Skarels 		return (error);
132237741Smckusick 	vp = (struct vnode *)fp->f_data;
132337741Smckusick 	VOP_LOCK(vp);
132441400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
132537741Smckusick 		error = EROFS;
132637741Smckusick 		goto out;
13277439Sroot 	}
132845785Sbostic 	VATTR_NULL(&vattr);
132945785Sbostic 	vattr.va_mode = uap->fmode & 07777;
133052192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
133148026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
133237741Smckusick out:
133337741Smckusick 	VOP_UNLOCK(vp);
133447540Skarels 	return (error);
13355992Swnj }
13365992Swnj 
13379167Ssam /*
13389167Ssam  * Set ownership given a path name.
13399167Ssam  */
134042441Smckusick /* ARGSUSED */
134142441Smckusick chown(p, uap, retval)
134245914Smckusick 	struct proc *p;
134342441Smckusick 	register struct args {
13446254Sroot 		char	*fname;
13456254Sroot 		int	uid;
13466254Sroot 		int	gid;
134742441Smckusick 	} *uap;
134842441Smckusick 	int *retval;
134942441Smckusick {
135053548Sheideman 	USES_VOP_SETATTR;
135137741Smckusick 	register struct vnode *vp;
135237741Smckusick 	struct vattr vattr;
135337741Smckusick 	int error;
135447540Skarels 	struct nameidata nd;
135537Sbill 
135652322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
135752322Smckusick 	if (error = namei(&nd))
135847540Skarels 		return (error);
135952322Smckusick 	vp = nd.ni_vp;
136041400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
136137741Smckusick 		error = EROFS;
136237741Smckusick 		goto out;
136337741Smckusick 	}
136445785Sbostic 	VATTR_NULL(&vattr);
136545785Sbostic 	vattr.va_uid = uap->uid;
136645785Sbostic 	vattr.va_gid = uap->gid;
136752192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
136848026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
136937741Smckusick out:
137037741Smckusick 	vput(vp);
137147540Skarels 	return (error);
13727701Ssam }
13737439Sroot 
13749167Ssam /*
13759167Ssam  * Set ownership given a file descriptor.
13769167Ssam  */
137742441Smckusick /* ARGSUSED */
137842441Smckusick fchown(p, uap, retval)
137945914Smckusick 	struct proc *p;
138042441Smckusick 	register struct args {
13817701Ssam 		int	fd;
13827701Ssam 		int	uid;
13837701Ssam 		int	gid;
138442441Smckusick 	} *uap;
138542441Smckusick 	int *retval;
138642441Smckusick {
138753548Sheideman 	USES_VOP_LOCK;
138853548Sheideman 	USES_VOP_SETATTR;
138953548Sheideman 	USES_VOP_UNLOCK;
139037741Smckusick 	struct vattr vattr;
139137741Smckusick 	struct vnode *vp;
139237741Smckusick 	struct file *fp;
139337741Smckusick 	int error;
13947701Ssam 
139545914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
139647540Skarels 		return (error);
139737741Smckusick 	vp = (struct vnode *)fp->f_data;
139837741Smckusick 	VOP_LOCK(vp);
139941400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
140037741Smckusick 		error = EROFS;
140137741Smckusick 		goto out;
140237741Smckusick 	}
140345785Sbostic 	VATTR_NULL(&vattr);
140445785Sbostic 	vattr.va_uid = uap->uid;
140545785Sbostic 	vattr.va_gid = uap->gid;
140652192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
140748026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
140837741Smckusick out:
140937741Smckusick 	VOP_UNLOCK(vp);
141047540Skarels 	return (error);
14117701Ssam }
14127701Ssam 
141342441Smckusick /*
141442441Smckusick  * Set the access and modification times of a file.
141542441Smckusick  */
141642441Smckusick /* ARGSUSED */
141742441Smckusick utimes(p, uap, retval)
141845914Smckusick 	struct proc *p;
141942441Smckusick 	register struct args {
142011811Ssam 		char	*fname;
142111811Ssam 		struct	timeval *tptr;
142242441Smckusick 	} *uap;
142342441Smckusick 	int *retval;
142442441Smckusick {
142553548Sheideman 	USES_VOP_SETATTR;
142637741Smckusick 	register struct vnode *vp;
142711811Ssam 	struct timeval tv[2];
142837741Smckusick 	struct vattr vattr;
142937741Smckusick 	int error;
143047540Skarels 	struct nameidata nd;
143111811Ssam 
143237741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
143347540Skarels 		return (error);
143452322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
143552322Smckusick 	if (error = namei(&nd))
143647540Skarels 		return (error);
143752322Smckusick 	vp = nd.ni_vp;
143841400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
143937741Smckusick 		error = EROFS;
144037741Smckusick 		goto out;
144121015Smckusick 	}
144245785Sbostic 	VATTR_NULL(&vattr);
144354100Smckusick 	vattr.va_atime.ts_sec = tv[0].tv_sec;
144454100Smckusick 	vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
144554100Smckusick 	vattr.va_mtime.ts_sec = tv[1].tv_sec;
144654100Smckusick 	vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
144752192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
144848026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
144937741Smckusick out:
145037741Smckusick 	vput(vp);
145147540Skarels 	return (error);
145211811Ssam }
145311811Ssam 
145453468Smckusick #ifdef COMPAT_43
14559167Ssam /*
14569167Ssam  * Truncate a file given its path name.
14579167Ssam  */
145842441Smckusick /* ARGSUSED */
145942441Smckusick truncate(p, uap, retval)
146045914Smckusick 	struct proc *p;
146142441Smckusick 	register struct args {
14627701Ssam 		char	*fname;
146353468Smckusick 		long	length;
146453468Smckusick 	} *uap;
146553468Smckusick 	int *retval;
146653468Smckusick {
146753468Smckusick 	struct nargs {
146853468Smckusick 		char	*fname;
146926473Skarels 		off_t	length;
147053468Smckusick 	} nuap;
147153468Smckusick 
147253468Smckusick 	nuap.fname = uap->fname;
147353468Smckusick 	nuap.length = uap->length;
147453759Smckusick 	return (__truncate(p, &nuap, retval));
147553468Smckusick }
147653468Smckusick 
147753468Smckusick /*
147853468Smckusick  * Truncate a file given a file descriptor.
147953468Smckusick  */
148053468Smckusick /* ARGSUSED */
148153468Smckusick ftruncate(p, uap, retval)
148253468Smckusick 	struct proc *p;
148353468Smckusick 	register struct args {
148453468Smckusick 		int	fd;
148553468Smckusick 		long	length;
148642441Smckusick 	} *uap;
148742441Smckusick 	int *retval;
148842441Smckusick {
148953468Smckusick 	struct nargs {
149053468Smckusick 		int	fd;
149153468Smckusick 		off_t	length;
149253468Smckusick 	} nuap;
149353468Smckusick 
149453468Smckusick 	nuap.fd = uap->fd;
149553468Smckusick 	nuap.length = uap->length;
149653759Smckusick 	return (__ftruncate(p, &nuap, retval));
149753468Smckusick }
149853468Smckusick #endif /* COMPAT_43 */
149953468Smckusick 
150053468Smckusick /*
150153468Smckusick  * Truncate a file given its path name.
150253468Smckusick  */
150353468Smckusick /* ARGSUSED */
150453759Smckusick __truncate(p, uap, retval)
150553468Smckusick 	struct proc *p;
150653468Smckusick 	register struct args {
150753468Smckusick 		char	*fname;
150853468Smckusick 		off_t	length;
150953468Smckusick 	} *uap;
151053468Smckusick 	int *retval;
151153468Smckusick {
151253548Sheideman 	USES_VOP_ACCESS;
151353548Sheideman 	USES_VOP_SETATTR;
151437741Smckusick 	register struct vnode *vp;
151537741Smckusick 	struct vattr vattr;
151637741Smckusick 	int error;
151747540Skarels 	struct nameidata nd;
15187701Ssam 
151952322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
152052322Smckusick 	if (error = namei(&nd))
152147540Skarels 		return (error);
152252322Smckusick 	vp = nd.ni_vp;
152337741Smckusick 	if (vp->v_type == VDIR) {
152437741Smckusick 		error = EISDIR;
152537741Smckusick 		goto out;
15267701Ssam 	}
152738399Smckusick 	if ((error = vn_writechk(vp)) ||
152848026Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)))
152937741Smckusick 		goto out;
153045785Sbostic 	VATTR_NULL(&vattr);
153145785Sbostic 	vattr.va_size = uap->length;
153252192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
153348026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
153437741Smckusick out:
153537741Smckusick 	vput(vp);
153647540Skarels 	return (error);
15377701Ssam }
15387701Ssam 
15399167Ssam /*
15409167Ssam  * Truncate a file given a file descriptor.
15419167Ssam  */
154242441Smckusick /* ARGSUSED */
154353759Smckusick __ftruncate(p, uap, retval)
154445914Smckusick 	struct proc *p;
154542441Smckusick 	register struct args {
15467701Ssam 		int	fd;
154726473Skarels 		off_t	length;
154842441Smckusick 	} *uap;
154942441Smckusick 	int *retval;
155042441Smckusick {
155153548Sheideman 	USES_VOP_LOCK;
155253548Sheideman 	USES_VOP_SETATTR;
155353548Sheideman 	USES_VOP_UNLOCK;
155437741Smckusick 	struct vattr vattr;
155537741Smckusick 	struct vnode *vp;
15567701Ssam 	struct file *fp;
155737741Smckusick 	int error;
15587701Ssam 
155945914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
156047540Skarels 		return (error);
156137741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
156247540Skarels 		return (EINVAL);
156337741Smckusick 	vp = (struct vnode *)fp->f_data;
156437741Smckusick 	VOP_LOCK(vp);
156537741Smckusick 	if (vp->v_type == VDIR) {
156637741Smckusick 		error = EISDIR;
156737741Smckusick 		goto out;
15687701Ssam 	}
156938399Smckusick 	if (error = vn_writechk(vp))
157037741Smckusick 		goto out;
157145785Sbostic 	VATTR_NULL(&vattr);
157245785Sbostic 	vattr.va_size = uap->length;
157352192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
157448026Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
157537741Smckusick out:
157637741Smckusick 	VOP_UNLOCK(vp);
157747540Skarels 	return (error);
15787701Ssam }
15797701Ssam 
15809167Ssam /*
15819167Ssam  * Synch an open file.
15829167Ssam  */
158342441Smckusick /* ARGSUSED */
158442441Smckusick fsync(p, uap, retval)
158545914Smckusick 	struct proc *p;
158642441Smckusick 	struct args {
158742441Smckusick 		int	fd;
158842441Smckusick 	} *uap;
158942441Smckusick 	int *retval;
15909167Ssam {
159153548Sheideman 	USES_VOP_FSYNC;
159253548Sheideman 	USES_VOP_LOCK;
159353548Sheideman 	USES_VOP_UNLOCK;
159439592Smckusick 	register struct vnode *vp;
15959167Ssam 	struct file *fp;
159637741Smckusick 	int error;
15979167Ssam 
159845914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
159947540Skarels 		return (error);
160039592Smckusick 	vp = (struct vnode *)fp->f_data;
160139592Smckusick 	VOP_LOCK(vp);
160248026Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT, p);
160339592Smckusick 	VOP_UNLOCK(vp);
160447540Skarels 	return (error);
16059167Ssam }
16069167Ssam 
16079167Ssam /*
16089167Ssam  * Rename system call.
16099167Ssam  *
16109167Ssam  * Source and destination must either both be directories, or both
16119167Ssam  * not be directories.  If target is a directory, it must be empty.
16129167Ssam  */
161342441Smckusick /* ARGSUSED */
161442441Smckusick rename(p, uap, retval)
161545914Smckusick 	struct proc *p;
161642441Smckusick 	register struct args {
16177701Ssam 		char	*from;
16187701Ssam 		char	*to;
161942441Smckusick 	} *uap;
162042441Smckusick 	int *retval;
162142441Smckusick {
162253548Sheideman 	USES_VOP_ABORTOP;
162353548Sheideman 	USES_VOP_RENAME;
162437741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
162549735Smckusick 	struct nameidata fromnd, tond;
162637741Smckusick 	int error;
16277701Ssam 
162852322Smckusick 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
162952322Smckusick 		uap->from, p);
163052322Smckusick 	if (error = namei(&fromnd))
163147540Skarels 		return (error);
163249735Smckusick 	fvp = fromnd.ni_vp;
163352322Smckusick 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
163452322Smckusick 		UIO_USERSPACE, uap->to, p);
163552322Smckusick 	if (error = namei(&tond)) {
163652230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
163749735Smckusick 		vrele(fromnd.ni_dvp);
163842465Smckusick 		vrele(fvp);
163942465Smckusick 		goto out1;
164042465Smckusick 	}
164137741Smckusick 	tdvp = tond.ni_dvp;
164237741Smckusick 	tvp = tond.ni_vp;
164337741Smckusick 	if (tvp != NULL) {
164437741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
164539242Sbostic 			error = ENOTDIR;
164637741Smckusick 			goto out;
164737741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
164839242Sbostic 			error = EISDIR;
164937741Smckusick 			goto out;
16509167Ssam 		}
16519167Ssam 	}
165239286Smckusick 	if (fvp == tdvp)
165337741Smckusick 		error = EINVAL;
165439286Smckusick 	/*
165549735Smckusick 	 * If source is the same as the destination (that is the
165649735Smckusick 	 * same inode number with the same name in the same directory),
165739286Smckusick 	 * then there is nothing to do.
165839286Smckusick 	 */
165949735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
166052322Smckusick 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
166152322Smckusick 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
166252322Smckusick 	      fromnd.ni_cnd.cn_namelen))
166339286Smckusick 		error = -1;
166437741Smckusick out:
166542465Smckusick 	if (!error) {
166652192Smckusick 		LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE);
166752192Smckusick 		if (fromnd.ni_dvp != tdvp)
166852192Smckusick 			LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
166952192Smckusick 		if (tvp)
167052192Smckusick 			LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE);
167152230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
167252230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
167342465Smckusick 	} else {
167452230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
167543344Smckusick 		if (tdvp == tvp)
167643344Smckusick 			vrele(tdvp);
167743344Smckusick 		else
167843344Smckusick 			vput(tdvp);
167942465Smckusick 		if (tvp)
168042465Smckusick 			vput(tvp);
168152230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
168249735Smckusick 		vrele(fromnd.ni_dvp);
168342465Smckusick 		vrele(fvp);
16849167Ssam 	}
168549735Smckusick 	vrele(tond.ni_startdir);
168652322Smckusick 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
168737741Smckusick out1:
168849735Smckusick 	vrele(fromnd.ni_startdir);
168952322Smckusick 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
169039286Smckusick 	if (error == -1)
169147540Skarels 		return (0);
169247540Skarels 	return (error);
16937701Ssam }
16947701Ssam 
16957535Sroot /*
169649365Smckusick  * Mkdir system call.
169712756Ssam  */
169842441Smckusick /* ARGSUSED */
169942441Smckusick mkdir(p, uap, retval)
170045914Smckusick 	struct proc *p;
170142441Smckusick 	register struct args {
170212756Ssam 		char	*name;
170312756Ssam 		int	dmode;
170442441Smckusick 	} *uap;
170542441Smckusick 	int *retval;
170642441Smckusick {
170753548Sheideman 	USES_VOP_ABORTOP;
170853548Sheideman 	USES_VOP_MKDIR;
170937741Smckusick 	register struct vnode *vp;
171037741Smckusick 	struct vattr vattr;
171137741Smckusick 	int error;
171247540Skarels 	struct nameidata nd;
171312756Ssam 
171452322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p);
171552322Smckusick 	if (error = namei(&nd))
171647540Skarels 		return (error);
171752322Smckusick 	vp = nd.ni_vp;
171837741Smckusick 	if (vp != NULL) {
171952322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
172052322Smckusick 		if (nd.ni_dvp == vp)
172152322Smckusick 			vrele(nd.ni_dvp);
172243344Smckusick 		else
172352322Smckusick 			vput(nd.ni_dvp);
172442465Smckusick 		vrele(vp);
172547540Skarels 		return (EEXIST);
172612756Ssam 	}
172741362Smckusick 	VATTR_NULL(&vattr);
172837741Smckusick 	vattr.va_type = VDIR;
172945914Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask;
173052322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
173152322Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
173238145Smckusick 	if (!error)
173352322Smckusick 		vput(nd.ni_vp);
173447540Skarels 	return (error);
173512756Ssam }
173612756Ssam 
173712756Ssam /*
173812756Ssam  * Rmdir system call.
173912756Ssam  */
174042441Smckusick /* ARGSUSED */
174142441Smckusick rmdir(p, uap, retval)
174245914Smckusick 	struct proc *p;
174342441Smckusick 	struct args {
174442441Smckusick 		char	*name;
174542441Smckusick 	} *uap;
174642441Smckusick 	int *retval;
174712756Ssam {
174853548Sheideman 	USES_VOP_ABORTOP;
174953548Sheideman 	USES_VOP_RMDIR;
175037741Smckusick 	register struct vnode *vp;
175137741Smckusick 	int error;
175247540Skarels 	struct nameidata nd;
175312756Ssam 
175452322Smckusick 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p);
175552322Smckusick 	if (error = namei(&nd))
175647540Skarels 		return (error);
175752322Smckusick 	vp = nd.ni_vp;
175837741Smckusick 	if (vp->v_type != VDIR) {
175937741Smckusick 		error = ENOTDIR;
176012756Ssam 		goto out;
176112756Ssam 	}
176212756Ssam 	/*
176337741Smckusick 	 * No rmdir "." please.
176412756Ssam 	 */
176552322Smckusick 	if (nd.ni_dvp == vp) {
176637741Smckusick 		error = EINVAL;
176712756Ssam 		goto out;
176812756Ssam 	}
176912756Ssam 	/*
177049365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
177112756Ssam 	 */
177237741Smckusick 	if (vp->v_flag & VROOT)
177337741Smckusick 		error = EBUSY;
177412756Ssam out:
177542465Smckusick 	if (!error) {
177652322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
177752192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
177852322Smckusick 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
177942465Smckusick 	} else {
178052322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
178152322Smckusick 		if (nd.ni_dvp == vp)
178252322Smckusick 			vrele(nd.ni_dvp);
178343344Smckusick 		else
178452322Smckusick 			vput(nd.ni_dvp);
178542465Smckusick 		vput(vp);
178642465Smckusick 	}
178747540Skarels 	return (error);
178812756Ssam }
178912756Ssam 
179037741Smckusick /*
179149365Smckusick  * Read a block of directory entries in a file system independent format.
179237741Smckusick  */
179342441Smckusick getdirentries(p, uap, retval)
179445914Smckusick 	struct proc *p;
179542441Smckusick 	register struct args {
179637741Smckusick 		int	fd;
179737741Smckusick 		char	*buf;
179837741Smckusick 		unsigned count;
179937741Smckusick 		long	*basep;
180042441Smckusick 	} *uap;
180142441Smckusick 	int *retval;
180242441Smckusick {
180353548Sheideman 	USES_VOP_LOCK;
180453548Sheideman 	USES_VOP_READDIR;
180553548Sheideman 	USES_VOP_UNLOCK;
180639592Smckusick 	register struct vnode *vp;
180716540Ssam 	struct file *fp;
180837741Smckusick 	struct uio auio;
180937741Smckusick 	struct iovec aiov;
181038129Smckusick 	off_t off;
181140321Smckusick 	int error, eofflag;
181212756Ssam 
181345914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
181447540Skarels 		return (error);
181537741Smckusick 	if ((fp->f_flag & FREAD) == 0)
181647540Skarels 		return (EBADF);
181739592Smckusick 	vp = (struct vnode *)fp->f_data;
181839592Smckusick 	if (vp->v_type != VDIR)
181947540Skarels 		return (EINVAL);
182037741Smckusick 	aiov.iov_base = uap->buf;
182137741Smckusick 	aiov.iov_len = uap->count;
182237741Smckusick 	auio.uio_iov = &aiov;
182337741Smckusick 	auio.uio_iovcnt = 1;
182437741Smckusick 	auio.uio_rw = UIO_READ;
182537741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
182648026Smckusick 	auio.uio_procp = p;
182737741Smckusick 	auio.uio_resid = uap->count;
182839592Smckusick 	VOP_LOCK(vp);
182939592Smckusick 	auio.uio_offset = off = fp->f_offset;
183040321Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
183139592Smckusick 	fp->f_offset = auio.uio_offset;
183239592Smckusick 	VOP_UNLOCK(vp);
183339592Smckusick 	if (error)
183447540Skarels 		return (error);
183539592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
183642441Smckusick 	*retval = uap->count - auio.uio_resid;
183747540Skarels 	return (error);
183812756Ssam }
183912756Ssam 
184012756Ssam /*
184149365Smckusick  * Set the mode mask for creation of filesystem nodes.
184212756Ssam  */
184342441Smckusick mode_t
184442441Smckusick umask(p, uap, retval)
184545914Smckusick 	struct proc *p;
184642441Smckusick 	struct args {
184742441Smckusick 		int	mask;
184842441Smckusick 	} *uap;
184942441Smckusick 	int *retval;
185012756Ssam {
185145914Smckusick 	register struct filedesc *fdp = p->p_fd;
185212756Ssam 
185345914Smckusick 	*retval = fdp->fd_cmask;
185445914Smckusick 	fdp->fd_cmask = uap->mask & 07777;
185547540Skarels 	return (0);
185612756Ssam }
185737741Smckusick 
185839566Smarc /*
185939566Smarc  * Void all references to file by ripping underlying filesystem
186039566Smarc  * away from vnode.
186139566Smarc  */
186242441Smckusick /* ARGSUSED */
186342441Smckusick revoke(p, uap, retval)
186445914Smckusick 	struct proc *p;
186542441Smckusick 	register struct args {
186639566Smarc 		char	*fname;
186742441Smckusick 	} *uap;
186842441Smckusick 	int *retval;
186942441Smckusick {
187053548Sheideman 	USES_VOP_GETATTR;
187139566Smarc 	register struct vnode *vp;
187239566Smarc 	struct vattr vattr;
187339566Smarc 	int error;
187447540Skarels 	struct nameidata nd;
187539566Smarc 
187652322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
187752322Smckusick 	if (error = namei(&nd))
187847540Skarels 		return (error);
187952322Smckusick 	vp = nd.ni_vp;
188039566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
188139566Smarc 		error = EINVAL;
188239566Smarc 		goto out;
188339566Smarc 	}
188448026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
188539566Smarc 		goto out;
188647540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
188747540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
188839566Smarc 		goto out;
188939805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
189039632Smckusick 		vgoneall(vp);
189139566Smarc out:
189239566Smarc 	vrele(vp);
189347540Skarels 	return (error);
189439566Smarc }
189539566Smarc 
189649365Smckusick /*
189749365Smckusick  * Convert a user file descriptor to a kernel file entry.
189849365Smckusick  */
189945914Smckusick getvnode(fdp, fdes, fpp)
190045914Smckusick 	struct filedesc *fdp;
190137741Smckusick 	struct file **fpp;
190237741Smckusick 	int fdes;
190337741Smckusick {
190437741Smckusick 	struct file *fp;
190537741Smckusick 
190647540Skarels 	if ((unsigned)fdes >= fdp->fd_nfiles ||
190747688Skarels 	    (fp = fdp->fd_ofiles[fdes]) == NULL)
190837741Smckusick 		return (EBADF);
190937741Smckusick 	if (fp->f_type != DTYPE_VNODE)
191037741Smckusick 		return (EINVAL);
191137741Smckusick 	*fpp = fp;
191237741Smckusick 	return (0);
191337741Smckusick }
1914