xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 45922)
123405Smckusick /*
237741Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337741Smckusick  * All rights reserved.
423405Smckusick  *
544459Sbostic  * %sccs.include.redist.c%
637741Smckusick  *
7*45922Smckusick  *	@(#)vfs_syscalls.c	7.63 (Berkeley) 01/10/91
823405Smckusick  */
937Sbill 
1017101Sbloom #include "param.h"
1117101Sbloom #include "systm.h"
1244407Skarels #include "user.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"
2237Sbill 
2343450Smckusick #define RETURN(val) {if (u.u_spare[0] != 0) panic("lock count"); return (val);}
2439797Smckusick 
2537741Smckusick /*
2637741Smckusick  * Virtual File System System Calls
2737741Smckusick  */
2812756Ssam 
299167Ssam /*
3037741Smckusick  * mount system call
319167Ssam  */
3242441Smckusick /* ARGSUSED */
3342441Smckusick mount(p, uap, retval)
3445914Smckusick 	struct proc *p;
3542441Smckusick 	register struct args {
3637741Smckusick 		int	type;
3737741Smckusick 		char	*dir;
3837741Smckusick 		int	flags;
3937741Smckusick 		caddr_t	data;
4042441Smckusick 	} *uap;
4142441Smckusick 	int *retval;
4242441Smckusick {
4342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
4439335Smckusick 	register struct vnode *vp;
4539335Smckusick 	register struct mount *mp;
4640111Smckusick 	int error, flag;
476254Sroot 
4837741Smckusick 	/*
4937741Smckusick 	 * Must be super user
5037741Smckusick 	 */
5142441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
5237741Smckusick 		RETURN (error);
5337741Smckusick 	/*
5437741Smckusick 	 * Get vnode to be covered
5537741Smckusick 	 */
5637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
5737741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
5837741Smckusick 	ndp->ni_dirp = uap->dir;
5937741Smckusick 	if (error = namei(ndp))
6037741Smckusick 		RETURN (error);
6137741Smckusick 	vp = ndp->ni_vp;
6241400Smckusick 	if (uap->flags & MNT_UPDATE) {
6339335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
6439335Smckusick 			vput(vp);
6539335Smckusick 			RETURN (EINVAL);
6639335Smckusick 		}
6739335Smckusick 		mp = vp->v_mount;
6839335Smckusick 		/*
6939335Smckusick 		 * We allow going from read-only to read-write,
7039335Smckusick 		 * but not from read-write to read-only.
7139335Smckusick 		 */
7241400Smckusick 		if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
7341400Smckusick 		    (uap->flags & MNT_RDONLY) != 0) {
7439335Smckusick 			vput(vp);
7539335Smckusick 			RETURN (EOPNOTSUPP);	/* Needs translation */
7639335Smckusick 		}
7741400Smckusick 		flag = mp->mnt_flag;
7841400Smckusick 		mp->mnt_flag |= MNT_UPDATE;
7939335Smckusick 		VOP_UNLOCK(vp);
8039335Smckusick 		goto update;
8139335Smckusick 	}
8239665Smckusick 	vinvalbuf(vp, 1);
8339805Smckusick 	if (vp->v_usecount != 1) {
8437741Smckusick 		vput(vp);
8537741Smckusick 		RETURN (EBUSY);
8637741Smckusick 	}
8737741Smckusick 	if (vp->v_type != VDIR) {
8837741Smckusick 		vput(vp);
8937741Smckusick 		RETURN (ENOTDIR);
9037741Smckusick 	}
9139741Smckusick 	if ((unsigned long)uap->type > MOUNT_MAXTYPE ||
9237741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
9337741Smckusick 		vput(vp);
9437741Smckusick 		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);
10241400Smckusick 	mp->mnt_op = vfssw[uap->type];
10341400Smckusick 	mp->mnt_flag = 0;
10441400Smckusick 	mp->mnt_exroot = 0;
10541400Smckusick 	mp->mnt_mounth = NULLVP;
10639335Smckusick 	if (error = vfs_lock(mp)) {
10739335Smckusick 		free((caddr_t)mp, M_MOUNT);
10839335Smckusick 		vput(vp);
10939335Smckusick 		RETURN (error);
11039335Smckusick 	}
11139335Smckusick 	if (vp->v_mountedhere != (struct mount *)0) {
11239335Smckusick 		vfs_unlock(mp);
11339335Smckusick 		free((caddr_t)mp, M_MOUNT);
11439335Smckusick 		vput(vp);
11539335Smckusick 		RETURN (EBUSY);
11639335Smckusick 	}
11739335Smckusick 	vp->v_mountedhere = mp;
11841400Smckusick 	mp->mnt_vnodecovered = vp;
11939335Smckusick update:
12039335Smckusick 	/*
12139335Smckusick 	 * Set the mount level flags.
12239335Smckusick 	 */
12341400Smckusick 	if (uap->flags & MNT_RDONLY)
12441400Smckusick 		mp->mnt_flag |= MNT_RDONLY;
12539335Smckusick 	else
12641400Smckusick 		mp->mnt_flag &= ~MNT_RDONLY;
12741400Smckusick 	if (uap->flags & MNT_NOSUID)
12841400Smckusick 		mp->mnt_flag |= MNT_NOSUID;
12939335Smckusick 	else
13041400Smckusick 		mp->mnt_flag &= ~MNT_NOSUID;
13141400Smckusick 	if (uap->flags & MNT_NOEXEC)
13241400Smckusick 		mp->mnt_flag |= MNT_NOEXEC;
13339335Smckusick 	else
13441400Smckusick 		mp->mnt_flag &= ~MNT_NOEXEC;
13541400Smckusick 	if (uap->flags & MNT_NODEV)
13641400Smckusick 		mp->mnt_flag |= MNT_NODEV;
13739335Smckusick 	else
13841400Smckusick 		mp->mnt_flag &= ~MNT_NODEV;
13941400Smckusick 	if (uap->flags & MNT_SYNCHRONOUS)
14041400Smckusick 		mp->mnt_flag |= MNT_SYNCHRONOUS;
14139335Smckusick 	else
14241400Smckusick 		mp->mnt_flag &= ~MNT_SYNCHRONOUS;
14339335Smckusick 	/*
14439335Smckusick 	 * Mount the filesystem.
14539335Smckusick 	 */
14639335Smckusick 	error = VFS_MOUNT(mp, uap->dir, uap->data, ndp);
14741400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
14841400Smckusick 		mp->mnt_flag &= ~MNT_UPDATE;
14939335Smckusick 		vrele(vp);
15040111Smckusick 		if (error)
15141400Smckusick 			mp->mnt_flag = flag;
15239335Smckusick 		RETURN (error);
15339335Smckusick 	}
15440110Smckusick 	/*
15540110Smckusick 	 * Put the new filesystem on the mount list after root.
15640110Smckusick 	 */
15741400Smckusick 	mp->mnt_next = rootfs->mnt_next;
15841400Smckusick 	mp->mnt_prev = rootfs;
15941400Smckusick 	rootfs->mnt_next = mp;
16041400Smckusick 	mp->mnt_next->mnt_prev = mp;
16137741Smckusick 	cache_purge(vp);
16237741Smckusick 	if (!error) {
16339335Smckusick 		VOP_UNLOCK(vp);
16437741Smckusick 		vfs_unlock(mp);
16539044Smckusick 		error = VFS_START(mp, 0);
16637741Smckusick 	} else {
16737741Smckusick 		vfs_remove(mp);
16837741Smckusick 		free((caddr_t)mp, M_MOUNT);
16939335Smckusick 		vput(vp);
17037741Smckusick 	}
17137741Smckusick 	RETURN (error);
1726254Sroot }
1736254Sroot 
1749167Ssam /*
17537741Smckusick  * Unmount system call.
17637741Smckusick  *
17737741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
17837741Smckusick  * not special file (as before).
1799167Ssam  */
18042441Smckusick /* ARGSUSED */
18142441Smckusick unmount(p, uap, retval)
18245914Smckusick 	struct proc *p;
18342441Smckusick 	register struct args {
18437741Smckusick 		char	*pathp;
18537741Smckusick 		int	flags;
18642441Smckusick 	} *uap;
18742441Smckusick 	int *retval;
18842441Smckusick {
18937741Smckusick 	register struct vnode *vp;
19042441Smckusick 	register struct nameidata *ndp = &u.u_nd;
19139356Smckusick 	struct mount *mp;
19237741Smckusick 	int error;
1936254Sroot 
19437741Smckusick 	/*
19537741Smckusick 	 * Must be super user
19637741Smckusick 	 */
19742441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
19837741Smckusick 		RETURN (error);
19937741Smckusick 
20037741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
20137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
20237741Smckusick 	ndp->ni_dirp = uap->pathp;
20337741Smckusick 	if (error = namei(ndp))
20437741Smckusick 		RETURN (error);
20537741Smckusick 	vp = ndp->ni_vp;
20637741Smckusick 	/*
20737741Smckusick 	 * Must be the root of the filesystem
20837741Smckusick 	 */
20937741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
21037741Smckusick 		vput(vp);
21137741Smckusick 		RETURN (EINVAL);
21237741Smckusick 	}
21337741Smckusick 	mp = vp->v_mount;
21437741Smckusick 	vput(vp);
21539356Smckusick 	RETURN (dounmount(mp, uap->flags));
21639356Smckusick }
21739356Smckusick 
21839356Smckusick /*
21939356Smckusick  * Do an unmount.
22039356Smckusick  */
22139356Smckusick dounmount(mp, flags)
22239356Smckusick 	register struct mount *mp;
22339356Smckusick 	int flags;
22439356Smckusick {
22539356Smckusick 	struct vnode *coveredvp;
22639356Smckusick 	int error;
22739356Smckusick 
22841400Smckusick 	coveredvp = mp->mnt_vnodecovered;
22941298Smckusick 	if (vfs_busy(mp))
23041298Smckusick 		return (EBUSY);
23141400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
23237741Smckusick 	if (error = vfs_lock(mp))
23339356Smckusick 		return (error);
23437741Smckusick 
235*45922Smckusick #ifdef NVM
23645738Smckusick 	vnode_pager_umount(mp);	/* release cached vnodes */
237*45922Smckusick #else
238*45922Smckusick 	xumount(mp);		/* remove unused sticky files from text table */
239*45922Smckusick #endif
24037741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
24141676Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE))
24241676Smckusick 		error = VFS_UNMOUNT(mp, flags);
24341400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
24441298Smckusick 	vfs_unbusy(mp);
24537741Smckusick 	if (error) {
24637741Smckusick 		vfs_unlock(mp);
24737741Smckusick 	} else {
24837741Smckusick 		vrele(coveredvp);
24937741Smckusick 		vfs_remove(mp);
25037741Smckusick 		free((caddr_t)mp, M_MOUNT);
25137741Smckusick 	}
25239356Smckusick 	return (error);
2536254Sroot }
2546254Sroot 
2559167Ssam /*
25637741Smckusick  * Sync system call.
25737741Smckusick  * Sync each mounted filesystem.
2589167Ssam  */
25939491Smckusick /* ARGSUSED */
26042441Smckusick sync(p, uap, retval)
26145914Smckusick 	struct proc *p;
26242441Smckusick 	struct 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)) {
27637741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
27741298Smckusick 			omp = mp;
27841400Smckusick 			mp = mp->mnt_next;
27941298Smckusick 			vfs_unbusy(omp);
28041298Smckusick 		} else
28141400Smckusick 			mp = mp->mnt_next;
28237741Smckusick 	} while (mp != rootfs);
28337741Smckusick }
28437741Smckusick 
28537741Smckusick /*
28641298Smckusick  * operate on filesystem quotas
28741298Smckusick  */
28842441Smckusick /* ARGSUSED */
28942441Smckusick quotactl(p, uap, retval)
29045914Smckusick 	struct proc *p;
29142441Smckusick 	register struct args {
29241298Smckusick 		char *path;
29341298Smckusick 		int cmd;
29441298Smckusick 		int uid;
29541298Smckusick 		caddr_t arg;
29642441Smckusick 	} *uap;
29742441Smckusick 	int *retval;
29842441Smckusick {
29941298Smckusick 	register struct mount *mp;
30042441Smckusick 	register struct nameidata *ndp = &u.u_nd;
30141298Smckusick 	int error;
30241298Smckusick 
30341298Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
30441298Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
30541298Smckusick 	ndp->ni_dirp = uap->path;
30641298Smckusick 	if (error = namei(ndp))
30741298Smckusick 		RETURN (error);
30841298Smckusick 	mp = ndp->ni_vp->v_mount;
30941298Smckusick 	vrele(ndp->ni_vp);
31041298Smckusick 	RETURN (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg));
31141298Smckusick }
31241298Smckusick 
31341298Smckusick /*
31437741Smckusick  * get filesystem statistics
31537741Smckusick  */
31642441Smckusick /* ARGSUSED */
31742441Smckusick statfs(p, uap, retval)
31845914Smckusick 	struct proc *p;
31942441Smckusick 	register struct args {
32037741Smckusick 		char *path;
32137741Smckusick 		struct statfs *buf;
32242441Smckusick 	} *uap;
32342441Smckusick 	int *retval;
32442441Smckusick {
32539464Smckusick 	register struct mount *mp;
32642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
32740343Smckusick 	register struct statfs *sp;
32837741Smckusick 	int error;
32937741Smckusick 
33039544Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
33137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
33237741Smckusick 	ndp->ni_dirp = uap->path;
33337741Smckusick 	if (error = namei(ndp))
33437741Smckusick 		RETURN (error);
33539544Smckusick 	mp = ndp->ni_vp->v_mount;
33641400Smckusick 	sp = &mp->mnt_stat;
33739544Smckusick 	vrele(ndp->ni_vp);
33840343Smckusick 	if (error = VFS_STATFS(mp, sp))
33939544Smckusick 		RETURN (error);
34041400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
34140343Smckusick 	RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
34237741Smckusick }
34337741Smckusick 
34442441Smckusick /*
34542441Smckusick  * get filesystem statistics
34642441Smckusick  */
34742441Smckusick /* ARGSUSED */
34842441Smckusick fstatfs(p, uap, retval)
34945914Smckusick 	struct proc *p;
35042441Smckusick 	register struct args {
35137741Smckusick 		int fd;
35237741Smckusick 		struct statfs *buf;
35342441Smckusick 	} *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))
36237741Smckusick 		RETURN (error);
36339464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
36441400Smckusick 	sp = &mp->mnt_stat;
36540343Smckusick 	if (error = VFS_STATFS(mp, sp))
36637741Smckusick 		RETURN (error);
36741400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
36840343Smckusick 	RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
36937741Smckusick }
37037741Smckusick 
37137741Smckusick /*
37238270Smckusick  * get statistics on all filesystems
37338270Smckusick  */
37442441Smckusick getfsstat(p, uap, retval)
37545914Smckusick 	struct proc *p;
37642441Smckusick 	register struct args {
37738270Smckusick 		struct statfs *buf;
37838270Smckusick 		long bufsize;
37940343Smckusick 		int flags;
38042441Smckusick 	} *uap;
38142441Smckusick 	int *retval;
38242441Smckusick {
38338270Smckusick 	register struct mount *mp;
38440343Smckusick 	register struct statfs *sp;
38539606Smckusick 	caddr_t sfsp;
38638270Smckusick 	long count, maxcount, error;
38738270Smckusick 
38838270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
38939606Smckusick 	sfsp = (caddr_t)uap->buf;
39038270Smckusick 	mp = rootfs;
39138270Smckusick 	count = 0;
39238270Smckusick 	do {
39341400Smckusick 		if (sfsp && count < maxcount &&
39441400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
39541400Smckusick 			sp = &mp->mnt_stat;
39640343Smckusick 			/*
39740343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
39840343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
39940343Smckusick 			 */
40040343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
40140343Smckusick 			    (uap->flags & MNT_WAIT)) &&
40240343Smckusick 			    (error = VFS_STATFS(mp, sp))) {
40341400Smckusick 				mp = mp->mnt_prev;
40439607Smckusick 				continue;
40539607Smckusick 			}
40641400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
40740343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
40839606Smckusick 				RETURN (error);
40940343Smckusick 			sfsp += sizeof(*sp);
41038270Smckusick 		}
41139606Smckusick 		count++;
41241400Smckusick 		mp = mp->mnt_prev;
41338270Smckusick 	} while (mp != rootfs);
41438270Smckusick 	if (sfsp && count > maxcount)
41542441Smckusick 		*retval = maxcount;
41638270Smckusick 	else
41742441Smckusick 		*retval = count;
41838270Smckusick 	RETURN (0);
41938270Smckusick }
42038270Smckusick 
42138270Smckusick /*
42238259Smckusick  * Change current working directory to a given file descriptor.
42338259Smckusick  */
42442441Smckusick /* ARGSUSED */
42542441Smckusick fchdir(p, uap, retval)
42645914Smckusick 	struct proc *p;
42742441Smckusick 	struct args {
42842441Smckusick 		int	fd;
42942441Smckusick 	} *uap;
43042441Smckusick 	int *retval;
43138259Smckusick {
43242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
43345914Smckusick 	register struct filedesc *fdp = p->p_fd;
43438259Smckusick 	register struct vnode *vp;
43538259Smckusick 	struct file *fp;
43638259Smckusick 	int error;
43738259Smckusick 
43845914Smckusick 	if (error = getvnode(fdp, uap->fd, &fp))
43938259Smckusick 		RETURN (error);
44038259Smckusick 	vp = (struct vnode *)fp->f_data;
44138259Smckusick 	VOP_LOCK(vp);
44238259Smckusick 	if (vp->v_type != VDIR)
44338259Smckusick 		error = ENOTDIR;
44438259Smckusick 	else
44542441Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
44638259Smckusick 	VOP_UNLOCK(vp);
44739860Smckusick 	if (error)
44839860Smckusick 		RETURN (error);
44939860Smckusick 	VREF(vp);
45045914Smckusick 	vrele(fdp->fd_cdir);
45145914Smckusick 	fdp->fd_cdir = vp;
45239860Smckusick 	RETURN (0);
45338259Smckusick }
45438259Smckusick 
45538259Smckusick /*
45637741Smckusick  * Change current working directory (``.'').
45737741Smckusick  */
45842441Smckusick /* ARGSUSED */
45942441Smckusick chdir(p, uap, retval)
46045914Smckusick 	struct proc *p;
46142441Smckusick 	struct args {
46242441Smckusick 		char	*fname;
46342441Smckusick 	} *uap;
46442441Smckusick 	int *retval;
46537741Smckusick {
46642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
46745914Smckusick 	register struct filedesc *fdp = p->p_fd;
46837741Smckusick 	int error;
4696254Sroot 
47037741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
47116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
47216694Smckusick 	ndp->ni_dirp = uap->fname;
47337741Smckusick 	if (error = chdirec(ndp))
47437741Smckusick 		RETURN (error);
47545914Smckusick 	vrele(fdp->fd_cdir);
47645914Smckusick 	fdp->fd_cdir = ndp->ni_vp;
47737741Smckusick 	RETURN (0);
47837741Smckusick }
4796254Sroot 
48037741Smckusick /*
48137741Smckusick  * Change notion of root (``/'') directory.
48237741Smckusick  */
48342441Smckusick /* ARGSUSED */
48442441Smckusick chroot(p, uap, retval)
48545914Smckusick 	struct proc *p;
48642441Smckusick 	struct args {
48742441Smckusick 		char	*fname;
48842441Smckusick 	} *uap;
48942441Smckusick 	int *retval;
49037741Smckusick {
49142441Smckusick 	register struct nameidata *ndp = &u.u_nd;
49245914Smckusick 	register struct filedesc *fdp = p->p_fd;
49337741Smckusick 	int error;
49437741Smckusick 
49542441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
49637741Smckusick 		RETURN (error);
49737741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
49837741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
49937741Smckusick 	ndp->ni_dirp = uap->fname;
50037741Smckusick 	if (error = chdirec(ndp))
50137741Smckusick 		RETURN (error);
50245914Smckusick 	if (fdp->fd_rdir != NULL)
50345914Smckusick 		vrele(fdp->fd_rdir);
50445914Smckusick 	fdp->fd_rdir = ndp->ni_vp;
50537741Smckusick 	RETURN (0);
5066254Sroot }
5076254Sroot 
50837Sbill /*
50937741Smckusick  * Common routine for chroot and chdir.
51037741Smckusick  */
51137741Smckusick chdirec(ndp)
51237741Smckusick 	register struct nameidata *ndp;
51337741Smckusick {
51437741Smckusick 	struct vnode *vp;
51537741Smckusick 	int error;
51637741Smckusick 
51737741Smckusick 	if (error = namei(ndp))
51837741Smckusick 		return (error);
51937741Smckusick 	vp = ndp->ni_vp;
52037741Smckusick 	if (vp->v_type != VDIR)
52137741Smckusick 		error = ENOTDIR;
52237741Smckusick 	else
52338399Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
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  */
53542441Smckusick open(p, uap, retval)
53645914Smckusick 	struct proc *p;
53742441Smckusick 	register struct args {
5386254Sroot 		char	*fname;
5397701Ssam 		int	mode;
54012756Ssam 		int	crtmode;
54142441Smckusick 	} *uap;
54242441Smckusick 	int *retval;
5436254Sroot {
54442441Smckusick 	struct nameidata *ndp = &u.u_nd;
54545914Smckusick 	register struct filedesc *fdp = p->p_fd;
54642441Smckusick 	register struct file *fp;
54737741Smckusick 	int fmode, cmode;
54837741Smckusick 	struct file *nfp;
54937741Smckusick 	int indx, error;
55037741Smckusick 	extern struct fileops vnops;
5516254Sroot 
55245914Smckusick 	if (error = falloc(p, &nfp, &indx))
55342441Smckusick 		RETURN (error);
55437741Smckusick 	fp = nfp;
55542441Smckusick 	fmode = uap->mode - FOPEN;
55645914Smckusick 	cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX;
55742441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
55842441Smckusick 	ndp->ni_dirp = uap->fname;
55945202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
56042441Smckusick 	if (error = vn_open(ndp, fmode, cmode)) {
56137741Smckusick 		crfree(fp->f_cred);
56237741Smckusick 		fp->f_count--;
56343405Smckusick 		if (error == ENODEV &&		/* XXX from fdopen */
56445202Smckusick 		    p->p_dupfd >= 0 &&
56545914Smckusick 		    (error = dupfdopen(fdp, indx, p->p_dupfd, fmode)) == 0) {
56642441Smckusick 			*retval = indx;
56742441Smckusick 			RETURN (0);
56842441Smckusick 		}
56940884Smckusick 		if (error == ERESTART)
57040884Smckusick 			error = EINTR;
57145914Smckusick 		OFILE(fdp, indx) = NULL;
57242441Smckusick 		RETURN (error);
57312756Ssam 	}
57437741Smckusick 	fp->f_flag = fmode & FMASK;
57537741Smckusick 	fp->f_type = DTYPE_VNODE;
57637741Smckusick 	fp->f_ops = &vnops;
57737741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
57842441Smckusick 	*retval = indx;
57942441Smckusick 	RETURN (0);
5806254Sroot }
5816254Sroot 
58242955Smckusick #ifdef COMPAT_43
5836254Sroot /*
58442441Smckusick  * Creat system call.
5856254Sroot  */
58642955Smckusick ocreat(p, uap, retval)
58742441Smckusick 	struct proc *p;
58842441Smckusick 	register struct args {
58942441Smckusick 		char	*fname;
59042441Smckusick 		int	fmode;
59142441Smckusick 	} *uap;
59242441Smckusick 	int *retval;
5936254Sroot {
59442441Smckusick 	struct args {
5956254Sroot 		char	*fname;
59642441Smckusick 		int	mode;
59742441Smckusick 		int	crtmode;
59842441Smckusick 	} openuap;
59942441Smckusick 
60042441Smckusick 	openuap.fname = uap->fname;
60142441Smckusick 	openuap.crtmode = uap->fmode;
60242441Smckusick 	openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
60342441Smckusick 	RETURN (open(p, &openuap, retval));
60442441Smckusick }
60542955Smckusick #endif /* COMPAT_43 */
60642441Smckusick 
60742441Smckusick /*
60842441Smckusick  * Mknod system call
60942441Smckusick  */
61042441Smckusick /* ARGSUSED */
61142441Smckusick mknod(p, uap, retval)
61245914Smckusick 	struct proc *p;
61342441Smckusick 	register struct args {
61442441Smckusick 		char	*fname;
6156254Sroot 		int	fmode;
6166254Sroot 		int	dev;
61742441Smckusick 	} *uap;
61842441Smckusick 	int *retval;
61942441Smckusick {
62042441Smckusick 	register struct nameidata *ndp = &u.u_nd;
62137741Smckusick 	register struct vnode *vp;
62237741Smckusick 	struct vattr vattr;
62337741Smckusick 	int error;
6246254Sroot 
62542441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
62637741Smckusick 		RETURN (error);
62737741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
62816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
62916694Smckusick 	ndp->ni_dirp = uap->fname;
63037741Smckusick 	if (error = namei(ndp))
63137741Smckusick 		RETURN (error);
63237741Smckusick 	vp = ndp->ni_vp;
63337741Smckusick 	if (vp != NULL) {
63437741Smckusick 		error = EEXIST;
63512756Ssam 		goto out;
6366254Sroot 	}
63741362Smckusick 	VATTR_NULL(&vattr);
63840635Smckusick 	switch (uap->fmode & S_IFMT) {
63912756Ssam 
64040635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
64137741Smckusick 		vattr.va_type = VBAD;
64237741Smckusick 		break;
64340635Smckusick 	case S_IFCHR:
64437741Smckusick 		vattr.va_type = VCHR;
64537741Smckusick 		break;
64640635Smckusick 	case S_IFBLK:
64737741Smckusick 		vattr.va_type = VBLK;
64837741Smckusick 		break;
64937741Smckusick 	default:
65037741Smckusick 		error = EINVAL;
65137741Smckusick 		goto out;
6526254Sroot 	}
65345914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
65437741Smckusick 	vattr.va_rdev = uap->dev;
6556254Sroot out:
65642465Smckusick 	if (!error) {
65742465Smckusick 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
65842465Smckusick 	} else {
65937741Smckusick 		VOP_ABORTOP(ndp);
66043344Smckusick 		if (ndp->ni_dvp == vp)
66143344Smckusick 			vrele(ndp->ni_dvp);
66243344Smckusick 		else
66343344Smckusick 			vput(ndp->ni_dvp);
66442465Smckusick 		if (vp)
66542465Smckusick 			vrele(vp);
66642465Smckusick 	}
66737741Smckusick 	RETURN (error);
6686254Sroot }
6696254Sroot 
6706254Sroot /*
67140285Smckusick  * Mkfifo system call
67240285Smckusick  */
67342441Smckusick /* ARGSUSED */
67442441Smckusick mkfifo(p, uap, retval)
67545914Smckusick 	struct proc *p;
67642441Smckusick 	register struct args {
67740285Smckusick 		char	*fname;
67840285Smckusick 		int	fmode;
67942441Smckusick 	} *uap;
68042441Smckusick 	int *retval;
68142441Smckusick {
68242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
68340285Smckusick 	struct vattr vattr;
68440285Smckusick 	int error;
68540285Smckusick 
68640285Smckusick #ifndef FIFO
68740285Smckusick 	RETURN (EOPNOTSUPP);
68840285Smckusick #else
68940285Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
69040285Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
69140285Smckusick 	ndp->ni_dirp = uap->fname;
69240285Smckusick 	if (error = namei(ndp))
69340285Smckusick 		RETURN (error);
69440285Smckusick 	if (ndp->ni_vp != NULL) {
69540285Smckusick 		VOP_ABORTOP(ndp);
69643344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
69743344Smckusick 			vrele(ndp->ni_dvp);
69843344Smckusick 		else
69943344Smckusick 			vput(ndp->ni_dvp);
70042465Smckusick 		vrele(ndp->ni_vp);
70140285Smckusick 		RETURN (EEXIST);
70240285Smckusick 	}
70345785Sbostic 	VATTR_NULL(&vattr);
70445785Sbostic 	vattr.va_type = VFIFO;
70545914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
70640285Smckusick 	RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred));
70740285Smckusick #endif /* FIFO */
70840285Smckusick }
70940285Smckusick 
71040285Smckusick /*
7116254Sroot  * link system call
7126254Sroot  */
71342441Smckusick /* ARGSUSED */
71442441Smckusick link(p, uap, retval)
71545914Smckusick 	struct proc *p;
71642441Smckusick 	register struct args {
7176254Sroot 		char	*target;
7186254Sroot 		char	*linkname;
71942441Smckusick 	} *uap;
72042441Smckusick 	int *retval;
72142441Smckusick {
72242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
72337741Smckusick 	register struct vnode *vp, *xp;
72437741Smckusick 	int error;
7256254Sroot 
72616694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
72716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
72816694Smckusick 	ndp->ni_dirp = uap->target;
72937741Smckusick 	if (error = namei(ndp))
73037741Smckusick 		RETURN (error);
73137741Smckusick 	vp = ndp->ni_vp;
73237741Smckusick 	if (vp->v_type == VDIR &&
73342441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
73437741Smckusick 		goto out1;
73537741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
73616694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
73737741Smckusick 	if (error = namei(ndp))
73837741Smckusick 		goto out1;
73937741Smckusick 	xp = ndp->ni_vp;
7406254Sroot 	if (xp != NULL) {
74137741Smckusick 		error = EEXIST;
7426254Sroot 		goto out;
7436254Sroot 	}
74437741Smckusick 	xp = ndp->ni_dvp;
74537741Smckusick 	if (vp->v_mount != xp->v_mount)
74637741Smckusick 		error = EXDEV;
7476254Sroot out:
74842465Smckusick 	if (!error) {
74942465Smckusick 		error = VOP_LINK(vp, ndp);
75042465Smckusick 	} else {
75137741Smckusick 		VOP_ABORTOP(ndp);
75243344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
75343344Smckusick 			vrele(ndp->ni_dvp);
75443344Smckusick 		else
75543344Smckusick 			vput(ndp->ni_dvp);
75642465Smckusick 		if (ndp->ni_vp)
75742465Smckusick 			vrele(ndp->ni_vp);
75842465Smckusick 	}
75937741Smckusick out1:
76037741Smckusick 	vrele(vp);
76137741Smckusick 	RETURN (error);
7626254Sroot }
7636254Sroot 
7646254Sroot /*
7656254Sroot  * symlink -- make a symbolic link
7666254Sroot  */
76742441Smckusick /* ARGSUSED */
76842441Smckusick symlink(p, uap, retval)
76945914Smckusick 	struct proc *p;
77042441Smckusick 	register struct args {
7716254Sroot 		char	*target;
7726254Sroot 		char	*linkname;
77342441Smckusick 	} *uap;
77442441Smckusick 	int *retval;
77542441Smckusick {
77642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
77737741Smckusick 	struct vattr vattr;
77837741Smckusick 	char *target;
77937741Smckusick 	int error;
7806254Sroot 
78116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
78216694Smckusick 	ndp->ni_dirp = uap->linkname;
78337741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
78437741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
78542465Smckusick 		goto out;
78637741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
78737741Smckusick 	if (error = namei(ndp))
78842465Smckusick 		goto out;
78942465Smckusick 	if (ndp->ni_vp) {
79042465Smckusick 		VOP_ABORTOP(ndp);
79143344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
79243344Smckusick 			vrele(ndp->ni_dvp);
79343344Smckusick 		else
79443344Smckusick 			vput(ndp->ni_dvp);
79542465Smckusick 		vrele(ndp->ni_vp);
79637741Smckusick 		error = EEXIST;
79737741Smckusick 		goto out;
7986254Sroot 	}
79941362Smckusick 	VATTR_NULL(&vattr);
80045914Smckusick 	vattr.va_mode = 0777 &~ p->p_fd->fd_cmask;
80142465Smckusick 	error = VOP_SYMLINK(ndp, &vattr, target);
80237741Smckusick out:
80337741Smckusick 	FREE(target, M_NAMEI);
80437741Smckusick 	RETURN (error);
8056254Sroot }
8066254Sroot 
8076254Sroot /*
8086254Sroot  * Unlink system call.
8096254Sroot  * Hard to avoid races here, especially
8106254Sroot  * in unlinking directories.
8116254Sroot  */
81242441Smckusick /* ARGSUSED */
81342441Smckusick unlink(p, uap, retval)
81445914Smckusick 	struct proc *p;
81542441Smckusick 	struct args {
81642441Smckusick 		char	*fname;
81742441Smckusick 	} *uap;
81842441Smckusick 	int *retval;
8196254Sroot {
82042441Smckusick 	register struct nameidata *ndp = &u.u_nd;
82137741Smckusick 	register struct vnode *vp;
82237741Smckusick 	int error;
8236254Sroot 
82437741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
82516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
82616694Smckusick 	ndp->ni_dirp = uap->fname;
82737741Smckusick 	if (error = namei(ndp))
82837741Smckusick 		RETURN (error);
82937741Smckusick 	vp = ndp->ni_vp;
83037741Smckusick 	if (vp->v_type == VDIR &&
83142441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
8326254Sroot 		goto out;
8336254Sroot 	/*
8346254Sroot 	 * Don't unlink a mounted file.
8356254Sroot 	 */
83637741Smckusick 	if (vp->v_flag & VROOT) {
83737741Smckusick 		error = EBUSY;
8386254Sroot 		goto out;
8396254Sroot 	}
840*45922Smckusick #ifdef NVM
84145738Smckusick 	(void) vnode_pager_uncache(vp);
842*45922Smckusick #else
843*45922Smckusick 	if (vp->v_flag & VTEXT)
844*45922Smckusick 		xrele(vp);	/* try once to free text */
845*45922Smckusick #endif
8466254Sroot out:
84742465Smckusick 	if (!error) {
84842465Smckusick 		error = VOP_REMOVE(ndp);
84942465Smckusick 	} else {
85037741Smckusick 		VOP_ABORTOP(ndp);
85143344Smckusick 		if (ndp->ni_dvp == vp)
85243344Smckusick 			vrele(ndp->ni_dvp);
85343344Smckusick 		else
85443344Smckusick 			vput(ndp->ni_dvp);
85542465Smckusick 		vput(vp);
85642465Smckusick 	}
85737741Smckusick 	RETURN (error);
8586254Sroot }
8596254Sroot 
8606254Sroot /*
8616254Sroot  * Seek system call
8626254Sroot  */
86342441Smckusick lseek(p, uap, retval)
86445914Smckusick 	struct proc *p;
86542441Smckusick 	register struct args {
86637741Smckusick 		int	fdes;
8676254Sroot 		off_t	off;
8686254Sroot 		int	sbase;
86942441Smckusick 	} *uap;
87042441Smckusick 	off_t *retval;
87142441Smckusick {
87242441Smckusick 	struct ucred *cred = u.u_nd.ni_cred;
87345914Smckusick 	register struct filedesc *fdp = p->p_fd;
87442441Smckusick 	register struct file *fp;
87537741Smckusick 	struct vattr vattr;
87637741Smckusick 	int error;
8776254Sroot 
87845914Smckusick 	if ((unsigned)uap->fdes >= fdp->fd_maxfiles ||
87945914Smckusick 	    (fp = OFILE(fdp, uap->fdes)) == NULL)
88037741Smckusick 		RETURN (EBADF);
88137741Smckusick 	if (fp->f_type != DTYPE_VNODE)
88237741Smckusick 		RETURN (ESPIPE);
88313878Ssam 	switch (uap->sbase) {
88413878Ssam 
88513878Ssam 	case L_INCR:
88613878Ssam 		fp->f_offset += uap->off;
88713878Ssam 		break;
88813878Ssam 
88913878Ssam 	case L_XTND:
89037741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
89142441Smckusick 		    &vattr, cred))
89237741Smckusick 			RETURN (error);
89337741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
89413878Ssam 		break;
89513878Ssam 
89613878Ssam 	case L_SET:
89713878Ssam 		fp->f_offset = uap->off;
89813878Ssam 		break;
89913878Ssam 
90013878Ssam 	default:
90137741Smckusick 		RETURN (EINVAL);
90213878Ssam 	}
90342441Smckusick 	*retval = fp->f_offset;
90437741Smckusick 	RETURN (0);
9056254Sroot }
9066254Sroot 
9076254Sroot /*
9086254Sroot  * Access system call
9096254Sroot  */
91042441Smckusick /* ARGSUSED */
91142441Smckusick saccess(p, uap, retval)
91245914Smckusick 	struct proc *p;
91342441Smckusick 	register struct args {
9146254Sroot 		char	*fname;
9156254Sroot 		int	fmode;
91642441Smckusick 	} *uap;
91742441Smckusick 	int *retval;
91842441Smckusick {
91942441Smckusick 	register struct nameidata *ndp = &u.u_nd;
92042441Smckusick 	register struct ucred *cred = ndp->ni_cred;
92137741Smckusick 	register struct vnode *vp;
92237741Smckusick 	int error, mode, svuid, svgid;
9236254Sroot 
92442441Smckusick 	svuid = cred->cr_uid;
92542441Smckusick 	svgid = cred->cr_groups[0];
92642441Smckusick 	cred->cr_uid = p->p_ruid;
92742441Smckusick 	cred->cr_groups[0] = p->p_rgid;
92837741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
92916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
93016694Smckusick 	ndp->ni_dirp = uap->fname;
93137741Smckusick 	if (error = namei(ndp))
93237741Smckusick 		goto out1;
93337741Smckusick 	vp = ndp->ni_vp;
93437741Smckusick 	/*
93537741Smckusick 	 * fmode == 0 means only check for exist
93637741Smckusick 	 */
93737741Smckusick 	if (uap->fmode) {
93837741Smckusick 		mode = 0;
93937741Smckusick 		if (uap->fmode & R_OK)
94037741Smckusick 			mode |= VREAD;
94137741Smckusick 		if (uap->fmode & W_OK)
94237741Smckusick 			mode |= VWRITE;
94337741Smckusick 		if (uap->fmode & X_OK)
94437741Smckusick 			mode |= VEXEC;
94539543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
94638399Smckusick 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
9476254Sroot 	}
94837741Smckusick 	vput(vp);
94937741Smckusick out1:
95042441Smckusick 	cred->cr_uid = svuid;
95142441Smckusick 	cred->cr_groups[0] = svgid;
95237741Smckusick 	RETURN (error);
9536254Sroot }
9546254Sroot 
9556254Sroot /*
9566574Smckusic  * Stat system call.  This version follows links.
95737Sbill  */
95842441Smckusick /* ARGSUSED */
95942441Smckusick stat(p, uap, retval)
96045914Smckusick 	struct proc *p;
96142441Smckusick 	register struct args {
96242441Smckusick 		char	*fname;
96342441Smckusick 		struct stat *ub;
96442441Smckusick 	} *uap;
96542441Smckusick 	int *retval;
96637Sbill {
96742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
96842441Smckusick 	struct stat sb;
96942441Smckusick 	int error;
97037Sbill 
97142441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
97242441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
97342441Smckusick 	ndp->ni_dirp = uap->fname;
97442441Smckusick 	if (error = namei(ndp))
97542441Smckusick 		RETURN (error);
97642441Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
97742441Smckusick 	vput(ndp->ni_vp);
97842441Smckusick 	if (error)
97942441Smckusick 		RETURN (error);
98042441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
98142441Smckusick 	RETURN (error);
98237Sbill }
98337Sbill 
98437Sbill /*
9856574Smckusic  * Lstat system call.  This version does not follow links.
9865992Swnj  */
98742441Smckusick /* ARGSUSED */
98842441Smckusick lstat(p, uap, retval)
98945914Smckusick 	struct proc *p;
99042441Smckusick 	register struct args {
9915992Swnj 		char	*fname;
99212756Ssam 		struct stat *ub;
99342441Smckusick 	} *uap;
99442441Smckusick 	int *retval;
99542441Smckusick {
99642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
99712756Ssam 	struct stat sb;
99837741Smckusick 	int error;
9995992Swnj 
100042441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW;
100116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
100216694Smckusick 	ndp->ni_dirp = uap->fname;
100337741Smckusick 	if (error = namei(ndp))
100437741Smckusick 		RETURN (error);
100537741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
100637741Smckusick 	vput(ndp->ni_vp);
100737741Smckusick 	if (error)
100837741Smckusick 		RETURN (error);
100937741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
101037741Smckusick 	RETURN (error);
10115992Swnj }
10125992Swnj 
10135992Swnj /*
10145992Swnj  * Return target name of a symbolic link
101537Sbill  */
101642441Smckusick /* ARGSUSED */
101742441Smckusick readlink(p, uap, retval)
101845914Smckusick 	struct proc *p;
101942441Smckusick 	register struct args {
10205992Swnj 		char	*name;
10215992Swnj 		char	*buf;
10225992Swnj 		int	count;
102342441Smckusick 	} *uap;
102442441Smckusick 	int *retval;
102542441Smckusick {
102642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
102737741Smckusick 	register struct vnode *vp;
102837741Smckusick 	struct iovec aiov;
102937741Smckusick 	struct uio auio;
103037741Smckusick 	int error;
10315992Swnj 
103237741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
103316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
103416694Smckusick 	ndp->ni_dirp = uap->name;
103537741Smckusick 	if (error = namei(ndp))
103637741Smckusick 		RETURN (error);
103737741Smckusick 	vp = ndp->ni_vp;
103837741Smckusick 	if (vp->v_type != VLNK) {
103937741Smckusick 		error = EINVAL;
10405992Swnj 		goto out;
10415992Swnj 	}
104237741Smckusick 	aiov.iov_base = uap->buf;
104337741Smckusick 	aiov.iov_len = uap->count;
104437741Smckusick 	auio.uio_iov = &aiov;
104537741Smckusick 	auio.uio_iovcnt = 1;
104637741Smckusick 	auio.uio_offset = 0;
104737741Smckusick 	auio.uio_rw = UIO_READ;
104837741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
104937741Smckusick 	auio.uio_resid = uap->count;
105037741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
10515992Swnj out:
105237741Smckusick 	vput(vp);
105342441Smckusick 	*retval = uap->count - auio.uio_resid;
105437741Smckusick 	RETURN (error);
10555992Swnj }
10565992Swnj 
10579167Ssam /*
105838259Smckusick  * Change flags of a file given path name.
105938259Smckusick  */
106042441Smckusick /* ARGSUSED */
106142441Smckusick chflags(p, uap, retval)
106245914Smckusick 	struct proc *p;
106342441Smckusick 	register struct args {
106438259Smckusick 		char	*fname;
106538259Smckusick 		int	flags;
106642441Smckusick 	} *uap;
106742441Smckusick 	int *retval;
106842441Smckusick {
106942441Smckusick 	register struct nameidata *ndp = &u.u_nd;
107038259Smckusick 	register struct vnode *vp;
107138259Smckusick 	struct vattr vattr;
107238259Smckusick 	int error;
107338259Smckusick 
107438259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
107538259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
107638259Smckusick 	ndp->ni_dirp = uap->fname;
107738259Smckusick 	if (error = namei(ndp))
107838259Smckusick 		RETURN (error);
107938259Smckusick 	vp = ndp->ni_vp;
108041400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
108138259Smckusick 		error = EROFS;
108238259Smckusick 		goto out;
108338259Smckusick 	}
108445785Sbostic 	VATTR_NULL(&vattr);
108545785Sbostic 	vattr.va_flags = uap->flags;
108638259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
108738259Smckusick out:
108838259Smckusick 	vput(vp);
108938259Smckusick 	RETURN (error);
109038259Smckusick }
109138259Smckusick 
109238259Smckusick /*
109338259Smckusick  * Change flags of a file given a file descriptor.
109438259Smckusick  */
109542441Smckusick /* ARGSUSED */
109642441Smckusick fchflags(p, uap, retval)
109745914Smckusick 	struct proc *p;
109842441Smckusick 	register struct args {
109938259Smckusick 		int	fd;
110038259Smckusick 		int	flags;
110142441Smckusick 	} *uap;
110242441Smckusick 	int *retval;
110342441Smckusick {
110438259Smckusick 	struct vattr vattr;
110538259Smckusick 	struct vnode *vp;
110638259Smckusick 	struct file *fp;
110738259Smckusick 	int error;
110838259Smckusick 
110945914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
111038259Smckusick 		RETURN (error);
111138259Smckusick 	vp = (struct vnode *)fp->f_data;
111238259Smckusick 	VOP_LOCK(vp);
111341400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
111438259Smckusick 		error = EROFS;
111538259Smckusick 		goto out;
111638259Smckusick 	}
111745785Sbostic 	VATTR_NULL(&vattr);
111845785Sbostic 	vattr.va_flags = uap->flags;
111938259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
112038259Smckusick out:
112138259Smckusick 	VOP_UNLOCK(vp);
112238259Smckusick 	RETURN (error);
112338259Smckusick }
112438259Smckusick 
112538259Smckusick /*
11269167Ssam  * Change mode of a file given path name.
11279167Ssam  */
112842441Smckusick /* ARGSUSED */
112942441Smckusick chmod(p, uap, retval)
113045914Smckusick 	struct proc *p;
113142441Smckusick 	register struct args {
11326254Sroot 		char	*fname;
11336254Sroot 		int	fmode;
113442441Smckusick 	} *uap;
113542441Smckusick 	int *retval;
113642441Smckusick {
113742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
113837741Smckusick 	register struct vnode *vp;
113937741Smckusick 	struct vattr vattr;
114037741Smckusick 	int error;
11415992Swnj 
114237741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
114337741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
114437741Smckusick 	ndp->ni_dirp = uap->fname;
114537741Smckusick 	if (error = namei(ndp))
114637741Smckusick 		RETURN (error);
114737741Smckusick 	vp = ndp->ni_vp;
114841400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
114937741Smckusick 		error = EROFS;
115037741Smckusick 		goto out;
115137741Smckusick 	}
115245785Sbostic 	VATTR_NULL(&vattr);
115345785Sbostic 	vattr.va_mode = uap->fmode & 07777;
115437741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
115537741Smckusick out:
115637741Smckusick 	vput(vp);
115737741Smckusick 	RETURN (error);
11587701Ssam }
11597439Sroot 
11609167Ssam /*
11619167Ssam  * Change mode of a file given a file descriptor.
11629167Ssam  */
116342441Smckusick /* ARGSUSED */
116442441Smckusick fchmod(p, uap, retval)
116545914Smckusick 	struct proc *p;
116642441Smckusick 	register struct args {
11677701Ssam 		int	fd;
11687701Ssam 		int	fmode;
116942441Smckusick 	} *uap;
117042441Smckusick 	int *retval;
117142441Smckusick {
117237741Smckusick 	struct vattr vattr;
117337741Smckusick 	struct vnode *vp;
117437741Smckusick 	struct file *fp;
117537741Smckusick 	int error;
11767701Ssam 
117745914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
117837741Smckusick 		RETURN (error);
117937741Smckusick 	vp = (struct vnode *)fp->f_data;
118037741Smckusick 	VOP_LOCK(vp);
118141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
118237741Smckusick 		error = EROFS;
118337741Smckusick 		goto out;
11847439Sroot 	}
118545785Sbostic 	VATTR_NULL(&vattr);
118645785Sbostic 	vattr.va_mode = uap->fmode & 07777;
118737741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
118837741Smckusick out:
118937741Smckusick 	VOP_UNLOCK(vp);
119037741Smckusick 	RETURN (error);
11915992Swnj }
11925992Swnj 
11939167Ssam /*
11949167Ssam  * Set ownership given a path name.
11959167Ssam  */
119642441Smckusick /* ARGSUSED */
119742441Smckusick chown(p, uap, retval)
119845914Smckusick 	struct proc *p;
119942441Smckusick 	register struct args {
12006254Sroot 		char	*fname;
12016254Sroot 		int	uid;
12026254Sroot 		int	gid;
120342441Smckusick 	} *uap;
120442441Smckusick 	int *retval;
120542441Smckusick {
120642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
120737741Smckusick 	register struct vnode *vp;
120837741Smckusick 	struct vattr vattr;
120937741Smckusick 	int error;
121037Sbill 
121137741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
121236614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
121336614Sbostic 	ndp->ni_dirp = uap->fname;
121437741Smckusick 	if (error = namei(ndp))
121537741Smckusick 		RETURN (error);
121637741Smckusick 	vp = ndp->ni_vp;
121741400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
121837741Smckusick 		error = EROFS;
121937741Smckusick 		goto out;
122037741Smckusick 	}
122145785Sbostic 	VATTR_NULL(&vattr);
122245785Sbostic 	vattr.va_uid = uap->uid;
122345785Sbostic 	vattr.va_gid = uap->gid;
122437741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
122537741Smckusick out:
122637741Smckusick 	vput(vp);
122737741Smckusick 	RETURN (error);
12287701Ssam }
12297439Sroot 
12309167Ssam /*
12319167Ssam  * Set ownership given a file descriptor.
12329167Ssam  */
123342441Smckusick /* ARGSUSED */
123442441Smckusick fchown(p, uap, retval)
123545914Smckusick 	struct proc *p;
123642441Smckusick 	register struct args {
12377701Ssam 		int	fd;
12387701Ssam 		int	uid;
12397701Ssam 		int	gid;
124042441Smckusick 	} *uap;
124142441Smckusick 	int *retval;
124242441Smckusick {
124337741Smckusick 	struct vattr vattr;
124437741Smckusick 	struct vnode *vp;
124537741Smckusick 	struct file *fp;
124637741Smckusick 	int error;
12477701Ssam 
124845914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
124937741Smckusick 		RETURN (error);
125037741Smckusick 	vp = (struct vnode *)fp->f_data;
125137741Smckusick 	VOP_LOCK(vp);
125241400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
125337741Smckusick 		error = EROFS;
125437741Smckusick 		goto out;
125537741Smckusick 	}
125645785Sbostic 	VATTR_NULL(&vattr);
125745785Sbostic 	vattr.va_uid = uap->uid;
125845785Sbostic 	vattr.va_gid = uap->gid;
125937741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
126037741Smckusick out:
126137741Smckusick 	VOP_UNLOCK(vp);
126237741Smckusick 	RETURN (error);
12637701Ssam }
12647701Ssam 
126542441Smckusick /*
126642441Smckusick  * Set the access and modification times of a file.
126742441Smckusick  */
126842441Smckusick /* ARGSUSED */
126942441Smckusick utimes(p, uap, retval)
127045914Smckusick 	struct proc *p;
127142441Smckusick 	register struct args {
127211811Ssam 		char	*fname;
127311811Ssam 		struct	timeval *tptr;
127442441Smckusick 	} *uap;
127542441Smckusick 	int *retval;
127642441Smckusick {
127742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
127837741Smckusick 	register struct vnode *vp;
127911811Ssam 	struct timeval tv[2];
128037741Smckusick 	struct vattr vattr;
128137741Smckusick 	int error;
128211811Ssam 
128337741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
128437741Smckusick 		RETURN (error);
128537741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
128637741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
128737741Smckusick 	ndp->ni_dirp = uap->fname;
128837741Smckusick 	if (error = namei(ndp))
128937741Smckusick 		RETURN (error);
129037741Smckusick 	vp = ndp->ni_vp;
129141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
129237741Smckusick 		error = EROFS;
129337741Smckusick 		goto out;
129421015Smckusick 	}
129545785Sbostic 	VATTR_NULL(&vattr);
129645785Sbostic 	vattr.va_atime = tv[0];
129745785Sbostic 	vattr.va_mtime = tv[1];
129837741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
129937741Smckusick out:
130037741Smckusick 	vput(vp);
130137741Smckusick 	RETURN (error);
130211811Ssam }
130311811Ssam 
13049167Ssam /*
13059167Ssam  * Truncate a file given its path name.
13069167Ssam  */
130742441Smckusick /* ARGSUSED */
130842441Smckusick truncate(p, uap, retval)
130945914Smckusick 	struct proc *p;
131042441Smckusick 	register struct args {
13117701Ssam 		char	*fname;
131226473Skarels 		off_t	length;
131342441Smckusick 	} *uap;
131442441Smckusick 	int *retval;
131542441Smckusick {
131642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
131737741Smckusick 	register struct vnode *vp;
131837741Smckusick 	struct vattr vattr;
131937741Smckusick 	int error;
13207701Ssam 
132137741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
132216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
132316694Smckusick 	ndp->ni_dirp = uap->fname;
132437741Smckusick 	if (error = namei(ndp))
132537741Smckusick 		RETURN (error);
132637741Smckusick 	vp = ndp->ni_vp;
132737741Smckusick 	if (vp->v_type == VDIR) {
132837741Smckusick 		error = EISDIR;
132937741Smckusick 		goto out;
13307701Ssam 	}
133138399Smckusick 	if ((error = vn_writechk(vp)) ||
133238399Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
133337741Smckusick 		goto out;
133445785Sbostic 	VATTR_NULL(&vattr);
133545785Sbostic 	vattr.va_size = uap->length;
133637741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
133737741Smckusick out:
133837741Smckusick 	vput(vp);
133937741Smckusick 	RETURN (error);
13407701Ssam }
13417701Ssam 
13429167Ssam /*
13439167Ssam  * Truncate a file given a file descriptor.
13449167Ssam  */
134542441Smckusick /* ARGSUSED */
134642441Smckusick ftruncate(p, uap, retval)
134745914Smckusick 	struct proc *p;
134842441Smckusick 	register struct args {
13497701Ssam 		int	fd;
135026473Skarels 		off_t	length;
135142441Smckusick 	} *uap;
135242441Smckusick 	int *retval;
135342441Smckusick {
135437741Smckusick 	struct vattr vattr;
135537741Smckusick 	struct vnode *vp;
13567701Ssam 	struct file *fp;
135737741Smckusick 	int error;
13587701Ssam 
135945914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
136037741Smckusick 		RETURN (error);
136137741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
136237741Smckusick 		RETURN (EINVAL);
136337741Smckusick 	vp = (struct vnode *)fp->f_data;
136437741Smckusick 	VOP_LOCK(vp);
136537741Smckusick 	if (vp->v_type == VDIR) {
136637741Smckusick 		error = EISDIR;
136737741Smckusick 		goto out;
13687701Ssam 	}
136938399Smckusick 	if (error = vn_writechk(vp))
137037741Smckusick 		goto out;
137145785Sbostic 	VATTR_NULL(&vattr);
137245785Sbostic 	vattr.va_size = uap->length;
137337741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
137437741Smckusick out:
137537741Smckusick 	VOP_UNLOCK(vp);
137637741Smckusick 	RETURN (error);
13777701Ssam }
13787701Ssam 
13799167Ssam /*
13809167Ssam  * Synch an open file.
13819167Ssam  */
138242441Smckusick /* ARGSUSED */
138342441Smckusick fsync(p, uap, retval)
138445914Smckusick 	struct proc *p;
138542441Smckusick 	struct args {
138642441Smckusick 		int	fd;
138742441Smckusick 	} *uap;
138842441Smckusick 	int *retval;
13899167Ssam {
139039592Smckusick 	register struct vnode *vp;
13919167Ssam 	struct file *fp;
139237741Smckusick 	int error;
13939167Ssam 
139445914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
139537741Smckusick 		RETURN (error);
139639592Smckusick 	vp = (struct vnode *)fp->f_data;
139739592Smckusick 	VOP_LOCK(vp);
139839592Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT);
139939592Smckusick 	VOP_UNLOCK(vp);
140037741Smckusick 	RETURN (error);
14019167Ssam }
14029167Ssam 
14039167Ssam /*
14049167Ssam  * Rename system call.
14059167Ssam  *
14069167Ssam  * Source and destination must either both be directories, or both
14079167Ssam  * not be directories.  If target is a directory, it must be empty.
14089167Ssam  */
140942441Smckusick /* ARGSUSED */
141042441Smckusick rename(p, uap, retval)
141145914Smckusick 	struct proc *p;
141242441Smckusick 	register struct args {
14137701Ssam 		char	*from;
14147701Ssam 		char	*to;
141542441Smckusick 	} *uap;
141642441Smckusick 	int *retval;
141742441Smckusick {
141837741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
141942441Smckusick 	register struct nameidata *ndp = &u.u_nd;
142037741Smckusick 	struct nameidata tond;
142137741Smckusick 	int error;
14227701Ssam 
142337741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
142416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
142516694Smckusick 	ndp->ni_dirp = uap->from;
142637741Smckusick 	if (error = namei(ndp))
142737741Smckusick 		RETURN (error);
142837741Smckusick 	fvp = ndp->ni_vp;
142938266Smckusick 	nddup(ndp, &tond);
143037741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
143137741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
143237741Smckusick 	tond.ni_dirp = uap->to;
143342465Smckusick 	if (error = namei(&tond)) {
143442465Smckusick 		VOP_ABORTOP(ndp);
143542465Smckusick 		vrele(ndp->ni_dvp);
143642465Smckusick 		vrele(fvp);
143742465Smckusick 		goto out1;
143842465Smckusick 	}
143937741Smckusick 	tdvp = tond.ni_dvp;
144037741Smckusick 	tvp = tond.ni_vp;
144137741Smckusick 	if (tvp != NULL) {
144237741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
144339242Sbostic 			error = ENOTDIR;
144437741Smckusick 			goto out;
144537741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
144639242Sbostic 			error = EISDIR;
144737741Smckusick 			goto out;
14489167Ssam 		}
144945240Smckusick 		if (fvp->v_mount != tvp->v_mount) {
145045240Smckusick 			error = EXDEV;
145145240Smckusick 			goto out;
145245240Smckusick 		}
14539167Ssam 	}
145437741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
145537741Smckusick 		error = EXDEV;
14569167Ssam 		goto out;
145710051Ssam 	}
145839286Smckusick 	if (fvp == tdvp)
145937741Smckusick 		error = EINVAL;
146039286Smckusick 	/*
146139286Smckusick 	 * If source is the same as the destination,
146239286Smckusick 	 * then there is nothing to do.
146339286Smckusick 	 */
146439286Smckusick 	if (fvp == tvp)
146539286Smckusick 		error = -1;
146637741Smckusick out:
146742465Smckusick 	if (!error) {
146842465Smckusick 		error = VOP_RENAME(ndp, &tond);
146942465Smckusick 	} else {
147037741Smckusick 		VOP_ABORTOP(&tond);
147143344Smckusick 		if (tdvp == tvp)
147243344Smckusick 			vrele(tdvp);
147343344Smckusick 		else
147443344Smckusick 			vput(tdvp);
147542465Smckusick 		if (tvp)
147642465Smckusick 			vput(tvp);
147737741Smckusick 		VOP_ABORTOP(ndp);
147842465Smckusick 		vrele(ndp->ni_dvp);
147942465Smckusick 		vrele(fvp);
14809167Ssam 	}
148137741Smckusick out1:
148238266Smckusick 	ndrele(&tond);
148339286Smckusick 	if (error == -1)
148439286Smckusick 		RETURN (0);
148537741Smckusick 	RETURN (error);
14867701Ssam }
14877701Ssam 
14887535Sroot /*
148912756Ssam  * Mkdir system call
149012756Ssam  */
149142441Smckusick /* ARGSUSED */
149242441Smckusick mkdir(p, uap, retval)
149345914Smckusick 	struct proc *p;
149442441Smckusick 	register struct args {
149512756Ssam 		char	*name;
149612756Ssam 		int	dmode;
149742441Smckusick 	} *uap;
149842441Smckusick 	int *retval;
149942441Smckusick {
150042441Smckusick 	register struct nameidata *ndp = &u.u_nd;
150137741Smckusick 	register struct vnode *vp;
150237741Smckusick 	struct vattr vattr;
150337741Smckusick 	int error;
150412756Ssam 
150537741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
150616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
150716694Smckusick 	ndp->ni_dirp = uap->name;
150837741Smckusick 	if (error = namei(ndp))
150937741Smckusick 		RETURN (error);
151037741Smckusick 	vp = ndp->ni_vp;
151137741Smckusick 	if (vp != NULL) {
151237741Smckusick 		VOP_ABORTOP(ndp);
151343344Smckusick 		if (ndp->ni_dvp == vp)
151443344Smckusick 			vrele(ndp->ni_dvp);
151543344Smckusick 		else
151643344Smckusick 			vput(ndp->ni_dvp);
151742465Smckusick 		vrele(vp);
151837741Smckusick 		RETURN (EEXIST);
151912756Ssam 	}
152041362Smckusick 	VATTR_NULL(&vattr);
152137741Smckusick 	vattr.va_type = VDIR;
152245914Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask;
152337741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
152438145Smckusick 	if (!error)
152538145Smckusick 		vput(ndp->ni_vp);
152637741Smckusick 	RETURN (error);
152712756Ssam }
152812756Ssam 
152912756Ssam /*
153012756Ssam  * Rmdir system call.
153112756Ssam  */
153242441Smckusick /* ARGSUSED */
153342441Smckusick rmdir(p, uap, retval)
153445914Smckusick 	struct proc *p;
153542441Smckusick 	struct args {
153642441Smckusick 		char	*name;
153742441Smckusick 	} *uap;
153842441Smckusick 	int *retval;
153912756Ssam {
154042441Smckusick 	register struct nameidata *ndp = &u.u_nd;
154137741Smckusick 	register struct vnode *vp;
154237741Smckusick 	int error;
154312756Ssam 
154437741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
154516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
154616694Smckusick 	ndp->ni_dirp = uap->name;
154737741Smckusick 	if (error = namei(ndp))
154837741Smckusick 		RETURN (error);
154937741Smckusick 	vp = ndp->ni_vp;
155037741Smckusick 	if (vp->v_type != VDIR) {
155137741Smckusick 		error = ENOTDIR;
155212756Ssam 		goto out;
155312756Ssam 	}
155412756Ssam 	/*
155537741Smckusick 	 * No rmdir "." please.
155612756Ssam 	 */
155737741Smckusick 	if (ndp->ni_dvp == vp) {
155837741Smckusick 		error = EINVAL;
155912756Ssam 		goto out;
156012756Ssam 	}
156112756Ssam 	/*
156237741Smckusick 	 * Don't unlink a mounted file.
156312756Ssam 	 */
156437741Smckusick 	if (vp->v_flag & VROOT)
156537741Smckusick 		error = EBUSY;
156612756Ssam out:
156742465Smckusick 	if (!error) {
156842465Smckusick 		error = VOP_RMDIR(ndp);
156942465Smckusick 	} else {
157037741Smckusick 		VOP_ABORTOP(ndp);
157143344Smckusick 		if (ndp->ni_dvp == vp)
157243344Smckusick 			vrele(ndp->ni_dvp);
157343344Smckusick 		else
157443344Smckusick 			vput(ndp->ni_dvp);
157542465Smckusick 		vput(vp);
157642465Smckusick 	}
157737741Smckusick 	RETURN (error);
157812756Ssam }
157912756Ssam 
158037741Smckusick /*
158137741Smckusick  * Read a block of directory entries in a file system independent format
158237741Smckusick  */
158342441Smckusick getdirentries(p, uap, retval)
158445914Smckusick 	struct proc *p;
158542441Smckusick 	register struct args {
158637741Smckusick 		int	fd;
158737741Smckusick 		char	*buf;
158837741Smckusick 		unsigned count;
158937741Smckusick 		long	*basep;
159042441Smckusick 	} *uap;
159142441Smckusick 	int *retval;
159242441Smckusick {
159339592Smckusick 	register struct vnode *vp;
159416540Ssam 	struct file *fp;
159537741Smckusick 	struct uio auio;
159637741Smckusick 	struct iovec aiov;
159738129Smckusick 	off_t off;
159840321Smckusick 	int error, eofflag;
159912756Ssam 
160045914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
160137741Smckusick 		RETURN (error);
160237741Smckusick 	if ((fp->f_flag & FREAD) == 0)
160337741Smckusick 		RETURN (EBADF);
160439592Smckusick 	vp = (struct vnode *)fp->f_data;
160539592Smckusick 	if (vp->v_type != VDIR)
160639592Smckusick 		RETURN (EINVAL);
160737741Smckusick 	aiov.iov_base = uap->buf;
160837741Smckusick 	aiov.iov_len = uap->count;
160937741Smckusick 	auio.uio_iov = &aiov;
161037741Smckusick 	auio.uio_iovcnt = 1;
161137741Smckusick 	auio.uio_rw = UIO_READ;
161237741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
161337741Smckusick 	auio.uio_resid = uap->count;
161439592Smckusick 	VOP_LOCK(vp);
161539592Smckusick 	auio.uio_offset = off = fp->f_offset;
161640321Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
161739592Smckusick 	fp->f_offset = auio.uio_offset;
161839592Smckusick 	VOP_UNLOCK(vp);
161939592Smckusick 	if (error)
162037741Smckusick 		RETURN (error);
162139592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
162242441Smckusick 	*retval = uap->count - auio.uio_resid;
162337741Smckusick 	RETURN (error);
162412756Ssam }
162512756Ssam 
162612756Ssam /*
162712756Ssam  * mode mask for creation of files
162812756Ssam  */
162942441Smckusick mode_t
163042441Smckusick umask(p, uap, retval)
163145914Smckusick 	struct proc *p;
163242441Smckusick 	struct args {
163342441Smckusick 		int	mask;
163442441Smckusick 	} *uap;
163542441Smckusick 	int *retval;
163612756Ssam {
163745914Smckusick 	register struct filedesc *fdp = p->p_fd;
163812756Ssam 
163945914Smckusick 	*retval = fdp->fd_cmask;
164045914Smckusick 	fdp->fd_cmask = uap->mask & 07777;
164137741Smckusick 	RETURN (0);
164212756Ssam }
164337741Smckusick 
164439566Smarc /*
164539566Smarc  * Void all references to file by ripping underlying filesystem
164639566Smarc  * away from vnode.
164739566Smarc  */
164842441Smckusick /* ARGSUSED */
164942441Smckusick revoke(p, uap, retval)
165045914Smckusick 	struct proc *p;
165142441Smckusick 	register struct args {
165239566Smarc 		char	*fname;
165342441Smckusick 	} *uap;
165442441Smckusick 	int *retval;
165542441Smckusick {
165642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
165739566Smarc 	register struct vnode *vp;
165839566Smarc 	struct vattr vattr;
165939566Smarc 	int error;
166039566Smarc 
166139566Smarc 	ndp->ni_nameiop = LOOKUP | FOLLOW;
166239566Smarc 	ndp->ni_segflg = UIO_USERSPACE;
166339566Smarc 	ndp->ni_dirp = uap->fname;
166439566Smarc 	if (error = namei(ndp))
166539566Smarc 		RETURN (error);
166639566Smarc 	vp = ndp->ni_vp;
166739566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
166839566Smarc 		error = EINVAL;
166939566Smarc 		goto out;
167039566Smarc 	}
167142441Smckusick 	if (error = VOP_GETATTR(vp, &vattr, ndp->ni_cred))
167239566Smarc 		goto out;
167342955Smckusick 	if (ndp->ni_cred->cr_uid != vattr.va_uid &&
167442441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
167539566Smarc 		goto out;
167639805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
167739632Smckusick 		vgoneall(vp);
167839566Smarc out:
167939566Smarc 	vrele(vp);
168039566Smarc 	RETURN (error);
168139566Smarc }
168239566Smarc 
168345914Smckusick getvnode(fdp, fdes, fpp)
168445914Smckusick 	struct filedesc *fdp;
168537741Smckusick 	struct file **fpp;
168637741Smckusick 	int fdes;
168737741Smckusick {
168837741Smckusick 	struct file *fp;
168937741Smckusick 
169045914Smckusick 	if ((unsigned)fdes >= fdp->fd_maxfiles ||
169145914Smckusick 	    (fp = OFILE(fdp, fdes)) == NULL)
169237741Smckusick 		return (EBADF);
169337741Smckusick 	if (fp->f_type != DTYPE_VNODE)
169437741Smckusick 		return (EINVAL);
169537741Smckusick 	*fpp = fp;
169637741Smckusick 	return (0);
169737741Smckusick }
1698