xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 45914)
123405Smckusick /*
237741Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337741Smckusick  * All rights reserved.
423405Smckusick  *
544459Sbostic  * %sccs.include.redist.c%
637741Smckusick  *
7*45914Smckusick  *	@(#)vfs_syscalls.c	7.62 (Berkeley) 01/10/91
823405Smckusick  */
937Sbill 
1017101Sbloom #include "param.h"
1117101Sbloom #include "systm.h"
1244407Skarels #include "user.h"
13*45914Smckusick #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)
34*45914Smckusick 	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)
182*45914Smckusick 	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 
23545738Smckusick 	vnode_pager_umount(mp);	/* release cached vnodes */
23637741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
23741676Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE))
23841676Smckusick 		error = VFS_UNMOUNT(mp, flags);
23941400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
24041298Smckusick 	vfs_unbusy(mp);
24137741Smckusick 	if (error) {
24237741Smckusick 		vfs_unlock(mp);
24337741Smckusick 	} else {
24437741Smckusick 		vrele(coveredvp);
24537741Smckusick 		vfs_remove(mp);
24637741Smckusick 		free((caddr_t)mp, M_MOUNT);
24737741Smckusick 	}
24839356Smckusick 	return (error);
2496254Sroot }
2506254Sroot 
2519167Ssam /*
25237741Smckusick  * Sync system call.
25337741Smckusick  * Sync each mounted filesystem.
2549167Ssam  */
25539491Smckusick /* ARGSUSED */
25642441Smckusick sync(p, uap, retval)
257*45914Smckusick 	struct proc *p;
25842441Smckusick 	struct args *uap;
25942441Smckusick 	int *retval;
2606254Sroot {
26137741Smckusick 	register struct mount *mp;
26241298Smckusick 	struct mount *omp;
26337741Smckusick 
26437741Smckusick 	mp = rootfs;
26537741Smckusick 	do {
26640343Smckusick 		/*
26740343Smckusick 		 * The lock check below is to avoid races with mount
26840343Smckusick 		 * and unmount.
26940343Smckusick 		 */
27041400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
27141298Smckusick 		    !vfs_busy(mp)) {
27237741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
27341298Smckusick 			omp = mp;
27441400Smckusick 			mp = mp->mnt_next;
27541298Smckusick 			vfs_unbusy(omp);
27641298Smckusick 		} else
27741400Smckusick 			mp = mp->mnt_next;
27837741Smckusick 	} while (mp != rootfs);
27937741Smckusick }
28037741Smckusick 
28137741Smckusick /*
28241298Smckusick  * operate on filesystem quotas
28341298Smckusick  */
28442441Smckusick /* ARGSUSED */
28542441Smckusick quotactl(p, uap, retval)
286*45914Smckusick 	struct proc *p;
28742441Smckusick 	register struct args {
28841298Smckusick 		char *path;
28941298Smckusick 		int cmd;
29041298Smckusick 		int uid;
29141298Smckusick 		caddr_t arg;
29242441Smckusick 	} *uap;
29342441Smckusick 	int *retval;
29442441Smckusick {
29541298Smckusick 	register struct mount *mp;
29642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
29741298Smckusick 	int error;
29841298Smckusick 
29941298Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
30041298Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
30141298Smckusick 	ndp->ni_dirp = uap->path;
30241298Smckusick 	if (error = namei(ndp))
30341298Smckusick 		RETURN (error);
30441298Smckusick 	mp = ndp->ni_vp->v_mount;
30541298Smckusick 	vrele(ndp->ni_vp);
30641298Smckusick 	RETURN (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg));
30741298Smckusick }
30841298Smckusick 
30941298Smckusick /*
31037741Smckusick  * get filesystem statistics
31137741Smckusick  */
31242441Smckusick /* ARGSUSED */
31342441Smckusick statfs(p, uap, retval)
314*45914Smckusick 	struct proc *p;
31542441Smckusick 	register struct args {
31637741Smckusick 		char *path;
31737741Smckusick 		struct statfs *buf;
31842441Smckusick 	} *uap;
31942441Smckusick 	int *retval;
32042441Smckusick {
32139464Smckusick 	register struct mount *mp;
32242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
32340343Smckusick 	register struct statfs *sp;
32437741Smckusick 	int error;
32537741Smckusick 
32639544Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
32737741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
32837741Smckusick 	ndp->ni_dirp = uap->path;
32937741Smckusick 	if (error = namei(ndp))
33037741Smckusick 		RETURN (error);
33139544Smckusick 	mp = ndp->ni_vp->v_mount;
33241400Smckusick 	sp = &mp->mnt_stat;
33339544Smckusick 	vrele(ndp->ni_vp);
33440343Smckusick 	if (error = VFS_STATFS(mp, sp))
33539544Smckusick 		RETURN (error);
33641400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
33740343Smckusick 	RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
33837741Smckusick }
33937741Smckusick 
34042441Smckusick /*
34142441Smckusick  * get filesystem statistics
34242441Smckusick  */
34342441Smckusick /* ARGSUSED */
34442441Smckusick fstatfs(p, uap, retval)
345*45914Smckusick 	struct proc *p;
34642441Smckusick 	register struct args {
34737741Smckusick 		int fd;
34837741Smckusick 		struct statfs *buf;
34942441Smckusick 	} *uap;
35042441Smckusick 	int *retval;
35142441Smckusick {
35237741Smckusick 	struct file *fp;
35339464Smckusick 	struct mount *mp;
35440343Smckusick 	register struct statfs *sp;
35537741Smckusick 	int error;
35637741Smckusick 
357*45914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
35837741Smckusick 		RETURN (error);
35939464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
36041400Smckusick 	sp = &mp->mnt_stat;
36140343Smckusick 	if (error = VFS_STATFS(mp, sp))
36237741Smckusick 		RETURN (error);
36341400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
36440343Smckusick 	RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
36537741Smckusick }
36637741Smckusick 
36737741Smckusick /*
36838270Smckusick  * get statistics on all filesystems
36938270Smckusick  */
37042441Smckusick getfsstat(p, uap, retval)
371*45914Smckusick 	struct proc *p;
37242441Smckusick 	register struct args {
37338270Smckusick 		struct statfs *buf;
37438270Smckusick 		long bufsize;
37540343Smckusick 		int flags;
37642441Smckusick 	} *uap;
37742441Smckusick 	int *retval;
37842441Smckusick {
37938270Smckusick 	register struct mount *mp;
38040343Smckusick 	register struct statfs *sp;
38139606Smckusick 	caddr_t sfsp;
38238270Smckusick 	long count, maxcount, error;
38338270Smckusick 
38438270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
38539606Smckusick 	sfsp = (caddr_t)uap->buf;
38638270Smckusick 	mp = rootfs;
38738270Smckusick 	count = 0;
38838270Smckusick 	do {
38941400Smckusick 		if (sfsp && count < maxcount &&
39041400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
39141400Smckusick 			sp = &mp->mnt_stat;
39240343Smckusick 			/*
39340343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
39440343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
39540343Smckusick 			 */
39640343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
39740343Smckusick 			    (uap->flags & MNT_WAIT)) &&
39840343Smckusick 			    (error = VFS_STATFS(mp, sp))) {
39941400Smckusick 				mp = mp->mnt_prev;
40039607Smckusick 				continue;
40139607Smckusick 			}
40241400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
40340343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
40439606Smckusick 				RETURN (error);
40540343Smckusick 			sfsp += sizeof(*sp);
40638270Smckusick 		}
40739606Smckusick 		count++;
40841400Smckusick 		mp = mp->mnt_prev;
40938270Smckusick 	} while (mp != rootfs);
41038270Smckusick 	if (sfsp && count > maxcount)
41142441Smckusick 		*retval = maxcount;
41238270Smckusick 	else
41342441Smckusick 		*retval = count;
41438270Smckusick 	RETURN (0);
41538270Smckusick }
41638270Smckusick 
41738270Smckusick /*
41838259Smckusick  * Change current working directory to a given file descriptor.
41938259Smckusick  */
42042441Smckusick /* ARGSUSED */
42142441Smckusick fchdir(p, uap, retval)
422*45914Smckusick 	struct proc *p;
42342441Smckusick 	struct args {
42442441Smckusick 		int	fd;
42542441Smckusick 	} *uap;
42642441Smckusick 	int *retval;
42738259Smckusick {
42842441Smckusick 	register struct nameidata *ndp = &u.u_nd;
429*45914Smckusick 	register struct filedesc *fdp = p->p_fd;
43038259Smckusick 	register struct vnode *vp;
43138259Smckusick 	struct file *fp;
43238259Smckusick 	int error;
43338259Smckusick 
434*45914Smckusick 	if (error = getvnode(fdp, uap->fd, &fp))
43538259Smckusick 		RETURN (error);
43638259Smckusick 	vp = (struct vnode *)fp->f_data;
43738259Smckusick 	VOP_LOCK(vp);
43838259Smckusick 	if (vp->v_type != VDIR)
43938259Smckusick 		error = ENOTDIR;
44038259Smckusick 	else
44142441Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
44238259Smckusick 	VOP_UNLOCK(vp);
44339860Smckusick 	if (error)
44439860Smckusick 		RETURN (error);
44539860Smckusick 	VREF(vp);
446*45914Smckusick 	vrele(fdp->fd_cdir);
447*45914Smckusick 	fdp->fd_cdir = vp;
44839860Smckusick 	RETURN (0);
44938259Smckusick }
45038259Smckusick 
45138259Smckusick /*
45237741Smckusick  * Change current working directory (``.'').
45337741Smckusick  */
45442441Smckusick /* ARGSUSED */
45542441Smckusick chdir(p, uap, retval)
456*45914Smckusick 	struct proc *p;
45742441Smckusick 	struct args {
45842441Smckusick 		char	*fname;
45942441Smckusick 	} *uap;
46042441Smckusick 	int *retval;
46137741Smckusick {
46242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
463*45914Smckusick 	register struct filedesc *fdp = p->p_fd;
46437741Smckusick 	int error;
4656254Sroot 
46637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
46716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
46816694Smckusick 	ndp->ni_dirp = uap->fname;
46937741Smckusick 	if (error = chdirec(ndp))
47037741Smckusick 		RETURN (error);
471*45914Smckusick 	vrele(fdp->fd_cdir);
472*45914Smckusick 	fdp->fd_cdir = ndp->ni_vp;
47337741Smckusick 	RETURN (0);
47437741Smckusick }
4756254Sroot 
47637741Smckusick /*
47737741Smckusick  * Change notion of root (``/'') directory.
47837741Smckusick  */
47942441Smckusick /* ARGSUSED */
48042441Smckusick chroot(p, uap, retval)
481*45914Smckusick 	struct proc *p;
48242441Smckusick 	struct args {
48342441Smckusick 		char	*fname;
48442441Smckusick 	} *uap;
48542441Smckusick 	int *retval;
48637741Smckusick {
48742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
488*45914Smckusick 	register struct filedesc *fdp = p->p_fd;
48937741Smckusick 	int error;
49037741Smckusick 
49142441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
49237741Smckusick 		RETURN (error);
49337741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
49437741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
49537741Smckusick 	ndp->ni_dirp = uap->fname;
49637741Smckusick 	if (error = chdirec(ndp))
49737741Smckusick 		RETURN (error);
498*45914Smckusick 	if (fdp->fd_rdir != NULL)
499*45914Smckusick 		vrele(fdp->fd_rdir);
500*45914Smckusick 	fdp->fd_rdir = ndp->ni_vp;
50137741Smckusick 	RETURN (0);
5026254Sroot }
5036254Sroot 
50437Sbill /*
50537741Smckusick  * Common routine for chroot and chdir.
50637741Smckusick  */
50737741Smckusick chdirec(ndp)
50837741Smckusick 	register struct nameidata *ndp;
50937741Smckusick {
51037741Smckusick 	struct vnode *vp;
51137741Smckusick 	int error;
51237741Smckusick 
51337741Smckusick 	if (error = namei(ndp))
51437741Smckusick 		return (error);
51537741Smckusick 	vp = ndp->ni_vp;
51637741Smckusick 	if (vp->v_type != VDIR)
51737741Smckusick 		error = ENOTDIR;
51837741Smckusick 	else
51938399Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
52037741Smckusick 	VOP_UNLOCK(vp);
52137741Smckusick 	if (error)
52237741Smckusick 		vrele(vp);
52337741Smckusick 	return (error);
52437741Smckusick }
52537741Smckusick 
52637741Smckusick /*
5276254Sroot  * Open system call.
52842441Smckusick  * Check permissions, allocate an open file structure,
52942441Smckusick  * and call the device open routine if any.
5306254Sroot  */
53142441Smckusick open(p, uap, retval)
532*45914Smckusick 	struct proc *p;
53342441Smckusick 	register struct args {
5346254Sroot 		char	*fname;
5357701Ssam 		int	mode;
53612756Ssam 		int	crtmode;
53742441Smckusick 	} *uap;
53842441Smckusick 	int *retval;
5396254Sroot {
54042441Smckusick 	struct nameidata *ndp = &u.u_nd;
541*45914Smckusick 	register struct filedesc *fdp = p->p_fd;
54242441Smckusick 	register struct file *fp;
54337741Smckusick 	int fmode, cmode;
54437741Smckusick 	struct file *nfp;
54537741Smckusick 	int indx, error;
54637741Smckusick 	extern struct fileops vnops;
5476254Sroot 
548*45914Smckusick 	if (error = falloc(p, &nfp, &indx))
54942441Smckusick 		RETURN (error);
55037741Smckusick 	fp = nfp;
55142441Smckusick 	fmode = uap->mode - FOPEN;
552*45914Smckusick 	cmode = ((uap->crtmode &~ fdp->fd_cmask) & 07777) &~ S_ISVTX;
55342441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
55442441Smckusick 	ndp->ni_dirp = uap->fname;
55545202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
55642441Smckusick 	if (error = vn_open(ndp, fmode, cmode)) {
55737741Smckusick 		crfree(fp->f_cred);
55837741Smckusick 		fp->f_count--;
55943405Smckusick 		if (error == ENODEV &&		/* XXX from fdopen */
56045202Smckusick 		    p->p_dupfd >= 0 &&
561*45914Smckusick 		    (error = dupfdopen(fdp, indx, p->p_dupfd, fmode)) == 0) {
56242441Smckusick 			*retval = indx;
56342441Smckusick 			RETURN (0);
56442441Smckusick 		}
56540884Smckusick 		if (error == ERESTART)
56640884Smckusick 			error = EINTR;
567*45914Smckusick 		OFILE(fdp, indx) = NULL;
56842441Smckusick 		RETURN (error);
56912756Ssam 	}
57037741Smckusick 	fp->f_flag = fmode & FMASK;
57137741Smckusick 	fp->f_type = DTYPE_VNODE;
57237741Smckusick 	fp->f_ops = &vnops;
57337741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
57442441Smckusick 	*retval = indx;
57542441Smckusick 	RETURN (0);
5766254Sroot }
5776254Sroot 
57842955Smckusick #ifdef COMPAT_43
5796254Sroot /*
58042441Smckusick  * Creat system call.
5816254Sroot  */
58242955Smckusick ocreat(p, uap, retval)
58342441Smckusick 	struct proc *p;
58442441Smckusick 	register struct args {
58542441Smckusick 		char	*fname;
58642441Smckusick 		int	fmode;
58742441Smckusick 	} *uap;
58842441Smckusick 	int *retval;
5896254Sroot {
59042441Smckusick 	struct args {
5916254Sroot 		char	*fname;
59242441Smckusick 		int	mode;
59342441Smckusick 		int	crtmode;
59442441Smckusick 	} openuap;
59542441Smckusick 
59642441Smckusick 	openuap.fname = uap->fname;
59742441Smckusick 	openuap.crtmode = uap->fmode;
59842441Smckusick 	openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
59942441Smckusick 	RETURN (open(p, &openuap, retval));
60042441Smckusick }
60142955Smckusick #endif /* COMPAT_43 */
60242441Smckusick 
60342441Smckusick /*
60442441Smckusick  * Mknod system call
60542441Smckusick  */
60642441Smckusick /* ARGSUSED */
60742441Smckusick mknod(p, uap, retval)
608*45914Smckusick 	struct proc *p;
60942441Smckusick 	register struct args {
61042441Smckusick 		char	*fname;
6116254Sroot 		int	fmode;
6126254Sroot 		int	dev;
61342441Smckusick 	} *uap;
61442441Smckusick 	int *retval;
61542441Smckusick {
61642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
61737741Smckusick 	register struct vnode *vp;
61837741Smckusick 	struct vattr vattr;
61937741Smckusick 	int error;
6206254Sroot 
62142441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
62237741Smckusick 		RETURN (error);
62337741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
62416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
62516694Smckusick 	ndp->ni_dirp = uap->fname;
62637741Smckusick 	if (error = namei(ndp))
62737741Smckusick 		RETURN (error);
62837741Smckusick 	vp = ndp->ni_vp;
62937741Smckusick 	if (vp != NULL) {
63037741Smckusick 		error = EEXIST;
63112756Ssam 		goto out;
6326254Sroot 	}
63341362Smckusick 	VATTR_NULL(&vattr);
63440635Smckusick 	switch (uap->fmode & S_IFMT) {
63512756Ssam 
63640635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
63737741Smckusick 		vattr.va_type = VBAD;
63837741Smckusick 		break;
63940635Smckusick 	case S_IFCHR:
64037741Smckusick 		vattr.va_type = VCHR;
64137741Smckusick 		break;
64240635Smckusick 	case S_IFBLK:
64337741Smckusick 		vattr.va_type = VBLK;
64437741Smckusick 		break;
64537741Smckusick 	default:
64637741Smckusick 		error = EINVAL;
64737741Smckusick 		goto out;
6486254Sroot 	}
649*45914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
65037741Smckusick 	vattr.va_rdev = uap->dev;
6516254Sroot out:
65242465Smckusick 	if (!error) {
65342465Smckusick 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
65442465Smckusick 	} else {
65537741Smckusick 		VOP_ABORTOP(ndp);
65643344Smckusick 		if (ndp->ni_dvp == vp)
65743344Smckusick 			vrele(ndp->ni_dvp);
65843344Smckusick 		else
65943344Smckusick 			vput(ndp->ni_dvp);
66042465Smckusick 		if (vp)
66142465Smckusick 			vrele(vp);
66242465Smckusick 	}
66337741Smckusick 	RETURN (error);
6646254Sroot }
6656254Sroot 
6666254Sroot /*
66740285Smckusick  * Mkfifo system call
66840285Smckusick  */
66942441Smckusick /* ARGSUSED */
67042441Smckusick mkfifo(p, uap, retval)
671*45914Smckusick 	struct proc *p;
67242441Smckusick 	register struct args {
67340285Smckusick 		char	*fname;
67440285Smckusick 		int	fmode;
67542441Smckusick 	} *uap;
67642441Smckusick 	int *retval;
67742441Smckusick {
67842441Smckusick 	register struct nameidata *ndp = &u.u_nd;
67940285Smckusick 	struct vattr vattr;
68040285Smckusick 	int error;
68140285Smckusick 
68240285Smckusick #ifndef FIFO
68340285Smckusick 	RETURN (EOPNOTSUPP);
68440285Smckusick #else
68540285Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
68640285Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
68740285Smckusick 	ndp->ni_dirp = uap->fname;
68840285Smckusick 	if (error = namei(ndp))
68940285Smckusick 		RETURN (error);
69040285Smckusick 	if (ndp->ni_vp != NULL) {
69140285Smckusick 		VOP_ABORTOP(ndp);
69243344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
69343344Smckusick 			vrele(ndp->ni_dvp);
69443344Smckusick 		else
69543344Smckusick 			vput(ndp->ni_dvp);
69642465Smckusick 		vrele(ndp->ni_vp);
69740285Smckusick 		RETURN (EEXIST);
69840285Smckusick 	}
69945785Sbostic 	VATTR_NULL(&vattr);
70045785Sbostic 	vattr.va_type = VFIFO;
701*45914Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ p->p_fd->fd_cmask;
70240285Smckusick 	RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred));
70340285Smckusick #endif /* FIFO */
70440285Smckusick }
70540285Smckusick 
70640285Smckusick /*
7076254Sroot  * link system call
7086254Sroot  */
70942441Smckusick /* ARGSUSED */
71042441Smckusick link(p, uap, retval)
711*45914Smckusick 	struct proc *p;
71242441Smckusick 	register struct args {
7136254Sroot 		char	*target;
7146254Sroot 		char	*linkname;
71542441Smckusick 	} *uap;
71642441Smckusick 	int *retval;
71742441Smckusick {
71842441Smckusick 	register struct nameidata *ndp = &u.u_nd;
71937741Smckusick 	register struct vnode *vp, *xp;
72037741Smckusick 	int error;
7216254Sroot 
72216694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
72316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
72416694Smckusick 	ndp->ni_dirp = uap->target;
72537741Smckusick 	if (error = namei(ndp))
72637741Smckusick 		RETURN (error);
72737741Smckusick 	vp = ndp->ni_vp;
72837741Smckusick 	if (vp->v_type == VDIR &&
72942441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
73037741Smckusick 		goto out1;
73137741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
73216694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
73337741Smckusick 	if (error = namei(ndp))
73437741Smckusick 		goto out1;
73537741Smckusick 	xp = ndp->ni_vp;
7366254Sroot 	if (xp != NULL) {
73737741Smckusick 		error = EEXIST;
7386254Sroot 		goto out;
7396254Sroot 	}
74037741Smckusick 	xp = ndp->ni_dvp;
74137741Smckusick 	if (vp->v_mount != xp->v_mount)
74237741Smckusick 		error = EXDEV;
7436254Sroot out:
74442465Smckusick 	if (!error) {
74542465Smckusick 		error = VOP_LINK(vp, ndp);
74642465Smckusick 	} else {
74737741Smckusick 		VOP_ABORTOP(ndp);
74843344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
74943344Smckusick 			vrele(ndp->ni_dvp);
75043344Smckusick 		else
75143344Smckusick 			vput(ndp->ni_dvp);
75242465Smckusick 		if (ndp->ni_vp)
75342465Smckusick 			vrele(ndp->ni_vp);
75442465Smckusick 	}
75537741Smckusick out1:
75637741Smckusick 	vrele(vp);
75737741Smckusick 	RETURN (error);
7586254Sroot }
7596254Sroot 
7606254Sroot /*
7616254Sroot  * symlink -- make a symbolic link
7626254Sroot  */
76342441Smckusick /* ARGSUSED */
76442441Smckusick symlink(p, uap, retval)
765*45914Smckusick 	struct proc *p;
76642441Smckusick 	register struct args {
7676254Sroot 		char	*target;
7686254Sroot 		char	*linkname;
76942441Smckusick 	} *uap;
77042441Smckusick 	int *retval;
77142441Smckusick {
77242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
77337741Smckusick 	struct vattr vattr;
77437741Smckusick 	char *target;
77537741Smckusick 	int error;
7766254Sroot 
77716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
77816694Smckusick 	ndp->ni_dirp = uap->linkname;
77937741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
78037741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
78142465Smckusick 		goto out;
78237741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
78337741Smckusick 	if (error = namei(ndp))
78442465Smckusick 		goto out;
78542465Smckusick 	if (ndp->ni_vp) {
78642465Smckusick 		VOP_ABORTOP(ndp);
78743344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
78843344Smckusick 			vrele(ndp->ni_dvp);
78943344Smckusick 		else
79043344Smckusick 			vput(ndp->ni_dvp);
79142465Smckusick 		vrele(ndp->ni_vp);
79237741Smckusick 		error = EEXIST;
79337741Smckusick 		goto out;
7946254Sroot 	}
79541362Smckusick 	VATTR_NULL(&vattr);
796*45914Smckusick 	vattr.va_mode = 0777 &~ p->p_fd->fd_cmask;
79742465Smckusick 	error = VOP_SYMLINK(ndp, &vattr, target);
79837741Smckusick out:
79937741Smckusick 	FREE(target, M_NAMEI);
80037741Smckusick 	RETURN (error);
8016254Sroot }
8026254Sroot 
8036254Sroot /*
8046254Sroot  * Unlink system call.
8056254Sroot  * Hard to avoid races here, especially
8066254Sroot  * in unlinking directories.
8076254Sroot  */
80842441Smckusick /* ARGSUSED */
80942441Smckusick unlink(p, uap, retval)
810*45914Smckusick 	struct proc *p;
81142441Smckusick 	struct args {
81242441Smckusick 		char	*fname;
81342441Smckusick 	} *uap;
81442441Smckusick 	int *retval;
8156254Sroot {
81642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
81737741Smckusick 	register struct vnode *vp;
81837741Smckusick 	int error;
8196254Sroot 
82037741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
82116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
82216694Smckusick 	ndp->ni_dirp = uap->fname;
82337741Smckusick 	if (error = namei(ndp))
82437741Smckusick 		RETURN (error);
82537741Smckusick 	vp = ndp->ni_vp;
82637741Smckusick 	if (vp->v_type == VDIR &&
82742441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
8286254Sroot 		goto out;
8296254Sroot 	/*
8306254Sroot 	 * Don't unlink a mounted file.
8316254Sroot 	 */
83237741Smckusick 	if (vp->v_flag & VROOT) {
83337741Smckusick 		error = EBUSY;
8346254Sroot 		goto out;
8356254Sroot 	}
83645738Smckusick 	(void) vnode_pager_uncache(vp);
8376254Sroot out:
83842465Smckusick 	if (!error) {
83942465Smckusick 		error = VOP_REMOVE(ndp);
84042465Smckusick 	} else {
84137741Smckusick 		VOP_ABORTOP(ndp);
84243344Smckusick 		if (ndp->ni_dvp == vp)
84343344Smckusick 			vrele(ndp->ni_dvp);
84443344Smckusick 		else
84543344Smckusick 			vput(ndp->ni_dvp);
84642465Smckusick 		vput(vp);
84742465Smckusick 	}
84837741Smckusick 	RETURN (error);
8496254Sroot }
8506254Sroot 
8516254Sroot /*
8526254Sroot  * Seek system call
8536254Sroot  */
85442441Smckusick lseek(p, uap, retval)
855*45914Smckusick 	struct proc *p;
85642441Smckusick 	register struct args {
85737741Smckusick 		int	fdes;
8586254Sroot 		off_t	off;
8596254Sroot 		int	sbase;
86042441Smckusick 	} *uap;
86142441Smckusick 	off_t *retval;
86242441Smckusick {
86342441Smckusick 	struct ucred *cred = u.u_nd.ni_cred;
864*45914Smckusick 	register struct filedesc *fdp = p->p_fd;
86542441Smckusick 	register struct file *fp;
86637741Smckusick 	struct vattr vattr;
86737741Smckusick 	int error;
8686254Sroot 
869*45914Smckusick 	if ((unsigned)uap->fdes >= fdp->fd_maxfiles ||
870*45914Smckusick 	    (fp = OFILE(fdp, uap->fdes)) == NULL)
87137741Smckusick 		RETURN (EBADF);
87237741Smckusick 	if (fp->f_type != DTYPE_VNODE)
87337741Smckusick 		RETURN (ESPIPE);
87413878Ssam 	switch (uap->sbase) {
87513878Ssam 
87613878Ssam 	case L_INCR:
87713878Ssam 		fp->f_offset += uap->off;
87813878Ssam 		break;
87913878Ssam 
88013878Ssam 	case L_XTND:
88137741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
88242441Smckusick 		    &vattr, cred))
88337741Smckusick 			RETURN (error);
88437741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
88513878Ssam 		break;
88613878Ssam 
88713878Ssam 	case L_SET:
88813878Ssam 		fp->f_offset = uap->off;
88913878Ssam 		break;
89013878Ssam 
89113878Ssam 	default:
89237741Smckusick 		RETURN (EINVAL);
89313878Ssam 	}
89442441Smckusick 	*retval = fp->f_offset;
89537741Smckusick 	RETURN (0);
8966254Sroot }
8976254Sroot 
8986254Sroot /*
8996254Sroot  * Access system call
9006254Sroot  */
90142441Smckusick /* ARGSUSED */
90242441Smckusick saccess(p, uap, retval)
903*45914Smckusick 	struct proc *p;
90442441Smckusick 	register struct args {
9056254Sroot 		char	*fname;
9066254Sroot 		int	fmode;
90742441Smckusick 	} *uap;
90842441Smckusick 	int *retval;
90942441Smckusick {
91042441Smckusick 	register struct nameidata *ndp = &u.u_nd;
91142441Smckusick 	register struct ucred *cred = ndp->ni_cred;
91237741Smckusick 	register struct vnode *vp;
91337741Smckusick 	int error, mode, svuid, svgid;
9146254Sroot 
91542441Smckusick 	svuid = cred->cr_uid;
91642441Smckusick 	svgid = cred->cr_groups[0];
91742441Smckusick 	cred->cr_uid = p->p_ruid;
91842441Smckusick 	cred->cr_groups[0] = p->p_rgid;
91937741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
92016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
92116694Smckusick 	ndp->ni_dirp = uap->fname;
92237741Smckusick 	if (error = namei(ndp))
92337741Smckusick 		goto out1;
92437741Smckusick 	vp = ndp->ni_vp;
92537741Smckusick 	/*
92637741Smckusick 	 * fmode == 0 means only check for exist
92737741Smckusick 	 */
92837741Smckusick 	if (uap->fmode) {
92937741Smckusick 		mode = 0;
93037741Smckusick 		if (uap->fmode & R_OK)
93137741Smckusick 			mode |= VREAD;
93237741Smckusick 		if (uap->fmode & W_OK)
93337741Smckusick 			mode |= VWRITE;
93437741Smckusick 		if (uap->fmode & X_OK)
93537741Smckusick 			mode |= VEXEC;
93639543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
93738399Smckusick 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
9386254Sroot 	}
93937741Smckusick 	vput(vp);
94037741Smckusick out1:
94142441Smckusick 	cred->cr_uid = svuid;
94242441Smckusick 	cred->cr_groups[0] = svgid;
94337741Smckusick 	RETURN (error);
9446254Sroot }
9456254Sroot 
9466254Sroot /*
9476574Smckusic  * Stat system call.  This version follows links.
94837Sbill  */
94942441Smckusick /* ARGSUSED */
95042441Smckusick stat(p, uap, retval)
951*45914Smckusick 	struct proc *p;
95242441Smckusick 	register struct args {
95342441Smckusick 		char	*fname;
95442441Smckusick 		struct stat *ub;
95542441Smckusick 	} *uap;
95642441Smckusick 	int *retval;
95737Sbill {
95842441Smckusick 	register struct nameidata *ndp = &u.u_nd;
95942441Smckusick 	struct stat sb;
96042441Smckusick 	int error;
96137Sbill 
96242441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
96342441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
96442441Smckusick 	ndp->ni_dirp = uap->fname;
96542441Smckusick 	if (error = namei(ndp))
96642441Smckusick 		RETURN (error);
96742441Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
96842441Smckusick 	vput(ndp->ni_vp);
96942441Smckusick 	if (error)
97042441Smckusick 		RETURN (error);
97142441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
97242441Smckusick 	RETURN (error);
97337Sbill }
97437Sbill 
97537Sbill /*
9766574Smckusic  * Lstat system call.  This version does not follow links.
9775992Swnj  */
97842441Smckusick /* ARGSUSED */
97942441Smckusick lstat(p, uap, retval)
980*45914Smckusick 	struct proc *p;
98142441Smckusick 	register struct args {
9825992Swnj 		char	*fname;
98312756Ssam 		struct stat *ub;
98442441Smckusick 	} *uap;
98542441Smckusick 	int *retval;
98642441Smckusick {
98742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
98812756Ssam 	struct stat sb;
98937741Smckusick 	int error;
9905992Swnj 
99142441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW;
99216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
99316694Smckusick 	ndp->ni_dirp = uap->fname;
99437741Smckusick 	if (error = namei(ndp))
99537741Smckusick 		RETURN (error);
99637741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
99737741Smckusick 	vput(ndp->ni_vp);
99837741Smckusick 	if (error)
99937741Smckusick 		RETURN (error);
100037741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
100137741Smckusick 	RETURN (error);
10025992Swnj }
10035992Swnj 
10045992Swnj /*
10055992Swnj  * Return target name of a symbolic link
100637Sbill  */
100742441Smckusick /* ARGSUSED */
100842441Smckusick readlink(p, uap, retval)
1009*45914Smckusick 	struct proc *p;
101042441Smckusick 	register struct args {
10115992Swnj 		char	*name;
10125992Swnj 		char	*buf;
10135992Swnj 		int	count;
101442441Smckusick 	} *uap;
101542441Smckusick 	int *retval;
101642441Smckusick {
101742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
101837741Smckusick 	register struct vnode *vp;
101937741Smckusick 	struct iovec aiov;
102037741Smckusick 	struct uio auio;
102137741Smckusick 	int error;
10225992Swnj 
102337741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
102416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
102516694Smckusick 	ndp->ni_dirp = uap->name;
102637741Smckusick 	if (error = namei(ndp))
102737741Smckusick 		RETURN (error);
102837741Smckusick 	vp = ndp->ni_vp;
102937741Smckusick 	if (vp->v_type != VLNK) {
103037741Smckusick 		error = EINVAL;
10315992Swnj 		goto out;
10325992Swnj 	}
103337741Smckusick 	aiov.iov_base = uap->buf;
103437741Smckusick 	aiov.iov_len = uap->count;
103537741Smckusick 	auio.uio_iov = &aiov;
103637741Smckusick 	auio.uio_iovcnt = 1;
103737741Smckusick 	auio.uio_offset = 0;
103837741Smckusick 	auio.uio_rw = UIO_READ;
103937741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
104037741Smckusick 	auio.uio_resid = uap->count;
104137741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
10425992Swnj out:
104337741Smckusick 	vput(vp);
104442441Smckusick 	*retval = uap->count - auio.uio_resid;
104537741Smckusick 	RETURN (error);
10465992Swnj }
10475992Swnj 
10489167Ssam /*
104938259Smckusick  * Change flags of a file given path name.
105038259Smckusick  */
105142441Smckusick /* ARGSUSED */
105242441Smckusick chflags(p, uap, retval)
1053*45914Smckusick 	struct proc *p;
105442441Smckusick 	register struct args {
105538259Smckusick 		char	*fname;
105638259Smckusick 		int	flags;
105742441Smckusick 	} *uap;
105842441Smckusick 	int *retval;
105942441Smckusick {
106042441Smckusick 	register struct nameidata *ndp = &u.u_nd;
106138259Smckusick 	register struct vnode *vp;
106238259Smckusick 	struct vattr vattr;
106338259Smckusick 	int error;
106438259Smckusick 
106538259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
106638259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
106738259Smckusick 	ndp->ni_dirp = uap->fname;
106838259Smckusick 	if (error = namei(ndp))
106938259Smckusick 		RETURN (error);
107038259Smckusick 	vp = ndp->ni_vp;
107141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
107238259Smckusick 		error = EROFS;
107338259Smckusick 		goto out;
107438259Smckusick 	}
107545785Sbostic 	VATTR_NULL(&vattr);
107645785Sbostic 	vattr.va_flags = uap->flags;
107738259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
107838259Smckusick out:
107938259Smckusick 	vput(vp);
108038259Smckusick 	RETURN (error);
108138259Smckusick }
108238259Smckusick 
108338259Smckusick /*
108438259Smckusick  * Change flags of a file given a file descriptor.
108538259Smckusick  */
108642441Smckusick /* ARGSUSED */
108742441Smckusick fchflags(p, uap, retval)
1088*45914Smckusick 	struct proc *p;
108942441Smckusick 	register struct args {
109038259Smckusick 		int	fd;
109138259Smckusick 		int	flags;
109242441Smckusick 	} *uap;
109342441Smckusick 	int *retval;
109442441Smckusick {
109538259Smckusick 	struct vattr vattr;
109638259Smckusick 	struct vnode *vp;
109738259Smckusick 	struct file *fp;
109838259Smckusick 	int error;
109938259Smckusick 
1100*45914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
110138259Smckusick 		RETURN (error);
110238259Smckusick 	vp = (struct vnode *)fp->f_data;
110338259Smckusick 	VOP_LOCK(vp);
110441400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
110538259Smckusick 		error = EROFS;
110638259Smckusick 		goto out;
110738259Smckusick 	}
110845785Sbostic 	VATTR_NULL(&vattr);
110945785Sbostic 	vattr.va_flags = uap->flags;
111038259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
111138259Smckusick out:
111238259Smckusick 	VOP_UNLOCK(vp);
111338259Smckusick 	RETURN (error);
111438259Smckusick }
111538259Smckusick 
111638259Smckusick /*
11179167Ssam  * Change mode of a file given path name.
11189167Ssam  */
111942441Smckusick /* ARGSUSED */
112042441Smckusick chmod(p, uap, retval)
1121*45914Smckusick 	struct proc *p;
112242441Smckusick 	register struct args {
11236254Sroot 		char	*fname;
11246254Sroot 		int	fmode;
112542441Smckusick 	} *uap;
112642441Smckusick 	int *retval;
112742441Smckusick {
112842441Smckusick 	register struct nameidata *ndp = &u.u_nd;
112937741Smckusick 	register struct vnode *vp;
113037741Smckusick 	struct vattr vattr;
113137741Smckusick 	int error;
11325992Swnj 
113337741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
113437741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
113537741Smckusick 	ndp->ni_dirp = uap->fname;
113637741Smckusick 	if (error = namei(ndp))
113737741Smckusick 		RETURN (error);
113837741Smckusick 	vp = ndp->ni_vp;
113941400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
114037741Smckusick 		error = EROFS;
114137741Smckusick 		goto out;
114237741Smckusick 	}
114345785Sbostic 	VATTR_NULL(&vattr);
114445785Sbostic 	vattr.va_mode = uap->fmode & 07777;
114537741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
114637741Smckusick out:
114737741Smckusick 	vput(vp);
114837741Smckusick 	RETURN (error);
11497701Ssam }
11507439Sroot 
11519167Ssam /*
11529167Ssam  * Change mode of a file given a file descriptor.
11539167Ssam  */
115442441Smckusick /* ARGSUSED */
115542441Smckusick fchmod(p, uap, retval)
1156*45914Smckusick 	struct proc *p;
115742441Smckusick 	register struct args {
11587701Ssam 		int	fd;
11597701Ssam 		int	fmode;
116042441Smckusick 	} *uap;
116142441Smckusick 	int *retval;
116242441Smckusick {
116337741Smckusick 	struct vattr vattr;
116437741Smckusick 	struct vnode *vp;
116537741Smckusick 	struct file *fp;
116637741Smckusick 	int error;
11677701Ssam 
1168*45914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
116937741Smckusick 		RETURN (error);
117037741Smckusick 	vp = (struct vnode *)fp->f_data;
117137741Smckusick 	VOP_LOCK(vp);
117241400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
117337741Smckusick 		error = EROFS;
117437741Smckusick 		goto out;
11757439Sroot 	}
117645785Sbostic 	VATTR_NULL(&vattr);
117745785Sbostic 	vattr.va_mode = uap->fmode & 07777;
117837741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
117937741Smckusick out:
118037741Smckusick 	VOP_UNLOCK(vp);
118137741Smckusick 	RETURN (error);
11825992Swnj }
11835992Swnj 
11849167Ssam /*
11859167Ssam  * Set ownership given a path name.
11869167Ssam  */
118742441Smckusick /* ARGSUSED */
118842441Smckusick chown(p, uap, retval)
1189*45914Smckusick 	struct proc *p;
119042441Smckusick 	register struct args {
11916254Sroot 		char	*fname;
11926254Sroot 		int	uid;
11936254Sroot 		int	gid;
119442441Smckusick 	} *uap;
119542441Smckusick 	int *retval;
119642441Smckusick {
119742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
119837741Smckusick 	register struct vnode *vp;
119937741Smckusick 	struct vattr vattr;
120037741Smckusick 	int error;
120137Sbill 
120237741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
120336614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
120436614Sbostic 	ndp->ni_dirp = uap->fname;
120537741Smckusick 	if (error = namei(ndp))
120637741Smckusick 		RETURN (error);
120737741Smckusick 	vp = ndp->ni_vp;
120841400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
120937741Smckusick 		error = EROFS;
121037741Smckusick 		goto out;
121137741Smckusick 	}
121245785Sbostic 	VATTR_NULL(&vattr);
121345785Sbostic 	vattr.va_uid = uap->uid;
121445785Sbostic 	vattr.va_gid = uap->gid;
121537741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
121637741Smckusick out:
121737741Smckusick 	vput(vp);
121837741Smckusick 	RETURN (error);
12197701Ssam }
12207439Sroot 
12219167Ssam /*
12229167Ssam  * Set ownership given a file descriptor.
12239167Ssam  */
122442441Smckusick /* ARGSUSED */
122542441Smckusick fchown(p, uap, retval)
1226*45914Smckusick 	struct proc *p;
122742441Smckusick 	register struct args {
12287701Ssam 		int	fd;
12297701Ssam 		int	uid;
12307701Ssam 		int	gid;
123142441Smckusick 	} *uap;
123242441Smckusick 	int *retval;
123342441Smckusick {
123437741Smckusick 	struct vattr vattr;
123537741Smckusick 	struct vnode *vp;
123637741Smckusick 	struct file *fp;
123737741Smckusick 	int error;
12387701Ssam 
1239*45914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
124037741Smckusick 		RETURN (error);
124137741Smckusick 	vp = (struct vnode *)fp->f_data;
124237741Smckusick 	VOP_LOCK(vp);
124341400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
124437741Smckusick 		error = EROFS;
124537741Smckusick 		goto out;
124637741Smckusick 	}
124745785Sbostic 	VATTR_NULL(&vattr);
124845785Sbostic 	vattr.va_uid = uap->uid;
124945785Sbostic 	vattr.va_gid = uap->gid;
125037741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
125137741Smckusick out:
125237741Smckusick 	VOP_UNLOCK(vp);
125337741Smckusick 	RETURN (error);
12547701Ssam }
12557701Ssam 
125642441Smckusick /*
125742441Smckusick  * Set the access and modification times of a file.
125842441Smckusick  */
125942441Smckusick /* ARGSUSED */
126042441Smckusick utimes(p, uap, retval)
1261*45914Smckusick 	struct proc *p;
126242441Smckusick 	register struct args {
126311811Ssam 		char	*fname;
126411811Ssam 		struct	timeval *tptr;
126542441Smckusick 	} *uap;
126642441Smckusick 	int *retval;
126742441Smckusick {
126842441Smckusick 	register struct nameidata *ndp = &u.u_nd;
126937741Smckusick 	register struct vnode *vp;
127011811Ssam 	struct timeval tv[2];
127137741Smckusick 	struct vattr vattr;
127237741Smckusick 	int error;
127311811Ssam 
127437741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
127537741Smckusick 		RETURN (error);
127637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
127737741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
127837741Smckusick 	ndp->ni_dirp = uap->fname;
127937741Smckusick 	if (error = namei(ndp))
128037741Smckusick 		RETURN (error);
128137741Smckusick 	vp = ndp->ni_vp;
128241400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
128337741Smckusick 		error = EROFS;
128437741Smckusick 		goto out;
128521015Smckusick 	}
128645785Sbostic 	VATTR_NULL(&vattr);
128745785Sbostic 	vattr.va_atime = tv[0];
128845785Sbostic 	vattr.va_mtime = tv[1];
128937741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
129037741Smckusick out:
129137741Smckusick 	vput(vp);
129237741Smckusick 	RETURN (error);
129311811Ssam }
129411811Ssam 
12959167Ssam /*
12969167Ssam  * Truncate a file given its path name.
12979167Ssam  */
129842441Smckusick /* ARGSUSED */
129942441Smckusick truncate(p, uap, retval)
1300*45914Smckusick 	struct proc *p;
130142441Smckusick 	register struct args {
13027701Ssam 		char	*fname;
130326473Skarels 		off_t	length;
130442441Smckusick 	} *uap;
130542441Smckusick 	int *retval;
130642441Smckusick {
130742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
130837741Smckusick 	register struct vnode *vp;
130937741Smckusick 	struct vattr vattr;
131037741Smckusick 	int error;
13117701Ssam 
131237741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
131316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
131416694Smckusick 	ndp->ni_dirp = uap->fname;
131537741Smckusick 	if (error = namei(ndp))
131637741Smckusick 		RETURN (error);
131737741Smckusick 	vp = ndp->ni_vp;
131837741Smckusick 	if (vp->v_type == VDIR) {
131937741Smckusick 		error = EISDIR;
132037741Smckusick 		goto out;
13217701Ssam 	}
132238399Smckusick 	if ((error = vn_writechk(vp)) ||
132338399Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
132437741Smckusick 		goto out;
132545785Sbostic 	VATTR_NULL(&vattr);
132645785Sbostic 	vattr.va_size = uap->length;
132737741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
132837741Smckusick out:
132937741Smckusick 	vput(vp);
133037741Smckusick 	RETURN (error);
13317701Ssam }
13327701Ssam 
13339167Ssam /*
13349167Ssam  * Truncate a file given a file descriptor.
13359167Ssam  */
133642441Smckusick /* ARGSUSED */
133742441Smckusick ftruncate(p, uap, retval)
1338*45914Smckusick 	struct proc *p;
133942441Smckusick 	register struct args {
13407701Ssam 		int	fd;
134126473Skarels 		off_t	length;
134242441Smckusick 	} *uap;
134342441Smckusick 	int *retval;
134442441Smckusick {
134537741Smckusick 	struct vattr vattr;
134637741Smckusick 	struct vnode *vp;
13477701Ssam 	struct file *fp;
134837741Smckusick 	int error;
13497701Ssam 
1350*45914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
135137741Smckusick 		RETURN (error);
135237741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
135337741Smckusick 		RETURN (EINVAL);
135437741Smckusick 	vp = (struct vnode *)fp->f_data;
135537741Smckusick 	VOP_LOCK(vp);
135637741Smckusick 	if (vp->v_type == VDIR) {
135737741Smckusick 		error = EISDIR;
135837741Smckusick 		goto out;
13597701Ssam 	}
136038399Smckusick 	if (error = vn_writechk(vp))
136137741Smckusick 		goto out;
136245785Sbostic 	VATTR_NULL(&vattr);
136345785Sbostic 	vattr.va_size = uap->length;
136437741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
136537741Smckusick out:
136637741Smckusick 	VOP_UNLOCK(vp);
136737741Smckusick 	RETURN (error);
13687701Ssam }
13697701Ssam 
13709167Ssam /*
13719167Ssam  * Synch an open file.
13729167Ssam  */
137342441Smckusick /* ARGSUSED */
137442441Smckusick fsync(p, uap, retval)
1375*45914Smckusick 	struct proc *p;
137642441Smckusick 	struct args {
137742441Smckusick 		int	fd;
137842441Smckusick 	} *uap;
137942441Smckusick 	int *retval;
13809167Ssam {
138139592Smckusick 	register struct vnode *vp;
13829167Ssam 	struct file *fp;
138337741Smckusick 	int error;
13849167Ssam 
1385*45914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
138637741Smckusick 		RETURN (error);
138739592Smckusick 	vp = (struct vnode *)fp->f_data;
138839592Smckusick 	VOP_LOCK(vp);
138939592Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT);
139039592Smckusick 	VOP_UNLOCK(vp);
139137741Smckusick 	RETURN (error);
13929167Ssam }
13939167Ssam 
13949167Ssam /*
13959167Ssam  * Rename system call.
13969167Ssam  *
13979167Ssam  * Source and destination must either both be directories, or both
13989167Ssam  * not be directories.  If target is a directory, it must be empty.
13999167Ssam  */
140042441Smckusick /* ARGSUSED */
140142441Smckusick rename(p, uap, retval)
1402*45914Smckusick 	struct proc *p;
140342441Smckusick 	register struct args {
14047701Ssam 		char	*from;
14057701Ssam 		char	*to;
140642441Smckusick 	} *uap;
140742441Smckusick 	int *retval;
140842441Smckusick {
140937741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
141042441Smckusick 	register struct nameidata *ndp = &u.u_nd;
141137741Smckusick 	struct nameidata tond;
141237741Smckusick 	int error;
14137701Ssam 
141437741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
141516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
141616694Smckusick 	ndp->ni_dirp = uap->from;
141737741Smckusick 	if (error = namei(ndp))
141837741Smckusick 		RETURN (error);
141937741Smckusick 	fvp = ndp->ni_vp;
142038266Smckusick 	nddup(ndp, &tond);
142137741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
142237741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
142337741Smckusick 	tond.ni_dirp = uap->to;
142442465Smckusick 	if (error = namei(&tond)) {
142542465Smckusick 		VOP_ABORTOP(ndp);
142642465Smckusick 		vrele(ndp->ni_dvp);
142742465Smckusick 		vrele(fvp);
142842465Smckusick 		goto out1;
142942465Smckusick 	}
143037741Smckusick 	tdvp = tond.ni_dvp;
143137741Smckusick 	tvp = tond.ni_vp;
143237741Smckusick 	if (tvp != NULL) {
143337741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
143439242Sbostic 			error = ENOTDIR;
143537741Smckusick 			goto out;
143637741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
143739242Sbostic 			error = EISDIR;
143837741Smckusick 			goto out;
14399167Ssam 		}
144045240Smckusick 		if (fvp->v_mount != tvp->v_mount) {
144145240Smckusick 			error = EXDEV;
144245240Smckusick 			goto out;
144345240Smckusick 		}
14449167Ssam 	}
144537741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
144637741Smckusick 		error = EXDEV;
14479167Ssam 		goto out;
144810051Ssam 	}
144939286Smckusick 	if (fvp == tdvp)
145037741Smckusick 		error = EINVAL;
145139286Smckusick 	/*
145239286Smckusick 	 * If source is the same as the destination,
145339286Smckusick 	 * then there is nothing to do.
145439286Smckusick 	 */
145539286Smckusick 	if (fvp == tvp)
145639286Smckusick 		error = -1;
145737741Smckusick out:
145842465Smckusick 	if (!error) {
145942465Smckusick 		error = VOP_RENAME(ndp, &tond);
146042465Smckusick 	} else {
146137741Smckusick 		VOP_ABORTOP(&tond);
146243344Smckusick 		if (tdvp == tvp)
146343344Smckusick 			vrele(tdvp);
146443344Smckusick 		else
146543344Smckusick 			vput(tdvp);
146642465Smckusick 		if (tvp)
146742465Smckusick 			vput(tvp);
146837741Smckusick 		VOP_ABORTOP(ndp);
146942465Smckusick 		vrele(ndp->ni_dvp);
147042465Smckusick 		vrele(fvp);
14719167Ssam 	}
147237741Smckusick out1:
147338266Smckusick 	ndrele(&tond);
147439286Smckusick 	if (error == -1)
147539286Smckusick 		RETURN (0);
147637741Smckusick 	RETURN (error);
14777701Ssam }
14787701Ssam 
14797535Sroot /*
148012756Ssam  * Mkdir system call
148112756Ssam  */
148242441Smckusick /* ARGSUSED */
148342441Smckusick mkdir(p, uap, retval)
1484*45914Smckusick 	struct proc *p;
148542441Smckusick 	register struct args {
148612756Ssam 		char	*name;
148712756Ssam 		int	dmode;
148842441Smckusick 	} *uap;
148942441Smckusick 	int *retval;
149042441Smckusick {
149142441Smckusick 	register struct nameidata *ndp = &u.u_nd;
149237741Smckusick 	register struct vnode *vp;
149337741Smckusick 	struct vattr vattr;
149437741Smckusick 	int error;
149512756Ssam 
149637741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
149716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
149816694Smckusick 	ndp->ni_dirp = uap->name;
149937741Smckusick 	if (error = namei(ndp))
150037741Smckusick 		RETURN (error);
150137741Smckusick 	vp = ndp->ni_vp;
150237741Smckusick 	if (vp != NULL) {
150337741Smckusick 		VOP_ABORTOP(ndp);
150443344Smckusick 		if (ndp->ni_dvp == vp)
150543344Smckusick 			vrele(ndp->ni_dvp);
150643344Smckusick 		else
150743344Smckusick 			vput(ndp->ni_dvp);
150842465Smckusick 		vrele(vp);
150937741Smckusick 		RETURN (EEXIST);
151012756Ssam 	}
151141362Smckusick 	VATTR_NULL(&vattr);
151237741Smckusick 	vattr.va_type = VDIR;
1513*45914Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ p->p_fd->fd_cmask;
151437741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
151538145Smckusick 	if (!error)
151638145Smckusick 		vput(ndp->ni_vp);
151737741Smckusick 	RETURN (error);
151812756Ssam }
151912756Ssam 
152012756Ssam /*
152112756Ssam  * Rmdir system call.
152212756Ssam  */
152342441Smckusick /* ARGSUSED */
152442441Smckusick rmdir(p, uap, retval)
1525*45914Smckusick 	struct proc *p;
152642441Smckusick 	struct args {
152742441Smckusick 		char	*name;
152842441Smckusick 	} *uap;
152942441Smckusick 	int *retval;
153012756Ssam {
153142441Smckusick 	register struct nameidata *ndp = &u.u_nd;
153237741Smckusick 	register struct vnode *vp;
153337741Smckusick 	int error;
153412756Ssam 
153537741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
153616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
153716694Smckusick 	ndp->ni_dirp = uap->name;
153837741Smckusick 	if (error = namei(ndp))
153937741Smckusick 		RETURN (error);
154037741Smckusick 	vp = ndp->ni_vp;
154137741Smckusick 	if (vp->v_type != VDIR) {
154237741Smckusick 		error = ENOTDIR;
154312756Ssam 		goto out;
154412756Ssam 	}
154512756Ssam 	/*
154637741Smckusick 	 * No rmdir "." please.
154712756Ssam 	 */
154837741Smckusick 	if (ndp->ni_dvp == vp) {
154937741Smckusick 		error = EINVAL;
155012756Ssam 		goto out;
155112756Ssam 	}
155212756Ssam 	/*
155337741Smckusick 	 * Don't unlink a mounted file.
155412756Ssam 	 */
155537741Smckusick 	if (vp->v_flag & VROOT)
155637741Smckusick 		error = EBUSY;
155712756Ssam out:
155842465Smckusick 	if (!error) {
155942465Smckusick 		error = VOP_RMDIR(ndp);
156042465Smckusick 	} else {
156137741Smckusick 		VOP_ABORTOP(ndp);
156243344Smckusick 		if (ndp->ni_dvp == vp)
156343344Smckusick 			vrele(ndp->ni_dvp);
156443344Smckusick 		else
156543344Smckusick 			vput(ndp->ni_dvp);
156642465Smckusick 		vput(vp);
156742465Smckusick 	}
156837741Smckusick 	RETURN (error);
156912756Ssam }
157012756Ssam 
157137741Smckusick /*
157237741Smckusick  * Read a block of directory entries in a file system independent format
157337741Smckusick  */
157442441Smckusick getdirentries(p, uap, retval)
1575*45914Smckusick 	struct proc *p;
157642441Smckusick 	register struct args {
157737741Smckusick 		int	fd;
157837741Smckusick 		char	*buf;
157937741Smckusick 		unsigned count;
158037741Smckusick 		long	*basep;
158142441Smckusick 	} *uap;
158242441Smckusick 	int *retval;
158342441Smckusick {
158439592Smckusick 	register struct vnode *vp;
158516540Ssam 	struct file *fp;
158637741Smckusick 	struct uio auio;
158737741Smckusick 	struct iovec aiov;
158838129Smckusick 	off_t off;
158940321Smckusick 	int error, eofflag;
159012756Ssam 
1591*45914Smckusick 	if (error = getvnode(p->p_fd, uap->fd, &fp))
159237741Smckusick 		RETURN (error);
159337741Smckusick 	if ((fp->f_flag & FREAD) == 0)
159437741Smckusick 		RETURN (EBADF);
159539592Smckusick 	vp = (struct vnode *)fp->f_data;
159639592Smckusick 	if (vp->v_type != VDIR)
159739592Smckusick 		RETURN (EINVAL);
159837741Smckusick 	aiov.iov_base = uap->buf;
159937741Smckusick 	aiov.iov_len = uap->count;
160037741Smckusick 	auio.uio_iov = &aiov;
160137741Smckusick 	auio.uio_iovcnt = 1;
160237741Smckusick 	auio.uio_rw = UIO_READ;
160337741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
160437741Smckusick 	auio.uio_resid = uap->count;
160539592Smckusick 	VOP_LOCK(vp);
160639592Smckusick 	auio.uio_offset = off = fp->f_offset;
160740321Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
160839592Smckusick 	fp->f_offset = auio.uio_offset;
160939592Smckusick 	VOP_UNLOCK(vp);
161039592Smckusick 	if (error)
161137741Smckusick 		RETURN (error);
161239592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
161342441Smckusick 	*retval = uap->count - auio.uio_resid;
161437741Smckusick 	RETURN (error);
161512756Ssam }
161612756Ssam 
161712756Ssam /*
161812756Ssam  * mode mask for creation of files
161912756Ssam  */
162042441Smckusick mode_t
162142441Smckusick umask(p, uap, retval)
1622*45914Smckusick 	struct proc *p;
162342441Smckusick 	struct args {
162442441Smckusick 		int	mask;
162542441Smckusick 	} *uap;
162642441Smckusick 	int *retval;
162712756Ssam {
1628*45914Smckusick 	register struct filedesc *fdp = p->p_fd;
162912756Ssam 
1630*45914Smckusick 	*retval = fdp->fd_cmask;
1631*45914Smckusick 	fdp->fd_cmask = uap->mask & 07777;
163237741Smckusick 	RETURN (0);
163312756Ssam }
163437741Smckusick 
163539566Smarc /*
163639566Smarc  * Void all references to file by ripping underlying filesystem
163739566Smarc  * away from vnode.
163839566Smarc  */
163942441Smckusick /* ARGSUSED */
164042441Smckusick revoke(p, uap, retval)
1641*45914Smckusick 	struct proc *p;
164242441Smckusick 	register struct args {
164339566Smarc 		char	*fname;
164442441Smckusick 	} *uap;
164542441Smckusick 	int *retval;
164642441Smckusick {
164742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
164839566Smarc 	register struct vnode *vp;
164939566Smarc 	struct vattr vattr;
165039566Smarc 	int error;
165139566Smarc 
165239566Smarc 	ndp->ni_nameiop = LOOKUP | FOLLOW;
165339566Smarc 	ndp->ni_segflg = UIO_USERSPACE;
165439566Smarc 	ndp->ni_dirp = uap->fname;
165539566Smarc 	if (error = namei(ndp))
165639566Smarc 		RETURN (error);
165739566Smarc 	vp = ndp->ni_vp;
165839566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
165939566Smarc 		error = EINVAL;
166039566Smarc 		goto out;
166139566Smarc 	}
166242441Smckusick 	if (error = VOP_GETATTR(vp, &vattr, ndp->ni_cred))
166339566Smarc 		goto out;
166442955Smckusick 	if (ndp->ni_cred->cr_uid != vattr.va_uid &&
166542441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
166639566Smarc 		goto out;
166739805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
166839632Smckusick 		vgoneall(vp);
166939566Smarc out:
167039566Smarc 	vrele(vp);
167139566Smarc 	RETURN (error);
167239566Smarc }
167339566Smarc 
1674*45914Smckusick getvnode(fdp, fdes, fpp)
1675*45914Smckusick 	struct filedesc *fdp;
167637741Smckusick 	struct file **fpp;
167737741Smckusick 	int fdes;
167837741Smckusick {
167937741Smckusick 	struct file *fp;
168037741Smckusick 
1681*45914Smckusick 	if ((unsigned)fdes >= fdp->fd_maxfiles ||
1682*45914Smckusick 	    (fp = OFILE(fdp, fdes)) == NULL)
168337741Smckusick 		return (EBADF);
168437741Smckusick 	if (fp->f_type != DTYPE_VNODE)
168537741Smckusick 		return (EINVAL);
168637741Smckusick 	*fpp = fp;
168737741Smckusick 	return (0);
168837741Smckusick }
1689