xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 59382)
123405Smckusick /*
237741Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337741Smckusick  * All rights reserved.
423405Smckusick  *
544459Sbostic  * %sccs.include.redist.c%
637741Smckusick  *
7*59382Smckusick  *	@(#)vfs_syscalls.c	7.107 (Berkeley) 04/27/93
823405Smckusick  */
937Sbill 
1056517Sbostic #include <sys/param.h>
1156517Sbostic #include <sys/systm.h>
1256517Sbostic #include <sys/namei.h>
1356517Sbostic #include <sys/filedesc.h>
1456517Sbostic #include <sys/kernel.h>
1556517Sbostic #include <sys/file.h>
1656517Sbostic #include <sys/stat.h>
1756517Sbostic #include <sys/vnode.h>
1856517Sbostic #include <sys/mount.h>
1956517Sbostic #include <sys/proc.h>
2056517Sbostic #include <sys/uio.h>
2156517Sbostic #include <sys/malloc.h>
2256517Sbostic #include <sys/dirent.h>
2356517Sbostic 
2453468Smckusick #include <vm/vm.h>
2537Sbill 
2637741Smckusick /*
2737741Smckusick  * Virtual File System System Calls
2837741Smckusick  */
2912756Ssam 
309167Ssam /*
3149365Smckusick  * Mount system call.
329167Ssam  */
3354916Storek struct mount_args {
3454916Storek 	int	type;
3554916Storek 	char	*dir;
3654916Storek 	int	flags;
3754916Storek 	caddr_t	data;
3854916Storek };
3942441Smckusick /* ARGSUSED */
4042441Smckusick mount(p, uap, retval)
4145914Smckusick 	struct proc *p;
4254916Storek 	register struct mount_args *uap;
4342441Smckusick 	int *retval;
4442441Smckusick {
4539335Smckusick 	register struct vnode *vp;
4639335Smckusick 	register struct mount *mp;
4740111Smckusick 	int error, flag;
4847540Skarels 	struct nameidata nd;
496254Sroot 
5037741Smckusick 	/*
5137741Smckusick 	 * Must be super user
5237741Smckusick 	 */
5347540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
5447540Skarels 		return (error);
5537741Smckusick 	/*
5637741Smckusick 	 * Get vnode to be covered
5737741Smckusick 	 */
5852322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->dir, p);
5952322Smckusick 	if (error = namei(&nd))
6047540Skarels 		return (error);
6152322Smckusick 	vp = nd.ni_vp;
6241400Smckusick 	if (uap->flags & MNT_UPDATE) {
6339335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
6439335Smckusick 			vput(vp);
6547540Skarels 			return (EINVAL);
6639335Smckusick 		}
6739335Smckusick 		mp = vp->v_mount;
6857047Smckusick 		flag = mp->mnt_flag;
6939335Smckusick 		/*
7057047Smckusick 		 * We only allow the filesystem to be reloaded if it
7157047Smckusick 		 * is currently mounted read-only.
7239335Smckusick 		 */
7357047Smckusick 		if ((uap->flags & MNT_RELOAD) &&
7457047Smckusick 		    ((mp->mnt_flag & MNT_RDONLY) == 0)) {
7539335Smckusick 			vput(vp);
7647540Skarels 			return (EOPNOTSUPP);	/* Needs translation */
7739335Smckusick 		}
7857047Smckusick 		mp->mnt_flag |=
7957047Smckusick 		    uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
8039335Smckusick 		VOP_UNLOCK(vp);
8139335Smckusick 		goto update;
8239335Smckusick 	}
8355451Spendry 	if (vp->v_usecount != 1 && (uap->flags & MNT_UNION) == 0) {
8437741Smckusick 		vput(vp);
8547540Skarels 		return (EBUSY);
8637741Smckusick 	}
8757793Smckusick 	if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0))
8854441Smckusick 		return (error);
8937741Smckusick 	if (vp->v_type != VDIR) {
9037741Smckusick 		vput(vp);
9147540Skarels 		return (ENOTDIR);
9237741Smckusick 	}
9339741Smckusick 	if ((unsigned long)uap->type > MOUNT_MAXTYPE ||
9437741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
9537741Smckusick 		vput(vp);
9647540Skarels 		return (ENODEV);
9737741Smckusick 	}
9837741Smckusick 
9937741Smckusick 	/*
10039335Smckusick 	 * Allocate and initialize the file system.
10137741Smckusick 	 */
10237741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
10337741Smckusick 		M_MOUNT, M_WAITOK);
10454172Smckusick 	bzero((char *)mp, (u_long)sizeof(struct mount));
10541400Smckusick 	mp->mnt_op = vfssw[uap->type];
10639335Smckusick 	if (error = vfs_lock(mp)) {
10739335Smckusick 		free((caddr_t)mp, M_MOUNT);
10839335Smckusick 		vput(vp);
10947540Skarels 		return (error);
11039335Smckusick 	}
11139335Smckusick 	if (vp->v_mountedhere != (struct mount *)0) {
11239335Smckusick 		vfs_unlock(mp);
11339335Smckusick 		free((caddr_t)mp, M_MOUNT);
11439335Smckusick 		vput(vp);
11547540Skarels 		return (EBUSY);
11639335Smckusick 	}
11739335Smckusick 	vp->v_mountedhere = mp;
11841400Smckusick 	mp->mnt_vnodecovered = vp;
11939335Smckusick update:
12039335Smckusick 	/*
12139335Smckusick 	 * Set the mount level flags.
12239335Smckusick 	 */
12341400Smckusick 	if (uap->flags & MNT_RDONLY)
12441400Smckusick 		mp->mnt_flag |= MNT_RDONLY;
12557047Smckusick 	else if (mp->mnt_flag & MNT_RDONLY)
12657047Smckusick 		mp->mnt_flag |= MNT_WANTRDWR;
12757047Smckusick 	mp->mnt_flag &=~
12857047Smckusick 	    (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION);
12957047Smckusick 	mp->mnt_flag |= uap->flags &
13057047Smckusick 	    (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION);
13139335Smckusick 	/*
13239335Smckusick 	 * Mount the filesystem.
13339335Smckusick 	 */
13452322Smckusick 	error = VFS_MOUNT(mp, uap->dir, uap->data, &nd, p);
13541400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
13639335Smckusick 		vrele(vp);
13757047Smckusick 		if (mp->mnt_flag & MNT_WANTRDWR)
13857047Smckusick 			mp->mnt_flag &= ~MNT_RDONLY;
13957047Smckusick 		mp->mnt_flag &=~
14057047Smckusick 		    (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
14140111Smckusick 		if (error)
14241400Smckusick 			mp->mnt_flag = flag;
14347540Skarels 		return (error);
14439335Smckusick 	}
14540110Smckusick 	/*
14640110Smckusick 	 * Put the new filesystem on the mount list after root.
14740110Smckusick 	 */
14841400Smckusick 	mp->mnt_next = rootfs->mnt_next;
14941400Smckusick 	mp->mnt_prev = rootfs;
15041400Smckusick 	rootfs->mnt_next = mp;
15141400Smckusick 	mp->mnt_next->mnt_prev = mp;
15237741Smckusick 	cache_purge(vp);
15337741Smckusick 	if (!error) {
15439335Smckusick 		VOP_UNLOCK(vp);
15537741Smckusick 		vfs_unlock(mp);
15648026Smckusick 		error = VFS_START(mp, 0, p);
15737741Smckusick 	} else {
15837741Smckusick 		vfs_remove(mp);
15937741Smckusick 		free((caddr_t)mp, M_MOUNT);
16039335Smckusick 		vput(vp);
16137741Smckusick 	}
16247540Skarels 	return (error);
1636254Sroot }
1646254Sroot 
1659167Ssam /*
16637741Smckusick  * Unmount system call.
16737741Smckusick  *
16837741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
16937741Smckusick  * not special file (as before).
1709167Ssam  */
17154916Storek struct unmount_args {
17254916Storek 	char	*pathp;
17354916Storek 	int	flags;
17454916Storek };
17542441Smckusick /* ARGSUSED */
17642441Smckusick unmount(p, uap, retval)
17745914Smckusick 	struct proc *p;
17854916Storek 	register struct unmount_args *uap;
17942441Smckusick 	int *retval;
18042441Smckusick {
18137741Smckusick 	register struct vnode *vp;
18239356Smckusick 	struct mount *mp;
18337741Smckusick 	int error;
18447540Skarels 	struct nameidata nd;
1856254Sroot 
18637741Smckusick 	/*
18737741Smckusick 	 * Must be super user
18837741Smckusick 	 */
18947540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
19047540Skarels 		return (error);
19137741Smckusick 
19252322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->pathp, p);
19352322Smckusick 	if (error = namei(&nd))
19447540Skarels 		return (error);
19552322Smckusick 	vp = nd.ni_vp;
19637741Smckusick 	/*
19737741Smckusick 	 * Must be the root of the filesystem
19837741Smckusick 	 */
19937741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
20037741Smckusick 		vput(vp);
20147540Skarels 		return (EINVAL);
20237741Smckusick 	}
20337741Smckusick 	mp = vp->v_mount;
20437741Smckusick 	vput(vp);
20548026Smckusick 	return (dounmount(mp, uap->flags, p));
20639356Smckusick }
20739356Smckusick 
20839356Smckusick /*
20939356Smckusick  * Do an unmount.
21039356Smckusick  */
21148026Smckusick dounmount(mp, flags, p)
21239356Smckusick 	register struct mount *mp;
21339356Smckusick 	int flags;
21448026Smckusick 	struct proc *p;
21539356Smckusick {
21639356Smckusick 	struct vnode *coveredvp;
21739356Smckusick 	int error;
21839356Smckusick 
21941400Smckusick 	coveredvp = mp->mnt_vnodecovered;
22041298Smckusick 	if (vfs_busy(mp))
22141298Smckusick 		return (EBUSY);
22241400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
22337741Smckusick 	if (error = vfs_lock(mp))
22439356Smckusick 		return (error);
22537741Smckusick 
22645738Smckusick 	vnode_pager_umount(mp);	/* release cached vnodes */
22737741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
22854441Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 ||
22954441Smckusick 	    (flags & MNT_FORCE))
23048026Smckusick 		error = VFS_UNMOUNT(mp, flags, p);
23141400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
23241298Smckusick 	vfs_unbusy(mp);
23337741Smckusick 	if (error) {
23437741Smckusick 		vfs_unlock(mp);
23537741Smckusick 	} else {
23637741Smckusick 		vrele(coveredvp);
23737741Smckusick 		vfs_remove(mp);
23852287Smckusick 		if (mp->mnt_mounth != NULL)
23952287Smckusick 			panic("unmount: dangling vnode");
24037741Smckusick 		free((caddr_t)mp, M_MOUNT);
24137741Smckusick 	}
24239356Smckusick 	return (error);
2436254Sroot }
2446254Sroot 
2459167Ssam /*
24637741Smckusick  * Sync system call.
24737741Smckusick  * Sync each mounted filesystem.
2489167Ssam  */
24956352Smckusick #ifdef DIAGNOSTIC
25056352Smckusick int syncprt = 0;
25156352Smckusick #endif
25256352Smckusick 
25354916Storek struct sync_args {
25454916Storek 	int	dummy;
25554916Storek };
25639491Smckusick /* ARGSUSED */
25742441Smckusick sync(p, uap, retval)
25845914Smckusick 	struct proc *p;
25954916Storek 	struct sync_args *uap;
26042441Smckusick 	int *retval;
2616254Sroot {
26237741Smckusick 	register struct mount *mp;
26341298Smckusick 	struct mount *omp;
26437741Smckusick 
26537741Smckusick 	mp = rootfs;
26637741Smckusick 	do {
26740343Smckusick 		/*
26840343Smckusick 		 * The lock check below is to avoid races with mount
26940343Smckusick 		 * and unmount.
27040343Smckusick 		 */
27141400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
27241298Smckusick 		    !vfs_busy(mp)) {
27354441Smckusick 			VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
27441298Smckusick 			omp = mp;
27541400Smckusick 			mp = mp->mnt_next;
27641298Smckusick 			vfs_unbusy(omp);
27741298Smckusick 		} else
27841400Smckusick 			mp = mp->mnt_next;
27937741Smckusick 	} while (mp != rootfs);
28056352Smckusick #ifdef DIAGNOSTIC
28156352Smckusick 	if (syncprt)
28256352Smckusick 		vfs_bufstats();
28356352Smckusick #endif /* DIAGNOSTIC */
28447688Skarels 	return (0);
28537741Smckusick }
28637741Smckusick 
28737741Smckusick /*
28849365Smckusick  * Operate on filesystem quotas.
28941298Smckusick  */
29054916Storek struct quotactl_args {
29154916Storek 	char *path;
29254916Storek 	int cmd;
29354916Storek 	int uid;
29454916Storek 	caddr_t arg;
29554916Storek };
29642441Smckusick /* ARGSUSED */
29742441Smckusick quotactl(p, uap, retval)
29845914Smckusick 	struct proc *p;
29954916Storek 	register struct quotactl_args *uap;
30042441Smckusick 	int *retval;
30142441Smckusick {
30241298Smckusick 	register struct mount *mp;
30341298Smckusick 	int error;
30447540Skarels 	struct nameidata nd;
30541298Smckusick 
30652322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
30752322Smckusick 	if (error = namei(&nd))
30847540Skarels 		return (error);
30952322Smckusick 	mp = nd.ni_vp->v_mount;
31052322Smckusick 	vrele(nd.ni_vp);
31148026Smckusick 	return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p));
31241298Smckusick }
31341298Smckusick 
31441298Smckusick /*
31549365Smckusick  * Get filesystem statistics.
31637741Smckusick  */
31754916Storek struct statfs_args {
31854916Storek 	char *path;
31954916Storek 	struct statfs *buf;
32054916Storek };
32142441Smckusick /* ARGSUSED */
32242441Smckusick statfs(p, uap, retval)
32345914Smckusick 	struct proc *p;
32454916Storek 	register struct statfs_args *uap;
32542441Smckusick 	int *retval;
32642441Smckusick {
32739464Smckusick 	register struct mount *mp;
32840343Smckusick 	register struct statfs *sp;
32937741Smckusick 	int error;
33047540Skarels 	struct nameidata nd;
33137741Smckusick 
33252322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
33352322Smckusick 	if (error = namei(&nd))
33447540Skarels 		return (error);
33552322Smckusick 	mp = nd.ni_vp->v_mount;
33641400Smckusick 	sp = &mp->mnt_stat;
33752322Smckusick 	vrele(nd.ni_vp);
33848026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
33947540Skarels 		return (error);
34041400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
34147540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
34237741Smckusick }
34337741Smckusick 
34442441Smckusick /*
34549365Smckusick  * Get filesystem statistics.
34642441Smckusick  */
34754916Storek struct fstatfs_args {
34854916Storek 	int fd;
34954916Storek 	struct statfs *buf;
35054916Storek };
35142441Smckusick /* ARGSUSED */
35242441Smckusick fstatfs(p, uap, retval)
35345914Smckusick 	struct proc *p;
35454916Storek 	register struct fstatfs_args *uap;
35542441Smckusick 	int *retval;
35642441Smckusick {
35737741Smckusick 	struct file *fp;
35839464Smckusick 	struct mount *mp;
35940343Smckusick 	register struct statfs *sp;
36037741Smckusick 	int error;
36137741Smckusick 
36245914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
36347540Skarels 		return (error);
36439464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
36541400Smckusick 	sp = &mp->mnt_stat;
36648026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
36747540Skarels 		return (error);
36841400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
36947540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
37037741Smckusick }
37137741Smckusick 
37237741Smckusick /*
37349365Smckusick  * Get statistics on all filesystems.
37438270Smckusick  */
37554916Storek struct getfsstat_args {
37654916Storek 	struct statfs *buf;
37754916Storek 	long bufsize;
37854916Storek 	int flags;
37954916Storek };
38042441Smckusick getfsstat(p, uap, retval)
38145914Smckusick 	struct proc *p;
38254916Storek 	register struct getfsstat_args *uap;
38342441Smckusick 	int *retval;
38442441Smckusick {
38538270Smckusick 	register struct mount *mp;
38640343Smckusick 	register struct statfs *sp;
38739606Smckusick 	caddr_t sfsp;
38838270Smckusick 	long count, maxcount, error;
38938270Smckusick 
39038270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
39139606Smckusick 	sfsp = (caddr_t)uap->buf;
39238270Smckusick 	mp = rootfs;
39338270Smckusick 	count = 0;
39438270Smckusick 	do {
39541400Smckusick 		if (sfsp && count < maxcount &&
39641400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
39741400Smckusick 			sp = &mp->mnt_stat;
39840343Smckusick 			/*
39940343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
40040343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
40140343Smckusick 			 */
40240343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
40340343Smckusick 			    (uap->flags & MNT_WAIT)) &&
40448026Smckusick 			    (error = VFS_STATFS(mp, sp, p))) {
40541400Smckusick 				mp = mp->mnt_prev;
40639607Smckusick 				continue;
40739607Smckusick 			}
40841400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
40940343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
41047540Skarels 				return (error);
41140343Smckusick 			sfsp += sizeof(*sp);
41238270Smckusick 		}
41339606Smckusick 		count++;
41441400Smckusick 		mp = mp->mnt_prev;
41538270Smckusick 	} while (mp != rootfs);
41638270Smckusick 	if (sfsp && count > maxcount)
41742441Smckusick 		*retval = maxcount;
41838270Smckusick 	else
41942441Smckusick 		*retval = count;
42047540Skarels 	return (0);
42138270Smckusick }
42238270Smckusick 
42338270Smckusick /*
42438259Smckusick  * Change current working directory to a given file descriptor.
42538259Smckusick  */
42654916Storek struct fchdir_args {
42754916Storek 	int	fd;
42854916Storek };
42942441Smckusick /* ARGSUSED */
43042441Smckusick fchdir(p, uap, retval)
43145914Smckusick 	struct proc *p;
43254916Storek 	struct fchdir_args *uap;
43342441Smckusick 	int *retval;
43438259Smckusick {
43545914Smckusick 	register struct filedesc *fdp = p->p_fd;
43638259Smckusick 	register struct vnode *vp;
43738259Smckusick 	struct file *fp;
43838259Smckusick 	int error;
43938259Smckusick 
44045914Smckusick 	if (error = getvnode(fdp, uap->fd, &fp))
44147540Skarels 		return (error);
44238259Smckusick 	vp = (struct vnode *)fp->f_data;
44338259Smckusick 	VOP_LOCK(vp);
44438259Smckusick 	if (vp->v_type != VDIR)
44538259Smckusick 		error = ENOTDIR;
44638259Smckusick 	else
44748026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
44838259Smckusick 	VOP_UNLOCK(vp);
44939860Smckusick 	if (error)
45047540Skarels 		return (error);
45139860Smckusick 	VREF(vp);
45245914Smckusick 	vrele(fdp->fd_cdir);
45345914Smckusick 	fdp->fd_cdir = vp;
45447540Skarels 	return (0);
45538259Smckusick }
45638259Smckusick 
45738259Smckusick /*
45837741Smckusick  * Change current working directory (``.'').
45937741Smckusick  */
46054916Storek struct chdir_args {
46154916Storek 	char	*fname;
46254916Storek };
46342441Smckusick /* ARGSUSED */
46442441Smckusick chdir(p, uap, retval)
46545914Smckusick 	struct proc *p;
46654916Storek 	struct chdir_args *uap;
46742441Smckusick 	int *retval;
46837741Smckusick {
46945914Smckusick 	register struct filedesc *fdp = p->p_fd;
47037741Smckusick 	int error;
47147540Skarels 	struct nameidata nd;
4726254Sroot 
47352322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
47452781Sralph 	if (error = chdirec(&nd, p))
47547540Skarels 		return (error);
47645914Smckusick 	vrele(fdp->fd_cdir);
47752322Smckusick 	fdp->fd_cdir = nd.ni_vp;
47847540Skarels 	return (0);
47937741Smckusick }
4806254Sroot 
48137741Smckusick /*
48237741Smckusick  * Change notion of root (``/'') directory.
48337741Smckusick  */
48454916Storek struct chroot_args {
48554916Storek 	char	*fname;
48654916Storek };
48742441Smckusick /* ARGSUSED */
48842441Smckusick chroot(p, uap, retval)
48945914Smckusick 	struct proc *p;
49054916Storek 	struct chroot_args *uap;
49142441Smckusick 	int *retval;
49237741Smckusick {
49345914Smckusick 	register struct filedesc *fdp = p->p_fd;
49437741Smckusick 	int error;
49547540Skarels 	struct nameidata nd;
49637741Smckusick 
49747540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
49847540Skarels 		return (error);
49952322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
50052781Sralph 	if (error = chdirec(&nd, p))
50147540Skarels 		return (error);
50245914Smckusick 	if (fdp->fd_rdir != NULL)
50345914Smckusick 		vrele(fdp->fd_rdir);
50452322Smckusick 	fdp->fd_rdir = nd.ni_vp;
50547540Skarels 	return (0);
5066254Sroot }
5076254Sroot 
50837Sbill /*
50937741Smckusick  * Common routine for chroot and chdir.
51037741Smckusick  */
51147540Skarels chdirec(ndp, p)
51252322Smckusick 	register struct nameidata *ndp;
51347540Skarels 	struct proc *p;
51437741Smckusick {
51537741Smckusick 	struct vnode *vp;
51637741Smckusick 	int error;
51737741Smckusick 
51852322Smckusick 	if (error = namei(ndp))
51937741Smckusick 		return (error);
52037741Smckusick 	vp = ndp->ni_vp;
52137741Smckusick 	if (vp->v_type != VDIR)
52237741Smckusick 		error = ENOTDIR;
52337741Smckusick 	else
52448026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
52537741Smckusick 	VOP_UNLOCK(vp);
52637741Smckusick 	if (error)
52737741Smckusick 		vrele(vp);
52837741Smckusick 	return (error);
52937741Smckusick }
53037741Smckusick 
53137741Smckusick /*
5326254Sroot  * Open system call.
53342441Smckusick  * Check permissions, allocate an open file structure,
53442441Smckusick  * and call the device open routine if any.
5356254Sroot  */
53654916Storek struct open_args {
53754916Storek 	char	*fname;
53854916Storek 	int	mode;
53954916Storek 	int	crtmode;
54054916Storek };
54142441Smckusick open(p, uap, retval)
54245914Smckusick 	struct proc *p;
54354916Storek 	register struct open_args *uap;
54442441Smckusick 	int *retval;
5456254Sroot {
54645914Smckusick 	register struct filedesc *fdp = p->p_fd;
54742441Smckusick 	register struct file *fp;
54850111Smckusick 	register struct vnode *vp;
54937741Smckusick 	int fmode, cmode;
55037741Smckusick 	struct file *nfp;
55149945Smckusick 	int type, indx, error;
55249945Smckusick 	struct flock lf;
55347540Skarels 	struct nameidata nd;
55437741Smckusick 	extern struct fileops vnops;
5556254Sroot 
55645914Smckusick 	if (error = falloc(p, &nfp, &indx))
55747540Skarels 		return (error);
55837741Smckusick 	fp = nfp;
55946553Skarels 	fmode = FFLAGS(uap->mode);
56045914Smckusick 	cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX;
56152322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
56245202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
56352322Smckusick 	if (error = vn_open(&nd, fmode, cmode)) {
56449980Smckusick 		ffree(fp);
56554723Smckusick 		if ((error == ENODEV || error == ENXIO) &&
56654723Smckusick 		    p->p_dupfd >= 0 && 			/* XXX from fdopen */
56753828Spendry 		    (error = dupfdopen(fdp, indx, p->p_dupfd,
56853828Spendry 					fmode, error)) == 0) {
56942441Smckusick 			*retval = indx;
57047540Skarels 			return (0);
57142441Smckusick 		}
57240884Smckusick 		if (error == ERESTART)
57340884Smckusick 			error = EINTR;
57447688Skarels 		fdp->fd_ofiles[indx] = NULL;
57547540Skarels 		return (error);
57612756Ssam 	}
57753828Spendry 	p->p_dupfd = 0;
57852322Smckusick 	vp = nd.ni_vp;
57949949Smckusick 	fp->f_flag = fmode & FMASK;
58054348Smckusick 	fp->f_type = DTYPE_VNODE;
58154348Smckusick 	fp->f_ops = &vnops;
58254348Smckusick 	fp->f_data = (caddr_t)vp;
58349945Smckusick 	if (fmode & (O_EXLOCK | O_SHLOCK)) {
58449945Smckusick 		lf.l_whence = SEEK_SET;
58549945Smckusick 		lf.l_start = 0;
58649945Smckusick 		lf.l_len = 0;
58749945Smckusick 		if (fmode & O_EXLOCK)
58849945Smckusick 			lf.l_type = F_WRLCK;
58949945Smckusick 		else
59049945Smckusick 			lf.l_type = F_RDLCK;
59149945Smckusick 		type = F_FLOCK;
59249945Smckusick 		if ((fmode & FNONBLOCK) == 0)
59349945Smckusick 			type |= F_WAIT;
59450111Smckusick 		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
59550111Smckusick 			VOP_UNLOCK(vp);
59650111Smckusick 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
59749980Smckusick 			ffree(fp);
59849945Smckusick 			fdp->fd_ofiles[indx] = NULL;
59949945Smckusick 			return (error);
60049945Smckusick 		}
60149949Smckusick 		fp->f_flag |= FHASLOCK;
60249945Smckusick 	}
60350111Smckusick 	VOP_UNLOCK(vp);
60442441Smckusick 	*retval = indx;
60547540Skarels 	return (0);
6066254Sroot }
6076254Sroot 
60842955Smckusick #ifdef COMPAT_43
6096254Sroot /*
61042441Smckusick  * Creat system call.
6116254Sroot  */
61254916Storek struct ocreat_args {
61354916Storek 	char	*fname;
61454916Storek 	int	fmode;
61554916Storek };
61642955Smckusick ocreat(p, uap, retval)
61742441Smckusick 	struct proc *p;
61854916Storek 	register struct ocreat_args *uap;
61942441Smckusick 	int *retval;
6206254Sroot {
62154916Storek 	struct open_args openuap;
62242441Smckusick 
62342441Smckusick 	openuap.fname = uap->fname;
62442441Smckusick 	openuap.crtmode = uap->fmode;
62542441Smckusick 	openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
62647540Skarels 	return (open(p, &openuap, retval));
62742441Smckusick }
62842955Smckusick #endif /* COMPAT_43 */
62942441Smckusick 
63042441Smckusick /*
63149365Smckusick  * Mknod system call.
63242441Smckusick  */
63354916Storek struct mknod_args {
63454916Storek 	char	*fname;
63554916Storek 	int	fmode;
63654916Storek 	int	dev;
63754916Storek };
63842441Smckusick /* ARGSUSED */
63942441Smckusick mknod(p, uap, retval)
64045914Smckusick 	struct proc *p;
64154916Storek 	register struct mknod_args *uap;
64242441Smckusick 	int *retval;
64342441Smckusick {
64437741Smckusick 	register struct vnode *vp;
64537741Smckusick 	struct vattr vattr;
64637741Smckusick 	int error;
64747540Skarels 	struct nameidata nd;
6486254Sroot 
64947540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
65047540Skarels 		return (error);
65152322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p);
65252322Smckusick 	if (error = namei(&nd))
65347540Skarels 		return (error);
65452322Smckusick 	vp = nd.ni_vp;
65537741Smckusick 	if (vp != NULL) {
65637741Smckusick 		error = EEXIST;
65712756Ssam 		goto out;
6586254Sroot 	}
65941362Smckusick 	VATTR_NULL(&vattr);
66040635Smckusick 	switch (uap->fmode & S_IFMT) {
66112756Ssam 
66240635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
66337741Smckusick 		vattr.va_type = VBAD;
66437741Smckusick 		break;
66540635Smckusick 	case S_IFCHR:
66637741Smckusick 		vattr.va_type = VCHR;
66737741Smckusick 		break;
66840635Smckusick 	case S_IFBLK:
66937741Smckusick 		vattr.va_type = VBLK;
67037741Smckusick 		break;
67137741Smckusick 	default:
67237741Smckusick 		error = EINVAL;
67337741Smckusick 		goto out;
6746254Sroot 	}
67545914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
67637741Smckusick 	vattr.va_rdev = uap->dev;
6776254Sroot out:
67842465Smckusick 	if (!error) {
67952322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
68052322Smckusick 		error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
68142465Smckusick 	} else {
68252322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
68352322Smckusick 		if (nd.ni_dvp == vp)
68452322Smckusick 			vrele(nd.ni_dvp);
68543344Smckusick 		else
68652322Smckusick 			vput(nd.ni_dvp);
68742465Smckusick 		if (vp)
68842465Smckusick 			vrele(vp);
68942465Smckusick 	}
69047540Skarels 	return (error);
6916254Sroot }
6926254Sroot 
6936254Sroot /*
69449365Smckusick  * Mkfifo system call.
69540285Smckusick  */
69654916Storek struct mkfifo_args {
69754916Storek 	char	*fname;
69854916Storek 	int	fmode;
69954916Storek };
70042441Smckusick /* ARGSUSED */
70142441Smckusick mkfifo(p, uap, retval)
70245914Smckusick 	struct proc *p;
70354916Storek 	register struct mkfifo_args *uap;
70442441Smckusick 	int *retval;
70542441Smckusick {
70640285Smckusick 	struct vattr vattr;
70740285Smckusick 	int error;
70847540Skarels 	struct nameidata nd;
70940285Smckusick 
71040285Smckusick #ifndef FIFO
71147540Skarels 	return (EOPNOTSUPP);
71240285Smckusick #else
71352322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p);
71452322Smckusick 	if (error = namei(&nd))
71547540Skarels 		return (error);
71652322Smckusick 	if (nd.ni_vp != NULL) {
71752322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
71852322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
71952322Smckusick 			vrele(nd.ni_dvp);
72043344Smckusick 		else
72152322Smckusick 			vput(nd.ni_dvp);
72252322Smckusick 		vrele(nd.ni_vp);
72347540Skarels 		return (EEXIST);
72440285Smckusick 	}
72545785Sbostic 	VATTR_NULL(&vattr);
72645785Sbostic 	vattr.va_type = VFIFO;
72745914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
72852322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
72952322Smckusick 	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
73040285Smckusick #endif /* FIFO */
73140285Smckusick }
73240285Smckusick 
73340285Smckusick /*
73449365Smckusick  * Link system call.
7356254Sroot  */
73654916Storek struct link_args {
73754916Storek 	char	*target;
73854916Storek 	char	*linkname;
73954916Storek };
74042441Smckusick /* ARGSUSED */
74142441Smckusick link(p, uap, retval)
74245914Smckusick 	struct proc *p;
74354916Storek 	register struct link_args *uap;
74442441Smckusick 	int *retval;
74542441Smckusick {
74637741Smckusick 	register struct vnode *vp, *xp;
74737741Smckusick 	int error;
74847540Skarels 	struct nameidata nd;
7496254Sroot 
75052322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->target, p);
75152322Smckusick 	if (error = namei(&nd))
75247540Skarels 		return (error);
75352322Smckusick 	vp = nd.ni_vp;
75437741Smckusick 	if (vp->v_type == VDIR &&
75547540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
75637741Smckusick 		goto out1;
75752322Smckusick 	nd.ni_cnd.cn_nameiop = CREATE;
75852322Smckusick 	nd.ni_cnd.cn_flags = LOCKPARENT;
75952322Smckusick 	nd.ni_dirp = (caddr_t)uap->linkname;
76052322Smckusick 	if (error = namei(&nd))
76137741Smckusick 		goto out1;
76252322Smckusick 	xp = nd.ni_vp;
7636254Sroot 	if (xp != NULL) {
76437741Smckusick 		error = EEXIST;
7656254Sroot 		goto out;
7666254Sroot 	}
76752322Smckusick 	xp = nd.ni_dvp;
7686254Sroot out:
76942465Smckusick 	if (!error) {
77052192Smckusick 		LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE);
77152192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
77252821Smckusick 		error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
77342465Smckusick 	} else {
77452322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
77552322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
77652322Smckusick 			vrele(nd.ni_dvp);
77743344Smckusick 		else
77852322Smckusick 			vput(nd.ni_dvp);
77952322Smckusick 		if (nd.ni_vp)
78052322Smckusick 			vrele(nd.ni_vp);
78142465Smckusick 	}
78237741Smckusick out1:
78337741Smckusick 	vrele(vp);
78447540Skarels 	return (error);
7856254Sroot }
7866254Sroot 
7876254Sroot /*
78849365Smckusick  * Make a symbolic link.
7896254Sroot  */
79054916Storek struct symlink_args {
79154916Storek 	char	*target;
79254916Storek 	char	*linkname;
79354916Storek };
79442441Smckusick /* ARGSUSED */
79542441Smckusick symlink(p, uap, retval)
79645914Smckusick 	struct proc *p;
79754916Storek 	register struct symlink_args *uap;
79842441Smckusick 	int *retval;
79942441Smckusick {
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  */
83354916Storek struct unlink_args {
83454916Storek 	char	*name;
83554916Storek };
83642441Smckusick /* ARGSUSED */
83742441Smckusick unlink(p, uap, retval)
83845914Smckusick 	struct proc *p;
83954916Storek 	struct unlink_args *uap;
84042441Smckusick 	int *retval;
8416254Sroot {
84237741Smckusick 	register struct vnode *vp;
84337741Smckusick 	int error;
84447540Skarels 	struct nameidata nd;
8456254Sroot 
846*59382Smckusick 	NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->name, p);
84752322Smckusick 	if (error = namei(&nd))
84847540Skarels 		return (error);
84952322Smckusick 	vp = nd.ni_vp;
850*59382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
851*59382Smckusick 	VOP_LOCK(vp);
85237741Smckusick 	if (vp->v_type == VDIR &&
85347540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
8546254Sroot 		goto out;
8556254Sroot 	/*
85649365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
8576254Sroot 	 */
85837741Smckusick 	if (vp->v_flag & VROOT) {
85937741Smckusick 		error = EBUSY;
8606254Sroot 		goto out;
8616254Sroot 	}
86245738Smckusick 	(void) vnode_pager_uncache(vp);
8636254Sroot out:
86442465Smckusick 	if (!error) {
86552322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
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 
87854916Storek struct __lseek_args {
87954863Storek 	int	fdes;
88054863Storek 	int	pad;
88154863Storek 	off_t	off;
88254863Storek 	int	sbase;
88354863Storek };
88454863Storek 
88554348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
8866254Sroot /*
88749365Smckusick  * Seek system call.
8886254Sroot  */
88954916Storek struct lseek_args {
89054916Storek 	int	fdes;
89154916Storek 	long	off;
89254916Storek 	int	sbase;
89354916Storek };
89442441Smckusick lseek(p, uap, retval)
89545914Smckusick 	struct proc *p;
89654916Storek 	register struct lseek_args *uap;
89754916Storek 	int *retval;
89853468Smckusick {
89954916Storek 	struct __lseek_args nuap;
90054863Storek 	off_t qret;
90153468Smckusick 	int error;
90253468Smckusick 
90353468Smckusick 	nuap.fdes = uap->fdes;
90453468Smckusick 	nuap.off = uap->off;
90553468Smckusick 	nuap.sbase = uap->sbase;
90653759Smckusick 	error = __lseek(p, &nuap, &qret);
90754916Storek 	*(long *)retval = qret;
90853468Smckusick 	return (error);
90953468Smckusick }
91054348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
91153468Smckusick 
91253468Smckusick /*
91353468Smckusick  * Seek system call.
91453468Smckusick  */
91553759Smckusick __lseek(p, uap, retval)
91653468Smckusick 	struct proc *p;
91754916Storek 	register struct __lseek_args *uap;
91854916Storek 	int *retval;
91942441Smckusick {
92047540Skarels 	struct ucred *cred = p->p_ucred;
92145914Smckusick 	register struct filedesc *fdp = p->p_fd;
92242441Smckusick 	register struct file *fp;
92337741Smckusick 	struct vattr vattr;
92437741Smckusick 	int error;
9256254Sroot 
92647540Skarels 	if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
92747688Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL)
92847540Skarels 		return (EBADF);
92937741Smckusick 	if (fp->f_type != DTYPE_VNODE)
93047540Skarels 		return (ESPIPE);
93113878Ssam 	switch (uap->sbase) {
93213878Ssam 
93313878Ssam 	case L_INCR:
93413878Ssam 		fp->f_offset += uap->off;
93513878Ssam 		break;
93613878Ssam 
93713878Ssam 	case L_XTND:
93837741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
93948026Smckusick 		    &vattr, cred, p))
94047540Skarels 			return (error);
94137741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
94213878Ssam 		break;
94313878Ssam 
94413878Ssam 	case L_SET:
94513878Ssam 		fp->f_offset = uap->off;
94613878Ssam 		break;
94713878Ssam 
94813878Ssam 	default:
94947540Skarels 		return (EINVAL);
95013878Ssam 	}
95154916Storek 	*(off_t *)retval = fp->f_offset;
95247540Skarels 	return (0);
9536254Sroot }
9546254Sroot 
9556254Sroot /*
95649365Smckusick  * Check access permissions.
9576254Sroot  */
95854916Storek struct saccess_args {
95954916Storek 	char	*fname;
96054916Storek 	int	fmode;
96154916Storek };
96242441Smckusick /* ARGSUSED */
96342441Smckusick saccess(p, uap, retval)
96445914Smckusick 	struct proc *p;
96554916Storek 	register struct saccess_args *uap;
96642441Smckusick 	int *retval;
96742441Smckusick {
96847540Skarels 	register struct ucred *cred = p->p_ucred;
96937741Smckusick 	register struct vnode *vp;
97037741Smckusick 	int error, mode, svuid, svgid;
97147540Skarels 	struct nameidata nd;
9726254Sroot 
97342441Smckusick 	svuid = cred->cr_uid;
97442441Smckusick 	svgid = cred->cr_groups[0];
97547540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
97647540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
97752322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
97852322Smckusick 	if (error = namei(&nd))
97937741Smckusick 		goto out1;
98052322Smckusick 	vp = nd.ni_vp;
98137741Smckusick 	/*
98237741Smckusick 	 * fmode == 0 means only check for exist
98337741Smckusick 	 */
98437741Smckusick 	if (uap->fmode) {
98537741Smckusick 		mode = 0;
98637741Smckusick 		if (uap->fmode & R_OK)
98737741Smckusick 			mode |= VREAD;
98837741Smckusick 		if (uap->fmode & W_OK)
98937741Smckusick 			mode |= VWRITE;
99037741Smckusick 		if (uap->fmode & X_OK)
99137741Smckusick 			mode |= VEXEC;
99239543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
99348026Smckusick 			error = VOP_ACCESS(vp, mode, cred, p);
9946254Sroot 	}
99537741Smckusick 	vput(vp);
99637741Smckusick out1:
99742441Smckusick 	cred->cr_uid = svuid;
99842441Smckusick 	cred->cr_groups[0] = svgid;
99947540Skarels 	return (error);
10006254Sroot }
10016254Sroot 
100254348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
10036254Sroot /*
100449365Smckusick  * Stat system call.
100549365Smckusick  * This version follows links.
100637Sbill  */
100754916Storek struct ostat_args {
100854916Storek 	char	*fname;
100954916Storek 	struct ostat *ub;
101054916Storek };
101142441Smckusick /* ARGSUSED */
101253759Smckusick ostat(p, uap, retval)
101345914Smckusick 	struct proc *p;
101454916Storek 	register struct ostat_args *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  */
103854916Storek struct olstat_args {
103954916Storek 	char	*fname;
104054916Storek 	struct ostat *ub;
104154916Storek };
104253468Smckusick /* ARGSUSED */
104353759Smckusick olstat(p, uap, retval)
104453468Smckusick 	struct proc *p;
104554916Storek 	register struct olstat_args *uap;
104653468Smckusick 	int *retval;
104753468Smckusick {
104853468Smckusick 	struct stat sb;
104953468Smckusick 	struct ostat osb;
105053468Smckusick 	int error;
105153468Smckusick 	struct nameidata nd;
105253468Smckusick 
105353468Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
105453468Smckusick 	if (error = namei(&nd))
105553468Smckusick 		return (error);
105653468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
105753468Smckusick 	vput(nd.ni_vp);
105853468Smckusick 	if (error)
105953468Smckusick 		return (error);
106053468Smckusick 	cvtstat(&sb, &osb);
106153468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
106253468Smckusick 	return (error);
106353468Smckusick }
106453468Smckusick 
106553468Smckusick /*
106653468Smckusick  * convert from an old to a new stat structure.
106753468Smckusick  */
106853468Smckusick cvtstat(st, ost)
106953468Smckusick 	struct stat *st;
107053468Smckusick 	struct ostat *ost;
107153468Smckusick {
107253468Smckusick 
107353468Smckusick 	ost->st_dev = st->st_dev;
107453468Smckusick 	ost->st_ino = st->st_ino;
107553468Smckusick 	ost->st_mode = st->st_mode;
107653468Smckusick 	ost->st_nlink = st->st_nlink;
107753468Smckusick 	ost->st_uid = st->st_uid;
107853468Smckusick 	ost->st_gid = st->st_gid;
107953468Smckusick 	ost->st_rdev = st->st_rdev;
108053468Smckusick 	if (st->st_size < (quad_t)1 << 32)
108153468Smckusick 		ost->st_size = st->st_size;
108253468Smckusick 	else
108353468Smckusick 		ost->st_size = -2;
108453468Smckusick 	ost->st_atime = st->st_atime;
108553468Smckusick 	ost->st_mtime = st->st_mtime;
108653468Smckusick 	ost->st_ctime = st->st_ctime;
108753468Smckusick 	ost->st_blksize = st->st_blksize;
108853468Smckusick 	ost->st_blocks = st->st_blocks;
108953468Smckusick 	ost->st_flags = st->st_flags;
109053468Smckusick 	ost->st_gen = st->st_gen;
109153468Smckusick }
109254348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
109353468Smckusick 
109453468Smckusick /*
109553468Smckusick  * Stat system call.
109653468Smckusick  * This version follows links.
109753468Smckusick  */
109854916Storek struct stat_args {
109954916Storek 	char	*fname;
110054916Storek 	struct stat *ub;
110154916Storek };
110253468Smckusick /* ARGSUSED */
110353759Smckusick stat(p, uap, retval)
110453468Smckusick 	struct proc *p;
110554916Storek 	register struct stat_args *uap;
110642441Smckusick 	int *retval;
110737Sbill {
110842441Smckusick 	struct stat sb;
110942441Smckusick 	int error;
111047540Skarels 	struct nameidata nd;
111137Sbill 
111252322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
111352322Smckusick 	if (error = namei(&nd))
111447540Skarels 		return (error);
111552322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
111652322Smckusick 	vput(nd.ni_vp);
111742441Smckusick 	if (error)
111847540Skarels 		return (error);
111942441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
112047540Skarels 	return (error);
112137Sbill }
112237Sbill 
112337Sbill /*
112449365Smckusick  * Lstat system call.
112549365Smckusick  * This version does not follow links.
11265992Swnj  */
112754916Storek struct lstat_args {
112854916Storek 	char	*fname;
112954916Storek 	struct stat *ub;
113054916Storek };
113142441Smckusick /* ARGSUSED */
113253759Smckusick lstat(p, uap, retval)
113345914Smckusick 	struct proc *p;
113454916Storek 	register struct lstat_args *uap;
113542441Smckusick 	int *retval;
113642441Smckusick {
113737741Smckusick 	int error;
113859373Smckusick 	struct vnode *vp, *dvp;
113959373Smckusick 	struct stat sb, sb1;
114047540Skarels 	struct nameidata nd;
11415992Swnj 
114259373Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
114359373Smckusick 	    uap->fname, p);
114452322Smckusick 	if (error = namei(&nd))
114547540Skarels 		return (error);
114659373Smckusick 	/*
114759373Smckusick 	 * For symbolic links, always return the attributes of its
114859373Smckusick 	 * containing directory, except for mode, size, and links.
114959373Smckusick 	 */
115059373Smckusick 	vp = nd.ni_vp;
115159373Smckusick 	dvp = nd.ni_dvp;
115259373Smckusick 	if (vp->v_type != VLNK) {
115359373Smckusick 		if (dvp == vp)
115459373Smckusick 			vrele(dvp);
115559373Smckusick 		else
115659373Smckusick 			vput(dvp);
115759373Smckusick 		error = vn_stat(vp, &sb, p);
115859373Smckusick 		vput(vp);
115959373Smckusick 		if (error)
116059373Smckusick 			return (error);
116159373Smckusick 	} else {
116259373Smckusick 		error = vn_stat(dvp, &sb, p);
116359373Smckusick 		vput(dvp);
116459373Smckusick 		if (error) {
116559373Smckusick 			vput(vp);
116659373Smckusick 			return (error);
116759373Smckusick 		}
116859373Smckusick 		error = vn_stat(vp, &sb1, p);
116959373Smckusick 		vput(vp);
117059373Smckusick 		if (error)
117159373Smckusick 			return (error);
117259373Smckusick 		sb.st_mode &= ~S_IFDIR;
117359373Smckusick 		sb.st_mode |= S_IFLNK;
117459373Smckusick 		sb.st_nlink = sb1.st_nlink;
117559373Smckusick 		sb.st_size = sb1.st_size;
117659373Smckusick 		sb.st_blocks = sb1.st_blocks;
117759373Smckusick 	}
117837741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
117947540Skarels 	return (error);
11805992Swnj }
11815992Swnj 
11825992Swnj /*
118349365Smckusick  * Return target name of a symbolic link.
118437Sbill  */
118554916Storek struct readlink_args {
118654916Storek 	char	*name;
118754916Storek 	char	*buf;
118854916Storek 	int	count;
118954916Storek };
119042441Smckusick /* ARGSUSED */
119142441Smckusick readlink(p, uap, retval)
119245914Smckusick 	struct proc *p;
119354916Storek 	register struct readlink_args *uap;
119442441Smckusick 	int *retval;
119542441Smckusick {
119637741Smckusick 	register struct vnode *vp;
119737741Smckusick 	struct iovec aiov;
119837741Smckusick 	struct uio auio;
119937741Smckusick 	int error;
120047540Skarels 	struct nameidata nd;
12015992Swnj 
120252322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p);
120352322Smckusick 	if (error = namei(&nd))
120447540Skarels 		return (error);
120552322Smckusick 	vp = nd.ni_vp;
120637741Smckusick 	if (vp->v_type != VLNK) {
120737741Smckusick 		error = EINVAL;
12085992Swnj 		goto out;
12095992Swnj 	}
121037741Smckusick 	aiov.iov_base = uap->buf;
121137741Smckusick 	aiov.iov_len = uap->count;
121237741Smckusick 	auio.uio_iov = &aiov;
121337741Smckusick 	auio.uio_iovcnt = 1;
121437741Smckusick 	auio.uio_offset = 0;
121537741Smckusick 	auio.uio_rw = UIO_READ;
121637741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
121748026Smckusick 	auio.uio_procp = p;
121837741Smckusick 	auio.uio_resid = uap->count;
121947540Skarels 	error = VOP_READLINK(vp, &auio, p->p_ucred);
12205992Swnj out:
122137741Smckusick 	vput(vp);
122242441Smckusick 	*retval = uap->count - auio.uio_resid;
122347540Skarels 	return (error);
12245992Swnj }
12255992Swnj 
12269167Ssam /*
122738259Smckusick  * Change flags of a file given path name.
122838259Smckusick  */
122954916Storek struct chflags_args {
123054916Storek 	char	*fname;
123154916Storek 	int	flags;
123254916Storek };
123342441Smckusick /* ARGSUSED */
123442441Smckusick chflags(p, uap, retval)
123545914Smckusick 	struct proc *p;
123654916Storek 	register struct chflags_args *uap;
123742441Smckusick 	int *retval;
123842441Smckusick {
123938259Smckusick 	register struct vnode *vp;
124038259Smckusick 	struct vattr vattr;
124138259Smckusick 	int error;
124247540Skarels 	struct nameidata nd;
124338259Smckusick 
1244*59382Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
124552322Smckusick 	if (error = namei(&nd))
124647540Skarels 		return (error);
124752322Smckusick 	vp = nd.ni_vp;
1248*59382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
1249*59382Smckusick 	VOP_LOCK(vp);
125041400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
125138259Smckusick 		error = EROFS;
125238259Smckusick 		goto out;
125338259Smckusick 	}
125445785Sbostic 	VATTR_NULL(&vattr);
125545785Sbostic 	vattr.va_flags = uap->flags;
125648026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
125738259Smckusick out:
125838259Smckusick 	vput(vp);
125947540Skarels 	return (error);
126038259Smckusick }
126138259Smckusick 
126238259Smckusick /*
126338259Smckusick  * Change flags of a file given a file descriptor.
126438259Smckusick  */
126554916Storek struct fchflags_args {
126654916Storek 	int	fd;
126754916Storek 	int	flags;
126854916Storek };
126942441Smckusick /* ARGSUSED */
127042441Smckusick fchflags(p, uap, retval)
127145914Smckusick 	struct proc *p;
127254916Storek 	register struct fchflags_args *uap;
127342441Smckusick 	int *retval;
127442441Smckusick {
127538259Smckusick 	struct vattr vattr;
127638259Smckusick 	struct vnode *vp;
127738259Smckusick 	struct file *fp;
127838259Smckusick 	int error;
127938259Smckusick 
128045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
128147540Skarels 		return (error);
128238259Smckusick 	vp = (struct vnode *)fp->f_data;
1283*59382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
128438259Smckusick 	VOP_LOCK(vp);
128541400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
128638259Smckusick 		error = EROFS;
128738259Smckusick 		goto out;
128838259Smckusick 	}
128945785Sbostic 	VATTR_NULL(&vattr);
129045785Sbostic 	vattr.va_flags = uap->flags;
129148026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
129238259Smckusick out:
129338259Smckusick 	VOP_UNLOCK(vp);
129447540Skarels 	return (error);
129538259Smckusick }
129638259Smckusick 
129738259Smckusick /*
12989167Ssam  * Change mode of a file given path name.
12999167Ssam  */
130054916Storek struct chmod_args {
130154916Storek 	char	*fname;
130254916Storek 	int	fmode;
130354916Storek };
130442441Smckusick /* ARGSUSED */
130542441Smckusick chmod(p, uap, retval)
130645914Smckusick 	struct proc *p;
130754916Storek 	register struct chmod_args *uap;
130842441Smckusick 	int *retval;
130942441Smckusick {
131037741Smckusick 	register struct vnode *vp;
131137741Smckusick 	struct vattr vattr;
131237741Smckusick 	int error;
131347540Skarels 	struct nameidata nd;
13145992Swnj 
1315*59382Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
131652322Smckusick 	if (error = namei(&nd))
131747540Skarels 		return (error);
131852322Smckusick 	vp = nd.ni_vp;
1319*59382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
1320*59382Smckusick 	VOP_LOCK(vp);
132141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
132237741Smckusick 		error = EROFS;
132337741Smckusick 		goto out;
132437741Smckusick 	}
132545785Sbostic 	VATTR_NULL(&vattr);
132645785Sbostic 	vattr.va_mode = uap->fmode & 07777;
132748026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
132837741Smckusick out:
132937741Smckusick 	vput(vp);
133047540Skarels 	return (error);
13317701Ssam }
13327439Sroot 
13339167Ssam /*
13349167Ssam  * Change mode of a file given a file descriptor.
13359167Ssam  */
133654916Storek struct fchmod_args {
133754916Storek 	int	fd;
133854916Storek 	int	fmode;
133954916Storek };
134042441Smckusick /* ARGSUSED */
134142441Smckusick fchmod(p, uap, retval)
134245914Smckusick 	struct proc *p;
134354916Storek 	register struct fchmod_args *uap;
134442441Smckusick 	int *retval;
134542441Smckusick {
134637741Smckusick 	struct vattr vattr;
134737741Smckusick 	struct vnode *vp;
134837741Smckusick 	struct file *fp;
134937741Smckusick 	int error;
13507701Ssam 
135145914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
135247540Skarels 		return (error);
135337741Smckusick 	vp = (struct vnode *)fp->f_data;
1354*59382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
135537741Smckusick 	VOP_LOCK(vp);
135641400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
135737741Smckusick 		error = EROFS;
135837741Smckusick 		goto out;
13597439Sroot 	}
136045785Sbostic 	VATTR_NULL(&vattr);
136145785Sbostic 	vattr.va_mode = uap->fmode & 07777;
136248026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
136337741Smckusick out:
136437741Smckusick 	VOP_UNLOCK(vp);
136547540Skarels 	return (error);
13665992Swnj }
13675992Swnj 
13689167Ssam /*
13699167Ssam  * Set ownership given a path name.
13709167Ssam  */
137154916Storek struct chown_args {
137254916Storek 	char	*fname;
137354916Storek 	int	uid;
137454916Storek 	int	gid;
137554916Storek };
137642441Smckusick /* ARGSUSED */
137742441Smckusick chown(p, uap, retval)
137845914Smckusick 	struct proc *p;
137954916Storek 	register struct chown_args *uap;
138042441Smckusick 	int *retval;
138142441Smckusick {
138237741Smckusick 	register struct vnode *vp;
138337741Smckusick 	struct vattr vattr;
138437741Smckusick 	int error;
138547540Skarels 	struct nameidata nd;
138637Sbill 
1387*59382Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->fname, p);
138852322Smckusick 	if (error = namei(&nd))
138947540Skarels 		return (error);
139052322Smckusick 	vp = nd.ni_vp;
1391*59382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
1392*59382Smckusick 	VOP_LOCK(vp);
139341400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
139437741Smckusick 		error = EROFS;
139537741Smckusick 		goto out;
139637741Smckusick 	}
139745785Sbostic 	VATTR_NULL(&vattr);
139845785Sbostic 	vattr.va_uid = uap->uid;
139945785Sbostic 	vattr.va_gid = uap->gid;
140048026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
140137741Smckusick out:
140237741Smckusick 	vput(vp);
140347540Skarels 	return (error);
14047701Ssam }
14057439Sroot 
14069167Ssam /*
14079167Ssam  * Set ownership given a file descriptor.
14089167Ssam  */
140954916Storek struct fchown_args {
141054916Storek 	int	fd;
141154916Storek 	int	uid;
141254916Storek 	int	gid;
141354916Storek };
141442441Smckusick /* ARGSUSED */
141542441Smckusick fchown(p, uap, retval)
141645914Smckusick 	struct proc *p;
141754916Storek 	register struct fchown_args *uap;
141842441Smckusick 	int *retval;
141942441Smckusick {
142037741Smckusick 	struct vattr vattr;
142137741Smckusick 	struct vnode *vp;
142237741Smckusick 	struct file *fp;
142337741Smckusick 	int error;
14247701Ssam 
142545914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
142647540Skarels 		return (error);
142737741Smckusick 	vp = (struct vnode *)fp->f_data;
1428*59382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
142937741Smckusick 	VOP_LOCK(vp);
143041400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
143137741Smckusick 		error = EROFS;
143237741Smckusick 		goto out;
143337741Smckusick 	}
143445785Sbostic 	VATTR_NULL(&vattr);
143545785Sbostic 	vattr.va_uid = uap->uid;
143645785Sbostic 	vattr.va_gid = uap->gid;
143748026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
143837741Smckusick out:
143937741Smckusick 	VOP_UNLOCK(vp);
144047540Skarels 	return (error);
14417701Ssam }
14427701Ssam 
144342441Smckusick /*
144442441Smckusick  * Set the access and modification times of a file.
144542441Smckusick  */
144654916Storek struct utimes_args {
144754916Storek 	char	*fname;
144854916Storek 	struct	timeval *tptr;
144954916Storek };
145042441Smckusick /* ARGSUSED */
145142441Smckusick utimes(p, uap, retval)
145245914Smckusick 	struct proc *p;
145354916Storek 	register struct utimes_args *uap;
145442441Smckusick 	int *retval;
145542441Smckusick {
145637741Smckusick 	register struct vnode *vp;
145711811Ssam 	struct timeval tv[2];
145837741Smckusick 	struct vattr vattr;
145958840Storek 	int error;
146047540Skarels 	struct nameidata nd;
146111811Ssam 
146258505Sbostic 	VATTR_NULL(&vattr);
146358505Sbostic 	if (uap->tptr == NULL) {
146458505Sbostic 		microtime(&tv[0]);
146558505Sbostic 		tv[1] = tv[0];
146658548Sbostic 		vattr.va_vaflags |= VA_UTIMES_NULL;
146758505Sbostic 	} else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
146858505Sbostic   		return (error);
1469*59382Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
147052322Smckusick 	if (error = namei(&nd))
147147540Skarels 		return (error);
147252322Smckusick 	vp = nd.ni_vp;
1473*59382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
1474*59382Smckusick 	VOP_LOCK(vp);
147541400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
147637741Smckusick 		error = EROFS;
147737741Smckusick 		goto out;
147821015Smckusick 	}
147954100Smckusick 	vattr.va_atime.ts_sec = tv[0].tv_sec;
148054100Smckusick 	vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
148154100Smckusick 	vattr.va_mtime.ts_sec = tv[1].tv_sec;
148254100Smckusick 	vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
148348026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
148437741Smckusick out:
148537741Smckusick 	vput(vp);
148647540Skarels 	return (error);
148711811Ssam }
148811811Ssam 
148954916Storek struct __truncate_args {
149054863Storek 	char	*fname;
149154863Storek 	int	pad;
149254863Storek 	off_t	length;
149354863Storek };
149453468Smckusick 
149553468Smckusick /*
149653468Smckusick  * Truncate a file given its path name.
149753468Smckusick  */
149853468Smckusick /* ARGSUSED */
149953759Smckusick __truncate(p, uap, retval)
150053468Smckusick 	struct proc *p;
150154916Storek 	register struct __truncate_args *uap;
150253468Smckusick 	int *retval;
150353468Smckusick {
150437741Smckusick 	register struct vnode *vp;
150537741Smckusick 	struct vattr vattr;
150637741Smckusick 	int error;
150747540Skarels 	struct nameidata nd;
15087701Ssam 
1509*59382Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
151052322Smckusick 	if (error = namei(&nd))
151147540Skarels 		return (error);
151252322Smckusick 	vp = nd.ni_vp;
1513*59382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
1514*59382Smckusick 	VOP_LOCK(vp);
151537741Smckusick 	if (vp->v_type == VDIR) {
151637741Smckusick 		error = EISDIR;
151737741Smckusick 		goto out;
15187701Ssam 	}
151938399Smckusick 	if ((error = vn_writechk(vp)) ||
152048026Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)))
152137741Smckusick 		goto out;
152245785Sbostic 	VATTR_NULL(&vattr);
152345785Sbostic 	vattr.va_size = uap->length;
152448026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
152537741Smckusick out:
152637741Smckusick 	vput(vp);
152747540Skarels 	return (error);
15287701Ssam }
15297701Ssam 
153054916Storek struct __ftruncate_args {
153154863Storek 	int	fd;
153254863Storek 	int	pad;
153354863Storek 	off_t	length;
153454863Storek };
153554863Storek 
15369167Ssam /*
15379167Ssam  * Truncate a file given a file descriptor.
15389167Ssam  */
153942441Smckusick /* ARGSUSED */
154053759Smckusick __ftruncate(p, uap, retval)
154145914Smckusick 	struct proc *p;
154254916Storek 	register struct __ftruncate_args *uap;
154342441Smckusick 	int *retval;
154442441Smckusick {
154537741Smckusick 	struct vattr vattr;
154637741Smckusick 	struct vnode *vp;
15477701Ssam 	struct file *fp;
154837741Smckusick 	int error;
15497701Ssam 
155045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
155147540Skarels 		return (error);
155237741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
155347540Skarels 		return (EINVAL);
155437741Smckusick 	vp = (struct vnode *)fp->f_data;
1555*59382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
155637741Smckusick 	VOP_LOCK(vp);
155737741Smckusick 	if (vp->v_type == VDIR) {
155837741Smckusick 		error = EISDIR;
155937741Smckusick 		goto out;
15607701Ssam 	}
156138399Smckusick 	if (error = vn_writechk(vp))
156237741Smckusick 		goto out;
156345785Sbostic 	VATTR_NULL(&vattr);
156445785Sbostic 	vattr.va_size = uap->length;
156548026Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
156637741Smckusick out:
156737741Smckusick 	VOP_UNLOCK(vp);
156847540Skarels 	return (error);
15697701Ssam }
15707701Ssam 
157154863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
15729167Ssam /*
157354863Storek  * Truncate a file given its path name.
157454863Storek  */
157554916Storek struct truncate_args {
157654916Storek 	char	*fname;
157754916Storek 	long	length;
157854916Storek };
157954863Storek /* ARGSUSED */
158054863Storek truncate(p, uap, retval)
158154863Storek 	struct proc *p;
158254916Storek 	register struct truncate_args *uap;
158354863Storek 	int *retval;
158454863Storek {
158554916Storek 	struct __truncate_args nuap;
158654863Storek 
158754863Storek 	nuap.fname = uap->fname;
158854863Storek 	nuap.length = uap->length;
158954863Storek 	return (__truncate(p, &nuap, retval));
159054863Storek }
159154863Storek 
159254863Storek /*
159354863Storek  * Truncate a file given a file descriptor.
159454863Storek  */
159554916Storek struct ftruncate_args {
159654916Storek 	int	fd;
159754916Storek 	long	length;
159854916Storek };
159954863Storek /* ARGSUSED */
160054863Storek ftruncate(p, uap, retval)
160154863Storek 	struct proc *p;
160254916Storek 	register struct ftruncate_args *uap;
160354863Storek 	int *retval;
160454863Storek {
160554969Smckusick 	struct __ftruncate_args nuap;
160654863Storek 
160754863Storek 	nuap.fd = uap->fd;
160854863Storek 	nuap.length = uap->length;
160954863Storek 	return (__ftruncate(p, &nuap, retval));
161054863Storek }
161154863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */
161254863Storek 
161354863Storek /*
16149167Ssam  * Synch an open file.
16159167Ssam  */
161654916Storek struct fsync_args {
161754916Storek 	int	fd;
161854916Storek };
161942441Smckusick /* ARGSUSED */
162042441Smckusick fsync(p, uap, retval)
162145914Smckusick 	struct proc *p;
162254916Storek 	struct fsync_args *uap;
162342441Smckusick 	int *retval;
16249167Ssam {
162539592Smckusick 	register struct vnode *vp;
16269167Ssam 	struct file *fp;
162737741Smckusick 	int error;
16289167Ssam 
162945914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
163047540Skarels 		return (error);
163139592Smckusick 	vp = (struct vnode *)fp->f_data;
163239592Smckusick 	VOP_LOCK(vp);
163354441Smckusick 	error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
163439592Smckusick 	VOP_UNLOCK(vp);
163547540Skarels 	return (error);
16369167Ssam }
16379167Ssam 
16389167Ssam /*
16399167Ssam  * Rename system call.
16409167Ssam  *
16419167Ssam  * Source and destination must either both be directories, or both
16429167Ssam  * not be directories.  If target is a directory, it must be empty.
16439167Ssam  */
164454916Storek struct rename_args {
164554916Storek 	char	*from;
164654916Storek 	char	*to;
164754916Storek };
164842441Smckusick /* ARGSUSED */
164942441Smckusick rename(p, uap, retval)
165045914Smckusick 	struct proc *p;
165154916Storek 	register struct rename_args *uap;
165242441Smckusick 	int *retval;
165342441Smckusick {
165437741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
165549735Smckusick 	struct nameidata fromnd, tond;
165637741Smckusick 	int error;
16577701Ssam 
165852322Smckusick 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
165952322Smckusick 		uap->from, p);
166052322Smckusick 	if (error = namei(&fromnd))
166147540Skarels 		return (error);
166249735Smckusick 	fvp = fromnd.ni_vp;
166352322Smckusick 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
166452322Smckusick 		UIO_USERSPACE, uap->to, p);
166552322Smckusick 	if (error = namei(&tond)) {
166652230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
166749735Smckusick 		vrele(fromnd.ni_dvp);
166842465Smckusick 		vrele(fvp);
166942465Smckusick 		goto out1;
167042465Smckusick 	}
167137741Smckusick 	tdvp = tond.ni_dvp;
167237741Smckusick 	tvp = tond.ni_vp;
167337741Smckusick 	if (tvp != NULL) {
167437741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
167539242Sbostic 			error = ENOTDIR;
167637741Smckusick 			goto out;
167737741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
167839242Sbostic 			error = EISDIR;
167937741Smckusick 			goto out;
16809167Ssam 		}
16819167Ssam 	}
168239286Smckusick 	if (fvp == tdvp)
168337741Smckusick 		error = EINVAL;
168439286Smckusick 	/*
168549735Smckusick 	 * If source is the same as the destination (that is the
168649735Smckusick 	 * same inode number with the same name in the same directory),
168739286Smckusick 	 * then there is nothing to do.
168839286Smckusick 	 */
168949735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
169052322Smckusick 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
169152322Smckusick 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
169252322Smckusick 	      fromnd.ni_cnd.cn_namelen))
169339286Smckusick 		error = -1;
169437741Smckusick out:
169542465Smckusick 	if (!error) {
169652192Smckusick 		LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE);
169752192Smckusick 		if (fromnd.ni_dvp != tdvp)
169852192Smckusick 			LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
169952192Smckusick 		if (tvp)
170052192Smckusick 			LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE);
170152230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
170252230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
170342465Smckusick 	} else {
170452230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
170543344Smckusick 		if (tdvp == tvp)
170643344Smckusick 			vrele(tdvp);
170743344Smckusick 		else
170843344Smckusick 			vput(tdvp);
170942465Smckusick 		if (tvp)
171042465Smckusick 			vput(tvp);
171152230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
171249735Smckusick 		vrele(fromnd.ni_dvp);
171342465Smckusick 		vrele(fvp);
17149167Ssam 	}
171549735Smckusick 	vrele(tond.ni_startdir);
171652322Smckusick 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
171737741Smckusick out1:
171849735Smckusick 	vrele(fromnd.ni_startdir);
171952322Smckusick 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
172039286Smckusick 	if (error == -1)
172147540Skarels 		return (0);
172247540Skarels 	return (error);
17237701Ssam }
17247701Ssam 
17257535Sroot /*
172649365Smckusick  * Mkdir system call.
172712756Ssam  */
172854916Storek struct mkdir_args {
172954916Storek 	char	*name;
173054916Storek 	int	dmode;
173154916Storek };
173242441Smckusick /* ARGSUSED */
173342441Smckusick mkdir(p, uap, retval)
173445914Smckusick 	struct proc *p;
173554916Storek 	register struct mkdir_args *uap;
173642441Smckusick 	int *retval;
173742441Smckusick {
173837741Smckusick 	register struct vnode *vp;
173937741Smckusick 	struct vattr vattr;
174037741Smckusick 	int error;
174147540Skarels 	struct nameidata nd;
174212756Ssam 
174352322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p);
174452322Smckusick 	if (error = namei(&nd))
174547540Skarels 		return (error);
174652322Smckusick 	vp = nd.ni_vp;
174737741Smckusick 	if (vp != NULL) {
174852322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
174952322Smckusick 		if (nd.ni_dvp == vp)
175052322Smckusick 			vrele(nd.ni_dvp);
175143344Smckusick 		else
175252322Smckusick 			vput(nd.ni_dvp);
175342465Smckusick 		vrele(vp);
175447540Skarels 		return (EEXIST);
175512756Ssam 	}
175641362Smckusick 	VATTR_NULL(&vattr);
175737741Smckusick 	vattr.va_type = VDIR;
175845914Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask;
175952322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
176052322Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
176138145Smckusick 	if (!error)
176252322Smckusick 		vput(nd.ni_vp);
176347540Skarels 	return (error);
176412756Ssam }
176512756Ssam 
176612756Ssam /*
176712756Ssam  * Rmdir system call.
176812756Ssam  */
176954916Storek struct rmdir_args {
177054916Storek 	char	*name;
177154916Storek };
177242441Smckusick /* ARGSUSED */
177342441Smckusick rmdir(p, uap, retval)
177445914Smckusick 	struct proc *p;
177554916Storek 	struct rmdir_args *uap;
177642441Smckusick 	int *retval;
177712756Ssam {
177837741Smckusick 	register struct vnode *vp;
177937741Smckusick 	int error;
178047540Skarels 	struct nameidata nd;
178112756Ssam 
178252322Smckusick 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p);
178352322Smckusick 	if (error = namei(&nd))
178447540Skarels 		return (error);
178552322Smckusick 	vp = nd.ni_vp;
178637741Smckusick 	if (vp->v_type != VDIR) {
178737741Smckusick 		error = ENOTDIR;
178812756Ssam 		goto out;
178912756Ssam 	}
179012756Ssam 	/*
179137741Smckusick 	 * No rmdir "." please.
179212756Ssam 	 */
179352322Smckusick 	if (nd.ni_dvp == vp) {
179437741Smckusick 		error = EINVAL;
179512756Ssam 		goto out;
179612756Ssam 	}
179712756Ssam 	/*
179849365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
179912756Ssam 	 */
180037741Smckusick 	if (vp->v_flag & VROOT)
180137741Smckusick 		error = EBUSY;
180212756Ssam out:
180342465Smckusick 	if (!error) {
180452322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
180552192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
180652322Smckusick 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
180742465Smckusick 	} else {
180852322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
180952322Smckusick 		if (nd.ni_dvp == vp)
181052322Smckusick 			vrele(nd.ni_dvp);
181143344Smckusick 		else
181252322Smckusick 			vput(nd.ni_dvp);
181342465Smckusick 		vput(vp);
181442465Smckusick 	}
181547540Skarels 	return (error);
181612756Ssam }
181712756Ssam 
181854620Smckusick #ifdef COMPAT_43
181937741Smckusick /*
182049365Smckusick  * Read a block of directory entries in a file system independent format.
182137741Smckusick  */
182254916Storek struct ogetdirentries_args {
182354916Storek 	int	fd;
182454916Storek 	char	*buf;
182554916Storek 	unsigned count;
182654916Storek 	long	*basep;
182754916Storek };
182854620Smckusick ogetdirentries(p, uap, retval)
182954620Smckusick 	struct proc *p;
183054916Storek 	register struct ogetdirentries_args *uap;
183154620Smckusick 	int *retval;
183254620Smckusick {
183354620Smckusick 	register struct vnode *vp;
183454620Smckusick 	struct file *fp;
183554620Smckusick 	struct uio auio, kuio;
183654620Smckusick 	struct iovec aiov, kiov;
183754620Smckusick 	struct dirent *dp, *edp;
183854620Smckusick 	caddr_t dirbuf;
183954620Smckusick 	int error, readcnt;
184054969Smckusick 	long loff;
184154620Smckusick 
184254620Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
184354620Smckusick 		return (error);
184454620Smckusick 	if ((fp->f_flag & FREAD) == 0)
184554620Smckusick 		return (EBADF);
184654620Smckusick 	vp = (struct vnode *)fp->f_data;
184754620Smckusick 	if (vp->v_type != VDIR)
184854620Smckusick 		return (EINVAL);
184954620Smckusick 	aiov.iov_base = uap->buf;
185054620Smckusick 	aiov.iov_len = uap->count;
185154620Smckusick 	auio.uio_iov = &aiov;
185254620Smckusick 	auio.uio_iovcnt = 1;
185354620Smckusick 	auio.uio_rw = UIO_READ;
185454620Smckusick 	auio.uio_segflg = UIO_USERSPACE;
185554620Smckusick 	auio.uio_procp = p;
185654620Smckusick 	auio.uio_resid = uap->count;
185754620Smckusick 	VOP_LOCK(vp);
185854969Smckusick 	loff = auio.uio_offset = fp->f_offset;
185954620Smckusick #	if (BYTE_ORDER != LITTLE_ENDIAN)
186056339Smckusick 		if (vp->v_mount->mnt_maxsymlinklen <= 0) {
186154620Smckusick 			error = VOP_READDIR(vp, &auio, fp->f_cred);
186256339Smckusick 			fp->f_offset = auio.uio_offset;
186356339Smckusick 		} else
186454620Smckusick #	endif
186554620Smckusick 	{
186654620Smckusick 		kuio = auio;
186754620Smckusick 		kuio.uio_iov = &kiov;
186854620Smckusick 		kuio.uio_segflg = UIO_SYSSPACE;
186954620Smckusick 		kiov.iov_len = uap->count;
187054620Smckusick 		MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK);
187154620Smckusick 		kiov.iov_base = dirbuf;
187254620Smckusick 		error = VOP_READDIR(vp, &kuio, fp->f_cred);
187356339Smckusick 		fp->f_offset = kuio.uio_offset;
187454620Smckusick 		if (error == 0) {
187554620Smckusick 			readcnt = uap->count - kuio.uio_resid;
187654620Smckusick 			edp = (struct dirent *)&dirbuf[readcnt];
187754620Smckusick 			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
187854620Smckusick #				if (BYTE_ORDER == LITTLE_ENDIAN)
187954969Smckusick 					/*
188055009Smckusick 					 * The expected low byte of
188155009Smckusick 					 * dp->d_namlen is our dp->d_type.
188255009Smckusick 					 * The high MBZ byte of dp->d_namlen
188355009Smckusick 					 * is our dp->d_namlen.
188454969Smckusick 					 */
188555009Smckusick 					dp->d_type = dp->d_namlen;
188655009Smckusick 					dp->d_namlen = 0;
188755009Smckusick #				else
188855009Smckusick 					/*
188955009Smckusick 					 * The dp->d_type is the high byte
189055009Smckusick 					 * of the expected dp->d_namlen,
189155009Smckusick 					 * so must be zero'ed.
189255009Smckusick 					 */
189355009Smckusick 					dp->d_type = 0;
189454620Smckusick #				endif
189554620Smckusick 				if (dp->d_reclen > 0) {
189654620Smckusick 					dp = (struct dirent *)
189754620Smckusick 					    ((char *)dp + dp->d_reclen);
189854620Smckusick 				} else {
189954620Smckusick 					error = EIO;
190054620Smckusick 					break;
190154620Smckusick 				}
190254620Smckusick 			}
190354620Smckusick 			if (dp >= edp)
190454620Smckusick 				error = uiomove(dirbuf, readcnt, &auio);
190554620Smckusick 		}
190654620Smckusick 		FREE(dirbuf, M_TEMP);
190754620Smckusick 	}
190854620Smckusick 	VOP_UNLOCK(vp);
190954620Smckusick 	if (error)
191054620Smckusick 		return (error);
191154969Smckusick 	error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
191254620Smckusick 	*retval = uap->count - auio.uio_resid;
191354620Smckusick 	return (error);
191454620Smckusick }
191554620Smckusick #endif
191654620Smckusick 
191754620Smckusick /*
191854620Smckusick  * Read a block of directory entries in a file system independent format.
191954620Smckusick  */
192054916Storek struct getdirentries_args {
192154916Storek 	int	fd;
192254916Storek 	char	*buf;
192354916Storek 	unsigned count;
192454916Storek 	long	*basep;
192554916Storek };
192642441Smckusick getdirentries(p, uap, retval)
192745914Smckusick 	struct proc *p;
192854916Storek 	register struct getdirentries_args *uap;
192942441Smckusick 	int *retval;
193042441Smckusick {
193139592Smckusick 	register struct vnode *vp;
193216540Ssam 	struct file *fp;
193337741Smckusick 	struct uio auio;
193437741Smckusick 	struct iovec aiov;
193554969Smckusick 	long loff;
193654441Smckusick 	int error;
193712756Ssam 
193845914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
193947540Skarels 		return (error);
194037741Smckusick 	if ((fp->f_flag & FREAD) == 0)
194147540Skarels 		return (EBADF);
194239592Smckusick 	vp = (struct vnode *)fp->f_data;
194355451Spendry unionread:
194439592Smckusick 	if (vp->v_type != VDIR)
194547540Skarels 		return (EINVAL);
194637741Smckusick 	aiov.iov_base = uap->buf;
194737741Smckusick 	aiov.iov_len = uap->count;
194837741Smckusick 	auio.uio_iov = &aiov;
194937741Smckusick 	auio.uio_iovcnt = 1;
195037741Smckusick 	auio.uio_rw = UIO_READ;
195137741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
195248026Smckusick 	auio.uio_procp = p;
195337741Smckusick 	auio.uio_resid = uap->count;
195439592Smckusick 	VOP_LOCK(vp);
195554969Smckusick 	loff = auio.uio_offset = fp->f_offset;
195654441Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred);
195739592Smckusick 	fp->f_offset = auio.uio_offset;
195839592Smckusick 	VOP_UNLOCK(vp);
195939592Smckusick 	if (error)
196047540Skarels 		return (error);
196155451Spendry 	if ((uap->count == auio.uio_resid) &&
196255451Spendry 	    (vp->v_flag & VROOT) &&
196355451Spendry 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
196455451Spendry 		struct vnode *tvp = vp;
196555451Spendry 		vp = vp->v_mount->mnt_vnodecovered;
196655451Spendry 		VREF(vp);
196755451Spendry 		fp->f_data = (caddr_t) vp;
196855451Spendry 		fp->f_offset = 0;
196955451Spendry 		vrele(tvp);
197055451Spendry 		goto unionread;
197155451Spendry 	}
197254969Smckusick 	error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
197342441Smckusick 	*retval = uap->count - auio.uio_resid;
197447540Skarels 	return (error);
197512756Ssam }
197612756Ssam 
197712756Ssam /*
197849365Smckusick  * Set the mode mask for creation of filesystem nodes.
197912756Ssam  */
198054916Storek struct umask_args {
198154916Storek 	int	mask;
198254916Storek };
198354916Storek mode_t				/* XXX */
198442441Smckusick umask(p, uap, retval)
198545914Smckusick 	struct proc *p;
198654916Storek 	struct umask_args *uap;
198742441Smckusick 	int *retval;
198812756Ssam {
198945914Smckusick 	register struct filedesc *fdp = p->p_fd;
199012756Ssam 
199145914Smckusick 	*retval = fdp->fd_cmask;
199245914Smckusick 	fdp->fd_cmask = uap->mask & 07777;
199347540Skarels 	return (0);
199412756Ssam }
199537741Smckusick 
199639566Smarc /*
199739566Smarc  * Void all references to file by ripping underlying filesystem
199839566Smarc  * away from vnode.
199939566Smarc  */
200054916Storek struct revoke_args {
200154916Storek 	char	*fname;
200254916Storek };
200342441Smckusick /* ARGSUSED */
200442441Smckusick revoke(p, uap, retval)
200545914Smckusick 	struct proc *p;
200654916Storek 	register struct revoke_args *uap;
200742441Smckusick 	int *retval;
200842441Smckusick {
200939566Smarc 	register struct vnode *vp;
201039566Smarc 	struct vattr vattr;
201139566Smarc 	int error;
201247540Skarels 	struct nameidata nd;
201339566Smarc 
201452322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
201552322Smckusick 	if (error = namei(&nd))
201647540Skarels 		return (error);
201752322Smckusick 	vp = nd.ni_vp;
201839566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
201939566Smarc 		error = EINVAL;
202039566Smarc 		goto out;
202139566Smarc 	}
202248026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
202339566Smarc 		goto out;
202447540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
202547540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
202639566Smarc 		goto out;
202739805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
202839632Smckusick 		vgoneall(vp);
202939566Smarc out:
203039566Smarc 	vrele(vp);
203147540Skarels 	return (error);
203239566Smarc }
203339566Smarc 
203449365Smckusick /*
203549365Smckusick  * Convert a user file descriptor to a kernel file entry.
203649365Smckusick  */
203745914Smckusick getvnode(fdp, fdes, fpp)
203845914Smckusick 	struct filedesc *fdp;
203937741Smckusick 	struct file **fpp;
204037741Smckusick 	int fdes;
204137741Smckusick {
204237741Smckusick 	struct file *fp;
204337741Smckusick 
204447540Skarels 	if ((unsigned)fdes >= fdp->fd_nfiles ||
204547688Skarels 	    (fp = fdp->fd_ofiles[fdes]) == NULL)
204637741Smckusick 		return (EBADF);
204737741Smckusick 	if (fp->f_type != DTYPE_VNODE)
204837741Smckusick 		return (EINVAL);
204937741Smckusick 	*fpp = fp;
205037741Smckusick 	return (0);
205137741Smckusick }
2052