xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 55451)
123405Smckusick /*
237741Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337741Smckusick  * All rights reserved.
423405Smckusick  *
544459Sbostic  * %sccs.include.redist.c%
637741Smckusick  *
7*55451Spendry  *	@(#)vfs_syscalls.c	7.96 (Berkeley) 07/20/92
823405Smckusick  */
937Sbill 
1017101Sbloom #include "param.h"
1117101Sbloom #include "systm.h"
1247540Skarels #include "namei.h"
1345914Smckusick #include "filedesc.h"
1417101Sbloom #include "kernel.h"
1517101Sbloom #include "file.h"
1617101Sbloom #include "stat.h"
1737741Smckusick #include "vnode.h"
1837741Smckusick #include "mount.h"
1917101Sbloom #include "proc.h"
2017101Sbloom #include "uio.h"
2137741Smckusick #include "malloc.h"
2254620Smckusick #include "dirent.h"
2353468Smckusick #include <vm/vm.h>
2437Sbill 
2537741Smckusick /*
2637741Smckusick  * Virtual File System System Calls
2737741Smckusick  */
2812756Ssam 
299167Ssam /*
3049365Smckusick  * Mount system call.
319167Ssam  */
3254916Storek struct mount_args {
3354916Storek 	int	type;
3454916Storek 	char	*dir;
3554916Storek 	int	flags;
3654916Storek 	caddr_t	data;
3754916Storek };
3842441Smckusick /* ARGSUSED */
3942441Smckusick mount(p, uap, retval)
4045914Smckusick 	struct proc *p;
4154916Storek 	register struct mount_args *uap;
4242441Smckusick 	int *retval;
4342441Smckusick {
4439335Smckusick 	register struct vnode *vp;
4539335Smckusick 	register struct mount *mp;
4640111Smckusick 	int error, flag;
4747540Skarels 	struct nameidata nd;
486254Sroot 
4937741Smckusick 	/*
5037741Smckusick 	 * Must be super user
5137741Smckusick 	 */
5247540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
5347540Skarels 		return (error);
5437741Smckusick 	/*
5537741Smckusick 	 * Get vnode to be covered
5637741Smckusick 	 */
5752322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->dir, p);
5852322Smckusick 	if (error = namei(&nd))
5947540Skarels 		return (error);
6052322Smckusick 	vp = nd.ni_vp;
6141400Smckusick 	if (uap->flags & MNT_UPDATE) {
6239335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
6339335Smckusick 			vput(vp);
6447540Skarels 			return (EINVAL);
6539335Smckusick 		}
6639335Smckusick 		mp = vp->v_mount;
6739335Smckusick 		/*
6839335Smckusick 		 * We allow going from read-only to read-write,
6939335Smckusick 		 * but not from read-write to read-only.
7039335Smckusick 		 */
7141400Smckusick 		if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
7241400Smckusick 		    (uap->flags & MNT_RDONLY) != 0) {
7339335Smckusick 			vput(vp);
7447540Skarels 			return (EOPNOTSUPP);	/* Needs translation */
7539335Smckusick 		}
7641400Smckusick 		flag = mp->mnt_flag;
7741400Smckusick 		mp->mnt_flag |= MNT_UPDATE;
7839335Smckusick 		VOP_UNLOCK(vp);
7939335Smckusick 		goto update;
8039335Smckusick 	}
81*55451Spendry 	if (vp->v_usecount != 1 && (uap->flags & MNT_UNION) == 0) {
8237741Smckusick 		vput(vp);
8347540Skarels 		return (EBUSY);
8437741Smckusick 	}
8554441Smckusick 	if (error = vinvalbuf(vp, 1, p->p_ucred, p))
8654441Smckusick 		return (error);
8737741Smckusick 	if (vp->v_type != VDIR) {
8837741Smckusick 		vput(vp);
8947540Skarels 		return (ENOTDIR);
9037741Smckusick 	}
9139741Smckusick 	if ((unsigned long)uap->type > MOUNT_MAXTYPE ||
9237741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
9337741Smckusick 		vput(vp);
9447540Skarels 		return (ENODEV);
9537741Smckusick 	}
9637741Smckusick 
9737741Smckusick 	/*
9839335Smckusick 	 * Allocate and initialize the file system.
9937741Smckusick 	 */
10037741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
10137741Smckusick 		M_MOUNT, M_WAITOK);
10254172Smckusick 	bzero((char *)mp, (u_long)sizeof(struct mount));
10341400Smckusick 	mp->mnt_op = vfssw[uap->type];
10439335Smckusick 	if (error = vfs_lock(mp)) {
10539335Smckusick 		free((caddr_t)mp, M_MOUNT);
10639335Smckusick 		vput(vp);
10747540Skarels 		return (error);
10839335Smckusick 	}
10939335Smckusick 	if (vp->v_mountedhere != (struct mount *)0) {
11039335Smckusick 		vfs_unlock(mp);
11139335Smckusick 		free((caddr_t)mp, M_MOUNT);
11239335Smckusick 		vput(vp);
11347540Skarels 		return (EBUSY);
11439335Smckusick 	}
11539335Smckusick 	vp->v_mountedhere = mp;
11641400Smckusick 	mp->mnt_vnodecovered = vp;
11739335Smckusick update:
11839335Smckusick 	/*
11939335Smckusick 	 * Set the mount level flags.
12039335Smckusick 	 */
12141400Smckusick 	if (uap->flags & MNT_RDONLY)
12241400Smckusick 		mp->mnt_flag |= MNT_RDONLY;
12339335Smckusick 	else
12441400Smckusick 		mp->mnt_flag &= ~MNT_RDONLY;
12541400Smckusick 	if (uap->flags & MNT_NOSUID)
12641400Smckusick 		mp->mnt_flag |= MNT_NOSUID;
12739335Smckusick 	else
12841400Smckusick 		mp->mnt_flag &= ~MNT_NOSUID;
12941400Smckusick 	if (uap->flags & MNT_NOEXEC)
13041400Smckusick 		mp->mnt_flag |= MNT_NOEXEC;
13139335Smckusick 	else
13241400Smckusick 		mp->mnt_flag &= ~MNT_NOEXEC;
13341400Smckusick 	if (uap->flags & MNT_NODEV)
13441400Smckusick 		mp->mnt_flag |= MNT_NODEV;
13539335Smckusick 	else
13641400Smckusick 		mp->mnt_flag &= ~MNT_NODEV;
13741400Smckusick 	if (uap->flags & MNT_SYNCHRONOUS)
13841400Smckusick 		mp->mnt_flag |= MNT_SYNCHRONOUS;
13939335Smckusick 	else
14041400Smckusick 		mp->mnt_flag &= ~MNT_SYNCHRONOUS;
141*55451Spendry 	if (uap->flags & MNT_UNION)
142*55451Spendry 		mp->mnt_flag |= MNT_UNION;
143*55451Spendry 	else
144*55451Spendry 		mp->mnt_flag &= ~MNT_UNION;
14539335Smckusick 	/*
14639335Smckusick 	 * Mount the filesystem.
14739335Smckusick 	 */
14852322Smckusick 	error = VFS_MOUNT(mp, uap->dir, uap->data, &nd, p);
14941400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
15041400Smckusick 		mp->mnt_flag &= ~MNT_UPDATE;
15139335Smckusick 		vrele(vp);
15240111Smckusick 		if (error)
15341400Smckusick 			mp->mnt_flag = flag;
15447540Skarels 		return (error);
15539335Smckusick 	}
15640110Smckusick 	/*
15740110Smckusick 	 * Put the new filesystem on the mount list after root.
15840110Smckusick 	 */
15941400Smckusick 	mp->mnt_next = rootfs->mnt_next;
16041400Smckusick 	mp->mnt_prev = rootfs;
16141400Smckusick 	rootfs->mnt_next = mp;
16241400Smckusick 	mp->mnt_next->mnt_prev = mp;
16337741Smckusick 	cache_purge(vp);
16437741Smckusick 	if (!error) {
16539335Smckusick 		VOP_UNLOCK(vp);
16637741Smckusick 		vfs_unlock(mp);
16748026Smckusick 		error = VFS_START(mp, 0, p);
16837741Smckusick 	} else {
16937741Smckusick 		vfs_remove(mp);
17037741Smckusick 		free((caddr_t)mp, M_MOUNT);
17139335Smckusick 		vput(vp);
17237741Smckusick 	}
17347540Skarels 	return (error);
1746254Sroot }
1756254Sroot 
1769167Ssam /*
17737741Smckusick  * Unmount system call.
17837741Smckusick  *
17937741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
18037741Smckusick  * not special file (as before).
1819167Ssam  */
18254916Storek struct unmount_args {
18354916Storek 	char	*pathp;
18454916Storek 	int	flags;
18554916Storek };
18642441Smckusick /* ARGSUSED */
18742441Smckusick unmount(p, uap, retval)
18845914Smckusick 	struct proc *p;
18954916Storek 	register struct unmount_args *uap;
19042441Smckusick 	int *retval;
19142441Smckusick {
19237741Smckusick 	register struct vnode *vp;
19339356Smckusick 	struct mount *mp;
19437741Smckusick 	int error;
19547540Skarels 	struct nameidata nd;
1966254Sroot 
19737741Smckusick 	/*
19837741Smckusick 	 * Must be super user
19937741Smckusick 	 */
20047540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
20147540Skarels 		return (error);
20237741Smckusick 
20352322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->pathp, p);
20452322Smckusick 	if (error = namei(&nd))
20547540Skarels 		return (error);
20652322Smckusick 	vp = nd.ni_vp;
20737741Smckusick 	/*
20837741Smckusick 	 * Must be the root of the filesystem
20937741Smckusick 	 */
21037741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
21137741Smckusick 		vput(vp);
21247540Skarels 		return (EINVAL);
21337741Smckusick 	}
21437741Smckusick 	mp = vp->v_mount;
21537741Smckusick 	vput(vp);
21648026Smckusick 	return (dounmount(mp, uap->flags, p));
21739356Smckusick }
21839356Smckusick 
21939356Smckusick /*
22039356Smckusick  * Do an unmount.
22139356Smckusick  */
22248026Smckusick dounmount(mp, flags, p)
22339356Smckusick 	register struct mount *mp;
22439356Smckusick 	int flags;
22548026Smckusick 	struct proc *p;
22639356Smckusick {
22739356Smckusick 	struct vnode *coveredvp;
22839356Smckusick 	int error;
22939356Smckusick 
23041400Smckusick 	coveredvp = mp->mnt_vnodecovered;
23141298Smckusick 	if (vfs_busy(mp))
23241298Smckusick 		return (EBUSY);
23341400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
23437741Smckusick 	if (error = vfs_lock(mp))
23539356Smckusick 		return (error);
23637741Smckusick 
23745738Smckusick 	vnode_pager_umount(mp);	/* release cached vnodes */
23837741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
23954441Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 ||
24054441Smckusick 	    (flags & MNT_FORCE))
24148026Smckusick 		error = VFS_UNMOUNT(mp, flags, p);
24241400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
24341298Smckusick 	vfs_unbusy(mp);
24437741Smckusick 	if (error) {
24537741Smckusick 		vfs_unlock(mp);
24637741Smckusick 	} else {
24737741Smckusick 		vrele(coveredvp);
24837741Smckusick 		vfs_remove(mp);
24952287Smckusick 		if (mp->mnt_mounth != NULL)
25052287Smckusick 			panic("unmount: dangling vnode");
25137741Smckusick 		free((caddr_t)mp, M_MOUNT);
25237741Smckusick 	}
25339356Smckusick 	return (error);
2546254Sroot }
2556254Sroot 
2569167Ssam /*
25737741Smckusick  * Sync system call.
25837741Smckusick  * Sync each mounted filesystem.
2599167Ssam  */
26054916Storek struct sync_args {
26154916Storek 	int	dummy;
26254916Storek };
26339491Smckusick /* ARGSUSED */
26442441Smckusick sync(p, uap, retval)
26545914Smckusick 	struct proc *p;
26654916Storek 	struct sync_args *uap;
26742441Smckusick 	int *retval;
2686254Sroot {
26937741Smckusick 	register struct mount *mp;
27041298Smckusick 	struct mount *omp;
27137741Smckusick 
27237741Smckusick 	mp = rootfs;
27337741Smckusick 	do {
27440343Smckusick 		/*
27540343Smckusick 		 * The lock check below is to avoid races with mount
27640343Smckusick 		 * and unmount.
27740343Smckusick 		 */
27841400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
27941298Smckusick 		    !vfs_busy(mp)) {
28054441Smckusick 			VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
28141298Smckusick 			omp = mp;
28241400Smckusick 			mp = mp->mnt_next;
28341298Smckusick 			vfs_unbusy(omp);
28441298Smckusick 		} else
28541400Smckusick 			mp = mp->mnt_next;
28637741Smckusick 	} while (mp != rootfs);
28747688Skarels 	return (0);
28837741Smckusick }
28937741Smckusick 
29037741Smckusick /*
29149365Smckusick  * Operate on filesystem quotas.
29241298Smckusick  */
29354916Storek struct quotactl_args {
29454916Storek 	char *path;
29554916Storek 	int cmd;
29654916Storek 	int uid;
29754916Storek 	caddr_t arg;
29854916Storek };
29942441Smckusick /* ARGSUSED */
30042441Smckusick quotactl(p, uap, retval)
30145914Smckusick 	struct proc *p;
30254916Storek 	register struct quotactl_args *uap;
30342441Smckusick 	int *retval;
30442441Smckusick {
30541298Smckusick 	register struct mount *mp;
30641298Smckusick 	int error;
30747540Skarels 	struct nameidata nd;
30841298Smckusick 
30952322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
31052322Smckusick 	if (error = namei(&nd))
31147540Skarels 		return (error);
31252322Smckusick 	mp = nd.ni_vp->v_mount;
31352322Smckusick 	vrele(nd.ni_vp);
31448026Smckusick 	return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p));
31541298Smckusick }
31641298Smckusick 
31741298Smckusick /*
31849365Smckusick  * Get filesystem statistics.
31937741Smckusick  */
32054916Storek struct statfs_args {
32154916Storek 	char *path;
32254916Storek 	struct statfs *buf;
32354916Storek };
32442441Smckusick /* ARGSUSED */
32542441Smckusick statfs(p, uap, retval)
32645914Smckusick 	struct proc *p;
32754916Storek 	register struct statfs_args *uap;
32842441Smckusick 	int *retval;
32942441Smckusick {
33039464Smckusick 	register struct mount *mp;
33140343Smckusick 	register struct statfs *sp;
33237741Smckusick 	int error;
33347540Skarels 	struct nameidata nd;
33437741Smckusick 
33552322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
33652322Smckusick 	if (error = namei(&nd))
33747540Skarels 		return (error);
33852322Smckusick 	mp = nd.ni_vp->v_mount;
33941400Smckusick 	sp = &mp->mnt_stat;
34052322Smckusick 	vrele(nd.ni_vp);
34148026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
34247540Skarels 		return (error);
34341400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
34447540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
34537741Smckusick }
34637741Smckusick 
34742441Smckusick /*
34849365Smckusick  * Get filesystem statistics.
34942441Smckusick  */
35054916Storek struct fstatfs_args {
35154916Storek 	int fd;
35254916Storek 	struct statfs *buf;
35354916Storek };
35442441Smckusick /* ARGSUSED */
35542441Smckusick fstatfs(p, uap, retval)
35645914Smckusick 	struct proc *p;
35754916Storek 	register struct fstatfs_args *uap;
35842441Smckusick 	int *retval;
35942441Smckusick {
36037741Smckusick 	struct file *fp;
36139464Smckusick 	struct mount *mp;
36240343Smckusick 	register struct statfs *sp;
36337741Smckusick 	int error;
36437741Smckusick 
36545914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
36647540Skarels 		return (error);
36739464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
36841400Smckusick 	sp = &mp->mnt_stat;
36948026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
37047540Skarels 		return (error);
37141400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
37247540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
37337741Smckusick }
37437741Smckusick 
37537741Smckusick /*
37649365Smckusick  * Get statistics on all filesystems.
37738270Smckusick  */
37854916Storek struct getfsstat_args {
37954916Storek 	struct statfs *buf;
38054916Storek 	long bufsize;
38154916Storek 	int flags;
38254916Storek };
38342441Smckusick getfsstat(p, uap, retval)
38445914Smckusick 	struct proc *p;
38554916Storek 	register struct getfsstat_args *uap;
38642441Smckusick 	int *retval;
38742441Smckusick {
38838270Smckusick 	register struct mount *mp;
38940343Smckusick 	register struct statfs *sp;
39039606Smckusick 	caddr_t sfsp;
39138270Smckusick 	long count, maxcount, error;
39238270Smckusick 
39338270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
39439606Smckusick 	sfsp = (caddr_t)uap->buf;
39538270Smckusick 	mp = rootfs;
39638270Smckusick 	count = 0;
39738270Smckusick 	do {
39841400Smckusick 		if (sfsp && count < maxcount &&
39941400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
40041400Smckusick 			sp = &mp->mnt_stat;
40140343Smckusick 			/*
40240343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
40340343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
40440343Smckusick 			 */
40540343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
40640343Smckusick 			    (uap->flags & MNT_WAIT)) &&
40748026Smckusick 			    (error = VFS_STATFS(mp, sp, p))) {
40841400Smckusick 				mp = mp->mnt_prev;
40939607Smckusick 				continue;
41039607Smckusick 			}
41141400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
41240343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
41347540Skarels 				return (error);
41440343Smckusick 			sfsp += sizeof(*sp);
41538270Smckusick 		}
41639606Smckusick 		count++;
41741400Smckusick 		mp = mp->mnt_prev;
41838270Smckusick 	} while (mp != rootfs);
41938270Smckusick 	if (sfsp && count > maxcount)
42042441Smckusick 		*retval = maxcount;
42138270Smckusick 	else
42242441Smckusick 		*retval = count;
42347540Skarels 	return (0);
42438270Smckusick }
42538270Smckusick 
42638270Smckusick /*
42738259Smckusick  * Change current working directory to a given file descriptor.
42838259Smckusick  */
42954916Storek struct fchdir_args {
43054916Storek 	int	fd;
43154916Storek };
43242441Smckusick /* ARGSUSED */
43342441Smckusick fchdir(p, uap, retval)
43445914Smckusick 	struct proc *p;
43554916Storek 	struct fchdir_args *uap;
43642441Smckusick 	int *retval;
43738259Smckusick {
43845914Smckusick 	register struct filedesc *fdp = p->p_fd;
43938259Smckusick 	register struct vnode *vp;
44038259Smckusick 	struct file *fp;
44138259Smckusick 	int error;
44238259Smckusick 
44345914Smckusick 	if (error = getvnode(fdp, uap->fd, &fp))
44447540Skarels 		return (error);
44538259Smckusick 	vp = (struct vnode *)fp->f_data;
44638259Smckusick 	VOP_LOCK(vp);
44738259Smckusick 	if (vp->v_type != VDIR)
44838259Smckusick 		error = ENOTDIR;
44938259Smckusick 	else
45048026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
45138259Smckusick 	VOP_UNLOCK(vp);
45239860Smckusick 	if (error)
45347540Skarels 		return (error);
45439860Smckusick 	VREF(vp);
45545914Smckusick 	vrele(fdp->fd_cdir);
45645914Smckusick 	fdp->fd_cdir = vp;
45747540Skarels 	return (0);
45838259Smckusick }
45938259Smckusick 
46038259Smckusick /*
46137741Smckusick  * Change current working directory (``.'').
46237741Smckusick  */
46354916Storek struct chdir_args {
46454916Storek 	char	*fname;
46554916Storek };
46642441Smckusick /* ARGSUSED */
46742441Smckusick chdir(p, uap, retval)
46845914Smckusick 	struct proc *p;
46954916Storek 	struct chdir_args *uap;
47042441Smckusick 	int *retval;
47137741Smckusick {
47245914Smckusick 	register struct filedesc *fdp = p->p_fd;
47337741Smckusick 	int error;
47447540Skarels 	struct nameidata nd;
4756254Sroot 
47652322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
47752781Sralph 	if (error = chdirec(&nd, p))
47847540Skarels 		return (error);
47945914Smckusick 	vrele(fdp->fd_cdir);
48052322Smckusick 	fdp->fd_cdir = nd.ni_vp;
48147540Skarels 	return (0);
48237741Smckusick }
4836254Sroot 
48437741Smckusick /*
48537741Smckusick  * Change notion of root (``/'') directory.
48637741Smckusick  */
48754916Storek struct chroot_args {
48854916Storek 	char	*fname;
48954916Storek };
49042441Smckusick /* ARGSUSED */
49142441Smckusick chroot(p, uap, retval)
49245914Smckusick 	struct proc *p;
49354916Storek 	struct chroot_args *uap;
49442441Smckusick 	int *retval;
49537741Smckusick {
49645914Smckusick 	register struct filedesc *fdp = p->p_fd;
49737741Smckusick 	int error;
49847540Skarels 	struct nameidata nd;
49937741Smckusick 
50047540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
50147540Skarels 		return (error);
50252322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
50352781Sralph 	if (error = chdirec(&nd, p))
50447540Skarels 		return (error);
50545914Smckusick 	if (fdp->fd_rdir != NULL)
50645914Smckusick 		vrele(fdp->fd_rdir);
50752322Smckusick 	fdp->fd_rdir = nd.ni_vp;
50847540Skarels 	return (0);
5096254Sroot }
5106254Sroot 
51137Sbill /*
51237741Smckusick  * Common routine for chroot and chdir.
51337741Smckusick  */
51447540Skarels chdirec(ndp, p)
51552322Smckusick 	register struct nameidata *ndp;
51647540Skarels 	struct proc *p;
51737741Smckusick {
51837741Smckusick 	struct vnode *vp;
51937741Smckusick 	int error;
52037741Smckusick 
52152322Smckusick 	if (error = namei(ndp))
52237741Smckusick 		return (error);
52337741Smckusick 	vp = ndp->ni_vp;
52437741Smckusick 	if (vp->v_type != VDIR)
52537741Smckusick 		error = ENOTDIR;
52637741Smckusick 	else
52748026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
52837741Smckusick 	VOP_UNLOCK(vp);
52937741Smckusick 	if (error)
53037741Smckusick 		vrele(vp);
53137741Smckusick 	return (error);
53237741Smckusick }
53337741Smckusick 
53437741Smckusick /*
5356254Sroot  * Open system call.
53642441Smckusick  * Check permissions, allocate an open file structure,
53742441Smckusick  * and call the device open routine if any.
5386254Sroot  */
53954916Storek struct open_args {
54054916Storek 	char	*fname;
54154916Storek 	int	mode;
54254916Storek 	int	crtmode;
54354916Storek };
54442441Smckusick open(p, uap, retval)
54545914Smckusick 	struct proc *p;
54654916Storek 	register struct open_args *uap;
54742441Smckusick 	int *retval;
5486254Sroot {
54945914Smckusick 	register struct filedesc *fdp = p->p_fd;
55042441Smckusick 	register struct file *fp;
55150111Smckusick 	register struct vnode *vp;
55237741Smckusick 	int fmode, cmode;
55337741Smckusick 	struct file *nfp;
55449945Smckusick 	int type, indx, error;
55549945Smckusick 	struct flock lf;
55647540Skarels 	struct nameidata nd;
55737741Smckusick 	extern struct fileops vnops;
5586254Sroot 
55945914Smckusick 	if (error = falloc(p, &nfp, &indx))
56047540Skarels 		return (error);
56137741Smckusick 	fp = nfp;
56246553Skarels 	fmode = FFLAGS(uap->mode);
56345914Smckusick 	cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX;
56452322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
56545202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
56652322Smckusick 	if (error = vn_open(&nd, fmode, cmode)) {
56749980Smckusick 		ffree(fp);
56854723Smckusick 		if ((error == ENODEV || error == ENXIO) &&
56954723Smckusick 		    p->p_dupfd >= 0 && 			/* XXX from fdopen */
57053828Spendry 		    (error = dupfdopen(fdp, indx, p->p_dupfd,
57153828Spendry 					fmode, error)) == 0) {
57242441Smckusick 			*retval = indx;
57347540Skarels 			return (0);
57442441Smckusick 		}
57540884Smckusick 		if (error == ERESTART)
57640884Smckusick 			error = EINTR;
57747688Skarels 		fdp->fd_ofiles[indx] = NULL;
57847540Skarels 		return (error);
57912756Ssam 	}
58053828Spendry 	p->p_dupfd = 0;
58152322Smckusick 	vp = nd.ni_vp;
58249949Smckusick 	fp->f_flag = fmode & FMASK;
58354348Smckusick 	fp->f_type = DTYPE_VNODE;
58454348Smckusick 	fp->f_ops = &vnops;
58554348Smckusick 	fp->f_data = (caddr_t)vp;
58649945Smckusick 	if (fmode & (O_EXLOCK | O_SHLOCK)) {
58749945Smckusick 		lf.l_whence = SEEK_SET;
58849945Smckusick 		lf.l_start = 0;
58949945Smckusick 		lf.l_len = 0;
59049945Smckusick 		if (fmode & O_EXLOCK)
59149945Smckusick 			lf.l_type = F_WRLCK;
59249945Smckusick 		else
59349945Smckusick 			lf.l_type = F_RDLCK;
59449945Smckusick 		type = F_FLOCK;
59549945Smckusick 		if ((fmode & FNONBLOCK) == 0)
59649945Smckusick 			type |= F_WAIT;
59750111Smckusick 		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
59850111Smckusick 			VOP_UNLOCK(vp);
59950111Smckusick 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
60049980Smckusick 			ffree(fp);
60149945Smckusick 			fdp->fd_ofiles[indx] = NULL;
60249945Smckusick 			return (error);
60349945Smckusick 		}
60449949Smckusick 		fp->f_flag |= FHASLOCK;
60549945Smckusick 	}
60650111Smckusick 	VOP_UNLOCK(vp);
60742441Smckusick 	*retval = indx;
60847540Skarels 	return (0);
6096254Sroot }
6106254Sroot 
61142955Smckusick #ifdef COMPAT_43
6126254Sroot /*
61342441Smckusick  * Creat system call.
6146254Sroot  */
61554916Storek struct ocreat_args {
61654916Storek 	char	*fname;
61754916Storek 	int	fmode;
61854916Storek };
61942955Smckusick ocreat(p, uap, retval)
62042441Smckusick 	struct proc *p;
62154916Storek 	register struct ocreat_args *uap;
62242441Smckusick 	int *retval;
6236254Sroot {
62454916Storek 	struct open_args openuap;
62542441Smckusick 
62642441Smckusick 	openuap.fname = uap->fname;
62742441Smckusick 	openuap.crtmode = uap->fmode;
62842441Smckusick 	openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
62947540Skarels 	return (open(p, &openuap, retval));
63042441Smckusick }
63142955Smckusick #endif /* COMPAT_43 */
63242441Smckusick 
63342441Smckusick /*
63449365Smckusick  * Mknod system call.
63542441Smckusick  */
63654916Storek struct mknod_args {
63754916Storek 	char	*fname;
63854916Storek 	int	fmode;
63954916Storek 	int	dev;
64054916Storek };
64142441Smckusick /* ARGSUSED */
64242441Smckusick mknod(p, uap, retval)
64345914Smckusick 	struct proc *p;
64454916Storek 	register struct mknod_args *uap;
64542441Smckusick 	int *retval;
64642441Smckusick {
64737741Smckusick 	register struct vnode *vp;
64837741Smckusick 	struct vattr vattr;
64937741Smckusick 	int error;
65047540Skarels 	struct nameidata nd;
6516254Sroot 
65247540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
65347540Skarels 		return (error);
65452322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p);
65552322Smckusick 	if (error = namei(&nd))
65647540Skarels 		return (error);
65752322Smckusick 	vp = nd.ni_vp;
65837741Smckusick 	if (vp != NULL) {
65937741Smckusick 		error = EEXIST;
66012756Ssam 		goto out;
6616254Sroot 	}
66241362Smckusick 	VATTR_NULL(&vattr);
66340635Smckusick 	switch (uap->fmode & S_IFMT) {
66412756Ssam 
66540635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
66637741Smckusick 		vattr.va_type = VBAD;
66737741Smckusick 		break;
66840635Smckusick 	case S_IFCHR:
66937741Smckusick 		vattr.va_type = VCHR;
67037741Smckusick 		break;
67140635Smckusick 	case S_IFBLK:
67237741Smckusick 		vattr.va_type = VBLK;
67337741Smckusick 		break;
67437741Smckusick 	default:
67537741Smckusick 		error = EINVAL;
67637741Smckusick 		goto out;
6776254Sroot 	}
67845914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
67937741Smckusick 	vattr.va_rdev = uap->dev;
6806254Sroot out:
68142465Smckusick 	if (!error) {
68252322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
68352322Smckusick 		error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
68442465Smckusick 	} else {
68552322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
68652322Smckusick 		if (nd.ni_dvp == vp)
68752322Smckusick 			vrele(nd.ni_dvp);
68843344Smckusick 		else
68952322Smckusick 			vput(nd.ni_dvp);
69042465Smckusick 		if (vp)
69142465Smckusick 			vrele(vp);
69242465Smckusick 	}
69347540Skarels 	return (error);
6946254Sroot }
6956254Sroot 
6966254Sroot /*
69749365Smckusick  * Mkfifo system call.
69840285Smckusick  */
69954916Storek struct mkfifo_args {
70054916Storek 	char	*fname;
70154916Storek 	int	fmode;
70254916Storek };
70342441Smckusick /* ARGSUSED */
70442441Smckusick mkfifo(p, uap, retval)
70545914Smckusick 	struct proc *p;
70654916Storek 	register struct mkfifo_args *uap;
70742441Smckusick 	int *retval;
70842441Smckusick {
70940285Smckusick 	struct vattr vattr;
71040285Smckusick 	int error;
71147540Skarels 	struct nameidata nd;
71240285Smckusick 
71340285Smckusick #ifndef FIFO
71447540Skarels 	return (EOPNOTSUPP);
71540285Smckusick #else
71652322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p);
71752322Smckusick 	if (error = namei(&nd))
71847540Skarels 		return (error);
71952322Smckusick 	if (nd.ni_vp != NULL) {
72052322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
72152322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
72252322Smckusick 			vrele(nd.ni_dvp);
72343344Smckusick 		else
72452322Smckusick 			vput(nd.ni_dvp);
72552322Smckusick 		vrele(nd.ni_vp);
72647540Skarels 		return (EEXIST);
72740285Smckusick 	}
72845785Sbostic 	VATTR_NULL(&vattr);
72945785Sbostic 	vattr.va_type = VFIFO;
73045914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
73152322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
73252322Smckusick 	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
73340285Smckusick #endif /* FIFO */
73440285Smckusick }
73540285Smckusick 
73640285Smckusick /*
73749365Smckusick  * Link system call.
7386254Sroot  */
73954916Storek struct link_args {
74054916Storek 	char	*target;
74154916Storek 	char	*linkname;
74254916Storek };
74342441Smckusick /* ARGSUSED */
74442441Smckusick link(p, uap, retval)
74545914Smckusick 	struct proc *p;
74654916Storek 	register struct link_args *uap;
74742441Smckusick 	int *retval;
74842441Smckusick {
74937741Smckusick 	register struct vnode *vp, *xp;
75037741Smckusick 	int error;
75147540Skarels 	struct nameidata nd;
7526254Sroot 
75352322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->target, p);
75452322Smckusick 	if (error = namei(&nd))
75547540Skarels 		return (error);
75652322Smckusick 	vp = nd.ni_vp;
75737741Smckusick 	if (vp->v_type == VDIR &&
75847540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
75937741Smckusick 		goto out1;
76052322Smckusick 	nd.ni_cnd.cn_nameiop = CREATE;
76152322Smckusick 	nd.ni_cnd.cn_flags = LOCKPARENT;
76252322Smckusick 	nd.ni_dirp = (caddr_t)uap->linkname;
76352322Smckusick 	if (error = namei(&nd))
76437741Smckusick 		goto out1;
76552322Smckusick 	xp = nd.ni_vp;
7666254Sroot 	if (xp != NULL) {
76737741Smckusick 		error = EEXIST;
7686254Sroot 		goto out;
7696254Sroot 	}
77052322Smckusick 	xp = nd.ni_dvp;
7716254Sroot out:
77242465Smckusick 	if (!error) {
77352192Smckusick 		LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE);
77452192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
77552821Smckusick 		error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
77642465Smckusick 	} else {
77752322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
77852322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
77952322Smckusick 			vrele(nd.ni_dvp);
78043344Smckusick 		else
78152322Smckusick 			vput(nd.ni_dvp);
78252322Smckusick 		if (nd.ni_vp)
78352322Smckusick 			vrele(nd.ni_vp);
78442465Smckusick 	}
78537741Smckusick out1:
78637741Smckusick 	vrele(vp);
78747540Skarels 	return (error);
7886254Sroot }
7896254Sroot 
7906254Sroot /*
79149365Smckusick  * Make a symbolic link.
7926254Sroot  */
79354916Storek struct symlink_args {
79454916Storek 	char	*target;
79554916Storek 	char	*linkname;
79654916Storek };
79742441Smckusick /* ARGSUSED */
79842441Smckusick symlink(p, uap, retval)
79945914Smckusick 	struct proc *p;
80054916Storek 	register struct symlink_args *uap;
80142441Smckusick 	int *retval;
80242441Smckusick {
80337741Smckusick 	struct vattr vattr;
80437741Smckusick 	char *target;
80537741Smckusick 	int error;
80647540Skarels 	struct nameidata nd;
8076254Sroot 
80837741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
80937741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
81042465Smckusick 		goto out;
81152322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->linkname, p);
81252322Smckusick 	if (error = namei(&nd))
81342465Smckusick 		goto out;
81452322Smckusick 	if (nd.ni_vp) {
81552322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
81652322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
81752322Smckusick 			vrele(nd.ni_dvp);
81843344Smckusick 		else
81952322Smckusick 			vput(nd.ni_dvp);
82052322Smckusick 		vrele(nd.ni_vp);
82137741Smckusick 		error = EEXIST;
82237741Smckusick 		goto out;
8236254Sroot 	}
82441362Smckusick 	VATTR_NULL(&vattr);
82545914Smckusick 	vattr.va_mode = 0777 &~ p->p_fd->fd_cmask;
82652322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
82752322Smckusick 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, target);
82837741Smckusick out:
82937741Smckusick 	FREE(target, M_NAMEI);
83047540Skarels 	return (error);
8316254Sroot }
8326254Sroot 
8336254Sroot /*
83449365Smckusick  * Delete a name from the filesystem.
8356254Sroot  */
83654916Storek struct unlink_args {
83754916Storek 	char	*name;
83854916Storek };
83942441Smckusick /* ARGSUSED */
84042441Smckusick unlink(p, uap, retval)
84145914Smckusick 	struct proc *p;
84254916Storek 	struct unlink_args *uap;
84342441Smckusick 	int *retval;
8446254Sroot {
84537741Smckusick 	register struct vnode *vp;
84637741Smckusick 	int error;
84747540Skarels 	struct nameidata nd;
8486254Sroot 
84952322Smckusick 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p);
85052322Smckusick 	if (error = namei(&nd))
85147540Skarels 		return (error);
85252322Smckusick 	vp = nd.ni_vp;
85337741Smckusick 	if (vp->v_type == VDIR &&
85447540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
8556254Sroot 		goto out;
8566254Sroot 	/*
85749365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
8586254Sroot 	 */
85937741Smckusick 	if (vp->v_flag & VROOT) {
86037741Smckusick 		error = EBUSY;
8616254Sroot 		goto out;
8626254Sroot 	}
86345738Smckusick 	(void) vnode_pager_uncache(vp);
8646254Sroot out:
86542465Smckusick 	if (!error) {
86652322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
86752192Smckusick 		LEASE_CHECK(vp, 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 
88754348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
8886254Sroot /*
88949365Smckusick  * Seek system call.
8906254Sroot  */
89154916Storek struct lseek_args {
89254916Storek 	int	fdes;
89354916Storek 	long	off;
89454916Storek 	int	sbase;
89554916Storek };
89642441Smckusick lseek(p, uap, retval)
89745914Smckusick 	struct proc *p;
89854916Storek 	register struct lseek_args *uap;
89954916Storek 	int *retval;
90053468Smckusick {
90154916Storek 	struct __lseek_args nuap;
90254863Storek 	off_t qret;
90353468Smckusick 	int error;
90453468Smckusick 
90553468Smckusick 	nuap.fdes = uap->fdes;
90653468Smckusick 	nuap.off = uap->off;
90753468Smckusick 	nuap.sbase = uap->sbase;
90853759Smckusick 	error = __lseek(p, &nuap, &qret);
90954916Storek 	*(long *)retval = qret;
91053468Smckusick 	return (error);
91153468Smckusick }
91254348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
91353468Smckusick 
91453468Smckusick /*
91553468Smckusick  * Seek system call.
91653468Smckusick  */
91753759Smckusick __lseek(p, uap, retval)
91853468Smckusick 	struct proc *p;
91954916Storek 	register struct __lseek_args *uap;
92054916Storek 	int *retval;
92142441Smckusick {
92247540Skarels 	struct ucred *cred = p->p_ucred;
92345914Smckusick 	register struct filedesc *fdp = p->p_fd;
92442441Smckusick 	register struct file *fp;
92537741Smckusick 	struct vattr vattr;
92637741Smckusick 	int error;
9276254Sroot 
92847540Skarels 	if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
92947688Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL)
93047540Skarels 		return (EBADF);
93137741Smckusick 	if (fp->f_type != DTYPE_VNODE)
93247540Skarels 		return (ESPIPE);
93313878Ssam 	switch (uap->sbase) {
93413878Ssam 
93513878Ssam 	case L_INCR:
93613878Ssam 		fp->f_offset += uap->off;
93713878Ssam 		break;
93813878Ssam 
93913878Ssam 	case L_XTND:
94037741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
94148026Smckusick 		    &vattr, cred, p))
94247540Skarels 			return (error);
94337741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
94413878Ssam 		break;
94513878Ssam 
94613878Ssam 	case L_SET:
94713878Ssam 		fp->f_offset = uap->off;
94813878Ssam 		break;
94913878Ssam 
95013878Ssam 	default:
95147540Skarels 		return (EINVAL);
95213878Ssam 	}
95354916Storek 	*(off_t *)retval = fp->f_offset;
95447540Skarels 	return (0);
9556254Sroot }
9566254Sroot 
9576254Sroot /*
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 {
113912756Ssam 	struct stat sb;
114037741Smckusick 	int error;
114147540Skarels 	struct nameidata nd;
11425992Swnj 
114352322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
114452322Smckusick 	if (error = namei(&nd))
114547540Skarels 		return (error);
114652322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
114752322Smckusick 	vput(nd.ni_vp);
114837741Smckusick 	if (error)
114947540Skarels 		return (error);
115037741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
115147540Skarels 	return (error);
11525992Swnj }
11535992Swnj 
11545992Swnj /*
115549365Smckusick  * Return target name of a symbolic link.
115637Sbill  */
115754916Storek struct readlink_args {
115854916Storek 	char	*name;
115954916Storek 	char	*buf;
116054916Storek 	int	count;
116154916Storek };
116242441Smckusick /* ARGSUSED */
116342441Smckusick readlink(p, uap, retval)
116445914Smckusick 	struct proc *p;
116554916Storek 	register struct readlink_args *uap;
116642441Smckusick 	int *retval;
116742441Smckusick {
116837741Smckusick 	register struct vnode *vp;
116937741Smckusick 	struct iovec aiov;
117037741Smckusick 	struct uio auio;
117137741Smckusick 	int error;
117247540Skarels 	struct nameidata nd;
11735992Swnj 
117452322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p);
117552322Smckusick 	if (error = namei(&nd))
117647540Skarels 		return (error);
117752322Smckusick 	vp = nd.ni_vp;
117837741Smckusick 	if (vp->v_type != VLNK) {
117937741Smckusick 		error = EINVAL;
11805992Swnj 		goto out;
11815992Swnj 	}
118237741Smckusick 	aiov.iov_base = uap->buf;
118337741Smckusick 	aiov.iov_len = uap->count;
118437741Smckusick 	auio.uio_iov = &aiov;
118537741Smckusick 	auio.uio_iovcnt = 1;
118637741Smckusick 	auio.uio_offset = 0;
118737741Smckusick 	auio.uio_rw = UIO_READ;
118837741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
118948026Smckusick 	auio.uio_procp = p;
119037741Smckusick 	auio.uio_resid = uap->count;
119147540Skarels 	error = VOP_READLINK(vp, &auio, p->p_ucred);
11925992Swnj out:
119337741Smckusick 	vput(vp);
119442441Smckusick 	*retval = uap->count - auio.uio_resid;
119547540Skarels 	return (error);
11965992Swnj }
11975992Swnj 
11989167Ssam /*
119938259Smckusick  * Change flags of a file given path name.
120038259Smckusick  */
120154916Storek struct chflags_args {
120254916Storek 	char	*fname;
120354916Storek 	int	flags;
120454916Storek };
120542441Smckusick /* ARGSUSED */
120642441Smckusick chflags(p, uap, retval)
120745914Smckusick 	struct proc *p;
120854916Storek 	register struct chflags_args *uap;
120942441Smckusick 	int *retval;
121042441Smckusick {
121138259Smckusick 	register struct vnode *vp;
121238259Smckusick 	struct vattr vattr;
121338259Smckusick 	int error;
121447540Skarels 	struct nameidata nd;
121538259Smckusick 
121652322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
121752322Smckusick 	if (error = namei(&nd))
121847540Skarels 		return (error);
121952322Smckusick 	vp = nd.ni_vp;
122041400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
122138259Smckusick 		error = EROFS;
122238259Smckusick 		goto out;
122338259Smckusick 	}
122445785Sbostic 	VATTR_NULL(&vattr);
122545785Sbostic 	vattr.va_flags = uap->flags;
122652192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
122748026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
122838259Smckusick out:
122938259Smckusick 	vput(vp);
123047540Skarels 	return (error);
123138259Smckusick }
123238259Smckusick 
123338259Smckusick /*
123438259Smckusick  * Change flags of a file given a file descriptor.
123538259Smckusick  */
123654916Storek struct fchflags_args {
123754916Storek 	int	fd;
123854916Storek 	int	flags;
123954916Storek };
124042441Smckusick /* ARGSUSED */
124142441Smckusick fchflags(p, uap, retval)
124245914Smckusick 	struct proc *p;
124354916Storek 	register struct fchflags_args *uap;
124442441Smckusick 	int *retval;
124542441Smckusick {
124638259Smckusick 	struct vattr vattr;
124738259Smckusick 	struct vnode *vp;
124838259Smckusick 	struct file *fp;
124938259Smckusick 	int error;
125038259Smckusick 
125145914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
125247540Skarels 		return (error);
125338259Smckusick 	vp = (struct vnode *)fp->f_data;
125438259Smckusick 	VOP_LOCK(vp);
125541400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
125638259Smckusick 		error = EROFS;
125738259Smckusick 		goto out;
125838259Smckusick 	}
125945785Sbostic 	VATTR_NULL(&vattr);
126045785Sbostic 	vattr.va_flags = uap->flags;
126152192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
126248026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
126338259Smckusick out:
126438259Smckusick 	VOP_UNLOCK(vp);
126547540Skarels 	return (error);
126638259Smckusick }
126738259Smckusick 
126838259Smckusick /*
12699167Ssam  * Change mode of a file given path name.
12709167Ssam  */
127154916Storek struct chmod_args {
127254916Storek 	char	*fname;
127354916Storek 	int	fmode;
127454916Storek };
127542441Smckusick /* ARGSUSED */
127642441Smckusick chmod(p, uap, retval)
127745914Smckusick 	struct proc *p;
127854916Storek 	register struct chmod_args *uap;
127942441Smckusick 	int *retval;
128042441Smckusick {
128137741Smckusick 	register struct vnode *vp;
128237741Smckusick 	struct vattr vattr;
128337741Smckusick 	int error;
128447540Skarels 	struct nameidata nd;
12855992Swnj 
128652322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
128752322Smckusick 	if (error = namei(&nd))
128847540Skarels 		return (error);
128952322Smckusick 	vp = nd.ni_vp;
129041400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
129137741Smckusick 		error = EROFS;
129237741Smckusick 		goto out;
129337741Smckusick 	}
129445785Sbostic 	VATTR_NULL(&vattr);
129545785Sbostic 	vattr.va_mode = uap->fmode & 07777;
129652192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
129748026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
129837741Smckusick out:
129937741Smckusick 	vput(vp);
130047540Skarels 	return (error);
13017701Ssam }
13027439Sroot 
13039167Ssam /*
13049167Ssam  * Change mode of a file given a file descriptor.
13059167Ssam  */
130654916Storek struct fchmod_args {
130754916Storek 	int	fd;
130854916Storek 	int	fmode;
130954916Storek };
131042441Smckusick /* ARGSUSED */
131142441Smckusick fchmod(p, uap, retval)
131245914Smckusick 	struct proc *p;
131354916Storek 	register struct fchmod_args *uap;
131442441Smckusick 	int *retval;
131542441Smckusick {
131637741Smckusick 	struct vattr vattr;
131737741Smckusick 	struct vnode *vp;
131837741Smckusick 	struct file *fp;
131937741Smckusick 	int error;
13207701Ssam 
132145914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
132247540Skarels 		return (error);
132337741Smckusick 	vp = (struct vnode *)fp->f_data;
132437741Smckusick 	VOP_LOCK(vp);
132541400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
132637741Smckusick 		error = EROFS;
132737741Smckusick 		goto out;
13287439Sroot 	}
132945785Sbostic 	VATTR_NULL(&vattr);
133045785Sbostic 	vattr.va_mode = uap->fmode & 07777;
133152192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
133248026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
133337741Smckusick out:
133437741Smckusick 	VOP_UNLOCK(vp);
133547540Skarels 	return (error);
13365992Swnj }
13375992Swnj 
13389167Ssam /*
13399167Ssam  * Set ownership given a path name.
13409167Ssam  */
134154916Storek struct chown_args {
134254916Storek 	char	*fname;
134354916Storek 	int	uid;
134454916Storek 	int	gid;
134554916Storek };
134642441Smckusick /* ARGSUSED */
134742441Smckusick chown(p, uap, retval)
134845914Smckusick 	struct proc *p;
134954916Storek 	register struct chown_args *uap;
135042441Smckusick 	int *retval;
135142441Smckusick {
135237741Smckusick 	register struct vnode *vp;
135337741Smckusick 	struct vattr vattr;
135437741Smckusick 	int error;
135547540Skarels 	struct nameidata nd;
135637Sbill 
135752322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
135852322Smckusick 	if (error = namei(&nd))
135947540Skarels 		return (error);
136052322Smckusick 	vp = nd.ni_vp;
136141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
136237741Smckusick 		error = EROFS;
136337741Smckusick 		goto out;
136437741Smckusick 	}
136545785Sbostic 	VATTR_NULL(&vattr);
136645785Sbostic 	vattr.va_uid = uap->uid;
136745785Sbostic 	vattr.va_gid = uap->gid;
136852192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
136948026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
137037741Smckusick out:
137137741Smckusick 	vput(vp);
137247540Skarels 	return (error);
13737701Ssam }
13747439Sroot 
13759167Ssam /*
13769167Ssam  * Set ownership given a file descriptor.
13779167Ssam  */
137854916Storek struct fchown_args {
137954916Storek 	int	fd;
138054916Storek 	int	uid;
138154916Storek 	int	gid;
138254916Storek };
138342441Smckusick /* ARGSUSED */
138442441Smckusick fchown(p, uap, retval)
138545914Smckusick 	struct proc *p;
138654916Storek 	register struct fchown_args *uap;
138742441Smckusick 	int *retval;
138842441Smckusick {
138937741Smckusick 	struct vattr vattr;
139037741Smckusick 	struct vnode *vp;
139137741Smckusick 	struct file *fp;
139237741Smckusick 	int error;
13937701Ssam 
139445914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
139547540Skarels 		return (error);
139637741Smckusick 	vp = (struct vnode *)fp->f_data;
139737741Smckusick 	VOP_LOCK(vp);
139841400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
139937741Smckusick 		error = EROFS;
140037741Smckusick 		goto out;
140137741Smckusick 	}
140245785Sbostic 	VATTR_NULL(&vattr);
140345785Sbostic 	vattr.va_uid = uap->uid;
140445785Sbostic 	vattr.va_gid = uap->gid;
140552192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
140648026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
140737741Smckusick out:
140837741Smckusick 	VOP_UNLOCK(vp);
140947540Skarels 	return (error);
14107701Ssam }
14117701Ssam 
141242441Smckusick /*
141342441Smckusick  * Set the access and modification times of a file.
141442441Smckusick  */
141554916Storek struct utimes_args {
141654916Storek 	char	*fname;
141754916Storek 	struct	timeval *tptr;
141854916Storek };
141942441Smckusick /* ARGSUSED */
142042441Smckusick utimes(p, uap, retval)
142145914Smckusick 	struct proc *p;
142254916Storek 	register struct utimes_args *uap;
142342441Smckusick 	int *retval;
142442441Smckusick {
142537741Smckusick 	register struct vnode *vp;
142611811Ssam 	struct timeval tv[2];
142737741Smckusick 	struct vattr vattr;
142837741Smckusick 	int error;
142947540Skarels 	struct nameidata nd;
143011811Ssam 
143137741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
143247540Skarels 		return (error);
143352322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
143452322Smckusick 	if (error = namei(&nd))
143547540Skarels 		return (error);
143652322Smckusick 	vp = nd.ni_vp;
143741400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
143837741Smckusick 		error = EROFS;
143937741Smckusick 		goto out;
144021015Smckusick 	}
144145785Sbostic 	VATTR_NULL(&vattr);
144254100Smckusick 	vattr.va_atime.ts_sec = tv[0].tv_sec;
144354100Smckusick 	vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
144454100Smckusick 	vattr.va_mtime.ts_sec = tv[1].tv_sec;
144554100Smckusick 	vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
144652192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
144748026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
144837741Smckusick out:
144937741Smckusick 	vput(vp);
145047540Skarels 	return (error);
145111811Ssam }
145211811Ssam 
145354916Storek struct __truncate_args {
145454863Storek 	char	*fname;
145554863Storek 	int	pad;
145654863Storek 	off_t	length;
145754863Storek };
145853468Smckusick 
145953468Smckusick /*
146053468Smckusick  * Truncate a file given its path name.
146153468Smckusick  */
146253468Smckusick /* ARGSUSED */
146353759Smckusick __truncate(p, uap, retval)
146453468Smckusick 	struct proc *p;
146554916Storek 	register struct __truncate_args *uap;
146653468Smckusick 	int *retval;
146753468Smckusick {
146837741Smckusick 	register struct vnode *vp;
146937741Smckusick 	struct vattr vattr;
147037741Smckusick 	int error;
147147540Skarels 	struct nameidata nd;
14727701Ssam 
147352322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
147452322Smckusick 	if (error = namei(&nd))
147547540Skarels 		return (error);
147652322Smckusick 	vp = nd.ni_vp;
147737741Smckusick 	if (vp->v_type == VDIR) {
147837741Smckusick 		error = EISDIR;
147937741Smckusick 		goto out;
14807701Ssam 	}
148138399Smckusick 	if ((error = vn_writechk(vp)) ||
148248026Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)))
148337741Smckusick 		goto out;
148445785Sbostic 	VATTR_NULL(&vattr);
148545785Sbostic 	vattr.va_size = uap->length;
148652192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
148748026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
148837741Smckusick out:
148937741Smckusick 	vput(vp);
149047540Skarels 	return (error);
14917701Ssam }
14927701Ssam 
149354916Storek struct __ftruncate_args {
149454863Storek 	int	fd;
149554863Storek 	int	pad;
149654863Storek 	off_t	length;
149754863Storek };
149854863Storek 
14999167Ssam /*
15009167Ssam  * Truncate a file given a file descriptor.
15019167Ssam  */
150242441Smckusick /* ARGSUSED */
150353759Smckusick __ftruncate(p, uap, retval)
150445914Smckusick 	struct proc *p;
150554916Storek 	register struct __ftruncate_args *uap;
150642441Smckusick 	int *retval;
150742441Smckusick {
150837741Smckusick 	struct vattr vattr;
150937741Smckusick 	struct vnode *vp;
15107701Ssam 	struct file *fp;
151137741Smckusick 	int error;
15127701Ssam 
151345914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
151447540Skarels 		return (error);
151537741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
151647540Skarels 		return (EINVAL);
151737741Smckusick 	vp = (struct vnode *)fp->f_data;
151837741Smckusick 	VOP_LOCK(vp);
151937741Smckusick 	if (vp->v_type == VDIR) {
152037741Smckusick 		error = EISDIR;
152137741Smckusick 		goto out;
15227701Ssam 	}
152338399Smckusick 	if (error = vn_writechk(vp))
152437741Smckusick 		goto out;
152545785Sbostic 	VATTR_NULL(&vattr);
152645785Sbostic 	vattr.va_size = uap->length;
152752192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
152848026Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
152937741Smckusick out:
153037741Smckusick 	VOP_UNLOCK(vp);
153147540Skarels 	return (error);
15327701Ssam }
15337701Ssam 
153454863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
15359167Ssam /*
153654863Storek  * Truncate a file given its path name.
153754863Storek  */
153854916Storek struct truncate_args {
153954916Storek 	char	*fname;
154054916Storek 	long	length;
154154916Storek };
154254863Storek /* ARGSUSED */
154354863Storek truncate(p, uap, retval)
154454863Storek 	struct proc *p;
154554916Storek 	register struct truncate_args *uap;
154654863Storek 	int *retval;
154754863Storek {
154854916Storek 	struct __truncate_args nuap;
154954863Storek 
155054863Storek 	nuap.fname = uap->fname;
155154863Storek 	nuap.length = uap->length;
155254863Storek 	return (__truncate(p, &nuap, retval));
155354863Storek }
155454863Storek 
155554863Storek /*
155654863Storek  * Truncate a file given a file descriptor.
155754863Storek  */
155854916Storek struct ftruncate_args {
155954916Storek 	int	fd;
156054916Storek 	long	length;
156154916Storek };
156254863Storek /* ARGSUSED */
156354863Storek ftruncate(p, uap, retval)
156454863Storek 	struct proc *p;
156554916Storek 	register struct ftruncate_args *uap;
156654863Storek 	int *retval;
156754863Storek {
156854969Smckusick 	struct __ftruncate_args nuap;
156954863Storek 
157054863Storek 	nuap.fd = uap->fd;
157154863Storek 	nuap.length = uap->length;
157254863Storek 	return (__ftruncate(p, &nuap, retval));
157354863Storek }
157454863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */
157554863Storek 
157654863Storek /*
15779167Ssam  * Synch an open file.
15789167Ssam  */
157954916Storek struct fsync_args {
158054916Storek 	int	fd;
158154916Storek };
158242441Smckusick /* ARGSUSED */
158342441Smckusick fsync(p, uap, retval)
158445914Smckusick 	struct proc *p;
158554916Storek 	struct fsync_args *uap;
158642441Smckusick 	int *retval;
15879167Ssam {
158839592Smckusick 	register struct vnode *vp;
15899167Ssam 	struct file *fp;
159037741Smckusick 	int error;
15919167Ssam 
159245914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
159347540Skarels 		return (error);
159439592Smckusick 	vp = (struct vnode *)fp->f_data;
159539592Smckusick 	VOP_LOCK(vp);
159654441Smckusick 	error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
159739592Smckusick 	VOP_UNLOCK(vp);
159847540Skarels 	return (error);
15999167Ssam }
16009167Ssam 
16019167Ssam /*
16029167Ssam  * Rename system call.
16039167Ssam  *
16049167Ssam  * Source and destination must either both be directories, or both
16059167Ssam  * not be directories.  If target is a directory, it must be empty.
16069167Ssam  */
160754916Storek struct rename_args {
160854916Storek 	char	*from;
160954916Storek 	char	*to;
161054916Storek };
161142441Smckusick /* ARGSUSED */
161242441Smckusick rename(p, uap, retval)
161345914Smckusick 	struct proc *p;
161454916Storek 	register struct rename_args *uap;
161542441Smckusick 	int *retval;
161642441Smckusick {
161737741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
161849735Smckusick 	struct nameidata fromnd, tond;
161937741Smckusick 	int error;
16207701Ssam 
162152322Smckusick 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
162252322Smckusick 		uap->from, p);
162352322Smckusick 	if (error = namei(&fromnd))
162447540Skarels 		return (error);
162549735Smckusick 	fvp = fromnd.ni_vp;
162652322Smckusick 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
162752322Smckusick 		UIO_USERSPACE, uap->to, p);
162852322Smckusick 	if (error = namei(&tond)) {
162952230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
163049735Smckusick 		vrele(fromnd.ni_dvp);
163142465Smckusick 		vrele(fvp);
163242465Smckusick 		goto out1;
163342465Smckusick 	}
163437741Smckusick 	tdvp = tond.ni_dvp;
163537741Smckusick 	tvp = tond.ni_vp;
163637741Smckusick 	if (tvp != NULL) {
163737741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
163839242Sbostic 			error = ENOTDIR;
163937741Smckusick 			goto out;
164037741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
164139242Sbostic 			error = EISDIR;
164237741Smckusick 			goto out;
16439167Ssam 		}
16449167Ssam 	}
164539286Smckusick 	if (fvp == tdvp)
164637741Smckusick 		error = EINVAL;
164739286Smckusick 	/*
164849735Smckusick 	 * If source is the same as the destination (that is the
164949735Smckusick 	 * same inode number with the same name in the same directory),
165039286Smckusick 	 * then there is nothing to do.
165139286Smckusick 	 */
165249735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
165352322Smckusick 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
165452322Smckusick 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
165552322Smckusick 	      fromnd.ni_cnd.cn_namelen))
165639286Smckusick 		error = -1;
165737741Smckusick out:
165842465Smckusick 	if (!error) {
165952192Smckusick 		LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE);
166052192Smckusick 		if (fromnd.ni_dvp != tdvp)
166152192Smckusick 			LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
166252192Smckusick 		if (tvp)
166352192Smckusick 			LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE);
166452230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
166552230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
166642465Smckusick 	} else {
166752230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
166843344Smckusick 		if (tdvp == tvp)
166943344Smckusick 			vrele(tdvp);
167043344Smckusick 		else
167143344Smckusick 			vput(tdvp);
167242465Smckusick 		if (tvp)
167342465Smckusick 			vput(tvp);
167452230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
167549735Smckusick 		vrele(fromnd.ni_dvp);
167642465Smckusick 		vrele(fvp);
16779167Ssam 	}
167849735Smckusick 	vrele(tond.ni_startdir);
167952322Smckusick 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
168037741Smckusick out1:
168149735Smckusick 	vrele(fromnd.ni_startdir);
168252322Smckusick 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
168339286Smckusick 	if (error == -1)
168447540Skarels 		return (0);
168547540Skarels 	return (error);
16867701Ssam }
16877701Ssam 
16887535Sroot /*
168949365Smckusick  * Mkdir system call.
169012756Ssam  */
169154916Storek struct mkdir_args {
169254916Storek 	char	*name;
169354916Storek 	int	dmode;
169454916Storek };
169542441Smckusick /* ARGSUSED */
169642441Smckusick mkdir(p, uap, retval)
169745914Smckusick 	struct proc *p;
169854916Storek 	register struct mkdir_args *uap;
169942441Smckusick 	int *retval;
170042441Smckusick {
170137741Smckusick 	register struct vnode *vp;
170237741Smckusick 	struct vattr vattr;
170337741Smckusick 	int error;
170447540Skarels 	struct nameidata nd;
170512756Ssam 
170652322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p);
170752322Smckusick 	if (error = namei(&nd))
170847540Skarels 		return (error);
170952322Smckusick 	vp = nd.ni_vp;
171037741Smckusick 	if (vp != NULL) {
171152322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
171252322Smckusick 		if (nd.ni_dvp == vp)
171352322Smckusick 			vrele(nd.ni_dvp);
171443344Smckusick 		else
171552322Smckusick 			vput(nd.ni_dvp);
171642465Smckusick 		vrele(vp);
171747540Skarels 		return (EEXIST);
171812756Ssam 	}
171941362Smckusick 	VATTR_NULL(&vattr);
172037741Smckusick 	vattr.va_type = VDIR;
172145914Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask;
172252322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
172352322Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
172438145Smckusick 	if (!error)
172552322Smckusick 		vput(nd.ni_vp);
172647540Skarels 	return (error);
172712756Ssam }
172812756Ssam 
172912756Ssam /*
173012756Ssam  * Rmdir system call.
173112756Ssam  */
173254916Storek struct rmdir_args {
173354916Storek 	char	*name;
173454916Storek };
173542441Smckusick /* ARGSUSED */
173642441Smckusick rmdir(p, uap, retval)
173745914Smckusick 	struct proc *p;
173854916Storek 	struct rmdir_args *uap;
173942441Smckusick 	int *retval;
174012756Ssam {
174137741Smckusick 	register struct vnode *vp;
174237741Smckusick 	int error;
174347540Skarels 	struct nameidata nd;
174412756Ssam 
174552322Smckusick 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p);
174652322Smckusick 	if (error = namei(&nd))
174747540Skarels 		return (error);
174852322Smckusick 	vp = nd.ni_vp;
174937741Smckusick 	if (vp->v_type != VDIR) {
175037741Smckusick 		error = ENOTDIR;
175112756Ssam 		goto out;
175212756Ssam 	}
175312756Ssam 	/*
175437741Smckusick 	 * No rmdir "." please.
175512756Ssam 	 */
175652322Smckusick 	if (nd.ni_dvp == vp) {
175737741Smckusick 		error = EINVAL;
175812756Ssam 		goto out;
175912756Ssam 	}
176012756Ssam 	/*
176149365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
176212756Ssam 	 */
176337741Smckusick 	if (vp->v_flag & VROOT)
176437741Smckusick 		error = EBUSY;
176512756Ssam out:
176642465Smckusick 	if (!error) {
176752322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
176852192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
176952322Smckusick 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
177042465Smckusick 	} else {
177152322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
177252322Smckusick 		if (nd.ni_dvp == vp)
177352322Smckusick 			vrele(nd.ni_dvp);
177443344Smckusick 		else
177552322Smckusick 			vput(nd.ni_dvp);
177642465Smckusick 		vput(vp);
177742465Smckusick 	}
177847540Skarels 	return (error);
177912756Ssam }
178012756Ssam 
178154620Smckusick #ifdef COMPAT_43
178237741Smckusick /*
178349365Smckusick  * Read a block of directory entries in a file system independent format.
178437741Smckusick  */
178554916Storek struct ogetdirentries_args {
178654916Storek 	int	fd;
178754916Storek 	char	*buf;
178854916Storek 	unsigned count;
178954916Storek 	long	*basep;
179054916Storek };
179154620Smckusick ogetdirentries(p, uap, retval)
179254620Smckusick 	struct proc *p;
179354916Storek 	register struct ogetdirentries_args *uap;
179454620Smckusick 	int *retval;
179554620Smckusick {
179654620Smckusick 	register struct vnode *vp;
179754620Smckusick 	struct file *fp;
179854620Smckusick 	struct uio auio, kuio;
179954620Smckusick 	struct iovec aiov, kiov;
180054620Smckusick 	struct dirent *dp, *edp;
180154620Smckusick 	caddr_t dirbuf;
180254620Smckusick 	int error, readcnt;
180354969Smckusick 	long loff;
180454620Smckusick 
180554620Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
180654620Smckusick 		return (error);
180754620Smckusick 	if ((fp->f_flag & FREAD) == 0)
180854620Smckusick 		return (EBADF);
180954620Smckusick 	vp = (struct vnode *)fp->f_data;
181054620Smckusick 	if (vp->v_type != VDIR)
181154620Smckusick 		return (EINVAL);
181254620Smckusick 	aiov.iov_base = uap->buf;
181354620Smckusick 	aiov.iov_len = uap->count;
181454620Smckusick 	auio.uio_iov = &aiov;
181554620Smckusick 	auio.uio_iovcnt = 1;
181654620Smckusick 	auio.uio_rw = UIO_READ;
181754620Smckusick 	auio.uio_segflg = UIO_USERSPACE;
181854620Smckusick 	auio.uio_procp = p;
181954620Smckusick 	auio.uio_resid = uap->count;
182054620Smckusick 	VOP_LOCK(vp);
182154969Smckusick 	loff = auio.uio_offset = fp->f_offset;
182254620Smckusick #	if (BYTE_ORDER != LITTLE_ENDIAN)
182354620Smckusick 		if (vp->v_mount->mnt_maxsymlinklen <= 0)
182454620Smckusick 			error = VOP_READDIR(vp, &auio, fp->f_cred);
182554620Smckusick 		else
182654620Smckusick #	endif
182754620Smckusick 	{
182854620Smckusick 		kuio = auio;
182954620Smckusick 		kuio.uio_iov = &kiov;
183054620Smckusick 		kuio.uio_segflg = UIO_SYSSPACE;
183154620Smckusick 		kiov.iov_len = uap->count;
183254620Smckusick 		MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK);
183354620Smckusick 		kiov.iov_base = dirbuf;
183454620Smckusick 		error = VOP_READDIR(vp, &kuio, fp->f_cred);
183554620Smckusick 		if (error == 0) {
183654620Smckusick 			readcnt = uap->count - kuio.uio_resid;
183754620Smckusick 			edp = (struct dirent *)&dirbuf[readcnt];
183854620Smckusick 			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
183954620Smckusick #				if (BYTE_ORDER == LITTLE_ENDIAN)
184054969Smckusick 					/*
184155009Smckusick 					 * The expected low byte of
184255009Smckusick 					 * dp->d_namlen is our dp->d_type.
184355009Smckusick 					 * The high MBZ byte of dp->d_namlen
184455009Smckusick 					 * is our dp->d_namlen.
184554969Smckusick 					 */
184655009Smckusick 					dp->d_type = dp->d_namlen;
184755009Smckusick 					dp->d_namlen = 0;
184855009Smckusick #				else
184955009Smckusick 					/*
185055009Smckusick 					 * The dp->d_type is the high byte
185155009Smckusick 					 * of the expected dp->d_namlen,
185255009Smckusick 					 * so must be zero'ed.
185355009Smckusick 					 */
185455009Smckusick 					dp->d_type = 0;
185554620Smckusick #				endif
185654620Smckusick 				if (dp->d_reclen > 0) {
185754620Smckusick 					dp = (struct dirent *)
185854620Smckusick 					    ((char *)dp + dp->d_reclen);
185954620Smckusick 				} else {
186054620Smckusick 					error = EIO;
186154620Smckusick 					break;
186254620Smckusick 				}
186354620Smckusick 			}
186454620Smckusick 			if (dp >= edp)
186554620Smckusick 				error = uiomove(dirbuf, readcnt, &auio);
186654620Smckusick 		}
186754620Smckusick 		FREE(dirbuf, M_TEMP);
186854620Smckusick 	}
186954620Smckusick 	fp->f_offset = auio.uio_offset;
187054620Smckusick 	VOP_UNLOCK(vp);
187154620Smckusick 	if (error)
187254620Smckusick 		return (error);
187354969Smckusick 	error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
187454620Smckusick 	*retval = uap->count - auio.uio_resid;
187554620Smckusick 	return (error);
187654620Smckusick }
187754620Smckusick #endif
187854620Smckusick 
187954620Smckusick /*
188054620Smckusick  * Read a block of directory entries in a file system independent format.
188154620Smckusick  */
188254916Storek struct getdirentries_args {
188354916Storek 	int	fd;
188454916Storek 	char	*buf;
188554916Storek 	unsigned count;
188654916Storek 	long	*basep;
188754916Storek };
188842441Smckusick getdirentries(p, uap, retval)
188945914Smckusick 	struct proc *p;
189054916Storek 	register struct getdirentries_args *uap;
189142441Smckusick 	int *retval;
189242441Smckusick {
189339592Smckusick 	register struct vnode *vp;
189416540Ssam 	struct file *fp;
189537741Smckusick 	struct uio auio;
189637741Smckusick 	struct iovec aiov;
189754969Smckusick 	long loff;
189854441Smckusick 	int error;
189912756Ssam 
190045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
190147540Skarels 		return (error);
190237741Smckusick 	if ((fp->f_flag & FREAD) == 0)
190347540Skarels 		return (EBADF);
190439592Smckusick 	vp = (struct vnode *)fp->f_data;
1905*55451Spendry unionread:
190639592Smckusick 	if (vp->v_type != VDIR)
190747540Skarels 		return (EINVAL);
190837741Smckusick 	aiov.iov_base = uap->buf;
190937741Smckusick 	aiov.iov_len = uap->count;
191037741Smckusick 	auio.uio_iov = &aiov;
191137741Smckusick 	auio.uio_iovcnt = 1;
191237741Smckusick 	auio.uio_rw = UIO_READ;
191337741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
191448026Smckusick 	auio.uio_procp = p;
191537741Smckusick 	auio.uio_resid = uap->count;
191639592Smckusick 	VOP_LOCK(vp);
191754969Smckusick 	loff = auio.uio_offset = fp->f_offset;
191854441Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred);
191939592Smckusick 	fp->f_offset = auio.uio_offset;
192039592Smckusick 	VOP_UNLOCK(vp);
192139592Smckusick 	if (error)
192247540Skarels 		return (error);
1923*55451Spendry 	if ((uap->count == auio.uio_resid) &&
1924*55451Spendry 	    (vp->v_flag & VROOT) &&
1925*55451Spendry 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
1926*55451Spendry 		struct vnode *tvp = vp;
1927*55451Spendry 		vp = vp->v_mount->mnt_vnodecovered;
1928*55451Spendry 		VREF(vp);
1929*55451Spendry 		fp->f_data = (caddr_t) vp;
1930*55451Spendry 		fp->f_offset = 0;
1931*55451Spendry 		vrele(tvp);
1932*55451Spendry 		goto unionread;
1933*55451Spendry 	}
193454969Smckusick 	error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
193542441Smckusick 	*retval = uap->count - auio.uio_resid;
193647540Skarels 	return (error);
193712756Ssam }
193812756Ssam 
193912756Ssam /*
194049365Smckusick  * Set the mode mask for creation of filesystem nodes.
194112756Ssam  */
194254916Storek struct umask_args {
194354916Storek 	int	mask;
194454916Storek };
194554916Storek mode_t				/* XXX */
194642441Smckusick umask(p, uap, retval)
194745914Smckusick 	struct proc *p;
194854916Storek 	struct umask_args *uap;
194942441Smckusick 	int *retval;
195012756Ssam {
195145914Smckusick 	register struct filedesc *fdp = p->p_fd;
195212756Ssam 
195345914Smckusick 	*retval = fdp->fd_cmask;
195445914Smckusick 	fdp->fd_cmask = uap->mask & 07777;
195547540Skarels 	return (0);
195612756Ssam }
195737741Smckusick 
195839566Smarc /*
195939566Smarc  * Void all references to file by ripping underlying filesystem
196039566Smarc  * away from vnode.
196139566Smarc  */
196254916Storek struct revoke_args {
196354916Storek 	char	*fname;
196454916Storek };
196542441Smckusick /* ARGSUSED */
196642441Smckusick revoke(p, uap, retval)
196745914Smckusick 	struct proc *p;
196854916Storek 	register struct revoke_args *uap;
196942441Smckusick 	int *retval;
197042441Smckusick {
197139566Smarc 	register struct vnode *vp;
197239566Smarc 	struct vattr vattr;
197339566Smarc 	int error;
197447540Skarels 	struct nameidata nd;
197539566Smarc 
197652322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
197752322Smckusick 	if (error = namei(&nd))
197847540Skarels 		return (error);
197952322Smckusick 	vp = nd.ni_vp;
198039566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
198139566Smarc 		error = EINVAL;
198239566Smarc 		goto out;
198339566Smarc 	}
198448026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
198539566Smarc 		goto out;
198647540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
198747540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
198839566Smarc 		goto out;
198939805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
199039632Smckusick 		vgoneall(vp);
199139566Smarc out:
199239566Smarc 	vrele(vp);
199347540Skarels 	return (error);
199439566Smarc }
199539566Smarc 
199649365Smckusick /*
199749365Smckusick  * Convert a user file descriptor to a kernel file entry.
199849365Smckusick  */
199945914Smckusick getvnode(fdp, fdes, fpp)
200045914Smckusick 	struct filedesc *fdp;
200137741Smckusick 	struct file **fpp;
200237741Smckusick 	int fdes;
200337741Smckusick {
200437741Smckusick 	struct file *fp;
200537741Smckusick 
200647540Skarels 	if ((unsigned)fdes >= fdp->fd_nfiles ||
200747688Skarels 	    (fp = fdp->fd_ofiles[fdes]) == NULL)
200837741Smckusick 		return (EBADF);
200937741Smckusick 	if (fp->f_type != DTYPE_VNODE)
201037741Smckusick 		return (EINVAL);
201137741Smckusick 	*fpp = fp;
201237741Smckusick 	return (0);
201337741Smckusick }
2014