xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 60414)
123405Smckusick /*
237741Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337741Smckusick  * All rights reserved.
423405Smckusick  *
544459Sbostic  * %sccs.include.redist.c%
637741Smckusick  *
7*60414Smckusick  *	@(#)vfs_syscalls.c	7.111 (Berkeley) 05/25/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>
2559875Smckusick #include <sys/sysctl.h>
2637Sbill 
2737741Smckusick /*
2837741Smckusick  * Virtual File System System Calls
2937741Smckusick  */
3012756Ssam 
319167Ssam /*
3249365Smckusick  * Mount system call.
339167Ssam  */
3454916Storek struct mount_args {
3554916Storek 	int	type;
3654916Storek 	char	*dir;
3754916Storek 	int	flags;
3854916Storek 	caddr_t	data;
3954916Storek };
4042441Smckusick /* ARGSUSED */
4142441Smckusick mount(p, uap, retval)
4245914Smckusick 	struct proc *p;
4354916Storek 	register struct mount_args *uap;
4442441Smckusick 	int *retval;
4542441Smckusick {
4639335Smckusick 	register struct vnode *vp;
4739335Smckusick 	register struct mount *mp;
4840111Smckusick 	int error, flag;
4947540Skarels 	struct nameidata nd;
506254Sroot 
5137741Smckusick 	/*
5237741Smckusick 	 * Must be super user
5337741Smckusick 	 */
5447540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
5547540Skarels 		return (error);
5637741Smckusick 	/*
5737741Smckusick 	 * Get vnode to be covered
5837741Smckusick 	 */
5952322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->dir, p);
6052322Smckusick 	if (error = namei(&nd))
6147540Skarels 		return (error);
6252322Smckusick 	vp = nd.ni_vp;
6341400Smckusick 	if (uap->flags & MNT_UPDATE) {
6439335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
6539335Smckusick 			vput(vp);
6647540Skarels 			return (EINVAL);
6739335Smckusick 		}
6839335Smckusick 		mp = vp->v_mount;
6957047Smckusick 		flag = mp->mnt_flag;
7039335Smckusick 		/*
7157047Smckusick 		 * We only allow the filesystem to be reloaded if it
7257047Smckusick 		 * is currently mounted read-only.
7339335Smckusick 		 */
7457047Smckusick 		if ((uap->flags & MNT_RELOAD) &&
7557047Smckusick 		    ((mp->mnt_flag & MNT_RDONLY) == 0)) {
7639335Smckusick 			vput(vp);
7747540Skarels 			return (EOPNOTSUPP);	/* Needs translation */
7839335Smckusick 		}
7957047Smckusick 		mp->mnt_flag |=
8057047Smckusick 		    uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
8139335Smckusick 		VOP_UNLOCK(vp);
8239335Smckusick 		goto update;
8339335Smckusick 	}
8455451Spendry 	if (vp->v_usecount != 1 && (uap->flags & MNT_UNION) == 0) {
8537741Smckusick 		vput(vp);
8647540Skarels 		return (EBUSY);
8737741Smckusick 	}
8857793Smckusick 	if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0))
8954441Smckusick 		return (error);
9037741Smckusick 	if (vp->v_type != VDIR) {
9137741Smckusick 		vput(vp);
9247540Skarels 		return (ENOTDIR);
9337741Smckusick 	}
9439741Smckusick 	if ((unsigned long)uap->type > MOUNT_MAXTYPE ||
9537741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
9637741Smckusick 		vput(vp);
9747540Skarels 		return (ENODEV);
9837741Smckusick 	}
9937741Smckusick 
10037741Smckusick 	/*
10139335Smckusick 	 * Allocate and initialize the file system.
10237741Smckusick 	 */
10337741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
10437741Smckusick 		M_MOUNT, M_WAITOK);
10554172Smckusick 	bzero((char *)mp, (u_long)sizeof(struct mount));
10641400Smckusick 	mp->mnt_op = vfssw[uap->type];
10739335Smckusick 	if (error = vfs_lock(mp)) {
10839335Smckusick 		free((caddr_t)mp, M_MOUNT);
10939335Smckusick 		vput(vp);
11047540Skarels 		return (error);
11139335Smckusick 	}
11239335Smckusick 	if (vp->v_mountedhere != (struct mount *)0) {
11339335Smckusick 		vfs_unlock(mp);
11439335Smckusick 		free((caddr_t)mp, M_MOUNT);
11539335Smckusick 		vput(vp);
11647540Skarels 		return (EBUSY);
11739335Smckusick 	}
11839335Smckusick 	vp->v_mountedhere = mp;
11941400Smckusick 	mp->mnt_vnodecovered = vp;
12039335Smckusick update:
12139335Smckusick 	/*
12239335Smckusick 	 * Set the mount level flags.
12339335Smckusick 	 */
12441400Smckusick 	if (uap->flags & MNT_RDONLY)
12541400Smckusick 		mp->mnt_flag |= MNT_RDONLY;
12657047Smckusick 	else if (mp->mnt_flag & MNT_RDONLY)
12757047Smckusick 		mp->mnt_flag |= MNT_WANTRDWR;
12857047Smckusick 	mp->mnt_flag &=~
12957047Smckusick 	    (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION);
13057047Smckusick 	mp->mnt_flag |= uap->flags &
13157047Smckusick 	    (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION);
13239335Smckusick 	/*
13339335Smckusick 	 * Mount the filesystem.
13439335Smckusick 	 */
13552322Smckusick 	error = VFS_MOUNT(mp, uap->dir, uap->data, &nd, p);
13641400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
13739335Smckusick 		vrele(vp);
13857047Smckusick 		if (mp->mnt_flag & MNT_WANTRDWR)
13957047Smckusick 			mp->mnt_flag &= ~MNT_RDONLY;
14057047Smckusick 		mp->mnt_flag &=~
14157047Smckusick 		    (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
14240111Smckusick 		if (error)
14341400Smckusick 			mp->mnt_flag = flag;
14447540Skarels 		return (error);
14539335Smckusick 	}
14640110Smckusick 	/*
14740110Smckusick 	 * Put the new filesystem on the mount list after root.
14840110Smckusick 	 */
14941400Smckusick 	mp->mnt_next = rootfs->mnt_next;
15041400Smckusick 	mp->mnt_prev = rootfs;
15141400Smckusick 	rootfs->mnt_next = mp;
15241400Smckusick 	mp->mnt_next->mnt_prev = mp;
15337741Smckusick 	cache_purge(vp);
15437741Smckusick 	if (!error) {
15539335Smckusick 		VOP_UNLOCK(vp);
15637741Smckusick 		vfs_unlock(mp);
15748026Smckusick 		error = VFS_START(mp, 0, p);
15837741Smckusick 	} else {
15937741Smckusick 		vfs_remove(mp);
16037741Smckusick 		free((caddr_t)mp, M_MOUNT);
16139335Smckusick 		vput(vp);
16237741Smckusick 	}
16347540Skarels 	return (error);
1646254Sroot }
1656254Sroot 
1669167Ssam /*
16737741Smckusick  * Unmount system call.
16837741Smckusick  *
16937741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
17037741Smckusick  * not special file (as before).
1719167Ssam  */
17254916Storek struct unmount_args {
17354916Storek 	char	*pathp;
17454916Storek 	int	flags;
17554916Storek };
17642441Smckusick /* ARGSUSED */
17742441Smckusick unmount(p, uap, retval)
17845914Smckusick 	struct proc *p;
17954916Storek 	register struct unmount_args *uap;
18042441Smckusick 	int *retval;
18142441Smckusick {
18237741Smckusick 	register struct vnode *vp;
18339356Smckusick 	struct mount *mp;
18437741Smckusick 	int error;
18547540Skarels 	struct nameidata nd;
1866254Sroot 
18737741Smckusick 	/*
18837741Smckusick 	 * Must be super user
18937741Smckusick 	 */
19047540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
19147540Skarels 		return (error);
19237741Smckusick 
19352322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->pathp, p);
19452322Smckusick 	if (error = namei(&nd))
19547540Skarels 		return (error);
19652322Smckusick 	vp = nd.ni_vp;
19737741Smckusick 	/*
19837741Smckusick 	 * Must be the root of the filesystem
19937741Smckusick 	 */
20037741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
20137741Smckusick 		vput(vp);
20247540Skarels 		return (EINVAL);
20337741Smckusick 	}
20437741Smckusick 	mp = vp->v_mount;
20537741Smckusick 	vput(vp);
20648026Smckusick 	return (dounmount(mp, uap->flags, p));
20739356Smckusick }
20839356Smckusick 
20939356Smckusick /*
21039356Smckusick  * Do an unmount.
21139356Smckusick  */
21248026Smckusick dounmount(mp, flags, p)
21339356Smckusick 	register struct mount *mp;
21439356Smckusick 	int flags;
21548026Smckusick 	struct proc *p;
21639356Smckusick {
21739356Smckusick 	struct vnode *coveredvp;
21839356Smckusick 	int error;
21939356Smckusick 
22041400Smckusick 	coveredvp = mp->mnt_vnodecovered;
22141298Smckusick 	if (vfs_busy(mp))
22241298Smckusick 		return (EBUSY);
22341400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
22437741Smckusick 	if (error = vfs_lock(mp))
22539356Smckusick 		return (error);
22637741Smckusick 
22745738Smckusick 	vnode_pager_umount(mp);	/* release cached vnodes */
22837741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
22954441Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 ||
23054441Smckusick 	    (flags & MNT_FORCE))
23148026Smckusick 		error = VFS_UNMOUNT(mp, flags, p);
23241400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
23341298Smckusick 	vfs_unbusy(mp);
23437741Smckusick 	if (error) {
23537741Smckusick 		vfs_unlock(mp);
23637741Smckusick 	} else {
23737741Smckusick 		vrele(coveredvp);
23837741Smckusick 		vfs_remove(mp);
23952287Smckusick 		if (mp->mnt_mounth != NULL)
24052287Smckusick 			panic("unmount: dangling vnode");
24137741Smckusick 		free((caddr_t)mp, M_MOUNT);
24237741Smckusick 	}
24339356Smckusick 	return (error);
2446254Sroot }
2456254Sroot 
2469167Ssam /*
24737741Smckusick  * Sync system call.
24837741Smckusick  * Sync each mounted filesystem.
2499167Ssam  */
25056352Smckusick #ifdef DIAGNOSTIC
25156352Smckusick int syncprt = 0;
25259875Smckusick struct ctldebug debug0 = { "syncprt", &syncprt };
25356352Smckusick #endif
25456352Smckusick 
25554916Storek struct sync_args {
25654916Storek 	int	dummy;
25754916Storek };
25839491Smckusick /* ARGSUSED */
25942441Smckusick sync(p, uap, retval)
26045914Smckusick 	struct proc *p;
26154916Storek 	struct sync_args *uap;
26242441Smckusick 	int *retval;
2636254Sroot {
26437741Smckusick 	register struct mount *mp;
26541298Smckusick 	struct mount *omp;
26637741Smckusick 
26737741Smckusick 	mp = rootfs;
26837741Smckusick 	do {
26940343Smckusick 		/*
27040343Smckusick 		 * The lock check below is to avoid races with mount
27140343Smckusick 		 * and unmount.
27240343Smckusick 		 */
27341400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
27441298Smckusick 		    !vfs_busy(mp)) {
27554441Smckusick 			VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
27641298Smckusick 			omp = mp;
27741400Smckusick 			mp = mp->mnt_next;
27841298Smckusick 			vfs_unbusy(omp);
27941298Smckusick 		} else
28041400Smckusick 			mp = mp->mnt_next;
28137741Smckusick 	} while (mp != rootfs);
28256352Smckusick #ifdef DIAGNOSTIC
28356352Smckusick 	if (syncprt)
28456352Smckusick 		vfs_bufstats();
28556352Smckusick #endif /* DIAGNOSTIC */
28647688Skarels 	return (0);
28737741Smckusick }
28837741Smckusick 
28937741Smckusick /*
29049365Smckusick  * Operate on filesystem quotas.
29141298Smckusick  */
29254916Storek struct quotactl_args {
29354916Storek 	char *path;
29454916Storek 	int cmd;
29554916Storek 	int uid;
29654916Storek 	caddr_t arg;
29754916Storek };
29842441Smckusick /* ARGSUSED */
29942441Smckusick quotactl(p, uap, retval)
30045914Smckusick 	struct proc *p;
30154916Storek 	register struct quotactl_args *uap;
30242441Smckusick 	int *retval;
30342441Smckusick {
30441298Smckusick 	register struct mount *mp;
30541298Smckusick 	int error;
30647540Skarels 	struct nameidata nd;
30741298Smckusick 
30852322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
30952322Smckusick 	if (error = namei(&nd))
31047540Skarels 		return (error);
31152322Smckusick 	mp = nd.ni_vp->v_mount;
31252322Smckusick 	vrele(nd.ni_vp);
31348026Smckusick 	return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p));
31441298Smckusick }
31541298Smckusick 
31641298Smckusick /*
31749365Smckusick  * Get filesystem statistics.
31837741Smckusick  */
31954916Storek struct statfs_args {
32054916Storek 	char *path;
32154916Storek 	struct statfs *buf;
32254916Storek };
32342441Smckusick /* ARGSUSED */
32442441Smckusick statfs(p, uap, retval)
32545914Smckusick 	struct proc *p;
32654916Storek 	register struct statfs_args *uap;
32742441Smckusick 	int *retval;
32842441Smckusick {
32939464Smckusick 	register struct mount *mp;
33040343Smckusick 	register struct statfs *sp;
33137741Smckusick 	int error;
33247540Skarels 	struct nameidata nd;
33337741Smckusick 
33452322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
33552322Smckusick 	if (error = namei(&nd))
33647540Skarels 		return (error);
33752322Smckusick 	mp = nd.ni_vp->v_mount;
33841400Smckusick 	sp = &mp->mnt_stat;
33952322Smckusick 	vrele(nd.ni_vp);
34048026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
34147540Skarels 		return (error);
34241400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
34347540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
34437741Smckusick }
34537741Smckusick 
34642441Smckusick /*
34749365Smckusick  * Get filesystem statistics.
34842441Smckusick  */
34954916Storek struct fstatfs_args {
35054916Storek 	int fd;
35154916Storek 	struct statfs *buf;
35254916Storek };
35342441Smckusick /* ARGSUSED */
35442441Smckusick fstatfs(p, uap, retval)
35545914Smckusick 	struct proc *p;
35654916Storek 	register struct fstatfs_args *uap;
35742441Smckusick 	int *retval;
35842441Smckusick {
35937741Smckusick 	struct file *fp;
36039464Smckusick 	struct mount *mp;
36140343Smckusick 	register struct statfs *sp;
36237741Smckusick 	int error;
36337741Smckusick 
36445914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
36547540Skarels 		return (error);
36639464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
36741400Smckusick 	sp = &mp->mnt_stat;
36848026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
36947540Skarels 		return (error);
37041400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
37147540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
37237741Smckusick }
37337741Smckusick 
37437741Smckusick /*
37549365Smckusick  * Get statistics on all filesystems.
37638270Smckusick  */
37754916Storek struct getfsstat_args {
37854916Storek 	struct statfs *buf;
37954916Storek 	long bufsize;
38054916Storek 	int flags;
38154916Storek };
38242441Smckusick getfsstat(p, uap, retval)
38345914Smckusick 	struct proc *p;
38454916Storek 	register struct getfsstat_args *uap;
38542441Smckusick 	int *retval;
38642441Smckusick {
38738270Smckusick 	register struct mount *mp;
38840343Smckusick 	register struct statfs *sp;
38939606Smckusick 	caddr_t sfsp;
39038270Smckusick 	long count, maxcount, error;
39138270Smckusick 
39238270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
39339606Smckusick 	sfsp = (caddr_t)uap->buf;
39438270Smckusick 	mp = rootfs;
39538270Smckusick 	count = 0;
39638270Smckusick 	do {
39741400Smckusick 		if (sfsp && count < maxcount &&
39841400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
39941400Smckusick 			sp = &mp->mnt_stat;
40040343Smckusick 			/*
40140343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
40240343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
40340343Smckusick 			 */
40440343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
40540343Smckusick 			    (uap->flags & MNT_WAIT)) &&
40648026Smckusick 			    (error = VFS_STATFS(mp, sp, p))) {
40741400Smckusick 				mp = mp->mnt_prev;
40839607Smckusick 				continue;
40939607Smckusick 			}
41041400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
41140343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
41247540Skarels 				return (error);
41340343Smckusick 			sfsp += sizeof(*sp);
41438270Smckusick 		}
41539606Smckusick 		count++;
41641400Smckusick 		mp = mp->mnt_prev;
41738270Smckusick 	} while (mp != rootfs);
41838270Smckusick 	if (sfsp && count > maxcount)
41942441Smckusick 		*retval = maxcount;
42038270Smckusick 	else
42142441Smckusick 		*retval = count;
42247540Skarels 	return (0);
42338270Smckusick }
42438270Smckusick 
42538270Smckusick /*
42638259Smckusick  * Change current working directory to a given file descriptor.
42738259Smckusick  */
42854916Storek struct fchdir_args {
42954916Storek 	int	fd;
43054916Storek };
43142441Smckusick /* ARGSUSED */
43242441Smckusick fchdir(p, uap, retval)
43345914Smckusick 	struct proc *p;
43454916Storek 	struct fchdir_args *uap;
43542441Smckusick 	int *retval;
43638259Smckusick {
43745914Smckusick 	register struct filedesc *fdp = p->p_fd;
43838259Smckusick 	register struct vnode *vp;
43938259Smckusick 	struct file *fp;
44038259Smckusick 	int error;
44138259Smckusick 
44245914Smckusick 	if (error = getvnode(fdp, uap->fd, &fp))
44347540Skarels 		return (error);
44438259Smckusick 	vp = (struct vnode *)fp->f_data;
44538259Smckusick 	VOP_LOCK(vp);
44638259Smckusick 	if (vp->v_type != VDIR)
44738259Smckusick 		error = ENOTDIR;
44838259Smckusick 	else
44948026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
45038259Smckusick 	VOP_UNLOCK(vp);
45139860Smckusick 	if (error)
45247540Skarels 		return (error);
45339860Smckusick 	VREF(vp);
45445914Smckusick 	vrele(fdp->fd_cdir);
45545914Smckusick 	fdp->fd_cdir = vp;
45647540Skarels 	return (0);
45738259Smckusick }
45838259Smckusick 
45938259Smckusick /*
46037741Smckusick  * Change current working directory (``.'').
46137741Smckusick  */
46254916Storek struct chdir_args {
46354916Storek 	char	*fname;
46454916Storek };
46542441Smckusick /* ARGSUSED */
46642441Smckusick chdir(p, uap, retval)
46745914Smckusick 	struct proc *p;
46854916Storek 	struct chdir_args *uap;
46942441Smckusick 	int *retval;
47037741Smckusick {
47145914Smckusick 	register struct filedesc *fdp = p->p_fd;
47237741Smckusick 	int error;
47347540Skarels 	struct nameidata nd;
4746254Sroot 
47552322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
47652781Sralph 	if (error = chdirec(&nd, p))
47747540Skarels 		return (error);
47845914Smckusick 	vrele(fdp->fd_cdir);
47952322Smckusick 	fdp->fd_cdir = nd.ni_vp;
48047540Skarels 	return (0);
48137741Smckusick }
4826254Sroot 
48337741Smckusick /*
48437741Smckusick  * Change notion of root (``/'') directory.
48537741Smckusick  */
48654916Storek struct chroot_args {
48754916Storek 	char	*fname;
48854916Storek };
48942441Smckusick /* ARGSUSED */
49042441Smckusick chroot(p, uap, retval)
49145914Smckusick 	struct proc *p;
49254916Storek 	struct chroot_args *uap;
49342441Smckusick 	int *retval;
49437741Smckusick {
49545914Smckusick 	register struct filedesc *fdp = p->p_fd;
49637741Smckusick 	int error;
49747540Skarels 	struct nameidata nd;
49837741Smckusick 
49947540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
50047540Skarels 		return (error);
50152322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
50252781Sralph 	if (error = chdirec(&nd, p))
50347540Skarels 		return (error);
50445914Smckusick 	if (fdp->fd_rdir != NULL)
50545914Smckusick 		vrele(fdp->fd_rdir);
50652322Smckusick 	fdp->fd_rdir = nd.ni_vp;
50747540Skarels 	return (0);
5086254Sroot }
5096254Sroot 
51037Sbill /*
51137741Smckusick  * Common routine for chroot and chdir.
51237741Smckusick  */
51347540Skarels chdirec(ndp, p)
51452322Smckusick 	register struct nameidata *ndp;
51547540Skarels 	struct proc *p;
51637741Smckusick {
51737741Smckusick 	struct vnode *vp;
51837741Smckusick 	int error;
51937741Smckusick 
52052322Smckusick 	if (error = namei(ndp))
52137741Smckusick 		return (error);
52237741Smckusick 	vp = ndp->ni_vp;
52337741Smckusick 	if (vp->v_type != VDIR)
52437741Smckusick 		error = ENOTDIR;
52537741Smckusick 	else
52648026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
52737741Smckusick 	VOP_UNLOCK(vp);
52837741Smckusick 	if (error)
52937741Smckusick 		vrele(vp);
53037741Smckusick 	return (error);
53137741Smckusick }
53237741Smckusick 
53337741Smckusick /*
5346254Sroot  * Open system call.
53542441Smckusick  * Check permissions, allocate an open file structure,
53642441Smckusick  * and call the device open routine if any.
5376254Sroot  */
53854916Storek struct open_args {
53954916Storek 	char	*fname;
54054916Storek 	int	mode;
54154916Storek 	int	crtmode;
54254916Storek };
54342441Smckusick open(p, uap, retval)
54445914Smckusick 	struct proc *p;
54554916Storek 	register struct open_args *uap;
54642441Smckusick 	int *retval;
5476254Sroot {
54845914Smckusick 	register struct filedesc *fdp = p->p_fd;
54942441Smckusick 	register struct file *fp;
55050111Smckusick 	register struct vnode *vp;
55137741Smckusick 	int fmode, cmode;
55237741Smckusick 	struct file *nfp;
55349945Smckusick 	int type, indx, error;
55449945Smckusick 	struct flock lf;
55547540Skarels 	struct nameidata nd;
55637741Smckusick 	extern struct fileops vnops;
5576254Sroot 
55845914Smckusick 	if (error = falloc(p, &nfp, &indx))
55947540Skarels 		return (error);
56037741Smckusick 	fp = nfp;
56146553Skarels 	fmode = FFLAGS(uap->mode);
56245914Smckusick 	cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX;
56352322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
56445202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
56552322Smckusick 	if (error = vn_open(&nd, fmode, cmode)) {
56649980Smckusick 		ffree(fp);
56754723Smckusick 		if ((error == ENODEV || error == ENXIO) &&
56854723Smckusick 		    p->p_dupfd >= 0 && 			/* XXX from fdopen */
56953828Spendry 		    (error = dupfdopen(fdp, indx, p->p_dupfd,
57053828Spendry 					fmode, error)) == 0) {
57142441Smckusick 			*retval = indx;
57247540Skarels 			return (0);
57342441Smckusick 		}
57440884Smckusick 		if (error == ERESTART)
57540884Smckusick 			error = EINTR;
57647688Skarels 		fdp->fd_ofiles[indx] = NULL;
57747540Skarels 		return (error);
57812756Ssam 	}
57953828Spendry 	p->p_dupfd = 0;
58052322Smckusick 	vp = nd.ni_vp;
58149949Smckusick 	fp->f_flag = fmode & FMASK;
58254348Smckusick 	fp->f_type = DTYPE_VNODE;
58354348Smckusick 	fp->f_ops = &vnops;
58454348Smckusick 	fp->f_data = (caddr_t)vp;
58549945Smckusick 	if (fmode & (O_EXLOCK | O_SHLOCK)) {
58649945Smckusick 		lf.l_whence = SEEK_SET;
58749945Smckusick 		lf.l_start = 0;
58849945Smckusick 		lf.l_len = 0;
58949945Smckusick 		if (fmode & O_EXLOCK)
59049945Smckusick 			lf.l_type = F_WRLCK;
59149945Smckusick 		else
59249945Smckusick 			lf.l_type = F_RDLCK;
59349945Smckusick 		type = F_FLOCK;
59449945Smckusick 		if ((fmode & FNONBLOCK) == 0)
59549945Smckusick 			type |= F_WAIT;
59650111Smckusick 		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
59750111Smckusick 			VOP_UNLOCK(vp);
59850111Smckusick 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
59949980Smckusick 			ffree(fp);
60049945Smckusick 			fdp->fd_ofiles[indx] = NULL;
60149945Smckusick 			return (error);
60249945Smckusick 		}
60349949Smckusick 		fp->f_flag |= FHASLOCK;
60449945Smckusick 	}
60550111Smckusick 	VOP_UNLOCK(vp);
60642441Smckusick 	*retval = indx;
60747540Skarels 	return (0);
6086254Sroot }
6096254Sroot 
61042955Smckusick #ifdef COMPAT_43
6116254Sroot /*
61242441Smckusick  * Creat system call.
6136254Sroot  */
61454916Storek struct ocreat_args {
61554916Storek 	char	*fname;
61654916Storek 	int	fmode;
61754916Storek };
61842955Smckusick ocreat(p, uap, retval)
61942441Smckusick 	struct proc *p;
62054916Storek 	register struct ocreat_args *uap;
62142441Smckusick 	int *retval;
6226254Sroot {
62354916Storek 	struct open_args openuap;
62442441Smckusick 
62542441Smckusick 	openuap.fname = uap->fname;
62642441Smckusick 	openuap.crtmode = uap->fmode;
62742441Smckusick 	openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
62847540Skarels 	return (open(p, &openuap, retval));
62942441Smckusick }
63042955Smckusick #endif /* COMPAT_43 */
63142441Smckusick 
63242441Smckusick /*
63349365Smckusick  * Mknod system call.
63442441Smckusick  */
63554916Storek struct mknod_args {
63654916Storek 	char	*fname;
63754916Storek 	int	fmode;
63854916Storek 	int	dev;
63954916Storek };
64042441Smckusick /* ARGSUSED */
64142441Smckusick mknod(p, uap, retval)
64245914Smckusick 	struct proc *p;
64354916Storek 	register struct mknod_args *uap;
64442441Smckusick 	int *retval;
64542441Smckusick {
64637741Smckusick 	register struct vnode *vp;
64737741Smckusick 	struct vattr vattr;
64837741Smckusick 	int error;
64947540Skarels 	struct nameidata nd;
6506254Sroot 
65147540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
65247540Skarels 		return (error);
65352322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p);
65452322Smckusick 	if (error = namei(&nd))
65547540Skarels 		return (error);
65652322Smckusick 	vp = nd.ni_vp;
65737741Smckusick 	if (vp != NULL) {
65837741Smckusick 		error = EEXIST;
65912756Ssam 		goto out;
6606254Sroot 	}
66141362Smckusick 	VATTR_NULL(&vattr);
66240635Smckusick 	switch (uap->fmode & S_IFMT) {
66312756Ssam 
66440635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
66537741Smckusick 		vattr.va_type = VBAD;
66637741Smckusick 		break;
66740635Smckusick 	case S_IFCHR:
66837741Smckusick 		vattr.va_type = VCHR;
66937741Smckusick 		break;
67040635Smckusick 	case S_IFBLK:
67137741Smckusick 		vattr.va_type = VBLK;
67237741Smckusick 		break;
67337741Smckusick 	default:
67437741Smckusick 		error = EINVAL;
67537741Smckusick 		goto out;
6766254Sroot 	}
67745914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
67837741Smckusick 	vattr.va_rdev = uap->dev;
6796254Sroot out:
68042465Smckusick 	if (!error) {
68152322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
68252322Smckusick 		error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
68342465Smckusick 	} else {
68452322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
68552322Smckusick 		if (nd.ni_dvp == vp)
68652322Smckusick 			vrele(nd.ni_dvp);
68743344Smckusick 		else
68852322Smckusick 			vput(nd.ni_dvp);
68942465Smckusick 		if (vp)
69042465Smckusick 			vrele(vp);
69142465Smckusick 	}
69247540Skarels 	return (error);
6936254Sroot }
6946254Sroot 
6956254Sroot /*
69649365Smckusick  * Mkfifo system call.
69740285Smckusick  */
69854916Storek struct mkfifo_args {
69954916Storek 	char	*fname;
70054916Storek 	int	fmode;
70154916Storek };
70242441Smckusick /* ARGSUSED */
70342441Smckusick mkfifo(p, uap, retval)
70445914Smckusick 	struct proc *p;
70554916Storek 	register struct mkfifo_args *uap;
70642441Smckusick 	int *retval;
70742441Smckusick {
70840285Smckusick 	struct vattr vattr;
70940285Smckusick 	int error;
71047540Skarels 	struct nameidata nd;
71140285Smckusick 
71240285Smckusick #ifndef FIFO
71347540Skarels 	return (EOPNOTSUPP);
71440285Smckusick #else
71552322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p);
71652322Smckusick 	if (error = namei(&nd))
71747540Skarels 		return (error);
71852322Smckusick 	if (nd.ni_vp != NULL) {
71952322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
72052322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
72152322Smckusick 			vrele(nd.ni_dvp);
72243344Smckusick 		else
72352322Smckusick 			vput(nd.ni_dvp);
72452322Smckusick 		vrele(nd.ni_vp);
72547540Skarels 		return (EEXIST);
72640285Smckusick 	}
72745785Sbostic 	VATTR_NULL(&vattr);
72845785Sbostic 	vattr.va_type = VFIFO;
72945914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
73052322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
73152322Smckusick 	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
73240285Smckusick #endif /* FIFO */
73340285Smckusick }
73440285Smckusick 
73540285Smckusick /*
73649365Smckusick  * Link system call.
7376254Sroot  */
73854916Storek struct link_args {
73954916Storek 	char	*target;
74054916Storek 	char	*linkname;
74154916Storek };
74242441Smckusick /* ARGSUSED */
74342441Smckusick link(p, uap, retval)
74445914Smckusick 	struct proc *p;
74554916Storek 	register struct link_args *uap;
74642441Smckusick 	int *retval;
74742441Smckusick {
74837741Smckusick 	register struct vnode *vp, *xp;
74937741Smckusick 	int error;
75047540Skarels 	struct nameidata nd;
7516254Sroot 
75252322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->target, p);
75352322Smckusick 	if (error = namei(&nd))
75447540Skarels 		return (error);
75552322Smckusick 	vp = nd.ni_vp;
75637741Smckusick 	if (vp->v_type == VDIR &&
75747540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
75837741Smckusick 		goto out1;
75952322Smckusick 	nd.ni_cnd.cn_nameiop = CREATE;
76052322Smckusick 	nd.ni_cnd.cn_flags = LOCKPARENT;
76152322Smckusick 	nd.ni_dirp = (caddr_t)uap->linkname;
76252322Smckusick 	if (error = namei(&nd))
76337741Smckusick 		goto out1;
76452322Smckusick 	xp = nd.ni_vp;
7656254Sroot 	if (xp != NULL) {
76637741Smckusick 		error = EEXIST;
7676254Sroot 		goto out;
7686254Sroot 	}
76952322Smckusick 	xp = nd.ni_dvp;
7706254Sroot out:
77142465Smckusick 	if (!error) {
77252192Smckusick 		LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE);
77352192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
77452821Smckusick 		error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
77542465Smckusick 	} else {
77652322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
77752322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
77852322Smckusick 			vrele(nd.ni_dvp);
77943344Smckusick 		else
78052322Smckusick 			vput(nd.ni_dvp);
78152322Smckusick 		if (nd.ni_vp)
78252322Smckusick 			vrele(nd.ni_vp);
78342465Smckusick 	}
78437741Smckusick out1:
78537741Smckusick 	vrele(vp);
78647540Skarels 	return (error);
7876254Sroot }
7886254Sroot 
7896254Sroot /*
79049365Smckusick  * Make a symbolic link.
7916254Sroot  */
79254916Storek struct symlink_args {
79354916Storek 	char	*target;
79454916Storek 	char	*linkname;
79554916Storek };
79642441Smckusick /* ARGSUSED */
79742441Smckusick symlink(p, uap, retval)
79845914Smckusick 	struct proc *p;
79954916Storek 	register struct symlink_args *uap;
80042441Smckusick 	int *retval;
80142441Smckusick {
80237741Smckusick 	struct vattr vattr;
80337741Smckusick 	char *target;
80437741Smckusick 	int error;
80547540Skarels 	struct nameidata nd;
8066254Sroot 
80737741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
80837741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
80942465Smckusick 		goto out;
81052322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->linkname, p);
81152322Smckusick 	if (error = namei(&nd))
81242465Smckusick 		goto out;
81352322Smckusick 	if (nd.ni_vp) {
81452322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
81552322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
81652322Smckusick 			vrele(nd.ni_dvp);
81743344Smckusick 		else
81852322Smckusick 			vput(nd.ni_dvp);
81952322Smckusick 		vrele(nd.ni_vp);
82037741Smckusick 		error = EEXIST;
82137741Smckusick 		goto out;
8226254Sroot 	}
82341362Smckusick 	VATTR_NULL(&vattr);
82445914Smckusick 	vattr.va_mode = 0777 &~ p->p_fd->fd_cmask;
82552322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
82652322Smckusick 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, target);
82737741Smckusick out:
82837741Smckusick 	FREE(target, M_NAMEI);
82947540Skarels 	return (error);
8306254Sroot }
8316254Sroot 
8326254Sroot /*
83349365Smckusick  * Delete a name from the filesystem.
8346254Sroot  */
83554916Storek struct unlink_args {
83654916Storek 	char	*name;
83754916Storek };
83842441Smckusick /* ARGSUSED */
83942441Smckusick unlink(p, uap, retval)
84045914Smckusick 	struct proc *p;
84154916Storek 	struct unlink_args *uap;
84242441Smckusick 	int *retval;
8436254Sroot {
84437741Smckusick 	register struct vnode *vp;
84537741Smckusick 	int error;
84647540Skarels 	struct nameidata nd;
8476254Sroot 
84859382Smckusick 	NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, uap->name, p);
84952322Smckusick 	if (error = namei(&nd))
85047540Skarels 		return (error);
85152322Smckusick 	vp = nd.ni_vp;
85259382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
85359382Smckusick 	VOP_LOCK(vp);
85437741Smckusick 	if (vp->v_type == VDIR &&
85547540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
8566254Sroot 		goto out;
8576254Sroot 	/*
85849365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
8596254Sroot 	 */
86037741Smckusick 	if (vp->v_flag & VROOT) {
86137741Smckusick 		error = EBUSY;
8626254Sroot 		goto out;
8636254Sroot 	}
86445738Smckusick 	(void) vnode_pager_uncache(vp);
8656254Sroot out:
86642465Smckusick 	if (!error) {
86752322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
86852322Smckusick 		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
86942465Smckusick 	} else {
87052322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
87152322Smckusick 		if (nd.ni_dvp == vp)
87252322Smckusick 			vrele(nd.ni_dvp);
87343344Smckusick 		else
87452322Smckusick 			vput(nd.ni_dvp);
87542465Smckusick 		vput(vp);
87642465Smckusick 	}
87747540Skarels 	return (error);
8786254Sroot }
8796254Sroot 
88054916Storek struct __lseek_args {
88154863Storek 	int	fdes;
88254863Storek 	int	pad;
88354863Storek 	off_t	off;
88454863Storek 	int	sbase;
88554863Storek };
88654863Storek 
8876254Sroot /*
88849365Smckusick  * Seek system call.
8896254Sroot  */
890*60414Smckusick lseek(p, uap, retval)
89153468Smckusick 	struct proc *p;
89254916Storek 	register struct __lseek_args *uap;
89354916Storek 	int *retval;
89442441Smckusick {
89547540Skarels 	struct ucred *cred = p->p_ucred;
89645914Smckusick 	register struct filedesc *fdp = p->p_fd;
89742441Smckusick 	register struct file *fp;
89837741Smckusick 	struct vattr vattr;
89937741Smckusick 	int error;
9006254Sroot 
90147540Skarels 	if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
90247688Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL)
90347540Skarels 		return (EBADF);
90437741Smckusick 	if (fp->f_type != DTYPE_VNODE)
90547540Skarels 		return (ESPIPE);
90613878Ssam 	switch (uap->sbase) {
90713878Ssam 
90813878Ssam 	case L_INCR:
90913878Ssam 		fp->f_offset += uap->off;
91013878Ssam 		break;
91113878Ssam 
91213878Ssam 	case L_XTND:
91337741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
91448026Smckusick 		    &vattr, cred, p))
91547540Skarels 			return (error);
91637741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
91713878Ssam 		break;
91813878Ssam 
91913878Ssam 	case L_SET:
92013878Ssam 		fp->f_offset = uap->off;
92113878Ssam 		break;
92213878Ssam 
92313878Ssam 	default:
92447540Skarels 		return (EINVAL);
92513878Ssam 	}
92654916Storek 	*(off_t *)retval = fp->f_offset;
92747540Skarels 	return (0);
9286254Sroot }
9296254Sroot 
930*60414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
9316254Sroot /*
93260036Smckusick  * Old lseek system call.
93360036Smckusick  */
93460036Smckusick struct lseek_args {
93560036Smckusick 	int	fdes;
93660036Smckusick 	long	off;
93760036Smckusick 	int	sbase;
93860036Smckusick };
939*60414Smckusick olseek(p, uap, retval)
94060036Smckusick 	struct proc *p;
94160036Smckusick 	register struct lseek_args *uap;
94260036Smckusick 	int *retval;
94360036Smckusick {
94460036Smckusick 	struct __lseek_args nuap;
94560036Smckusick 	off_t qret;
94660036Smckusick 	int error;
94760036Smckusick 
94860036Smckusick 	nuap.fdes = uap->fdes;
94960036Smckusick 	nuap.off = uap->off;
95060036Smckusick 	nuap.sbase = uap->sbase;
95160036Smckusick 	error = __lseek(p, &nuap, &qret);
95260036Smckusick 	*(long *)retval = qret;
95360036Smckusick 	return (error);
95460036Smckusick }
955*60414Smckusick #endif /* COMPAT_43 */
95660036Smckusick 
95760036Smckusick /*
95849365Smckusick  * Check access permissions.
9596254Sroot  */
96054916Storek struct saccess_args {
96154916Storek 	char	*fname;
96254916Storek 	int	fmode;
96354916Storek };
96442441Smckusick /* ARGSUSED */
96542441Smckusick saccess(p, uap, retval)
96645914Smckusick 	struct proc *p;
96754916Storek 	register struct saccess_args *uap;
96842441Smckusick 	int *retval;
96942441Smckusick {
97047540Skarels 	register struct ucred *cred = p->p_ucred;
97137741Smckusick 	register struct vnode *vp;
97237741Smckusick 	int error, mode, svuid, svgid;
97347540Skarels 	struct nameidata nd;
9746254Sroot 
97542441Smckusick 	svuid = cred->cr_uid;
97642441Smckusick 	svgid = cred->cr_groups[0];
97747540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
97847540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
97952322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
98052322Smckusick 	if (error = namei(&nd))
98137741Smckusick 		goto out1;
98252322Smckusick 	vp = nd.ni_vp;
98337741Smckusick 	/*
98437741Smckusick 	 * fmode == 0 means only check for exist
98537741Smckusick 	 */
98637741Smckusick 	if (uap->fmode) {
98737741Smckusick 		mode = 0;
98837741Smckusick 		if (uap->fmode & R_OK)
98937741Smckusick 			mode |= VREAD;
99037741Smckusick 		if (uap->fmode & W_OK)
99137741Smckusick 			mode |= VWRITE;
99237741Smckusick 		if (uap->fmode & X_OK)
99337741Smckusick 			mode |= VEXEC;
99439543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
99548026Smckusick 			error = VOP_ACCESS(vp, mode, cred, p);
9966254Sroot 	}
99737741Smckusick 	vput(vp);
99837741Smckusick out1:
99942441Smckusick 	cred->cr_uid = svuid;
100042441Smckusick 	cred->cr_groups[0] = svgid;
100147540Skarels 	return (error);
10026254Sroot }
10036254Sroot 
100454348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
10056254Sroot /*
100649365Smckusick  * Stat system call.
100749365Smckusick  * This version follows links.
100837Sbill  */
100954916Storek struct ostat_args {
101054916Storek 	char	*fname;
101154916Storek 	struct ostat *ub;
101254916Storek };
101342441Smckusick /* ARGSUSED */
101453759Smckusick ostat(p, uap, retval)
101545914Smckusick 	struct proc *p;
101654916Storek 	register struct ostat_args *uap;
101753468Smckusick 	int *retval;
101853468Smckusick {
101953468Smckusick 	struct stat sb;
102053468Smckusick 	struct ostat osb;
102153468Smckusick 	int error;
102253468Smckusick 	struct nameidata nd;
102353468Smckusick 
102453468Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
102553468Smckusick 	if (error = namei(&nd))
102653468Smckusick 		return (error);
102753468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
102853468Smckusick 	vput(nd.ni_vp);
102953468Smckusick 	if (error)
103053468Smckusick 		return (error);
103153468Smckusick 	cvtstat(&sb, &osb);
103253468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
103353468Smckusick 	return (error);
103453468Smckusick }
103553468Smckusick 
103653468Smckusick /*
103753468Smckusick  * Lstat system call.
103853468Smckusick  * This version does not follow links.
103953468Smckusick  */
104054916Storek struct olstat_args {
104154916Storek 	char	*fname;
104254916Storek 	struct ostat *ub;
104354916Storek };
104453468Smckusick /* ARGSUSED */
104553759Smckusick olstat(p, uap, retval)
104653468Smckusick 	struct proc *p;
104754916Storek 	register struct olstat_args *uap;
104853468Smckusick 	int *retval;
104953468Smckusick {
105053468Smckusick 	struct stat sb;
105153468Smckusick 	struct ostat osb;
105253468Smckusick 	int error;
105353468Smckusick 	struct nameidata nd;
105453468Smckusick 
105553468Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
105653468Smckusick 	if (error = namei(&nd))
105753468Smckusick 		return (error);
105853468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
105953468Smckusick 	vput(nd.ni_vp);
106053468Smckusick 	if (error)
106153468Smckusick 		return (error);
106253468Smckusick 	cvtstat(&sb, &osb);
106353468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
106453468Smckusick 	return (error);
106553468Smckusick }
106653468Smckusick 
106753468Smckusick /*
106853468Smckusick  * convert from an old to a new stat structure.
106953468Smckusick  */
107053468Smckusick cvtstat(st, ost)
107153468Smckusick 	struct stat *st;
107253468Smckusick 	struct ostat *ost;
107353468Smckusick {
107453468Smckusick 
107553468Smckusick 	ost->st_dev = st->st_dev;
107653468Smckusick 	ost->st_ino = st->st_ino;
107753468Smckusick 	ost->st_mode = st->st_mode;
107853468Smckusick 	ost->st_nlink = st->st_nlink;
107953468Smckusick 	ost->st_uid = st->st_uid;
108053468Smckusick 	ost->st_gid = st->st_gid;
108153468Smckusick 	ost->st_rdev = st->st_rdev;
108253468Smckusick 	if (st->st_size < (quad_t)1 << 32)
108353468Smckusick 		ost->st_size = st->st_size;
108453468Smckusick 	else
108553468Smckusick 		ost->st_size = -2;
108653468Smckusick 	ost->st_atime = st->st_atime;
108753468Smckusick 	ost->st_mtime = st->st_mtime;
108853468Smckusick 	ost->st_ctime = st->st_ctime;
108953468Smckusick 	ost->st_blksize = st->st_blksize;
109053468Smckusick 	ost->st_blocks = st->st_blocks;
109153468Smckusick 	ost->st_flags = st->st_flags;
109253468Smckusick 	ost->st_gen = st->st_gen;
109353468Smckusick }
109454348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
109553468Smckusick 
109653468Smckusick /*
109753468Smckusick  * Stat system call.
109853468Smckusick  * This version follows links.
109953468Smckusick  */
110054916Storek struct stat_args {
110154916Storek 	char	*fname;
110254916Storek 	struct stat *ub;
110354916Storek };
110453468Smckusick /* ARGSUSED */
110553759Smckusick stat(p, uap, retval)
110653468Smckusick 	struct proc *p;
110754916Storek 	register struct stat_args *uap;
110842441Smckusick 	int *retval;
110937Sbill {
111042441Smckusick 	struct stat sb;
111142441Smckusick 	int error;
111247540Skarels 	struct nameidata nd;
111337Sbill 
111452322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
111552322Smckusick 	if (error = namei(&nd))
111647540Skarels 		return (error);
111752322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
111852322Smckusick 	vput(nd.ni_vp);
111942441Smckusick 	if (error)
112047540Skarels 		return (error);
112142441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
112247540Skarels 	return (error);
112337Sbill }
112437Sbill 
112537Sbill /*
112649365Smckusick  * Lstat system call.
112749365Smckusick  * This version does not follow links.
11285992Swnj  */
112954916Storek struct lstat_args {
113054916Storek 	char	*fname;
113154916Storek 	struct stat *ub;
113254916Storek };
113342441Smckusick /* ARGSUSED */
113453759Smckusick lstat(p, uap, retval)
113545914Smckusick 	struct proc *p;
113654916Storek 	register struct lstat_args *uap;
113742441Smckusick 	int *retval;
113842441Smckusick {
113937741Smckusick 	int error;
114059373Smckusick 	struct vnode *vp, *dvp;
114159373Smckusick 	struct stat sb, sb1;
114247540Skarels 	struct nameidata nd;
11435992Swnj 
114459373Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
114559373Smckusick 	    uap->fname, p);
114652322Smckusick 	if (error = namei(&nd))
114747540Skarels 		return (error);
114859373Smckusick 	/*
114959373Smckusick 	 * For symbolic links, always return the attributes of its
115059373Smckusick 	 * containing directory, except for mode, size, and links.
115159373Smckusick 	 */
115259373Smckusick 	vp = nd.ni_vp;
115359373Smckusick 	dvp = nd.ni_dvp;
115459373Smckusick 	if (vp->v_type != VLNK) {
115559373Smckusick 		if (dvp == vp)
115659373Smckusick 			vrele(dvp);
115759373Smckusick 		else
115859373Smckusick 			vput(dvp);
115959373Smckusick 		error = vn_stat(vp, &sb, p);
116059373Smckusick 		vput(vp);
116159373Smckusick 		if (error)
116259373Smckusick 			return (error);
116359373Smckusick 	} else {
116459373Smckusick 		error = vn_stat(dvp, &sb, p);
116559373Smckusick 		vput(dvp);
116659373Smckusick 		if (error) {
116759373Smckusick 			vput(vp);
116859373Smckusick 			return (error);
116959373Smckusick 		}
117059373Smckusick 		error = vn_stat(vp, &sb1, p);
117159373Smckusick 		vput(vp);
117259373Smckusick 		if (error)
117359373Smckusick 			return (error);
117459373Smckusick 		sb.st_mode &= ~S_IFDIR;
117559373Smckusick 		sb.st_mode |= S_IFLNK;
117659373Smckusick 		sb.st_nlink = sb1.st_nlink;
117759373Smckusick 		sb.st_size = sb1.st_size;
117859373Smckusick 		sb.st_blocks = sb1.st_blocks;
117959373Smckusick 	}
118037741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
118147540Skarels 	return (error);
11825992Swnj }
11835992Swnj 
11845992Swnj /*
1185*60414Smckusick  * Pathconf system call.
1186*60414Smckusick  */
1187*60414Smckusick struct pathconf_args {
1188*60414Smckusick 	char	*fname;
1189*60414Smckusick 	int	name;
1190*60414Smckusick };
1191*60414Smckusick /* ARGSUSED */
1192*60414Smckusick pathconf(p, uap, retval)
1193*60414Smckusick 	struct proc *p;
1194*60414Smckusick 	register struct pathconf_args *uap;
1195*60414Smckusick 	int *retval;
1196*60414Smckusick {
1197*60414Smckusick 	int error;
1198*60414Smckusick 	struct nameidata nd;
1199*60414Smckusick 
1200*60414Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
1201*60414Smckusick 	if (error = namei(&nd))
1202*60414Smckusick 		return (error);
1203*60414Smckusick 	error = VOP_PATHCONF(nd.ni_vp, uap->name, retval);
1204*60414Smckusick 	vput(nd.ni_vp);
1205*60414Smckusick 	return (error);
1206*60414Smckusick }
1207*60414Smckusick 
1208*60414Smckusick /*
120949365Smckusick  * Return target name of a symbolic link.
121037Sbill  */
121154916Storek struct readlink_args {
121254916Storek 	char	*name;
121354916Storek 	char	*buf;
121454916Storek 	int	count;
121554916Storek };
121642441Smckusick /* ARGSUSED */
121742441Smckusick readlink(p, uap, retval)
121845914Smckusick 	struct proc *p;
121954916Storek 	register struct readlink_args *uap;
122042441Smckusick 	int *retval;
122142441Smckusick {
122237741Smckusick 	register struct vnode *vp;
122337741Smckusick 	struct iovec aiov;
122437741Smckusick 	struct uio auio;
122537741Smckusick 	int error;
122647540Skarels 	struct nameidata nd;
12275992Swnj 
122852322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p);
122952322Smckusick 	if (error = namei(&nd))
123047540Skarels 		return (error);
123152322Smckusick 	vp = nd.ni_vp;
123237741Smckusick 	if (vp->v_type != VLNK) {
123337741Smckusick 		error = EINVAL;
12345992Swnj 		goto out;
12355992Swnj 	}
123637741Smckusick 	aiov.iov_base = uap->buf;
123737741Smckusick 	aiov.iov_len = uap->count;
123837741Smckusick 	auio.uio_iov = &aiov;
123937741Smckusick 	auio.uio_iovcnt = 1;
124037741Smckusick 	auio.uio_offset = 0;
124137741Smckusick 	auio.uio_rw = UIO_READ;
124237741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
124348026Smckusick 	auio.uio_procp = p;
124437741Smckusick 	auio.uio_resid = uap->count;
124547540Skarels 	error = VOP_READLINK(vp, &auio, p->p_ucred);
12465992Swnj out:
124737741Smckusick 	vput(vp);
124842441Smckusick 	*retval = uap->count - auio.uio_resid;
124947540Skarels 	return (error);
12505992Swnj }
12515992Swnj 
12529167Ssam /*
125338259Smckusick  * Change flags of a file given path name.
125438259Smckusick  */
125554916Storek struct chflags_args {
125654916Storek 	char	*fname;
125754916Storek 	int	flags;
125854916Storek };
125942441Smckusick /* ARGSUSED */
126042441Smckusick chflags(p, uap, retval)
126145914Smckusick 	struct proc *p;
126254916Storek 	register struct chflags_args *uap;
126342441Smckusick 	int *retval;
126442441Smckusick {
126538259Smckusick 	register struct vnode *vp;
126638259Smckusick 	struct vattr vattr;
126738259Smckusick 	int error;
126847540Skarels 	struct nameidata nd;
126938259Smckusick 
127059382Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
127152322Smckusick 	if (error = namei(&nd))
127247540Skarels 		return (error);
127352322Smckusick 	vp = nd.ni_vp;
127459382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
127559382Smckusick 	VOP_LOCK(vp);
127641400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
127738259Smckusick 		error = EROFS;
127838259Smckusick 		goto out;
127938259Smckusick 	}
128045785Sbostic 	VATTR_NULL(&vattr);
128145785Sbostic 	vattr.va_flags = uap->flags;
128248026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
128338259Smckusick out:
128438259Smckusick 	vput(vp);
128547540Skarels 	return (error);
128638259Smckusick }
128738259Smckusick 
128838259Smckusick /*
128938259Smckusick  * Change flags of a file given a file descriptor.
129038259Smckusick  */
129154916Storek struct fchflags_args {
129254916Storek 	int	fd;
129354916Storek 	int	flags;
129454916Storek };
129542441Smckusick /* ARGSUSED */
129642441Smckusick fchflags(p, uap, retval)
129745914Smckusick 	struct proc *p;
129854916Storek 	register struct fchflags_args *uap;
129942441Smckusick 	int *retval;
130042441Smckusick {
130138259Smckusick 	struct vattr vattr;
130238259Smckusick 	struct vnode *vp;
130338259Smckusick 	struct file *fp;
130438259Smckusick 	int error;
130538259Smckusick 
130645914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
130747540Skarels 		return (error);
130838259Smckusick 	vp = (struct vnode *)fp->f_data;
130959382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
131038259Smckusick 	VOP_LOCK(vp);
131141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
131238259Smckusick 		error = EROFS;
131338259Smckusick 		goto out;
131438259Smckusick 	}
131545785Sbostic 	VATTR_NULL(&vattr);
131645785Sbostic 	vattr.va_flags = uap->flags;
131748026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
131838259Smckusick out:
131938259Smckusick 	VOP_UNLOCK(vp);
132047540Skarels 	return (error);
132138259Smckusick }
132238259Smckusick 
132338259Smckusick /*
13249167Ssam  * Change mode of a file given path name.
13259167Ssam  */
132654916Storek struct chmod_args {
132754916Storek 	char	*fname;
132854916Storek 	int	fmode;
132954916Storek };
133042441Smckusick /* ARGSUSED */
133142441Smckusick chmod(p, uap, retval)
133245914Smckusick 	struct proc *p;
133354916Storek 	register struct chmod_args *uap;
133442441Smckusick 	int *retval;
133542441Smckusick {
133637741Smckusick 	register struct vnode *vp;
133737741Smckusick 	struct vattr vattr;
133837741Smckusick 	int error;
133947540Skarels 	struct nameidata nd;
13405992Swnj 
134159382Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
134252322Smckusick 	if (error = namei(&nd))
134347540Skarels 		return (error);
134452322Smckusick 	vp = nd.ni_vp;
134559382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
134659382Smckusick 	VOP_LOCK(vp);
134741400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
134837741Smckusick 		error = EROFS;
134937741Smckusick 		goto out;
135037741Smckusick 	}
135145785Sbostic 	VATTR_NULL(&vattr);
135245785Sbostic 	vattr.va_mode = uap->fmode & 07777;
135348026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
135437741Smckusick out:
135537741Smckusick 	vput(vp);
135647540Skarels 	return (error);
13577701Ssam }
13587439Sroot 
13599167Ssam /*
13609167Ssam  * Change mode of a file given a file descriptor.
13619167Ssam  */
136254916Storek struct fchmod_args {
136354916Storek 	int	fd;
136454916Storek 	int	fmode;
136554916Storek };
136642441Smckusick /* ARGSUSED */
136742441Smckusick fchmod(p, uap, retval)
136845914Smckusick 	struct proc *p;
136954916Storek 	register struct fchmod_args *uap;
137042441Smckusick 	int *retval;
137142441Smckusick {
137237741Smckusick 	struct vattr vattr;
137337741Smckusick 	struct vnode *vp;
137437741Smckusick 	struct file *fp;
137537741Smckusick 	int error;
13767701Ssam 
137745914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
137847540Skarels 		return (error);
137937741Smckusick 	vp = (struct vnode *)fp->f_data;
138059382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
138137741Smckusick 	VOP_LOCK(vp);
138241400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
138337741Smckusick 		error = EROFS;
138437741Smckusick 		goto out;
13857439Sroot 	}
138645785Sbostic 	VATTR_NULL(&vattr);
138745785Sbostic 	vattr.va_mode = uap->fmode & 07777;
138848026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
138937741Smckusick out:
139037741Smckusick 	VOP_UNLOCK(vp);
139147540Skarels 	return (error);
13925992Swnj }
13935992Swnj 
13949167Ssam /*
13959167Ssam  * Set ownership given a path name.
13969167Ssam  */
139754916Storek struct chown_args {
139854916Storek 	char	*fname;
139954916Storek 	int	uid;
140054916Storek 	int	gid;
140154916Storek };
140242441Smckusick /* ARGSUSED */
140342441Smckusick chown(p, uap, retval)
140445914Smckusick 	struct proc *p;
140554916Storek 	register struct chown_args *uap;
140642441Smckusick 	int *retval;
140742441Smckusick {
140837741Smckusick 	register struct vnode *vp;
140937741Smckusick 	struct vattr vattr;
141037741Smckusick 	int error;
141147540Skarels 	struct nameidata nd;
141237Sbill 
141359382Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->fname, p);
141452322Smckusick 	if (error = namei(&nd))
141547540Skarels 		return (error);
141652322Smckusick 	vp = nd.ni_vp;
141759382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
141859382Smckusick 	VOP_LOCK(vp);
141941400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
142037741Smckusick 		error = EROFS;
142137741Smckusick 		goto out;
142237741Smckusick 	}
142345785Sbostic 	VATTR_NULL(&vattr);
142445785Sbostic 	vattr.va_uid = uap->uid;
142545785Sbostic 	vattr.va_gid = uap->gid;
142648026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
142737741Smckusick out:
142837741Smckusick 	vput(vp);
142947540Skarels 	return (error);
14307701Ssam }
14317439Sroot 
14329167Ssam /*
14339167Ssam  * Set ownership given a file descriptor.
14349167Ssam  */
143554916Storek struct fchown_args {
143654916Storek 	int	fd;
143754916Storek 	int	uid;
143854916Storek 	int	gid;
143954916Storek };
144042441Smckusick /* ARGSUSED */
144142441Smckusick fchown(p, uap, retval)
144245914Smckusick 	struct proc *p;
144354916Storek 	register struct fchown_args *uap;
144442441Smckusick 	int *retval;
144542441Smckusick {
144637741Smckusick 	struct vattr vattr;
144737741Smckusick 	struct vnode *vp;
144837741Smckusick 	struct file *fp;
144937741Smckusick 	int error;
14507701Ssam 
145145914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
145247540Skarels 		return (error);
145337741Smckusick 	vp = (struct vnode *)fp->f_data;
145459382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
145537741Smckusick 	VOP_LOCK(vp);
145641400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
145737741Smckusick 		error = EROFS;
145837741Smckusick 		goto out;
145937741Smckusick 	}
146045785Sbostic 	VATTR_NULL(&vattr);
146145785Sbostic 	vattr.va_uid = uap->uid;
146245785Sbostic 	vattr.va_gid = uap->gid;
146348026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
146437741Smckusick out:
146537741Smckusick 	VOP_UNLOCK(vp);
146647540Skarels 	return (error);
14677701Ssam }
14687701Ssam 
146942441Smckusick /*
147042441Smckusick  * Set the access and modification times of a file.
147142441Smckusick  */
147254916Storek struct utimes_args {
147354916Storek 	char	*fname;
147454916Storek 	struct	timeval *tptr;
147554916Storek };
147642441Smckusick /* ARGSUSED */
147742441Smckusick utimes(p, uap, retval)
147845914Smckusick 	struct proc *p;
147954916Storek 	register struct utimes_args *uap;
148042441Smckusick 	int *retval;
148142441Smckusick {
148237741Smckusick 	register struct vnode *vp;
148311811Ssam 	struct timeval tv[2];
148437741Smckusick 	struct vattr vattr;
148558840Storek 	int error;
148647540Skarels 	struct nameidata nd;
148711811Ssam 
148858505Sbostic 	VATTR_NULL(&vattr);
148958505Sbostic 	if (uap->tptr == NULL) {
149058505Sbostic 		microtime(&tv[0]);
149158505Sbostic 		tv[1] = tv[0];
149258548Sbostic 		vattr.va_vaflags |= VA_UTIMES_NULL;
149358505Sbostic 	} else if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
149458505Sbostic   		return (error);
149559382Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
149652322Smckusick 	if (error = namei(&nd))
149747540Skarels 		return (error);
149852322Smckusick 	vp = nd.ni_vp;
149959382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
150059382Smckusick 	VOP_LOCK(vp);
150141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
150237741Smckusick 		error = EROFS;
150337741Smckusick 		goto out;
150421015Smckusick 	}
150554100Smckusick 	vattr.va_atime.ts_sec = tv[0].tv_sec;
150654100Smckusick 	vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
150754100Smckusick 	vattr.va_mtime.ts_sec = tv[1].tv_sec;
150854100Smckusick 	vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
150948026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
151037741Smckusick out:
151137741Smckusick 	vput(vp);
151247540Skarels 	return (error);
151311811Ssam }
151411811Ssam 
151554916Storek struct __truncate_args {
151654863Storek 	char	*fname;
151754863Storek 	int	pad;
151854863Storek 	off_t	length;
151954863Storek };
152053468Smckusick 
152153468Smckusick /*
152253468Smckusick  * Truncate a file given its path name.
152353468Smckusick  */
152453468Smckusick /* ARGSUSED */
1525*60414Smckusick truncate(p, uap, retval)
152653468Smckusick 	struct proc *p;
152754916Storek 	register struct __truncate_args *uap;
152853468Smckusick 	int *retval;
152953468Smckusick {
153037741Smckusick 	register struct vnode *vp;
153137741Smckusick 	struct vattr vattr;
153237741Smckusick 	int error;
153347540Skarels 	struct nameidata nd;
15347701Ssam 
153559382Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
153652322Smckusick 	if (error = namei(&nd))
153747540Skarels 		return (error);
153852322Smckusick 	vp = nd.ni_vp;
153959382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
154059382Smckusick 	VOP_LOCK(vp);
154137741Smckusick 	if (vp->v_type == VDIR) {
154237741Smckusick 		error = EISDIR;
154337741Smckusick 		goto out;
15447701Ssam 	}
154538399Smckusick 	if ((error = vn_writechk(vp)) ||
154648026Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)))
154737741Smckusick 		goto out;
154845785Sbostic 	VATTR_NULL(&vattr);
154945785Sbostic 	vattr.va_size = uap->length;
155048026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
155137741Smckusick out:
155237741Smckusick 	vput(vp);
155347540Skarels 	return (error);
15547701Ssam }
15557701Ssam 
155654916Storek struct __ftruncate_args {
155754863Storek 	int	fd;
155854863Storek 	int	pad;
155954863Storek 	off_t	length;
156054863Storek };
156154863Storek 
15629167Ssam /*
15639167Ssam  * Truncate a file given a file descriptor.
15649167Ssam  */
156542441Smckusick /* ARGSUSED */
1566*60414Smckusick ftruncate(p, uap, retval)
156745914Smckusick 	struct proc *p;
156854916Storek 	register struct __ftruncate_args *uap;
156942441Smckusick 	int *retval;
157042441Smckusick {
157137741Smckusick 	struct vattr vattr;
157237741Smckusick 	struct vnode *vp;
15737701Ssam 	struct file *fp;
157437741Smckusick 	int error;
15757701Ssam 
157645914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
157747540Skarels 		return (error);
157837741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
157947540Skarels 		return (EINVAL);
158037741Smckusick 	vp = (struct vnode *)fp->f_data;
158159382Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
158237741Smckusick 	VOP_LOCK(vp);
158337741Smckusick 	if (vp->v_type == VDIR) {
158437741Smckusick 		error = EISDIR;
158537741Smckusick 		goto out;
15867701Ssam 	}
158738399Smckusick 	if (error = vn_writechk(vp))
158837741Smckusick 		goto out;
158945785Sbostic 	VATTR_NULL(&vattr);
159045785Sbostic 	vattr.va_size = uap->length;
159148026Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
159237741Smckusick out:
159337741Smckusick 	VOP_UNLOCK(vp);
159447540Skarels 	return (error);
15957701Ssam }
15967701Ssam 
159754863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
15989167Ssam /*
159954863Storek  * Truncate a file given its path name.
160054863Storek  */
160154916Storek struct truncate_args {
160254916Storek 	char	*fname;
160354916Storek 	long	length;
160454916Storek };
160554863Storek /* ARGSUSED */
160660105Smckusick otruncate(p, uap, retval)
160754863Storek 	struct proc *p;
160854916Storek 	register struct truncate_args *uap;
160954863Storek 	int *retval;
161054863Storek {
161154916Storek 	struct __truncate_args nuap;
161254863Storek 
161354863Storek 	nuap.fname = uap->fname;
161454863Storek 	nuap.length = uap->length;
161554863Storek 	return (__truncate(p, &nuap, retval));
161654863Storek }
161754863Storek 
161854863Storek /*
161954863Storek  * Truncate a file given a file descriptor.
162054863Storek  */
162154916Storek struct ftruncate_args {
162254916Storek 	int	fd;
162354916Storek 	long	length;
162454916Storek };
162554863Storek /* ARGSUSED */
162660105Smckusick oftruncate(p, uap, retval)
162754863Storek 	struct proc *p;
162854916Storek 	register struct ftruncate_args *uap;
162954863Storek 	int *retval;
163054863Storek {
163154969Smckusick 	struct __ftruncate_args nuap;
163254863Storek 
163354863Storek 	nuap.fd = uap->fd;
163454863Storek 	nuap.length = uap->length;
163554863Storek 	return (__ftruncate(p, &nuap, retval));
163654863Storek }
163754863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */
163854863Storek 
163954863Storek /*
16409167Ssam  * Synch an open file.
16419167Ssam  */
164254916Storek struct fsync_args {
164354916Storek 	int	fd;
164454916Storek };
164542441Smckusick /* ARGSUSED */
164642441Smckusick fsync(p, uap, retval)
164745914Smckusick 	struct proc *p;
164854916Storek 	struct fsync_args *uap;
164942441Smckusick 	int *retval;
16509167Ssam {
165139592Smckusick 	register struct vnode *vp;
16529167Ssam 	struct file *fp;
165337741Smckusick 	int error;
16549167Ssam 
165545914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
165647540Skarels 		return (error);
165739592Smckusick 	vp = (struct vnode *)fp->f_data;
165839592Smckusick 	VOP_LOCK(vp);
165954441Smckusick 	error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
166039592Smckusick 	VOP_UNLOCK(vp);
166147540Skarels 	return (error);
16629167Ssam }
16639167Ssam 
16649167Ssam /*
16659167Ssam  * Rename system call.
16669167Ssam  *
16679167Ssam  * Source and destination must either both be directories, or both
16689167Ssam  * not be directories.  If target is a directory, it must be empty.
16699167Ssam  */
167054916Storek struct rename_args {
167154916Storek 	char	*from;
167254916Storek 	char	*to;
167354916Storek };
167442441Smckusick /* ARGSUSED */
167542441Smckusick rename(p, uap, retval)
167645914Smckusick 	struct proc *p;
167754916Storek 	register struct rename_args *uap;
167842441Smckusick 	int *retval;
167942441Smckusick {
168037741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
168149735Smckusick 	struct nameidata fromnd, tond;
168237741Smckusick 	int error;
16837701Ssam 
168452322Smckusick 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
168552322Smckusick 		uap->from, p);
168652322Smckusick 	if (error = namei(&fromnd))
168747540Skarels 		return (error);
168849735Smckusick 	fvp = fromnd.ni_vp;
168952322Smckusick 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
169052322Smckusick 		UIO_USERSPACE, uap->to, p);
169152322Smckusick 	if (error = namei(&tond)) {
169252230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
169349735Smckusick 		vrele(fromnd.ni_dvp);
169442465Smckusick 		vrele(fvp);
169542465Smckusick 		goto out1;
169642465Smckusick 	}
169737741Smckusick 	tdvp = tond.ni_dvp;
169837741Smckusick 	tvp = tond.ni_vp;
169937741Smckusick 	if (tvp != NULL) {
170037741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
170139242Sbostic 			error = ENOTDIR;
170237741Smckusick 			goto out;
170337741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
170439242Sbostic 			error = EISDIR;
170537741Smckusick 			goto out;
17069167Ssam 		}
17079167Ssam 	}
170839286Smckusick 	if (fvp == tdvp)
170937741Smckusick 		error = EINVAL;
171039286Smckusick 	/*
171149735Smckusick 	 * If source is the same as the destination (that is the
171249735Smckusick 	 * same inode number with the same name in the same directory),
171339286Smckusick 	 * then there is nothing to do.
171439286Smckusick 	 */
171549735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
171652322Smckusick 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
171752322Smckusick 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
171852322Smckusick 	      fromnd.ni_cnd.cn_namelen))
171939286Smckusick 		error = -1;
172037741Smckusick out:
172142465Smckusick 	if (!error) {
172252192Smckusick 		LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE);
172352192Smckusick 		if (fromnd.ni_dvp != tdvp)
172452192Smckusick 			LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
172552192Smckusick 		if (tvp)
172652192Smckusick 			LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE);
172752230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
172852230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
172942465Smckusick 	} else {
173052230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
173143344Smckusick 		if (tdvp == tvp)
173243344Smckusick 			vrele(tdvp);
173343344Smckusick 		else
173443344Smckusick 			vput(tdvp);
173542465Smckusick 		if (tvp)
173642465Smckusick 			vput(tvp);
173752230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
173849735Smckusick 		vrele(fromnd.ni_dvp);
173942465Smckusick 		vrele(fvp);
17409167Ssam 	}
174149735Smckusick 	vrele(tond.ni_startdir);
174252322Smckusick 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
174337741Smckusick out1:
174449735Smckusick 	vrele(fromnd.ni_startdir);
174552322Smckusick 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
174639286Smckusick 	if (error == -1)
174747540Skarels 		return (0);
174847540Skarels 	return (error);
17497701Ssam }
17507701Ssam 
17517535Sroot /*
175249365Smckusick  * Mkdir system call.
175312756Ssam  */
175454916Storek struct mkdir_args {
175554916Storek 	char	*name;
175654916Storek 	int	dmode;
175754916Storek };
175842441Smckusick /* ARGSUSED */
175942441Smckusick mkdir(p, uap, retval)
176045914Smckusick 	struct proc *p;
176154916Storek 	register struct mkdir_args *uap;
176242441Smckusick 	int *retval;
176342441Smckusick {
176437741Smckusick 	register struct vnode *vp;
176537741Smckusick 	struct vattr vattr;
176637741Smckusick 	int error;
176747540Skarels 	struct nameidata nd;
176812756Ssam 
176952322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p);
177052322Smckusick 	if (error = namei(&nd))
177147540Skarels 		return (error);
177252322Smckusick 	vp = nd.ni_vp;
177337741Smckusick 	if (vp != NULL) {
177452322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
177552322Smckusick 		if (nd.ni_dvp == vp)
177652322Smckusick 			vrele(nd.ni_dvp);
177743344Smckusick 		else
177852322Smckusick 			vput(nd.ni_dvp);
177942465Smckusick 		vrele(vp);
178047540Skarels 		return (EEXIST);
178112756Ssam 	}
178241362Smckusick 	VATTR_NULL(&vattr);
178337741Smckusick 	vattr.va_type = VDIR;
178445914Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask;
178552322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
178652322Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
178738145Smckusick 	if (!error)
178852322Smckusick 		vput(nd.ni_vp);
178947540Skarels 	return (error);
179012756Ssam }
179112756Ssam 
179212756Ssam /*
179312756Ssam  * Rmdir system call.
179412756Ssam  */
179554916Storek struct rmdir_args {
179654916Storek 	char	*name;
179754916Storek };
179842441Smckusick /* ARGSUSED */
179942441Smckusick rmdir(p, uap, retval)
180045914Smckusick 	struct proc *p;
180154916Storek 	struct rmdir_args *uap;
180242441Smckusick 	int *retval;
180312756Ssam {
180437741Smckusick 	register struct vnode *vp;
180537741Smckusick 	int error;
180647540Skarels 	struct nameidata nd;
180712756Ssam 
180852322Smckusick 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p);
180952322Smckusick 	if (error = namei(&nd))
181047540Skarels 		return (error);
181152322Smckusick 	vp = nd.ni_vp;
181237741Smckusick 	if (vp->v_type != VDIR) {
181337741Smckusick 		error = ENOTDIR;
181412756Ssam 		goto out;
181512756Ssam 	}
181612756Ssam 	/*
181737741Smckusick 	 * No rmdir "." please.
181812756Ssam 	 */
181952322Smckusick 	if (nd.ni_dvp == vp) {
182037741Smckusick 		error = EINVAL;
182112756Ssam 		goto out;
182212756Ssam 	}
182312756Ssam 	/*
182449365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
182512756Ssam 	 */
182637741Smckusick 	if (vp->v_flag & VROOT)
182737741Smckusick 		error = EBUSY;
182812756Ssam out:
182942465Smckusick 	if (!error) {
183052322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
183152192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
183252322Smckusick 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
183342465Smckusick 	} else {
183452322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
183552322Smckusick 		if (nd.ni_dvp == vp)
183652322Smckusick 			vrele(nd.ni_dvp);
183743344Smckusick 		else
183852322Smckusick 			vput(nd.ni_dvp);
183942465Smckusick 		vput(vp);
184042465Smckusick 	}
184147540Skarels 	return (error);
184212756Ssam }
184312756Ssam 
184454620Smckusick #ifdef COMPAT_43
184537741Smckusick /*
184649365Smckusick  * Read a block of directory entries in a file system independent format.
184737741Smckusick  */
184854916Storek struct ogetdirentries_args {
184954916Storek 	int	fd;
185054916Storek 	char	*buf;
185154916Storek 	unsigned count;
185254916Storek 	long	*basep;
185354916Storek };
185454620Smckusick ogetdirentries(p, uap, retval)
185554620Smckusick 	struct proc *p;
185654916Storek 	register struct ogetdirentries_args *uap;
185754620Smckusick 	int *retval;
185854620Smckusick {
185954620Smckusick 	register struct vnode *vp;
186054620Smckusick 	struct file *fp;
186154620Smckusick 	struct uio auio, kuio;
186254620Smckusick 	struct iovec aiov, kiov;
186354620Smckusick 	struct dirent *dp, *edp;
186454620Smckusick 	caddr_t dirbuf;
186554620Smckusick 	int error, readcnt;
186654969Smckusick 	long loff;
186754620Smckusick 
186854620Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
186954620Smckusick 		return (error);
187054620Smckusick 	if ((fp->f_flag & FREAD) == 0)
187154620Smckusick 		return (EBADF);
187254620Smckusick 	vp = (struct vnode *)fp->f_data;
187354620Smckusick 	if (vp->v_type != VDIR)
187454620Smckusick 		return (EINVAL);
187554620Smckusick 	aiov.iov_base = uap->buf;
187654620Smckusick 	aiov.iov_len = uap->count;
187754620Smckusick 	auio.uio_iov = &aiov;
187854620Smckusick 	auio.uio_iovcnt = 1;
187954620Smckusick 	auio.uio_rw = UIO_READ;
188054620Smckusick 	auio.uio_segflg = UIO_USERSPACE;
188154620Smckusick 	auio.uio_procp = p;
188254620Smckusick 	auio.uio_resid = uap->count;
188354620Smckusick 	VOP_LOCK(vp);
188454969Smckusick 	loff = auio.uio_offset = fp->f_offset;
188554620Smckusick #	if (BYTE_ORDER != LITTLE_ENDIAN)
188656339Smckusick 		if (vp->v_mount->mnt_maxsymlinklen <= 0) {
188754620Smckusick 			error = VOP_READDIR(vp, &auio, fp->f_cred);
188856339Smckusick 			fp->f_offset = auio.uio_offset;
188956339Smckusick 		} else
189054620Smckusick #	endif
189154620Smckusick 	{
189254620Smckusick 		kuio = auio;
189354620Smckusick 		kuio.uio_iov = &kiov;
189454620Smckusick 		kuio.uio_segflg = UIO_SYSSPACE;
189554620Smckusick 		kiov.iov_len = uap->count;
189654620Smckusick 		MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK);
189754620Smckusick 		kiov.iov_base = dirbuf;
189854620Smckusick 		error = VOP_READDIR(vp, &kuio, fp->f_cred);
189956339Smckusick 		fp->f_offset = kuio.uio_offset;
190054620Smckusick 		if (error == 0) {
190154620Smckusick 			readcnt = uap->count - kuio.uio_resid;
190254620Smckusick 			edp = (struct dirent *)&dirbuf[readcnt];
190354620Smckusick 			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
190454620Smckusick #				if (BYTE_ORDER == LITTLE_ENDIAN)
190554969Smckusick 					/*
190655009Smckusick 					 * The expected low byte of
190755009Smckusick 					 * dp->d_namlen is our dp->d_type.
190855009Smckusick 					 * The high MBZ byte of dp->d_namlen
190955009Smckusick 					 * is our dp->d_namlen.
191054969Smckusick 					 */
191155009Smckusick 					dp->d_type = dp->d_namlen;
191255009Smckusick 					dp->d_namlen = 0;
191355009Smckusick #				else
191455009Smckusick 					/*
191555009Smckusick 					 * The dp->d_type is the high byte
191655009Smckusick 					 * of the expected dp->d_namlen,
191755009Smckusick 					 * so must be zero'ed.
191855009Smckusick 					 */
191955009Smckusick 					dp->d_type = 0;
192054620Smckusick #				endif
192154620Smckusick 				if (dp->d_reclen > 0) {
192254620Smckusick 					dp = (struct dirent *)
192354620Smckusick 					    ((char *)dp + dp->d_reclen);
192454620Smckusick 				} else {
192554620Smckusick 					error = EIO;
192654620Smckusick 					break;
192754620Smckusick 				}
192854620Smckusick 			}
192954620Smckusick 			if (dp >= edp)
193054620Smckusick 				error = uiomove(dirbuf, readcnt, &auio);
193154620Smckusick 		}
193254620Smckusick 		FREE(dirbuf, M_TEMP);
193354620Smckusick 	}
193454620Smckusick 	VOP_UNLOCK(vp);
193554620Smckusick 	if (error)
193654620Smckusick 		return (error);
193754969Smckusick 	error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
193854620Smckusick 	*retval = uap->count - auio.uio_resid;
193954620Smckusick 	return (error);
194054620Smckusick }
194154620Smckusick #endif
194254620Smckusick 
194354620Smckusick /*
194454620Smckusick  * Read a block of directory entries in a file system independent format.
194554620Smckusick  */
194654916Storek struct getdirentries_args {
194754916Storek 	int	fd;
194854916Storek 	char	*buf;
194954916Storek 	unsigned count;
195054916Storek 	long	*basep;
195154916Storek };
195242441Smckusick getdirentries(p, uap, retval)
195345914Smckusick 	struct proc *p;
195454916Storek 	register struct getdirentries_args *uap;
195542441Smckusick 	int *retval;
195642441Smckusick {
195739592Smckusick 	register struct vnode *vp;
195816540Ssam 	struct file *fp;
195937741Smckusick 	struct uio auio;
196037741Smckusick 	struct iovec aiov;
196154969Smckusick 	long loff;
196254441Smckusick 	int error;
196312756Ssam 
196445914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
196547540Skarels 		return (error);
196637741Smckusick 	if ((fp->f_flag & FREAD) == 0)
196747540Skarels 		return (EBADF);
196839592Smckusick 	vp = (struct vnode *)fp->f_data;
196955451Spendry unionread:
197039592Smckusick 	if (vp->v_type != VDIR)
197147540Skarels 		return (EINVAL);
197237741Smckusick 	aiov.iov_base = uap->buf;
197337741Smckusick 	aiov.iov_len = uap->count;
197437741Smckusick 	auio.uio_iov = &aiov;
197537741Smckusick 	auio.uio_iovcnt = 1;
197637741Smckusick 	auio.uio_rw = UIO_READ;
197737741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
197848026Smckusick 	auio.uio_procp = p;
197937741Smckusick 	auio.uio_resid = uap->count;
198039592Smckusick 	VOP_LOCK(vp);
198154969Smckusick 	loff = auio.uio_offset = fp->f_offset;
198254441Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred);
198339592Smckusick 	fp->f_offset = auio.uio_offset;
198439592Smckusick 	VOP_UNLOCK(vp);
198539592Smckusick 	if (error)
198647540Skarels 		return (error);
198755451Spendry 	if ((uap->count == auio.uio_resid) &&
198855451Spendry 	    (vp->v_flag & VROOT) &&
198955451Spendry 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
199055451Spendry 		struct vnode *tvp = vp;
199155451Spendry 		vp = vp->v_mount->mnt_vnodecovered;
199255451Spendry 		VREF(vp);
199355451Spendry 		fp->f_data = (caddr_t) vp;
199455451Spendry 		fp->f_offset = 0;
199555451Spendry 		vrele(tvp);
199655451Spendry 		goto unionread;
199755451Spendry 	}
199854969Smckusick 	error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
199942441Smckusick 	*retval = uap->count - auio.uio_resid;
200047540Skarels 	return (error);
200112756Ssam }
200212756Ssam 
200312756Ssam /*
200449365Smckusick  * Set the mode mask for creation of filesystem nodes.
200512756Ssam  */
200654916Storek struct umask_args {
200754916Storek 	int	mask;
200854916Storek };
200954916Storek mode_t				/* XXX */
201042441Smckusick umask(p, uap, retval)
201145914Smckusick 	struct proc *p;
201254916Storek 	struct umask_args *uap;
201342441Smckusick 	int *retval;
201412756Ssam {
201545914Smckusick 	register struct filedesc *fdp = p->p_fd;
201612756Ssam 
201745914Smckusick 	*retval = fdp->fd_cmask;
201845914Smckusick 	fdp->fd_cmask = uap->mask & 07777;
201947540Skarels 	return (0);
202012756Ssam }
202137741Smckusick 
202239566Smarc /*
202339566Smarc  * Void all references to file by ripping underlying filesystem
202439566Smarc  * away from vnode.
202539566Smarc  */
202654916Storek struct revoke_args {
202754916Storek 	char	*fname;
202854916Storek };
202942441Smckusick /* ARGSUSED */
203042441Smckusick revoke(p, uap, retval)
203145914Smckusick 	struct proc *p;
203254916Storek 	register struct revoke_args *uap;
203342441Smckusick 	int *retval;
203442441Smckusick {
203539566Smarc 	register struct vnode *vp;
203639566Smarc 	struct vattr vattr;
203739566Smarc 	int error;
203847540Skarels 	struct nameidata nd;
203939566Smarc 
204052322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
204152322Smckusick 	if (error = namei(&nd))
204247540Skarels 		return (error);
204352322Smckusick 	vp = nd.ni_vp;
204439566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
204539566Smarc 		error = EINVAL;
204639566Smarc 		goto out;
204739566Smarc 	}
204848026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
204939566Smarc 		goto out;
205047540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
205147540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
205239566Smarc 		goto out;
205339805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
205439632Smckusick 		vgoneall(vp);
205539566Smarc out:
205639566Smarc 	vrele(vp);
205747540Skarels 	return (error);
205839566Smarc }
205939566Smarc 
206049365Smckusick /*
206149365Smckusick  * Convert a user file descriptor to a kernel file entry.
206249365Smckusick  */
206345914Smckusick getvnode(fdp, fdes, fpp)
206445914Smckusick 	struct filedesc *fdp;
206537741Smckusick 	struct file **fpp;
206637741Smckusick 	int fdes;
206737741Smckusick {
206837741Smckusick 	struct file *fp;
206937741Smckusick 
207047540Skarels 	if ((unsigned)fdes >= fdp->fd_nfiles ||
207147688Skarels 	    (fp = fdp->fd_ofiles[fdes]) == NULL)
207237741Smckusick 		return (EBADF);
207337741Smckusick 	if (fp->f_type != DTYPE_VNODE)
207437741Smckusick 		return (EINVAL);
207537741Smckusick 	*fpp = fp;
207637741Smckusick 	return (0);
207737741Smckusick }
2078