xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 55009)
123405Smckusick /*
237741Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337741Smckusick  * All rights reserved.
423405Smckusick  *
544459Sbostic  * %sccs.include.redist.c%
637741Smckusick  *
7*55009Smckusick  *	@(#)vfs_syscalls.c	7.95 (Berkeley) 07/12/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 	}
8139805Smckusick 	if (vp->v_usecount != 1) {
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;
14139335Smckusick 	/*
14239335Smckusick 	 * Mount the filesystem.
14339335Smckusick 	 */
14452322Smckusick 	error = VFS_MOUNT(mp, uap->dir, uap->data, &nd, p);
14541400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
14641400Smckusick 		mp->mnt_flag &= ~MNT_UPDATE;
14739335Smckusick 		vrele(vp);
14840111Smckusick 		if (error)
14941400Smckusick 			mp->mnt_flag = flag;
15047540Skarels 		return (error);
15139335Smckusick 	}
15240110Smckusick 	/*
15340110Smckusick 	 * Put the new filesystem on the mount list after root.
15440110Smckusick 	 */
15541400Smckusick 	mp->mnt_next = rootfs->mnt_next;
15641400Smckusick 	mp->mnt_prev = rootfs;
15741400Smckusick 	rootfs->mnt_next = mp;
15841400Smckusick 	mp->mnt_next->mnt_prev = mp;
15937741Smckusick 	cache_purge(vp);
16037741Smckusick 	if (!error) {
16139335Smckusick 		VOP_UNLOCK(vp);
16237741Smckusick 		vfs_unlock(mp);
16348026Smckusick 		error = VFS_START(mp, 0, p);
16437741Smckusick 	} else {
16537741Smckusick 		vfs_remove(mp);
16637741Smckusick 		free((caddr_t)mp, M_MOUNT);
16739335Smckusick 		vput(vp);
16837741Smckusick 	}
16947540Skarels 	return (error);
1706254Sroot }
1716254Sroot 
1729167Ssam /*
17337741Smckusick  * Unmount system call.
17437741Smckusick  *
17537741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
17637741Smckusick  * not special file (as before).
1779167Ssam  */
17854916Storek struct unmount_args {
17954916Storek 	char	*pathp;
18054916Storek 	int	flags;
18154916Storek };
18242441Smckusick /* ARGSUSED */
18342441Smckusick unmount(p, uap, retval)
18445914Smckusick 	struct proc *p;
18554916Storek 	register struct unmount_args *uap;
18642441Smckusick 	int *retval;
18742441Smckusick {
18837741Smckusick 	register struct vnode *vp;
18939356Smckusick 	struct mount *mp;
19037741Smckusick 	int error;
19147540Skarels 	struct nameidata nd;
1926254Sroot 
19337741Smckusick 	/*
19437741Smckusick 	 * Must be super user
19537741Smckusick 	 */
19647540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
19747540Skarels 		return (error);
19837741Smckusick 
19952322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->pathp, p);
20052322Smckusick 	if (error = namei(&nd))
20147540Skarels 		return (error);
20252322Smckusick 	vp = nd.ni_vp;
20337741Smckusick 	/*
20437741Smckusick 	 * Must be the root of the filesystem
20537741Smckusick 	 */
20637741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
20737741Smckusick 		vput(vp);
20847540Skarels 		return (EINVAL);
20937741Smckusick 	}
21037741Smckusick 	mp = vp->v_mount;
21137741Smckusick 	vput(vp);
21248026Smckusick 	return (dounmount(mp, uap->flags, p));
21339356Smckusick }
21439356Smckusick 
21539356Smckusick /*
21639356Smckusick  * Do an unmount.
21739356Smckusick  */
21848026Smckusick dounmount(mp, flags, p)
21939356Smckusick 	register struct mount *mp;
22039356Smckusick 	int flags;
22148026Smckusick 	struct proc *p;
22239356Smckusick {
22339356Smckusick 	struct vnode *coveredvp;
22439356Smckusick 	int error;
22539356Smckusick 
22641400Smckusick 	coveredvp = mp->mnt_vnodecovered;
22741298Smckusick 	if (vfs_busy(mp))
22841298Smckusick 		return (EBUSY);
22941400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
23037741Smckusick 	if (error = vfs_lock(mp))
23139356Smckusick 		return (error);
23237741Smckusick 
23345738Smckusick 	vnode_pager_umount(mp);	/* release cached vnodes */
23437741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
23554441Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 ||
23654441Smckusick 	    (flags & MNT_FORCE))
23748026Smckusick 		error = VFS_UNMOUNT(mp, flags, p);
23841400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
23941298Smckusick 	vfs_unbusy(mp);
24037741Smckusick 	if (error) {
24137741Smckusick 		vfs_unlock(mp);
24237741Smckusick 	} else {
24337741Smckusick 		vrele(coveredvp);
24437741Smckusick 		vfs_remove(mp);
24552287Smckusick 		if (mp->mnt_mounth != NULL)
24652287Smckusick 			panic("unmount: dangling vnode");
24737741Smckusick 		free((caddr_t)mp, M_MOUNT);
24837741Smckusick 	}
24939356Smckusick 	return (error);
2506254Sroot }
2516254Sroot 
2529167Ssam /*
25337741Smckusick  * Sync system call.
25437741Smckusick  * Sync each mounted filesystem.
2559167Ssam  */
25654916Storek struct sync_args {
25754916Storek 	int	dummy;
25854916Storek };
25939491Smckusick /* ARGSUSED */
26042441Smckusick sync(p, uap, retval)
26145914Smckusick 	struct proc *p;
26254916Storek 	struct sync_args *uap;
26342441Smckusick 	int *retval;
2646254Sroot {
26537741Smckusick 	register struct mount *mp;
26641298Smckusick 	struct mount *omp;
26737741Smckusick 
26837741Smckusick 	mp = rootfs;
26937741Smckusick 	do {
27040343Smckusick 		/*
27140343Smckusick 		 * The lock check below is to avoid races with mount
27240343Smckusick 		 * and unmount.
27340343Smckusick 		 */
27441400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
27541298Smckusick 		    !vfs_busy(mp)) {
27654441Smckusick 			VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
27741298Smckusick 			omp = mp;
27841400Smckusick 			mp = mp->mnt_next;
27941298Smckusick 			vfs_unbusy(omp);
28041298Smckusick 		} else
28141400Smckusick 			mp = mp->mnt_next;
28237741Smckusick 	} while (mp != rootfs);
28347688Skarels 	return (0);
28437741Smckusick }
28537741Smckusick 
28637741Smckusick /*
28749365Smckusick  * Operate on filesystem quotas.
28841298Smckusick  */
28954916Storek struct quotactl_args {
29054916Storek 	char *path;
29154916Storek 	int cmd;
29254916Storek 	int uid;
29354916Storek 	caddr_t arg;
29454916Storek };
29542441Smckusick /* ARGSUSED */
29642441Smckusick quotactl(p, uap, retval)
29745914Smckusick 	struct proc *p;
29854916Storek 	register struct quotactl_args *uap;
29942441Smckusick 	int *retval;
30042441Smckusick {
30141298Smckusick 	register struct mount *mp;
30241298Smckusick 	int error;
30347540Skarels 	struct nameidata nd;
30441298Smckusick 
30552322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
30652322Smckusick 	if (error = namei(&nd))
30747540Skarels 		return (error);
30852322Smckusick 	mp = nd.ni_vp->v_mount;
30952322Smckusick 	vrele(nd.ni_vp);
31048026Smckusick 	return (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, p));
31141298Smckusick }
31241298Smckusick 
31341298Smckusick /*
31449365Smckusick  * Get filesystem statistics.
31537741Smckusick  */
31654916Storek struct statfs_args {
31754916Storek 	char *path;
31854916Storek 	struct statfs *buf;
31954916Storek };
32042441Smckusick /* ARGSUSED */
32142441Smckusick statfs(p, uap, retval)
32245914Smckusick 	struct proc *p;
32354916Storek 	register struct statfs_args *uap;
32442441Smckusick 	int *retval;
32542441Smckusick {
32639464Smckusick 	register struct mount *mp;
32740343Smckusick 	register struct statfs *sp;
32837741Smckusick 	int error;
32947540Skarels 	struct nameidata nd;
33037741Smckusick 
33152322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p);
33252322Smckusick 	if (error = namei(&nd))
33347540Skarels 		return (error);
33452322Smckusick 	mp = nd.ni_vp->v_mount;
33541400Smckusick 	sp = &mp->mnt_stat;
33652322Smckusick 	vrele(nd.ni_vp);
33748026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
33847540Skarels 		return (error);
33941400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
34047540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
34137741Smckusick }
34237741Smckusick 
34342441Smckusick /*
34449365Smckusick  * Get filesystem statistics.
34542441Smckusick  */
34654916Storek struct fstatfs_args {
34754916Storek 	int fd;
34854916Storek 	struct statfs *buf;
34954916Storek };
35042441Smckusick /* ARGSUSED */
35142441Smckusick fstatfs(p, uap, retval)
35245914Smckusick 	struct proc *p;
35354916Storek 	register struct fstatfs_args *uap;
35442441Smckusick 	int *retval;
35542441Smckusick {
35637741Smckusick 	struct file *fp;
35739464Smckusick 	struct mount *mp;
35840343Smckusick 	register struct statfs *sp;
35937741Smckusick 	int error;
36037741Smckusick 
36145914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
36247540Skarels 		return (error);
36339464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
36441400Smckusick 	sp = &mp->mnt_stat;
36548026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
36647540Skarels 		return (error);
36741400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
36847540Skarels 	return (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
36937741Smckusick }
37037741Smckusick 
37137741Smckusick /*
37249365Smckusick  * Get statistics on all filesystems.
37338270Smckusick  */
37454916Storek struct getfsstat_args {
37554916Storek 	struct statfs *buf;
37654916Storek 	long bufsize;
37754916Storek 	int flags;
37854916Storek };
37942441Smckusick getfsstat(p, uap, retval)
38045914Smckusick 	struct proc *p;
38154916Storek 	register struct getfsstat_args *uap;
38242441Smckusick 	int *retval;
38342441Smckusick {
38438270Smckusick 	register struct mount *mp;
38540343Smckusick 	register struct statfs *sp;
38639606Smckusick 	caddr_t sfsp;
38738270Smckusick 	long count, maxcount, error;
38838270Smckusick 
38938270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
39039606Smckusick 	sfsp = (caddr_t)uap->buf;
39138270Smckusick 	mp = rootfs;
39238270Smckusick 	count = 0;
39338270Smckusick 	do {
39441400Smckusick 		if (sfsp && count < maxcount &&
39541400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
39641400Smckusick 			sp = &mp->mnt_stat;
39740343Smckusick 			/*
39840343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
39940343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
40040343Smckusick 			 */
40140343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
40240343Smckusick 			    (uap->flags & MNT_WAIT)) &&
40348026Smckusick 			    (error = VFS_STATFS(mp, sp, p))) {
40441400Smckusick 				mp = mp->mnt_prev;
40539607Smckusick 				continue;
40639607Smckusick 			}
40741400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
40840343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
40947540Skarels 				return (error);
41040343Smckusick 			sfsp += sizeof(*sp);
41138270Smckusick 		}
41239606Smckusick 		count++;
41341400Smckusick 		mp = mp->mnt_prev;
41438270Smckusick 	} while (mp != rootfs);
41538270Smckusick 	if (sfsp && count > maxcount)
41642441Smckusick 		*retval = maxcount;
41738270Smckusick 	else
41842441Smckusick 		*retval = count;
41947540Skarels 	return (0);
42038270Smckusick }
42138270Smckusick 
42238270Smckusick /*
42338259Smckusick  * Change current working directory to a given file descriptor.
42438259Smckusick  */
42554916Storek struct fchdir_args {
42654916Storek 	int	fd;
42754916Storek };
42842441Smckusick /* ARGSUSED */
42942441Smckusick fchdir(p, uap, retval)
43045914Smckusick 	struct proc *p;
43154916Storek 	struct fchdir_args *uap;
43242441Smckusick 	int *retval;
43338259Smckusick {
43445914Smckusick 	register struct filedesc *fdp = p->p_fd;
43538259Smckusick 	register struct vnode *vp;
43638259Smckusick 	struct file *fp;
43738259Smckusick 	int error;
43838259Smckusick 
43945914Smckusick 	if (error = getvnode(fdp, uap->fd, &fp))
44047540Skarels 		return (error);
44138259Smckusick 	vp = (struct vnode *)fp->f_data;
44238259Smckusick 	VOP_LOCK(vp);
44338259Smckusick 	if (vp->v_type != VDIR)
44438259Smckusick 		error = ENOTDIR;
44538259Smckusick 	else
44648026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
44738259Smckusick 	VOP_UNLOCK(vp);
44839860Smckusick 	if (error)
44947540Skarels 		return (error);
45039860Smckusick 	VREF(vp);
45145914Smckusick 	vrele(fdp->fd_cdir);
45245914Smckusick 	fdp->fd_cdir = vp;
45347540Skarels 	return (0);
45438259Smckusick }
45538259Smckusick 
45638259Smckusick /*
45737741Smckusick  * Change current working directory (``.'').
45837741Smckusick  */
45954916Storek struct chdir_args {
46054916Storek 	char	*fname;
46154916Storek };
46242441Smckusick /* ARGSUSED */
46342441Smckusick chdir(p, uap, retval)
46445914Smckusick 	struct proc *p;
46554916Storek 	struct chdir_args *uap;
46642441Smckusick 	int *retval;
46737741Smckusick {
46845914Smckusick 	register struct filedesc *fdp = p->p_fd;
46937741Smckusick 	int error;
47047540Skarels 	struct nameidata nd;
4716254Sroot 
47252322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
47352781Sralph 	if (error = chdirec(&nd, p))
47447540Skarels 		return (error);
47545914Smckusick 	vrele(fdp->fd_cdir);
47652322Smckusick 	fdp->fd_cdir = nd.ni_vp;
47747540Skarels 	return (0);
47837741Smckusick }
4796254Sroot 
48037741Smckusick /*
48137741Smckusick  * Change notion of root (``/'') directory.
48237741Smckusick  */
48354916Storek struct chroot_args {
48454916Storek 	char	*fname;
48554916Storek };
48642441Smckusick /* ARGSUSED */
48742441Smckusick chroot(p, uap, retval)
48845914Smckusick 	struct proc *p;
48954916Storek 	struct chroot_args *uap;
49042441Smckusick 	int *retval;
49137741Smckusick {
49245914Smckusick 	register struct filedesc *fdp = p->p_fd;
49337741Smckusick 	int error;
49447540Skarels 	struct nameidata nd;
49537741Smckusick 
49647540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
49747540Skarels 		return (error);
49852322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
49952781Sralph 	if (error = chdirec(&nd, p))
50047540Skarels 		return (error);
50145914Smckusick 	if (fdp->fd_rdir != NULL)
50245914Smckusick 		vrele(fdp->fd_rdir);
50352322Smckusick 	fdp->fd_rdir = nd.ni_vp;
50447540Skarels 	return (0);
5056254Sroot }
5066254Sroot 
50737Sbill /*
50837741Smckusick  * Common routine for chroot and chdir.
50937741Smckusick  */
51047540Skarels chdirec(ndp, p)
51152322Smckusick 	register struct nameidata *ndp;
51247540Skarels 	struct proc *p;
51337741Smckusick {
51437741Smckusick 	struct vnode *vp;
51537741Smckusick 	int error;
51637741Smckusick 
51752322Smckusick 	if (error = namei(ndp))
51837741Smckusick 		return (error);
51937741Smckusick 	vp = ndp->ni_vp;
52037741Smckusick 	if (vp->v_type != VDIR)
52137741Smckusick 		error = ENOTDIR;
52237741Smckusick 	else
52348026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
52437741Smckusick 	VOP_UNLOCK(vp);
52537741Smckusick 	if (error)
52637741Smckusick 		vrele(vp);
52737741Smckusick 	return (error);
52837741Smckusick }
52937741Smckusick 
53037741Smckusick /*
5316254Sroot  * Open system call.
53242441Smckusick  * Check permissions, allocate an open file structure,
53342441Smckusick  * and call the device open routine if any.
5346254Sroot  */
53554916Storek struct open_args {
53654916Storek 	char	*fname;
53754916Storek 	int	mode;
53854916Storek 	int	crtmode;
53954916Storek };
54042441Smckusick open(p, uap, retval)
54145914Smckusick 	struct proc *p;
54254916Storek 	register struct open_args *uap;
54342441Smckusick 	int *retval;
5446254Sroot {
54545914Smckusick 	register struct filedesc *fdp = p->p_fd;
54642441Smckusick 	register struct file *fp;
54750111Smckusick 	register struct vnode *vp;
54837741Smckusick 	int fmode, cmode;
54937741Smckusick 	struct file *nfp;
55049945Smckusick 	int type, indx, error;
55149945Smckusick 	struct flock lf;
55247540Skarels 	struct nameidata nd;
55337741Smckusick 	extern struct fileops vnops;
5546254Sroot 
55545914Smckusick 	if (error = falloc(p, &nfp, &indx))
55647540Skarels 		return (error);
55737741Smckusick 	fp = nfp;
55846553Skarels 	fmode = FFLAGS(uap->mode);
55945914Smckusick 	cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX;
56052322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
56145202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
56252322Smckusick 	if (error = vn_open(&nd, fmode, cmode)) {
56349980Smckusick 		ffree(fp);
56454723Smckusick 		if ((error == ENODEV || error == ENXIO) &&
56554723Smckusick 		    p->p_dupfd >= 0 && 			/* XXX from fdopen */
56653828Spendry 		    (error = dupfdopen(fdp, indx, p->p_dupfd,
56753828Spendry 					fmode, error)) == 0) {
56842441Smckusick 			*retval = indx;
56947540Skarels 			return (0);
57042441Smckusick 		}
57140884Smckusick 		if (error == ERESTART)
57240884Smckusick 			error = EINTR;
57347688Skarels 		fdp->fd_ofiles[indx] = NULL;
57447540Skarels 		return (error);
57512756Ssam 	}
57653828Spendry 	p->p_dupfd = 0;
57752322Smckusick 	vp = nd.ni_vp;
57849949Smckusick 	fp->f_flag = fmode & FMASK;
57954348Smckusick 	fp->f_type = DTYPE_VNODE;
58054348Smckusick 	fp->f_ops = &vnops;
58154348Smckusick 	fp->f_data = (caddr_t)vp;
58249945Smckusick 	if (fmode & (O_EXLOCK | O_SHLOCK)) {
58349945Smckusick 		lf.l_whence = SEEK_SET;
58449945Smckusick 		lf.l_start = 0;
58549945Smckusick 		lf.l_len = 0;
58649945Smckusick 		if (fmode & O_EXLOCK)
58749945Smckusick 			lf.l_type = F_WRLCK;
58849945Smckusick 		else
58949945Smckusick 			lf.l_type = F_RDLCK;
59049945Smckusick 		type = F_FLOCK;
59149945Smckusick 		if ((fmode & FNONBLOCK) == 0)
59249945Smckusick 			type |= F_WAIT;
59350111Smckusick 		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
59450111Smckusick 			VOP_UNLOCK(vp);
59550111Smckusick 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
59649980Smckusick 			ffree(fp);
59749945Smckusick 			fdp->fd_ofiles[indx] = NULL;
59849945Smckusick 			return (error);
59949945Smckusick 		}
60049949Smckusick 		fp->f_flag |= FHASLOCK;
60149945Smckusick 	}
60250111Smckusick 	VOP_UNLOCK(vp);
60342441Smckusick 	*retval = indx;
60447540Skarels 	return (0);
6056254Sroot }
6066254Sroot 
60742955Smckusick #ifdef COMPAT_43
6086254Sroot /*
60942441Smckusick  * Creat system call.
6106254Sroot  */
61154916Storek struct ocreat_args {
61254916Storek 	char	*fname;
61354916Storek 	int	fmode;
61454916Storek };
61542955Smckusick ocreat(p, uap, retval)
61642441Smckusick 	struct proc *p;
61754916Storek 	register struct ocreat_args *uap;
61842441Smckusick 	int *retval;
6196254Sroot {
62054916Storek 	struct open_args openuap;
62142441Smckusick 
62242441Smckusick 	openuap.fname = uap->fname;
62342441Smckusick 	openuap.crtmode = uap->fmode;
62442441Smckusick 	openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
62547540Skarels 	return (open(p, &openuap, retval));
62642441Smckusick }
62742955Smckusick #endif /* COMPAT_43 */
62842441Smckusick 
62942441Smckusick /*
63049365Smckusick  * Mknod system call.
63142441Smckusick  */
63254916Storek struct mknod_args {
63354916Storek 	char	*fname;
63454916Storek 	int	fmode;
63554916Storek 	int	dev;
63654916Storek };
63742441Smckusick /* ARGSUSED */
63842441Smckusick mknod(p, uap, retval)
63945914Smckusick 	struct proc *p;
64054916Storek 	register struct mknod_args *uap;
64142441Smckusick 	int *retval;
64242441Smckusick {
64337741Smckusick 	register struct vnode *vp;
64437741Smckusick 	struct vattr vattr;
64537741Smckusick 	int error;
64647540Skarels 	struct nameidata nd;
6476254Sroot 
64847540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
64947540Skarels 		return (error);
65052322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p);
65152322Smckusick 	if (error = namei(&nd))
65247540Skarels 		return (error);
65352322Smckusick 	vp = nd.ni_vp;
65437741Smckusick 	if (vp != NULL) {
65537741Smckusick 		error = EEXIST;
65612756Ssam 		goto out;
6576254Sroot 	}
65841362Smckusick 	VATTR_NULL(&vattr);
65940635Smckusick 	switch (uap->fmode & S_IFMT) {
66012756Ssam 
66140635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
66237741Smckusick 		vattr.va_type = VBAD;
66337741Smckusick 		break;
66440635Smckusick 	case S_IFCHR:
66537741Smckusick 		vattr.va_type = VCHR;
66637741Smckusick 		break;
66740635Smckusick 	case S_IFBLK:
66837741Smckusick 		vattr.va_type = VBLK;
66937741Smckusick 		break;
67037741Smckusick 	default:
67137741Smckusick 		error = EINVAL;
67237741Smckusick 		goto out;
6736254Sroot 	}
67445914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
67537741Smckusick 	vattr.va_rdev = uap->dev;
6766254Sroot out:
67742465Smckusick 	if (!error) {
67852322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
67952322Smckusick 		error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
68042465Smckusick 	} else {
68152322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
68252322Smckusick 		if (nd.ni_dvp == vp)
68352322Smckusick 			vrele(nd.ni_dvp);
68443344Smckusick 		else
68552322Smckusick 			vput(nd.ni_dvp);
68642465Smckusick 		if (vp)
68742465Smckusick 			vrele(vp);
68842465Smckusick 	}
68947540Skarels 	return (error);
6906254Sroot }
6916254Sroot 
6926254Sroot /*
69349365Smckusick  * Mkfifo system call.
69440285Smckusick  */
69554916Storek struct mkfifo_args {
69654916Storek 	char	*fname;
69754916Storek 	int	fmode;
69854916Storek };
69942441Smckusick /* ARGSUSED */
70042441Smckusick mkfifo(p, uap, retval)
70145914Smckusick 	struct proc *p;
70254916Storek 	register struct mkfifo_args *uap;
70342441Smckusick 	int *retval;
70442441Smckusick {
70540285Smckusick 	struct vattr vattr;
70640285Smckusick 	int error;
70747540Skarels 	struct nameidata nd;
70840285Smckusick 
70940285Smckusick #ifndef FIFO
71047540Skarels 	return (EOPNOTSUPP);
71140285Smckusick #else
71252322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->fname, p);
71352322Smckusick 	if (error = namei(&nd))
71447540Skarels 		return (error);
71552322Smckusick 	if (nd.ni_vp != NULL) {
71652322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
71752322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
71852322Smckusick 			vrele(nd.ni_dvp);
71943344Smckusick 		else
72052322Smckusick 			vput(nd.ni_dvp);
72152322Smckusick 		vrele(nd.ni_vp);
72247540Skarels 		return (EEXIST);
72340285Smckusick 	}
72445785Sbostic 	VATTR_NULL(&vattr);
72545785Sbostic 	vattr.va_type = VFIFO;
72645914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
72752322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
72852322Smckusick 	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
72940285Smckusick #endif /* FIFO */
73040285Smckusick }
73140285Smckusick 
73240285Smckusick /*
73349365Smckusick  * Link system call.
7346254Sroot  */
73554916Storek struct link_args {
73654916Storek 	char	*target;
73754916Storek 	char	*linkname;
73854916Storek };
73942441Smckusick /* ARGSUSED */
74042441Smckusick link(p, uap, retval)
74145914Smckusick 	struct proc *p;
74254916Storek 	register struct link_args *uap;
74342441Smckusick 	int *retval;
74442441Smckusick {
74537741Smckusick 	register struct vnode *vp, *xp;
74637741Smckusick 	int error;
74747540Skarels 	struct nameidata nd;
7486254Sroot 
74952322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->target, p);
75052322Smckusick 	if (error = namei(&nd))
75147540Skarels 		return (error);
75252322Smckusick 	vp = nd.ni_vp;
75337741Smckusick 	if (vp->v_type == VDIR &&
75447540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
75537741Smckusick 		goto out1;
75652322Smckusick 	nd.ni_cnd.cn_nameiop = CREATE;
75752322Smckusick 	nd.ni_cnd.cn_flags = LOCKPARENT;
75852322Smckusick 	nd.ni_dirp = (caddr_t)uap->linkname;
75952322Smckusick 	if (error = namei(&nd))
76037741Smckusick 		goto out1;
76152322Smckusick 	xp = nd.ni_vp;
7626254Sroot 	if (xp != NULL) {
76337741Smckusick 		error = EEXIST;
7646254Sroot 		goto out;
7656254Sroot 	}
76652322Smckusick 	xp = nd.ni_dvp;
7676254Sroot out:
76842465Smckusick 	if (!error) {
76952192Smckusick 		LEASE_CHECK(xp, p, p->p_ucred, LEASE_WRITE);
77052192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
77152821Smckusick 		error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
77242465Smckusick 	} else {
77352322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
77452322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
77552322Smckusick 			vrele(nd.ni_dvp);
77643344Smckusick 		else
77752322Smckusick 			vput(nd.ni_dvp);
77852322Smckusick 		if (nd.ni_vp)
77952322Smckusick 			vrele(nd.ni_vp);
78042465Smckusick 	}
78137741Smckusick out1:
78237741Smckusick 	vrele(vp);
78347540Skarels 	return (error);
7846254Sroot }
7856254Sroot 
7866254Sroot /*
78749365Smckusick  * Make a symbolic link.
7886254Sroot  */
78954916Storek struct symlink_args {
79054916Storek 	char	*target;
79154916Storek 	char	*linkname;
79254916Storek };
79342441Smckusick /* ARGSUSED */
79442441Smckusick symlink(p, uap, retval)
79545914Smckusick 	struct proc *p;
79654916Storek 	register struct symlink_args *uap;
79742441Smckusick 	int *retval;
79842441Smckusick {
79937741Smckusick 	struct vattr vattr;
80037741Smckusick 	char *target;
80137741Smckusick 	int error;
80247540Skarels 	struct nameidata nd;
8036254Sroot 
80437741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
80537741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
80642465Smckusick 		goto out;
80752322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->linkname, p);
80852322Smckusick 	if (error = namei(&nd))
80942465Smckusick 		goto out;
81052322Smckusick 	if (nd.ni_vp) {
81152322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
81252322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
81352322Smckusick 			vrele(nd.ni_dvp);
81443344Smckusick 		else
81552322Smckusick 			vput(nd.ni_dvp);
81652322Smckusick 		vrele(nd.ni_vp);
81737741Smckusick 		error = EEXIST;
81837741Smckusick 		goto out;
8196254Sroot 	}
82041362Smckusick 	VATTR_NULL(&vattr);
82145914Smckusick 	vattr.va_mode = 0777 &~ p->p_fd->fd_cmask;
82252322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
82352322Smckusick 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, target);
82437741Smckusick out:
82537741Smckusick 	FREE(target, M_NAMEI);
82647540Skarels 	return (error);
8276254Sroot }
8286254Sroot 
8296254Sroot /*
83049365Smckusick  * Delete a name from the filesystem.
8316254Sroot  */
83254916Storek struct unlink_args {
83354916Storek 	char	*name;
83454916Storek };
83542441Smckusick /* ARGSUSED */
83642441Smckusick unlink(p, uap, retval)
83745914Smckusick 	struct proc *p;
83854916Storek 	struct unlink_args *uap;
83942441Smckusick 	int *retval;
8406254Sroot {
84137741Smckusick 	register struct vnode *vp;
84237741Smckusick 	int error;
84347540Skarels 	struct nameidata nd;
8446254Sroot 
84552322Smckusick 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p);
84652322Smckusick 	if (error = namei(&nd))
84747540Skarels 		return (error);
84852322Smckusick 	vp = nd.ni_vp;
84937741Smckusick 	if (vp->v_type == VDIR &&
85047540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
8516254Sroot 		goto out;
8526254Sroot 	/*
85349365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
8546254Sroot 	 */
85537741Smckusick 	if (vp->v_flag & VROOT) {
85637741Smckusick 		error = EBUSY;
8576254Sroot 		goto out;
8586254Sroot 	}
85945738Smckusick 	(void) vnode_pager_uncache(vp);
8606254Sroot out:
86142465Smckusick 	if (!error) {
86252322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
86352192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
86452322Smckusick 		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
86542465Smckusick 	} else {
86652322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
86752322Smckusick 		if (nd.ni_dvp == vp)
86852322Smckusick 			vrele(nd.ni_dvp);
86943344Smckusick 		else
87052322Smckusick 			vput(nd.ni_dvp);
87142465Smckusick 		vput(vp);
87242465Smckusick 	}
87347540Skarels 	return (error);
8746254Sroot }
8756254Sroot 
87654916Storek struct __lseek_args {
87754863Storek 	int	fdes;
87854863Storek 	int	pad;
87954863Storek 	off_t	off;
88054863Storek 	int	sbase;
88154863Storek };
88254863Storek 
88354348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
8846254Sroot /*
88549365Smckusick  * Seek system call.
8866254Sroot  */
88754916Storek struct lseek_args {
88854916Storek 	int	fdes;
88954916Storek 	long	off;
89054916Storek 	int	sbase;
89154916Storek };
89242441Smckusick lseek(p, uap, retval)
89345914Smckusick 	struct proc *p;
89454916Storek 	register struct lseek_args *uap;
89554916Storek 	int *retval;
89653468Smckusick {
89754916Storek 	struct __lseek_args nuap;
89854863Storek 	off_t qret;
89953468Smckusick 	int error;
90053468Smckusick 
90153468Smckusick 	nuap.fdes = uap->fdes;
90253468Smckusick 	nuap.off = uap->off;
90353468Smckusick 	nuap.sbase = uap->sbase;
90453759Smckusick 	error = __lseek(p, &nuap, &qret);
90554916Storek 	*(long *)retval = qret;
90653468Smckusick 	return (error);
90753468Smckusick }
90854348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
90953468Smckusick 
91053468Smckusick /*
91153468Smckusick  * Seek system call.
91253468Smckusick  */
91353759Smckusick __lseek(p, uap, retval)
91453468Smckusick 	struct proc *p;
91554916Storek 	register struct __lseek_args *uap;
91654916Storek 	int *retval;
91742441Smckusick {
91847540Skarels 	struct ucred *cred = p->p_ucred;
91945914Smckusick 	register struct filedesc *fdp = p->p_fd;
92042441Smckusick 	register struct file *fp;
92137741Smckusick 	struct vattr vattr;
92237741Smckusick 	int error;
9236254Sroot 
92447540Skarels 	if ((unsigned)uap->fdes >= fdp->fd_nfiles ||
92547688Skarels 	    (fp = fdp->fd_ofiles[uap->fdes]) == NULL)
92647540Skarels 		return (EBADF);
92737741Smckusick 	if (fp->f_type != DTYPE_VNODE)
92847540Skarels 		return (ESPIPE);
92913878Ssam 	switch (uap->sbase) {
93013878Ssam 
93113878Ssam 	case L_INCR:
93213878Ssam 		fp->f_offset += uap->off;
93313878Ssam 		break;
93413878Ssam 
93513878Ssam 	case L_XTND:
93637741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
93748026Smckusick 		    &vattr, cred, p))
93847540Skarels 			return (error);
93937741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
94013878Ssam 		break;
94113878Ssam 
94213878Ssam 	case L_SET:
94313878Ssam 		fp->f_offset = uap->off;
94413878Ssam 		break;
94513878Ssam 
94613878Ssam 	default:
94747540Skarels 		return (EINVAL);
94813878Ssam 	}
94954916Storek 	*(off_t *)retval = fp->f_offset;
95047540Skarels 	return (0);
9516254Sroot }
9526254Sroot 
9536254Sroot /*
95449365Smckusick  * Check access permissions.
9556254Sroot  */
95654916Storek struct saccess_args {
95754916Storek 	char	*fname;
95854916Storek 	int	fmode;
95954916Storek };
96042441Smckusick /* ARGSUSED */
96142441Smckusick saccess(p, uap, retval)
96245914Smckusick 	struct proc *p;
96354916Storek 	register struct saccess_args *uap;
96442441Smckusick 	int *retval;
96542441Smckusick {
96647540Skarels 	register struct ucred *cred = p->p_ucred;
96737741Smckusick 	register struct vnode *vp;
96837741Smckusick 	int error, mode, svuid, svgid;
96947540Skarels 	struct nameidata nd;
9706254Sroot 
97142441Smckusick 	svuid = cred->cr_uid;
97242441Smckusick 	svgid = cred->cr_groups[0];
97347540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
97447540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
97552322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
97652322Smckusick 	if (error = namei(&nd))
97737741Smckusick 		goto out1;
97852322Smckusick 	vp = nd.ni_vp;
97937741Smckusick 	/*
98037741Smckusick 	 * fmode == 0 means only check for exist
98137741Smckusick 	 */
98237741Smckusick 	if (uap->fmode) {
98337741Smckusick 		mode = 0;
98437741Smckusick 		if (uap->fmode & R_OK)
98537741Smckusick 			mode |= VREAD;
98637741Smckusick 		if (uap->fmode & W_OK)
98737741Smckusick 			mode |= VWRITE;
98837741Smckusick 		if (uap->fmode & X_OK)
98937741Smckusick 			mode |= VEXEC;
99039543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
99148026Smckusick 			error = VOP_ACCESS(vp, mode, cred, p);
9926254Sroot 	}
99337741Smckusick 	vput(vp);
99437741Smckusick out1:
99542441Smckusick 	cred->cr_uid = svuid;
99642441Smckusick 	cred->cr_groups[0] = svgid;
99747540Skarels 	return (error);
9986254Sroot }
9996254Sroot 
100054348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
10016254Sroot /*
100249365Smckusick  * Stat system call.
100349365Smckusick  * This version follows links.
100437Sbill  */
100554916Storek struct ostat_args {
100654916Storek 	char	*fname;
100754916Storek 	struct ostat *ub;
100854916Storek };
100942441Smckusick /* ARGSUSED */
101053759Smckusick ostat(p, uap, retval)
101145914Smckusick 	struct proc *p;
101254916Storek 	register struct ostat_args *uap;
101353468Smckusick 	int *retval;
101453468Smckusick {
101553468Smckusick 	struct stat sb;
101653468Smckusick 	struct ostat osb;
101753468Smckusick 	int error;
101853468Smckusick 	struct nameidata nd;
101953468Smckusick 
102053468Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
102153468Smckusick 	if (error = namei(&nd))
102253468Smckusick 		return (error);
102353468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
102453468Smckusick 	vput(nd.ni_vp);
102553468Smckusick 	if (error)
102653468Smckusick 		return (error);
102753468Smckusick 	cvtstat(&sb, &osb);
102853468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
102953468Smckusick 	return (error);
103053468Smckusick }
103153468Smckusick 
103253468Smckusick /*
103353468Smckusick  * Lstat system call.
103453468Smckusick  * This version does not follow links.
103553468Smckusick  */
103654916Storek struct olstat_args {
103754916Storek 	char	*fname;
103854916Storek 	struct ostat *ub;
103954916Storek };
104053468Smckusick /* ARGSUSED */
104153759Smckusick olstat(p, uap, retval)
104253468Smckusick 	struct proc *p;
104354916Storek 	register struct olstat_args *uap;
104453468Smckusick 	int *retval;
104553468Smckusick {
104653468Smckusick 	struct stat sb;
104753468Smckusick 	struct ostat osb;
104853468Smckusick 	int error;
104953468Smckusick 	struct nameidata nd;
105053468Smckusick 
105153468Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
105253468Smckusick 	if (error = namei(&nd))
105353468Smckusick 		return (error);
105453468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
105553468Smckusick 	vput(nd.ni_vp);
105653468Smckusick 	if (error)
105753468Smckusick 		return (error);
105853468Smckusick 	cvtstat(&sb, &osb);
105953468Smckusick 	error = copyout((caddr_t)&osb, (caddr_t)uap->ub, sizeof (osb));
106053468Smckusick 	return (error);
106153468Smckusick }
106253468Smckusick 
106353468Smckusick /*
106453468Smckusick  * convert from an old to a new stat structure.
106553468Smckusick  */
106653468Smckusick cvtstat(st, ost)
106753468Smckusick 	struct stat *st;
106853468Smckusick 	struct ostat *ost;
106953468Smckusick {
107053468Smckusick 
107153468Smckusick 	ost->st_dev = st->st_dev;
107253468Smckusick 	ost->st_ino = st->st_ino;
107353468Smckusick 	ost->st_mode = st->st_mode;
107453468Smckusick 	ost->st_nlink = st->st_nlink;
107553468Smckusick 	ost->st_uid = st->st_uid;
107653468Smckusick 	ost->st_gid = st->st_gid;
107753468Smckusick 	ost->st_rdev = st->st_rdev;
107853468Smckusick 	if (st->st_size < (quad_t)1 << 32)
107953468Smckusick 		ost->st_size = st->st_size;
108053468Smckusick 	else
108153468Smckusick 		ost->st_size = -2;
108253468Smckusick 	ost->st_atime = st->st_atime;
108353468Smckusick 	ost->st_mtime = st->st_mtime;
108453468Smckusick 	ost->st_ctime = st->st_ctime;
108553468Smckusick 	ost->st_blksize = st->st_blksize;
108653468Smckusick 	ost->st_blocks = st->st_blocks;
108753468Smckusick 	ost->st_flags = st->st_flags;
108853468Smckusick 	ost->st_gen = st->st_gen;
108953468Smckusick }
109054348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
109153468Smckusick 
109253468Smckusick /*
109353468Smckusick  * Stat system call.
109453468Smckusick  * This version follows links.
109553468Smckusick  */
109654916Storek struct stat_args {
109754916Storek 	char	*fname;
109854916Storek 	struct stat *ub;
109954916Storek };
110053468Smckusick /* ARGSUSED */
110153759Smckusick stat(p, uap, retval)
110253468Smckusick 	struct proc *p;
110354916Storek 	register struct stat_args *uap;
110442441Smckusick 	int *retval;
110537Sbill {
110642441Smckusick 	struct stat sb;
110742441Smckusick 	int error;
110847540Skarels 	struct nameidata nd;
110937Sbill 
111052322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
111152322Smckusick 	if (error = namei(&nd))
111247540Skarels 		return (error);
111352322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
111452322Smckusick 	vput(nd.ni_vp);
111542441Smckusick 	if (error)
111647540Skarels 		return (error);
111742441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
111847540Skarels 	return (error);
111937Sbill }
112037Sbill 
112137Sbill /*
112249365Smckusick  * Lstat system call.
112349365Smckusick  * This version does not follow links.
11245992Swnj  */
112554916Storek struct lstat_args {
112654916Storek 	char	*fname;
112754916Storek 	struct stat *ub;
112854916Storek };
112942441Smckusick /* ARGSUSED */
113053759Smckusick lstat(p, uap, retval)
113145914Smckusick 	struct proc *p;
113254916Storek 	register struct lstat_args *uap;
113342441Smckusick 	int *retval;
113442441Smckusick {
113512756Ssam 	struct stat sb;
113637741Smckusick 	int error;
113747540Skarels 	struct nameidata nd;
11385992Swnj 
113952322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
114052322Smckusick 	if (error = namei(&nd))
114147540Skarels 		return (error);
114252322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
114352322Smckusick 	vput(nd.ni_vp);
114437741Smckusick 	if (error)
114547540Skarels 		return (error);
114637741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
114747540Skarels 	return (error);
11485992Swnj }
11495992Swnj 
11505992Swnj /*
115149365Smckusick  * Return target name of a symbolic link.
115237Sbill  */
115354916Storek struct readlink_args {
115454916Storek 	char	*name;
115554916Storek 	char	*buf;
115654916Storek 	int	count;
115754916Storek };
115842441Smckusick /* ARGSUSED */
115942441Smckusick readlink(p, uap, retval)
116045914Smckusick 	struct proc *p;
116154916Storek 	register struct readlink_args *uap;
116242441Smckusick 	int *retval;
116342441Smckusick {
116437741Smckusick 	register struct vnode *vp;
116537741Smckusick 	struct iovec aiov;
116637741Smckusick 	struct uio auio;
116737741Smckusick 	int error;
116847540Skarels 	struct nameidata nd;
11695992Swnj 
117052322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->name, p);
117152322Smckusick 	if (error = namei(&nd))
117247540Skarels 		return (error);
117352322Smckusick 	vp = nd.ni_vp;
117437741Smckusick 	if (vp->v_type != VLNK) {
117537741Smckusick 		error = EINVAL;
11765992Swnj 		goto out;
11775992Swnj 	}
117837741Smckusick 	aiov.iov_base = uap->buf;
117937741Smckusick 	aiov.iov_len = uap->count;
118037741Smckusick 	auio.uio_iov = &aiov;
118137741Smckusick 	auio.uio_iovcnt = 1;
118237741Smckusick 	auio.uio_offset = 0;
118337741Smckusick 	auio.uio_rw = UIO_READ;
118437741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
118548026Smckusick 	auio.uio_procp = p;
118637741Smckusick 	auio.uio_resid = uap->count;
118747540Skarels 	error = VOP_READLINK(vp, &auio, p->p_ucred);
11885992Swnj out:
118937741Smckusick 	vput(vp);
119042441Smckusick 	*retval = uap->count - auio.uio_resid;
119147540Skarels 	return (error);
11925992Swnj }
11935992Swnj 
11949167Ssam /*
119538259Smckusick  * Change flags of a file given path name.
119638259Smckusick  */
119754916Storek struct chflags_args {
119854916Storek 	char	*fname;
119954916Storek 	int	flags;
120054916Storek };
120142441Smckusick /* ARGSUSED */
120242441Smckusick chflags(p, uap, retval)
120345914Smckusick 	struct proc *p;
120454916Storek 	register struct chflags_args *uap;
120542441Smckusick 	int *retval;
120642441Smckusick {
120738259Smckusick 	register struct vnode *vp;
120838259Smckusick 	struct vattr vattr;
120938259Smckusick 	int error;
121047540Skarels 	struct nameidata nd;
121138259Smckusick 
121252322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
121352322Smckusick 	if (error = namei(&nd))
121447540Skarels 		return (error);
121552322Smckusick 	vp = nd.ni_vp;
121641400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
121738259Smckusick 		error = EROFS;
121838259Smckusick 		goto out;
121938259Smckusick 	}
122045785Sbostic 	VATTR_NULL(&vattr);
122145785Sbostic 	vattr.va_flags = uap->flags;
122252192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
122348026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
122438259Smckusick out:
122538259Smckusick 	vput(vp);
122647540Skarels 	return (error);
122738259Smckusick }
122838259Smckusick 
122938259Smckusick /*
123038259Smckusick  * Change flags of a file given a file descriptor.
123138259Smckusick  */
123254916Storek struct fchflags_args {
123354916Storek 	int	fd;
123454916Storek 	int	flags;
123554916Storek };
123642441Smckusick /* ARGSUSED */
123742441Smckusick fchflags(p, uap, retval)
123845914Smckusick 	struct proc *p;
123954916Storek 	register struct fchflags_args *uap;
124042441Smckusick 	int *retval;
124142441Smckusick {
124238259Smckusick 	struct vattr vattr;
124338259Smckusick 	struct vnode *vp;
124438259Smckusick 	struct file *fp;
124538259Smckusick 	int error;
124638259Smckusick 
124745914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
124847540Skarels 		return (error);
124938259Smckusick 	vp = (struct vnode *)fp->f_data;
125038259Smckusick 	VOP_LOCK(vp);
125141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
125238259Smckusick 		error = EROFS;
125338259Smckusick 		goto out;
125438259Smckusick 	}
125545785Sbostic 	VATTR_NULL(&vattr);
125645785Sbostic 	vattr.va_flags = uap->flags;
125752192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
125848026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
125938259Smckusick out:
126038259Smckusick 	VOP_UNLOCK(vp);
126147540Skarels 	return (error);
126238259Smckusick }
126338259Smckusick 
126438259Smckusick /*
12659167Ssam  * Change mode of a file given path name.
12669167Ssam  */
126754916Storek struct chmod_args {
126854916Storek 	char	*fname;
126954916Storek 	int	fmode;
127054916Storek };
127142441Smckusick /* ARGSUSED */
127242441Smckusick chmod(p, uap, retval)
127345914Smckusick 	struct proc *p;
127454916Storek 	register struct chmod_args *uap;
127542441Smckusick 	int *retval;
127642441Smckusick {
127737741Smckusick 	register struct vnode *vp;
127837741Smckusick 	struct vattr vattr;
127937741Smckusick 	int error;
128047540Skarels 	struct nameidata nd;
12815992Swnj 
128252322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
128352322Smckusick 	if (error = namei(&nd))
128447540Skarels 		return (error);
128552322Smckusick 	vp = nd.ni_vp;
128641400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
128737741Smckusick 		error = EROFS;
128837741Smckusick 		goto out;
128937741Smckusick 	}
129045785Sbostic 	VATTR_NULL(&vattr);
129145785Sbostic 	vattr.va_mode = uap->fmode & 07777;
129252192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
129348026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
129437741Smckusick out:
129537741Smckusick 	vput(vp);
129647540Skarels 	return (error);
12977701Ssam }
12987439Sroot 
12999167Ssam /*
13009167Ssam  * Change mode of a file given a file descriptor.
13019167Ssam  */
130254916Storek struct fchmod_args {
130354916Storek 	int	fd;
130454916Storek 	int	fmode;
130554916Storek };
130642441Smckusick /* ARGSUSED */
130742441Smckusick fchmod(p, uap, retval)
130845914Smckusick 	struct proc *p;
130954916Storek 	register struct fchmod_args *uap;
131042441Smckusick 	int *retval;
131142441Smckusick {
131237741Smckusick 	struct vattr vattr;
131337741Smckusick 	struct vnode *vp;
131437741Smckusick 	struct file *fp;
131537741Smckusick 	int error;
13167701Ssam 
131745914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
131847540Skarels 		return (error);
131937741Smckusick 	vp = (struct vnode *)fp->f_data;
132037741Smckusick 	VOP_LOCK(vp);
132141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
132237741Smckusick 		error = EROFS;
132337741Smckusick 		goto out;
13247439Sroot 	}
132545785Sbostic 	VATTR_NULL(&vattr);
132645785Sbostic 	vattr.va_mode = uap->fmode & 07777;
132752192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
132848026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
132937741Smckusick out:
133037741Smckusick 	VOP_UNLOCK(vp);
133147540Skarels 	return (error);
13325992Swnj }
13335992Swnj 
13349167Ssam /*
13359167Ssam  * Set ownership given a path name.
13369167Ssam  */
133754916Storek struct chown_args {
133854916Storek 	char	*fname;
133954916Storek 	int	uid;
134054916Storek 	int	gid;
134154916Storek };
134242441Smckusick /* ARGSUSED */
134342441Smckusick chown(p, uap, retval)
134445914Smckusick 	struct proc *p;
134554916Storek 	register struct chown_args *uap;
134642441Smckusick 	int *retval;
134742441Smckusick {
134837741Smckusick 	register struct vnode *vp;
134937741Smckusick 	struct vattr vattr;
135037741Smckusick 	int error;
135147540Skarels 	struct nameidata nd;
135237Sbill 
135352322Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
135452322Smckusick 	if (error = namei(&nd))
135547540Skarels 		return (error);
135652322Smckusick 	vp = nd.ni_vp;
135741400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
135837741Smckusick 		error = EROFS;
135937741Smckusick 		goto out;
136037741Smckusick 	}
136145785Sbostic 	VATTR_NULL(&vattr);
136245785Sbostic 	vattr.va_uid = uap->uid;
136345785Sbostic 	vattr.va_gid = uap->gid;
136452192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
136548026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
136637741Smckusick out:
136737741Smckusick 	vput(vp);
136847540Skarels 	return (error);
13697701Ssam }
13707439Sroot 
13719167Ssam /*
13729167Ssam  * Set ownership given a file descriptor.
13739167Ssam  */
137454916Storek struct fchown_args {
137554916Storek 	int	fd;
137654916Storek 	int	uid;
137754916Storek 	int	gid;
137854916Storek };
137942441Smckusick /* ARGSUSED */
138042441Smckusick fchown(p, uap, retval)
138145914Smckusick 	struct proc *p;
138254916Storek 	register struct fchown_args *uap;
138342441Smckusick 	int *retval;
138442441Smckusick {
138537741Smckusick 	struct vattr vattr;
138637741Smckusick 	struct vnode *vp;
138737741Smckusick 	struct file *fp;
138837741Smckusick 	int error;
13897701Ssam 
139045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
139147540Skarels 		return (error);
139237741Smckusick 	vp = (struct vnode *)fp->f_data;
139337741Smckusick 	VOP_LOCK(vp);
139441400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
139537741Smckusick 		error = EROFS;
139637741Smckusick 		goto out;
139737741Smckusick 	}
139845785Sbostic 	VATTR_NULL(&vattr);
139945785Sbostic 	vattr.va_uid = uap->uid;
140045785Sbostic 	vattr.va_gid = uap->gid;
140152192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
140248026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
140337741Smckusick out:
140437741Smckusick 	VOP_UNLOCK(vp);
140547540Skarels 	return (error);
14067701Ssam }
14077701Ssam 
140842441Smckusick /*
140942441Smckusick  * Set the access and modification times of a file.
141042441Smckusick  */
141154916Storek struct utimes_args {
141254916Storek 	char	*fname;
141354916Storek 	struct	timeval *tptr;
141454916Storek };
141542441Smckusick /* ARGSUSED */
141642441Smckusick utimes(p, uap, retval)
141745914Smckusick 	struct proc *p;
141854916Storek 	register struct utimes_args *uap;
141942441Smckusick 	int *retval;
142042441Smckusick {
142137741Smckusick 	register struct vnode *vp;
142211811Ssam 	struct timeval tv[2];
142337741Smckusick 	struct vattr vattr;
142437741Smckusick 	int error;
142547540Skarels 	struct nameidata nd;
142611811Ssam 
142737741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
142847540Skarels 		return (error);
142952322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
143052322Smckusick 	if (error = namei(&nd))
143147540Skarels 		return (error);
143252322Smckusick 	vp = nd.ni_vp;
143341400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
143437741Smckusick 		error = EROFS;
143537741Smckusick 		goto out;
143621015Smckusick 	}
143745785Sbostic 	VATTR_NULL(&vattr);
143854100Smckusick 	vattr.va_atime.ts_sec = tv[0].tv_sec;
143954100Smckusick 	vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
144054100Smckusick 	vattr.va_mtime.ts_sec = tv[1].tv_sec;
144154100Smckusick 	vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
144252192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
144348026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
144437741Smckusick out:
144537741Smckusick 	vput(vp);
144647540Skarels 	return (error);
144711811Ssam }
144811811Ssam 
144954916Storek struct __truncate_args {
145054863Storek 	char	*fname;
145154863Storek 	int	pad;
145254863Storek 	off_t	length;
145354863Storek };
145453468Smckusick 
145553468Smckusick /*
145653468Smckusick  * Truncate a file given its path name.
145753468Smckusick  */
145853468Smckusick /* ARGSUSED */
145953759Smckusick __truncate(p, uap, retval)
146053468Smckusick 	struct proc *p;
146154916Storek 	register struct __truncate_args *uap;
146253468Smckusick 	int *retval;
146353468Smckusick {
146437741Smckusick 	register struct vnode *vp;
146537741Smckusick 	struct vattr vattr;
146637741Smckusick 	int error;
146747540Skarels 	struct nameidata nd;
14687701Ssam 
146952322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, p);
147052322Smckusick 	if (error = namei(&nd))
147147540Skarels 		return (error);
147252322Smckusick 	vp = nd.ni_vp;
147337741Smckusick 	if (vp->v_type == VDIR) {
147437741Smckusick 		error = EISDIR;
147537741Smckusick 		goto out;
14767701Ssam 	}
147738399Smckusick 	if ((error = vn_writechk(vp)) ||
147848026Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)))
147937741Smckusick 		goto out;
148045785Sbostic 	VATTR_NULL(&vattr);
148145785Sbostic 	vattr.va_size = uap->length;
148252192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
148348026Smckusick 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
148437741Smckusick out:
148537741Smckusick 	vput(vp);
148647540Skarels 	return (error);
14877701Ssam }
14887701Ssam 
148954916Storek struct __ftruncate_args {
149054863Storek 	int	fd;
149154863Storek 	int	pad;
149254863Storek 	off_t	length;
149354863Storek };
149454863Storek 
14959167Ssam /*
14969167Ssam  * Truncate a file given a file descriptor.
14979167Ssam  */
149842441Smckusick /* ARGSUSED */
149953759Smckusick __ftruncate(p, uap, retval)
150045914Smckusick 	struct proc *p;
150154916Storek 	register struct __ftruncate_args *uap;
150242441Smckusick 	int *retval;
150342441Smckusick {
150437741Smckusick 	struct vattr vattr;
150537741Smckusick 	struct vnode *vp;
15067701Ssam 	struct file *fp;
150737741Smckusick 	int error;
15087701Ssam 
150945914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
151047540Skarels 		return (error);
151137741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
151247540Skarels 		return (EINVAL);
151337741Smckusick 	vp = (struct vnode *)fp->f_data;
151437741Smckusick 	VOP_LOCK(vp);
151537741Smckusick 	if (vp->v_type == VDIR) {
151637741Smckusick 		error = EISDIR;
151737741Smckusick 		goto out;
15187701Ssam 	}
151938399Smckusick 	if (error = vn_writechk(vp))
152037741Smckusick 		goto out;
152145785Sbostic 	VATTR_NULL(&vattr);
152245785Sbostic 	vattr.va_size = uap->length;
152352192Smckusick 	LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
152448026Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
152537741Smckusick out:
152637741Smckusick 	VOP_UNLOCK(vp);
152747540Skarels 	return (error);
15287701Ssam }
15297701Ssam 
153054863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
15319167Ssam /*
153254863Storek  * Truncate a file given its path name.
153354863Storek  */
153454916Storek struct truncate_args {
153554916Storek 	char	*fname;
153654916Storek 	long	length;
153754916Storek };
153854863Storek /* ARGSUSED */
153954863Storek truncate(p, uap, retval)
154054863Storek 	struct proc *p;
154154916Storek 	register struct truncate_args *uap;
154254863Storek 	int *retval;
154354863Storek {
154454916Storek 	struct __truncate_args nuap;
154554863Storek 
154654863Storek 	nuap.fname = uap->fname;
154754863Storek 	nuap.length = uap->length;
154854863Storek 	return (__truncate(p, &nuap, retval));
154954863Storek }
155054863Storek 
155154863Storek /*
155254863Storek  * Truncate a file given a file descriptor.
155354863Storek  */
155454916Storek struct ftruncate_args {
155554916Storek 	int	fd;
155654916Storek 	long	length;
155754916Storek };
155854863Storek /* ARGSUSED */
155954863Storek ftruncate(p, uap, retval)
156054863Storek 	struct proc *p;
156154916Storek 	register struct ftruncate_args *uap;
156254863Storek 	int *retval;
156354863Storek {
156454969Smckusick 	struct __ftruncate_args nuap;
156554863Storek 
156654863Storek 	nuap.fd = uap->fd;
156754863Storek 	nuap.length = uap->length;
156854863Storek 	return (__ftruncate(p, &nuap, retval));
156954863Storek }
157054863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */
157154863Storek 
157254863Storek /*
15739167Ssam  * Synch an open file.
15749167Ssam  */
157554916Storek struct fsync_args {
157654916Storek 	int	fd;
157754916Storek };
157842441Smckusick /* ARGSUSED */
157942441Smckusick fsync(p, uap, retval)
158045914Smckusick 	struct proc *p;
158154916Storek 	struct fsync_args *uap;
158242441Smckusick 	int *retval;
15839167Ssam {
158439592Smckusick 	register struct vnode *vp;
15859167Ssam 	struct file *fp;
158637741Smckusick 	int error;
15879167Ssam 
158845914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
158947540Skarels 		return (error);
159039592Smckusick 	vp = (struct vnode *)fp->f_data;
159139592Smckusick 	VOP_LOCK(vp);
159254441Smckusick 	error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
159339592Smckusick 	VOP_UNLOCK(vp);
159447540Skarels 	return (error);
15959167Ssam }
15969167Ssam 
15979167Ssam /*
15989167Ssam  * Rename system call.
15999167Ssam  *
16009167Ssam  * Source and destination must either both be directories, or both
16019167Ssam  * not be directories.  If target is a directory, it must be empty.
16029167Ssam  */
160354916Storek struct rename_args {
160454916Storek 	char	*from;
160554916Storek 	char	*to;
160654916Storek };
160742441Smckusick /* ARGSUSED */
160842441Smckusick rename(p, uap, retval)
160945914Smckusick 	struct proc *p;
161054916Storek 	register struct rename_args *uap;
161142441Smckusick 	int *retval;
161242441Smckusick {
161337741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
161449735Smckusick 	struct nameidata fromnd, tond;
161537741Smckusick 	int error;
16167701Ssam 
161752322Smckusick 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
161852322Smckusick 		uap->from, p);
161952322Smckusick 	if (error = namei(&fromnd))
162047540Skarels 		return (error);
162149735Smckusick 	fvp = fromnd.ni_vp;
162252322Smckusick 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
162352322Smckusick 		UIO_USERSPACE, uap->to, p);
162452322Smckusick 	if (error = namei(&tond)) {
162552230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
162649735Smckusick 		vrele(fromnd.ni_dvp);
162742465Smckusick 		vrele(fvp);
162842465Smckusick 		goto out1;
162942465Smckusick 	}
163037741Smckusick 	tdvp = tond.ni_dvp;
163137741Smckusick 	tvp = tond.ni_vp;
163237741Smckusick 	if (tvp != NULL) {
163337741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
163439242Sbostic 			error = ENOTDIR;
163537741Smckusick 			goto out;
163637741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
163739242Sbostic 			error = EISDIR;
163837741Smckusick 			goto out;
16399167Ssam 		}
16409167Ssam 	}
164139286Smckusick 	if (fvp == tdvp)
164237741Smckusick 		error = EINVAL;
164339286Smckusick 	/*
164449735Smckusick 	 * If source is the same as the destination (that is the
164549735Smckusick 	 * same inode number with the same name in the same directory),
164639286Smckusick 	 * then there is nothing to do.
164739286Smckusick 	 */
164849735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
164952322Smckusick 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
165052322Smckusick 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
165152322Smckusick 	      fromnd.ni_cnd.cn_namelen))
165239286Smckusick 		error = -1;
165337741Smckusick out:
165442465Smckusick 	if (!error) {
165552192Smckusick 		LEASE_CHECK(tdvp, p, p->p_ucred, LEASE_WRITE);
165652192Smckusick 		if (fromnd.ni_dvp != tdvp)
165752192Smckusick 			LEASE_CHECK(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
165852192Smckusick 		if (tvp)
165952192Smckusick 			LEASE_CHECK(tvp, p, p->p_ucred, LEASE_WRITE);
166052230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
166152230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
166242465Smckusick 	} else {
166352230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
166443344Smckusick 		if (tdvp == tvp)
166543344Smckusick 			vrele(tdvp);
166643344Smckusick 		else
166743344Smckusick 			vput(tdvp);
166842465Smckusick 		if (tvp)
166942465Smckusick 			vput(tvp);
167052230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
167149735Smckusick 		vrele(fromnd.ni_dvp);
167242465Smckusick 		vrele(fvp);
16739167Ssam 	}
167449735Smckusick 	vrele(tond.ni_startdir);
167552322Smckusick 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
167637741Smckusick out1:
167749735Smckusick 	vrele(fromnd.ni_startdir);
167852322Smckusick 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
167939286Smckusick 	if (error == -1)
168047540Skarels 		return (0);
168147540Skarels 	return (error);
16827701Ssam }
16837701Ssam 
16847535Sroot /*
168549365Smckusick  * Mkdir system call.
168612756Ssam  */
168754916Storek struct mkdir_args {
168854916Storek 	char	*name;
168954916Storek 	int	dmode;
169054916Storek };
169142441Smckusick /* ARGSUSED */
169242441Smckusick mkdir(p, uap, retval)
169345914Smckusick 	struct proc *p;
169454916Storek 	register struct mkdir_args *uap;
169542441Smckusick 	int *retval;
169642441Smckusick {
169737741Smckusick 	register struct vnode *vp;
169837741Smckusick 	struct vattr vattr;
169937741Smckusick 	int error;
170047540Skarels 	struct nameidata nd;
170112756Ssam 
170252322Smckusick 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, uap->name, p);
170352322Smckusick 	if (error = namei(&nd))
170447540Skarels 		return (error);
170552322Smckusick 	vp = nd.ni_vp;
170637741Smckusick 	if (vp != NULL) {
170752322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
170852322Smckusick 		if (nd.ni_dvp == vp)
170952322Smckusick 			vrele(nd.ni_dvp);
171043344Smckusick 		else
171152322Smckusick 			vput(nd.ni_dvp);
171242465Smckusick 		vrele(vp);
171347540Skarels 		return (EEXIST);
171412756Ssam 	}
171541362Smckusick 	VATTR_NULL(&vattr);
171637741Smckusick 	vattr.va_type = VDIR;
171745914Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask;
171852322Smckusick 	LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
171952322Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
172038145Smckusick 	if (!error)
172152322Smckusick 		vput(nd.ni_vp);
172247540Skarels 	return (error);
172312756Ssam }
172412756Ssam 
172512756Ssam /*
172612756Ssam  * Rmdir system call.
172712756Ssam  */
172854916Storek struct rmdir_args {
172954916Storek 	char	*name;
173054916Storek };
173142441Smckusick /* ARGSUSED */
173242441Smckusick rmdir(p, uap, retval)
173345914Smckusick 	struct proc *p;
173454916Storek 	struct rmdir_args *uap;
173542441Smckusick 	int *retval;
173612756Ssam {
173737741Smckusick 	register struct vnode *vp;
173837741Smckusick 	int error;
173947540Skarels 	struct nameidata nd;
174012756Ssam 
174152322Smckusick 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE, uap->name, p);
174252322Smckusick 	if (error = namei(&nd))
174347540Skarels 		return (error);
174452322Smckusick 	vp = nd.ni_vp;
174537741Smckusick 	if (vp->v_type != VDIR) {
174637741Smckusick 		error = ENOTDIR;
174712756Ssam 		goto out;
174812756Ssam 	}
174912756Ssam 	/*
175037741Smckusick 	 * No rmdir "." please.
175112756Ssam 	 */
175252322Smckusick 	if (nd.ni_dvp == vp) {
175337741Smckusick 		error = EINVAL;
175412756Ssam 		goto out;
175512756Ssam 	}
175612756Ssam 	/*
175749365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
175812756Ssam 	 */
175937741Smckusick 	if (vp->v_flag & VROOT)
176037741Smckusick 		error = EBUSY;
176112756Ssam out:
176242465Smckusick 	if (!error) {
176352322Smckusick 		LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
176452192Smckusick 		LEASE_CHECK(vp, p, p->p_ucred, LEASE_WRITE);
176552322Smckusick 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
176642465Smckusick 	} else {
176752322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
176852322Smckusick 		if (nd.ni_dvp == vp)
176952322Smckusick 			vrele(nd.ni_dvp);
177043344Smckusick 		else
177152322Smckusick 			vput(nd.ni_dvp);
177242465Smckusick 		vput(vp);
177342465Smckusick 	}
177447540Skarels 	return (error);
177512756Ssam }
177612756Ssam 
177754620Smckusick #ifdef COMPAT_43
177837741Smckusick /*
177949365Smckusick  * Read a block of directory entries in a file system independent format.
178037741Smckusick  */
178154916Storek struct ogetdirentries_args {
178254916Storek 	int	fd;
178354916Storek 	char	*buf;
178454916Storek 	unsigned count;
178554916Storek 	long	*basep;
178654916Storek };
178754620Smckusick ogetdirentries(p, uap, retval)
178854620Smckusick 	struct proc *p;
178954916Storek 	register struct ogetdirentries_args *uap;
179054620Smckusick 	int *retval;
179154620Smckusick {
179254620Smckusick 	register struct vnode *vp;
179354620Smckusick 	struct file *fp;
179454620Smckusick 	struct uio auio, kuio;
179554620Smckusick 	struct iovec aiov, kiov;
179654620Smckusick 	struct dirent *dp, *edp;
179754620Smckusick 	caddr_t dirbuf;
179854620Smckusick 	int error, readcnt;
179954969Smckusick 	long loff;
180054620Smckusick 
180154620Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
180254620Smckusick 		return (error);
180354620Smckusick 	if ((fp->f_flag & FREAD) == 0)
180454620Smckusick 		return (EBADF);
180554620Smckusick 	vp = (struct vnode *)fp->f_data;
180654620Smckusick 	if (vp->v_type != VDIR)
180754620Smckusick 		return (EINVAL);
180854620Smckusick 	aiov.iov_base = uap->buf;
180954620Smckusick 	aiov.iov_len = uap->count;
181054620Smckusick 	auio.uio_iov = &aiov;
181154620Smckusick 	auio.uio_iovcnt = 1;
181254620Smckusick 	auio.uio_rw = UIO_READ;
181354620Smckusick 	auio.uio_segflg = UIO_USERSPACE;
181454620Smckusick 	auio.uio_procp = p;
181554620Smckusick 	auio.uio_resid = uap->count;
181654620Smckusick 	VOP_LOCK(vp);
181754969Smckusick 	loff = auio.uio_offset = fp->f_offset;
181854620Smckusick #	if (BYTE_ORDER != LITTLE_ENDIAN)
181954620Smckusick 		if (vp->v_mount->mnt_maxsymlinklen <= 0)
182054620Smckusick 			error = VOP_READDIR(vp, &auio, fp->f_cred);
182154620Smckusick 		else
182254620Smckusick #	endif
182354620Smckusick 	{
182454620Smckusick 		kuio = auio;
182554620Smckusick 		kuio.uio_iov = &kiov;
182654620Smckusick 		kuio.uio_segflg = UIO_SYSSPACE;
182754620Smckusick 		kiov.iov_len = uap->count;
182854620Smckusick 		MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK);
182954620Smckusick 		kiov.iov_base = dirbuf;
183054620Smckusick 		error = VOP_READDIR(vp, &kuio, fp->f_cred);
183154620Smckusick 		if (error == 0) {
183254620Smckusick 			readcnt = uap->count - kuio.uio_resid;
183354620Smckusick 			edp = (struct dirent *)&dirbuf[readcnt];
183454620Smckusick 			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
183554620Smckusick #				if (BYTE_ORDER == LITTLE_ENDIAN)
183654969Smckusick 					/*
1837*55009Smckusick 					 * The expected low byte of
1838*55009Smckusick 					 * dp->d_namlen is our dp->d_type.
1839*55009Smckusick 					 * The high MBZ byte of dp->d_namlen
1840*55009Smckusick 					 * is our dp->d_namlen.
184154969Smckusick 					 */
1842*55009Smckusick 					dp->d_type = dp->d_namlen;
1843*55009Smckusick 					dp->d_namlen = 0;
1844*55009Smckusick #				else
1845*55009Smckusick 					/*
1846*55009Smckusick 					 * The dp->d_type is the high byte
1847*55009Smckusick 					 * of the expected dp->d_namlen,
1848*55009Smckusick 					 * so must be zero'ed.
1849*55009Smckusick 					 */
1850*55009Smckusick 					dp->d_type = 0;
185154620Smckusick #				endif
185254620Smckusick 				if (dp->d_reclen > 0) {
185354620Smckusick 					dp = (struct dirent *)
185454620Smckusick 					    ((char *)dp + dp->d_reclen);
185554620Smckusick 				} else {
185654620Smckusick 					error = EIO;
185754620Smckusick 					break;
185854620Smckusick 				}
185954620Smckusick 			}
186054620Smckusick 			if (dp >= edp)
186154620Smckusick 				error = uiomove(dirbuf, readcnt, &auio);
186254620Smckusick 		}
186354620Smckusick 		FREE(dirbuf, M_TEMP);
186454620Smckusick 	}
186554620Smckusick 	fp->f_offset = auio.uio_offset;
186654620Smckusick 	VOP_UNLOCK(vp);
186754620Smckusick 	if (error)
186854620Smckusick 		return (error);
186954969Smckusick 	error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
187054620Smckusick 	*retval = uap->count - auio.uio_resid;
187154620Smckusick 	return (error);
187254620Smckusick }
187354620Smckusick #endif
187454620Smckusick 
187554620Smckusick /*
187654620Smckusick  * Read a block of directory entries in a file system independent format.
187754620Smckusick  */
187854916Storek struct getdirentries_args {
187954916Storek 	int	fd;
188054916Storek 	char	*buf;
188154916Storek 	unsigned count;
188254916Storek 	long	*basep;
188354916Storek };
188442441Smckusick getdirentries(p, uap, retval)
188545914Smckusick 	struct proc *p;
188654916Storek 	register struct getdirentries_args *uap;
188742441Smckusick 	int *retval;
188842441Smckusick {
188939592Smckusick 	register struct vnode *vp;
189016540Ssam 	struct file *fp;
189137741Smckusick 	struct uio auio;
189237741Smckusick 	struct iovec aiov;
189354969Smckusick 	long loff;
189454441Smckusick 	int error;
189512756Ssam 
189645914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
189747540Skarels 		return (error);
189837741Smckusick 	if ((fp->f_flag & FREAD) == 0)
189947540Skarels 		return (EBADF);
190039592Smckusick 	vp = (struct vnode *)fp->f_data;
190139592Smckusick 	if (vp->v_type != VDIR)
190247540Skarels 		return (EINVAL);
190337741Smckusick 	aiov.iov_base = uap->buf;
190437741Smckusick 	aiov.iov_len = uap->count;
190537741Smckusick 	auio.uio_iov = &aiov;
190637741Smckusick 	auio.uio_iovcnt = 1;
190737741Smckusick 	auio.uio_rw = UIO_READ;
190837741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
190948026Smckusick 	auio.uio_procp = p;
191037741Smckusick 	auio.uio_resid = uap->count;
191139592Smckusick 	VOP_LOCK(vp);
191254969Smckusick 	loff = auio.uio_offset = fp->f_offset;
191354441Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred);
191439592Smckusick 	fp->f_offset = auio.uio_offset;
191539592Smckusick 	VOP_UNLOCK(vp);
191639592Smckusick 	if (error)
191747540Skarels 		return (error);
191854969Smckusick 	error = copyout((caddr_t)&loff, (caddr_t)uap->basep, sizeof(long));
191942441Smckusick 	*retval = uap->count - auio.uio_resid;
192047540Skarels 	return (error);
192112756Ssam }
192212756Ssam 
192312756Ssam /*
192449365Smckusick  * Set the mode mask for creation of filesystem nodes.
192512756Ssam  */
192654916Storek struct umask_args {
192754916Storek 	int	mask;
192854916Storek };
192954916Storek mode_t				/* XXX */
193042441Smckusick umask(p, uap, retval)
193145914Smckusick 	struct proc *p;
193254916Storek 	struct umask_args *uap;
193342441Smckusick 	int *retval;
193412756Ssam {
193545914Smckusick 	register struct filedesc *fdp = p->p_fd;
193612756Ssam 
193745914Smckusick 	*retval = fdp->fd_cmask;
193845914Smckusick 	fdp->fd_cmask = uap->mask & 07777;
193947540Skarels 	return (0);
194012756Ssam }
194137741Smckusick 
194239566Smarc /*
194339566Smarc  * Void all references to file by ripping underlying filesystem
194439566Smarc  * away from vnode.
194539566Smarc  */
194654916Storek struct revoke_args {
194754916Storek 	char	*fname;
194854916Storek };
194942441Smckusick /* ARGSUSED */
195042441Smckusick revoke(p, uap, retval)
195145914Smckusick 	struct proc *p;
195254916Storek 	register struct revoke_args *uap;
195342441Smckusick 	int *retval;
195442441Smckusick {
195539566Smarc 	register struct vnode *vp;
195639566Smarc 	struct vattr vattr;
195739566Smarc 	int error;
195847540Skarels 	struct nameidata nd;
195939566Smarc 
196052322Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
196152322Smckusick 	if (error = namei(&nd))
196247540Skarels 		return (error);
196352322Smckusick 	vp = nd.ni_vp;
196439566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
196539566Smarc 		error = EINVAL;
196639566Smarc 		goto out;
196739566Smarc 	}
196848026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
196939566Smarc 		goto out;
197047540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
197147540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
197239566Smarc 		goto out;
197339805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
197439632Smckusick 		vgoneall(vp);
197539566Smarc out:
197639566Smarc 	vrele(vp);
197747540Skarels 	return (error);
197839566Smarc }
197939566Smarc 
198049365Smckusick /*
198149365Smckusick  * Convert a user file descriptor to a kernel file entry.
198249365Smckusick  */
198345914Smckusick getvnode(fdp, fdes, fpp)
198445914Smckusick 	struct filedesc *fdp;
198537741Smckusick 	struct file **fpp;
198637741Smckusick 	int fdes;
198737741Smckusick {
198837741Smckusick 	struct file *fp;
198937741Smckusick 
199047540Skarels 	if ((unsigned)fdes >= fdp->fd_nfiles ||
199147688Skarels 	    (fp = fdp->fd_ofiles[fdes]) == NULL)
199237741Smckusick 		return (EBADF);
199337741Smckusick 	if (fp->f_type != DTYPE_VNODE)
199437741Smckusick 		return (EINVAL);
199537741Smckusick 	*fpp = fp;
199637741Smckusick 	return (0);
199737741Smckusick }
1998