xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 45202)
123405Smckusick /*
237741Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337741Smckusick  * All rights reserved.
423405Smckusick  *
544459Sbostic  * %sccs.include.redist.c%
637741Smckusick  *
7*45202Smckusick  *	@(#)vfs_syscalls.c	7.58 (Berkeley) 09/05/90
823405Smckusick  */
937Sbill 
1017101Sbloom #include "param.h"
1117101Sbloom #include "systm.h"
1244407Skarels #include "user.h"
1317101Sbloom #include "kernel.h"
1417101Sbloom #include "file.h"
1517101Sbloom #include "stat.h"
1637741Smckusick #include "vnode.h"
1737741Smckusick #include "mount.h"
1817101Sbloom #include "proc.h"
1917101Sbloom #include "uio.h"
2037741Smckusick #include "malloc.h"
2137Sbill 
2243450Smckusick #define RETURN(val) {if (u.u_spare[0] != 0) panic("lock count"); return (val);}
2339797Smckusick 
2437741Smckusick /*
2537741Smckusick  * Virtual File System System Calls
2637741Smckusick  */
2712756Ssam 
289167Ssam /*
2937741Smckusick  * mount system call
309167Ssam  */
3142441Smckusick /* ARGSUSED */
3242441Smckusick mount(p, uap, retval)
3342441Smckusick 	register struct proc *p;
3442441Smckusick 	register struct args {
3537741Smckusick 		int	type;
3637741Smckusick 		char	*dir;
3737741Smckusick 		int	flags;
3837741Smckusick 		caddr_t	data;
3942441Smckusick 	} *uap;
4042441Smckusick 	int *retval;
4142441Smckusick {
4242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
4339335Smckusick 	register struct vnode *vp;
4439335Smckusick 	register struct mount *mp;
4540111Smckusick 	int error, flag;
466254Sroot 
4737741Smckusick 	/*
4837741Smckusick 	 * Must be super user
4937741Smckusick 	 */
5042441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
5137741Smckusick 		RETURN (error);
5237741Smckusick 	/*
5337741Smckusick 	 * Get vnode to be covered
5437741Smckusick 	 */
5537741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
5637741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
5737741Smckusick 	ndp->ni_dirp = uap->dir;
5837741Smckusick 	if (error = namei(ndp))
5937741Smckusick 		RETURN (error);
6037741Smckusick 	vp = ndp->ni_vp;
6141400Smckusick 	if (uap->flags & MNT_UPDATE) {
6239335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
6339335Smckusick 			vput(vp);
6439335Smckusick 			RETURN (EINVAL);
6539335Smckusick 		}
6639335Smckusick 		mp = vp->v_mount;
6739335Smckusick 		/*
6839335Smckusick 		 * We allow going from read-only to read-write,
6939335Smckusick 		 * but not from read-write to read-only.
7039335Smckusick 		 */
7141400Smckusick 		if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
7241400Smckusick 		    (uap->flags & MNT_RDONLY) != 0) {
7339335Smckusick 			vput(vp);
7439335Smckusick 			RETURN (EOPNOTSUPP);	/* Needs translation */
7539335Smckusick 		}
7641400Smckusick 		flag = mp->mnt_flag;
7741400Smckusick 		mp->mnt_flag |= MNT_UPDATE;
7839335Smckusick 		VOP_UNLOCK(vp);
7939335Smckusick 		goto update;
8039335Smckusick 	}
8139665Smckusick 	vinvalbuf(vp, 1);
8239805Smckusick 	if (vp->v_usecount != 1) {
8337741Smckusick 		vput(vp);
8437741Smckusick 		RETURN (EBUSY);
8537741Smckusick 	}
8637741Smckusick 	if (vp->v_type != VDIR) {
8737741Smckusick 		vput(vp);
8837741Smckusick 		RETURN (ENOTDIR);
8937741Smckusick 	}
9039741Smckusick 	if ((unsigned long)uap->type > MOUNT_MAXTYPE ||
9137741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
9237741Smckusick 		vput(vp);
9337741Smckusick 		RETURN (ENODEV);
9437741Smckusick 	}
9537741Smckusick 
9637741Smckusick 	/*
9739335Smckusick 	 * Allocate and initialize the file system.
9837741Smckusick 	 */
9937741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
10037741Smckusick 		M_MOUNT, M_WAITOK);
10141400Smckusick 	mp->mnt_op = vfssw[uap->type];
10241400Smckusick 	mp->mnt_flag = 0;
10341400Smckusick 	mp->mnt_exroot = 0;
10441400Smckusick 	mp->mnt_mounth = NULLVP;
10539335Smckusick 	if (error = vfs_lock(mp)) {
10639335Smckusick 		free((caddr_t)mp, M_MOUNT);
10739335Smckusick 		vput(vp);
10839335Smckusick 		RETURN (error);
10939335Smckusick 	}
11039335Smckusick 	if (vp->v_mountedhere != (struct mount *)0) {
11139335Smckusick 		vfs_unlock(mp);
11239335Smckusick 		free((caddr_t)mp, M_MOUNT);
11339335Smckusick 		vput(vp);
11439335Smckusick 		RETURN (EBUSY);
11539335Smckusick 	}
11639335Smckusick 	vp->v_mountedhere = mp;
11741400Smckusick 	mp->mnt_vnodecovered = vp;
11839335Smckusick update:
11939335Smckusick 	/*
12039335Smckusick 	 * Set the mount level flags.
12139335Smckusick 	 */
12241400Smckusick 	if (uap->flags & MNT_RDONLY)
12341400Smckusick 		mp->mnt_flag |= MNT_RDONLY;
12439335Smckusick 	else
12541400Smckusick 		mp->mnt_flag &= ~MNT_RDONLY;
12641400Smckusick 	if (uap->flags & MNT_NOSUID)
12741400Smckusick 		mp->mnt_flag |= MNT_NOSUID;
12839335Smckusick 	else
12941400Smckusick 		mp->mnt_flag &= ~MNT_NOSUID;
13041400Smckusick 	if (uap->flags & MNT_NOEXEC)
13141400Smckusick 		mp->mnt_flag |= MNT_NOEXEC;
13239335Smckusick 	else
13341400Smckusick 		mp->mnt_flag &= ~MNT_NOEXEC;
13441400Smckusick 	if (uap->flags & MNT_NODEV)
13541400Smckusick 		mp->mnt_flag |= MNT_NODEV;
13639335Smckusick 	else
13741400Smckusick 		mp->mnt_flag &= ~MNT_NODEV;
13841400Smckusick 	if (uap->flags & MNT_SYNCHRONOUS)
13941400Smckusick 		mp->mnt_flag |= MNT_SYNCHRONOUS;
14039335Smckusick 	else
14141400Smckusick 		mp->mnt_flag &= ~MNT_SYNCHRONOUS;
14239335Smckusick 	/*
14339335Smckusick 	 * Mount the filesystem.
14439335Smckusick 	 */
14539335Smckusick 	error = VFS_MOUNT(mp, uap->dir, uap->data, ndp);
14641400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
14741400Smckusick 		mp->mnt_flag &= ~MNT_UPDATE;
14839335Smckusick 		vrele(vp);
14940111Smckusick 		if (error)
15041400Smckusick 			mp->mnt_flag = flag;
15139335Smckusick 		RETURN (error);
15239335Smckusick 	}
15340110Smckusick 	/*
15440110Smckusick 	 * Put the new filesystem on the mount list after root.
15540110Smckusick 	 */
15641400Smckusick 	mp->mnt_next = rootfs->mnt_next;
15741400Smckusick 	mp->mnt_prev = rootfs;
15841400Smckusick 	rootfs->mnt_next = mp;
15941400Smckusick 	mp->mnt_next->mnt_prev = mp;
16037741Smckusick 	cache_purge(vp);
16137741Smckusick 	if (!error) {
16239335Smckusick 		VOP_UNLOCK(vp);
16337741Smckusick 		vfs_unlock(mp);
16439044Smckusick 		error = VFS_START(mp, 0);
16537741Smckusick 	} else {
16637741Smckusick 		vfs_remove(mp);
16737741Smckusick 		free((caddr_t)mp, M_MOUNT);
16839335Smckusick 		vput(vp);
16937741Smckusick 	}
17037741Smckusick 	RETURN (error);
1716254Sroot }
1726254Sroot 
1739167Ssam /*
17437741Smckusick  * Unmount system call.
17537741Smckusick  *
17637741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
17737741Smckusick  * not special file (as before).
1789167Ssam  */
17942441Smckusick /* ARGSUSED */
18042441Smckusick unmount(p, uap, retval)
18142441Smckusick 	register struct proc *p;
18242441Smckusick 	register struct args {
18337741Smckusick 		char	*pathp;
18437741Smckusick 		int	flags;
18542441Smckusick 	} *uap;
18642441Smckusick 	int *retval;
18742441Smckusick {
18837741Smckusick 	register struct vnode *vp;
18942441Smckusick 	register struct nameidata *ndp = &u.u_nd;
19039356Smckusick 	struct mount *mp;
19137741Smckusick 	int error;
1926254Sroot 
19337741Smckusick 	/*
19437741Smckusick 	 * Must be super user
19537741Smckusick 	 */
19642441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
19737741Smckusick 		RETURN (error);
19837741Smckusick 
19937741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
20037741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
20137741Smckusick 	ndp->ni_dirp = uap->pathp;
20237741Smckusick 	if (error = namei(ndp))
20337741Smckusick 		RETURN (error);
20437741Smckusick 	vp = ndp->ni_vp;
20537741Smckusick 	/*
20637741Smckusick 	 * Must be the root of the filesystem
20737741Smckusick 	 */
20837741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
20937741Smckusick 		vput(vp);
21037741Smckusick 		RETURN (EINVAL);
21137741Smckusick 	}
21237741Smckusick 	mp = vp->v_mount;
21337741Smckusick 	vput(vp);
21439356Smckusick 	RETURN (dounmount(mp, uap->flags));
21539356Smckusick }
21639356Smckusick 
21739356Smckusick /*
21839356Smckusick  * Do an unmount.
21939356Smckusick  */
22039356Smckusick dounmount(mp, flags)
22139356Smckusick 	register struct mount *mp;
22239356Smckusick 	int flags;
22339356Smckusick {
22439356Smckusick 	struct vnode *coveredvp;
22539356Smckusick 	int error;
22639356Smckusick 
22741400Smckusick 	coveredvp = mp->mnt_vnodecovered;
22841298Smckusick 	if (vfs_busy(mp))
22941298Smckusick 		return (EBUSY);
23041400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
23137741Smckusick 	if (error = vfs_lock(mp))
23239356Smckusick 		return (error);
23337741Smckusick 
23437741Smckusick 	xumount(mp);		/* remove unused sticky files from text table */
23537741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
23641676Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE))
23741676Smckusick 		error = VFS_UNMOUNT(mp, flags);
23841400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
23941298Smckusick 	vfs_unbusy(mp);
24037741Smckusick 	if (error) {
24137741Smckusick 		vfs_unlock(mp);
24237741Smckusick 	} else {
24337741Smckusick 		vrele(coveredvp);
24437741Smckusick 		vfs_remove(mp);
24537741Smckusick 		free((caddr_t)mp, M_MOUNT);
24637741Smckusick 	}
24739356Smckusick 	return (error);
2486254Sroot }
2496254Sroot 
2509167Ssam /*
25137741Smckusick  * Sync system call.
25237741Smckusick  * Sync each mounted filesystem.
2539167Ssam  */
25439491Smckusick /* ARGSUSED */
25542441Smckusick sync(p, uap, retval)
25642441Smckusick 	register struct proc *p;
25742441Smckusick 	struct args *uap;
25842441Smckusick 	int *retval;
2596254Sroot {
26037741Smckusick 	register struct mount *mp;
26141298Smckusick 	struct mount *omp;
26237741Smckusick 
26337741Smckusick 	mp = rootfs;
26437741Smckusick 	do {
26540343Smckusick 		/*
26640343Smckusick 		 * The lock check below is to avoid races with mount
26740343Smckusick 		 * and unmount.
26840343Smckusick 		 */
26941400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
27041298Smckusick 		    !vfs_busy(mp)) {
27137741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
27241298Smckusick 			omp = mp;
27341400Smckusick 			mp = mp->mnt_next;
27441298Smckusick 			vfs_unbusy(omp);
27541298Smckusick 		} else
27641400Smckusick 			mp = mp->mnt_next;
27737741Smckusick 	} while (mp != rootfs);
27837741Smckusick }
27937741Smckusick 
28037741Smckusick /*
28141298Smckusick  * operate on filesystem quotas
28241298Smckusick  */
28342441Smckusick /* ARGSUSED */
28442441Smckusick quotactl(p, uap, retval)
28542441Smckusick 	register struct proc *p;
28642441Smckusick 	register struct args {
28741298Smckusick 		char *path;
28841298Smckusick 		int cmd;
28941298Smckusick 		int uid;
29041298Smckusick 		caddr_t arg;
29142441Smckusick 	} *uap;
29242441Smckusick 	int *retval;
29342441Smckusick {
29441298Smckusick 	register struct mount *mp;
29542441Smckusick 	register struct nameidata *ndp = &u.u_nd;
29641298Smckusick 	int error;
29741298Smckusick 
29841298Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
29941298Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
30041298Smckusick 	ndp->ni_dirp = uap->path;
30141298Smckusick 	if (error = namei(ndp))
30241298Smckusick 		RETURN (error);
30341298Smckusick 	mp = ndp->ni_vp->v_mount;
30441298Smckusick 	vrele(ndp->ni_vp);
30541298Smckusick 	RETURN (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg));
30641298Smckusick }
30741298Smckusick 
30841298Smckusick /*
30937741Smckusick  * get filesystem statistics
31037741Smckusick  */
31142441Smckusick /* ARGSUSED */
31242441Smckusick statfs(p, uap, retval)
31342441Smckusick 	register struct proc *p;
31442441Smckusick 	register struct args {
31537741Smckusick 		char *path;
31637741Smckusick 		struct statfs *buf;
31742441Smckusick 	} *uap;
31842441Smckusick 	int *retval;
31942441Smckusick {
32039464Smckusick 	register struct mount *mp;
32142441Smckusick 	register struct nameidata *ndp = &u.u_nd;
32240343Smckusick 	register struct statfs *sp;
32337741Smckusick 	int error;
32437741Smckusick 
32539544Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
32637741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
32737741Smckusick 	ndp->ni_dirp = uap->path;
32837741Smckusick 	if (error = namei(ndp))
32937741Smckusick 		RETURN (error);
33039544Smckusick 	mp = ndp->ni_vp->v_mount;
33141400Smckusick 	sp = &mp->mnt_stat;
33239544Smckusick 	vrele(ndp->ni_vp);
33340343Smckusick 	if (error = VFS_STATFS(mp, sp))
33439544Smckusick 		RETURN (error);
33541400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
33640343Smckusick 	RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
33737741Smckusick }
33837741Smckusick 
33942441Smckusick /*
34042441Smckusick  * get filesystem statistics
34142441Smckusick  */
34242441Smckusick /* ARGSUSED */
34342441Smckusick fstatfs(p, uap, retval)
34442441Smckusick 	register struct proc *p;
34542441Smckusick 	register struct args {
34637741Smckusick 		int fd;
34737741Smckusick 		struct statfs *buf;
34842441Smckusick 	} *uap;
34942441Smckusick 	int *retval;
35042441Smckusick {
35137741Smckusick 	struct file *fp;
35239464Smckusick 	struct mount *mp;
35340343Smckusick 	register struct statfs *sp;
35437741Smckusick 	int error;
35537741Smckusick 
35642441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
35737741Smckusick 		RETURN (error);
35839464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
35941400Smckusick 	sp = &mp->mnt_stat;
36040343Smckusick 	if (error = VFS_STATFS(mp, sp))
36137741Smckusick 		RETURN (error);
36241400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
36340343Smckusick 	RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
36437741Smckusick }
36537741Smckusick 
36637741Smckusick /*
36738270Smckusick  * get statistics on all filesystems
36838270Smckusick  */
36942441Smckusick getfsstat(p, uap, retval)
37042441Smckusick 	register struct proc *p;
37142441Smckusick 	register struct args {
37238270Smckusick 		struct statfs *buf;
37338270Smckusick 		long bufsize;
37440343Smckusick 		int flags;
37542441Smckusick 	} *uap;
37642441Smckusick 	int *retval;
37742441Smckusick {
37838270Smckusick 	register struct mount *mp;
37940343Smckusick 	register struct statfs *sp;
38039606Smckusick 	caddr_t sfsp;
38138270Smckusick 	long count, maxcount, error;
38238270Smckusick 
38338270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
38439606Smckusick 	sfsp = (caddr_t)uap->buf;
38538270Smckusick 	mp = rootfs;
38638270Smckusick 	count = 0;
38738270Smckusick 	do {
38841400Smckusick 		if (sfsp && count < maxcount &&
38941400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
39041400Smckusick 			sp = &mp->mnt_stat;
39140343Smckusick 			/*
39240343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
39340343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
39440343Smckusick 			 */
39540343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
39640343Smckusick 			    (uap->flags & MNT_WAIT)) &&
39740343Smckusick 			    (error = VFS_STATFS(mp, sp))) {
39841400Smckusick 				mp = mp->mnt_prev;
39939607Smckusick 				continue;
40039607Smckusick 			}
40141400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
40240343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
40339606Smckusick 				RETURN (error);
40440343Smckusick 			sfsp += sizeof(*sp);
40538270Smckusick 		}
40639606Smckusick 		count++;
40741400Smckusick 		mp = mp->mnt_prev;
40838270Smckusick 	} while (mp != rootfs);
40938270Smckusick 	if (sfsp && count > maxcount)
41042441Smckusick 		*retval = maxcount;
41138270Smckusick 	else
41242441Smckusick 		*retval = count;
41338270Smckusick 	RETURN (0);
41438270Smckusick }
41538270Smckusick 
41638270Smckusick /*
41738259Smckusick  * Change current working directory to a given file descriptor.
41838259Smckusick  */
41942441Smckusick /* ARGSUSED */
42042441Smckusick fchdir(p, uap, retval)
42142441Smckusick 	register struct proc *p;
42242441Smckusick 	struct args {
42342441Smckusick 		int	fd;
42442441Smckusick 	} *uap;
42542441Smckusick 	int *retval;
42638259Smckusick {
42742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
42838259Smckusick 	register struct vnode *vp;
42938259Smckusick 	struct file *fp;
43038259Smckusick 	int error;
43138259Smckusick 
43242441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
43338259Smckusick 		RETURN (error);
43438259Smckusick 	vp = (struct vnode *)fp->f_data;
43538259Smckusick 	VOP_LOCK(vp);
43638259Smckusick 	if (vp->v_type != VDIR)
43738259Smckusick 		error = ENOTDIR;
43838259Smckusick 	else
43942441Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
44038259Smckusick 	VOP_UNLOCK(vp);
44139860Smckusick 	if (error)
44239860Smckusick 		RETURN (error);
44339860Smckusick 	VREF(vp);
44442441Smckusick 	vrele(ndp->ni_cdir);
44542441Smckusick 	ndp->ni_cdir = vp;
44639860Smckusick 	RETURN (0);
44738259Smckusick }
44838259Smckusick 
44938259Smckusick /*
45037741Smckusick  * Change current working directory (``.'').
45137741Smckusick  */
45242441Smckusick /* ARGSUSED */
45342441Smckusick chdir(p, uap, retval)
45442441Smckusick 	register struct proc *p;
45542441Smckusick 	struct args {
45642441Smckusick 		char	*fname;
45742441Smckusick 	} *uap;
45842441Smckusick 	int *retval;
45937741Smckusick {
46042441Smckusick 	register struct nameidata *ndp = &u.u_nd;
46137741Smckusick 	int error;
4626254Sroot 
46337741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
46416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
46516694Smckusick 	ndp->ni_dirp = uap->fname;
46637741Smckusick 	if (error = chdirec(ndp))
46737741Smckusick 		RETURN (error);
46842441Smckusick 	vrele(ndp->ni_cdir);
46942441Smckusick 	ndp->ni_cdir = ndp->ni_vp;
47037741Smckusick 	RETURN (0);
47137741Smckusick }
4726254Sroot 
47337741Smckusick /*
47437741Smckusick  * Change notion of root (``/'') directory.
47537741Smckusick  */
47642441Smckusick /* ARGSUSED */
47742441Smckusick chroot(p, uap, retval)
47842441Smckusick 	register struct proc *p;
47942441Smckusick 	struct args {
48042441Smckusick 		char	*fname;
48142441Smckusick 	} *uap;
48242441Smckusick 	int *retval;
48337741Smckusick {
48442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
48537741Smckusick 	int error;
48637741Smckusick 
48742441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
48837741Smckusick 		RETURN (error);
48937741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
49037741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
49137741Smckusick 	ndp->ni_dirp = uap->fname;
49237741Smckusick 	if (error = chdirec(ndp))
49337741Smckusick 		RETURN (error);
49442441Smckusick 	if (ndp->ni_rdir != NULL)
49542441Smckusick 		vrele(ndp->ni_rdir);
49642441Smckusick 	ndp->ni_rdir = ndp->ni_vp;
49737741Smckusick 	RETURN (0);
4986254Sroot }
4996254Sroot 
50037Sbill /*
50137741Smckusick  * Common routine for chroot and chdir.
50237741Smckusick  */
50337741Smckusick chdirec(ndp)
50437741Smckusick 	register struct nameidata *ndp;
50537741Smckusick {
50637741Smckusick 	struct vnode *vp;
50737741Smckusick 	int error;
50837741Smckusick 
50937741Smckusick 	if (error = namei(ndp))
51037741Smckusick 		return (error);
51137741Smckusick 	vp = ndp->ni_vp;
51237741Smckusick 	if (vp->v_type != VDIR)
51337741Smckusick 		error = ENOTDIR;
51437741Smckusick 	else
51538399Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
51637741Smckusick 	VOP_UNLOCK(vp);
51737741Smckusick 	if (error)
51837741Smckusick 		vrele(vp);
51937741Smckusick 	return (error);
52037741Smckusick }
52137741Smckusick 
52237741Smckusick /*
5236254Sroot  * Open system call.
52442441Smckusick  * Check permissions, allocate an open file structure,
52542441Smckusick  * and call the device open routine if any.
5266254Sroot  */
52742441Smckusick open(p, uap, retval)
52842441Smckusick 	register struct proc *p;
52942441Smckusick 	register struct args {
5306254Sroot 		char	*fname;
5317701Ssam 		int	mode;
53212756Ssam 		int	crtmode;
53342441Smckusick 	} *uap;
53442441Smckusick 	int *retval;
5356254Sroot {
53642441Smckusick 	struct nameidata *ndp = &u.u_nd;
53742441Smckusick 	register struct file *fp;
53837741Smckusick 	int fmode, cmode;
53937741Smckusick 	struct file *nfp;
54037741Smckusick 	int indx, error;
54137741Smckusick 	extern struct fileops vnops;
5426254Sroot 
54337741Smckusick 	if (error = falloc(&nfp, &indx))
54442441Smckusick 		RETURN (error);
54537741Smckusick 	fp = nfp;
54642441Smckusick 	fmode = uap->mode - FOPEN;
54742441Smckusick 	cmode = ((uap->crtmode &~ u.u_cmask) & 07777) &~ S_ISVTX;
54842441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
54942441Smckusick 	ndp->ni_dirp = uap->fname;
550*45202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
55142441Smckusick 	if (error = vn_open(ndp, fmode, cmode)) {
55237741Smckusick 		crfree(fp->f_cred);
55337741Smckusick 		fp->f_count--;
55443405Smckusick 		if (error == ENODEV &&		/* XXX from fdopen */
555*45202Smckusick 		    p->p_dupfd >= 0 &&
55643450Smckusick 		    (error = dupfdopen(indx, p->p_dupfd, fmode)) == 0) {
55742441Smckusick 			*retval = indx;
55842441Smckusick 			RETURN (0);
55942441Smckusick 		}
56040884Smckusick 		if (error == ERESTART)
56140884Smckusick 			error = EINTR;
56242441Smckusick 		u.u_ofile[indx] = NULL;
56342441Smckusick 		RETURN (error);
56412756Ssam 	}
56537741Smckusick 	fp->f_flag = fmode & FMASK;
56637741Smckusick 	fp->f_type = DTYPE_VNODE;
56737741Smckusick 	fp->f_ops = &vnops;
56837741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
56942441Smckusick 	*retval = indx;
57042441Smckusick 	RETURN (0);
5716254Sroot }
5726254Sroot 
57342955Smckusick #ifdef COMPAT_43
5746254Sroot /*
57542441Smckusick  * Creat system call.
5766254Sroot  */
57742955Smckusick ocreat(p, uap, retval)
57842441Smckusick 	struct proc *p;
57942441Smckusick 	register struct args {
58042441Smckusick 		char	*fname;
58142441Smckusick 		int	fmode;
58242441Smckusick 	} *uap;
58342441Smckusick 	int *retval;
5846254Sroot {
58542441Smckusick 	struct args {
5866254Sroot 		char	*fname;
58742441Smckusick 		int	mode;
58842441Smckusick 		int	crtmode;
58942441Smckusick 	} openuap;
59042441Smckusick 
59142441Smckusick 	openuap.fname = uap->fname;
59242441Smckusick 	openuap.crtmode = uap->fmode;
59342441Smckusick 	openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
59442441Smckusick 	RETURN (open(p, &openuap, retval));
59542441Smckusick }
59642955Smckusick #endif /* COMPAT_43 */
59742441Smckusick 
59842441Smckusick /*
59942441Smckusick  * Mknod system call
60042441Smckusick  */
60142441Smckusick /* ARGSUSED */
60242441Smckusick mknod(p, uap, retval)
60342441Smckusick 	register struct proc *p;
60442441Smckusick 	register struct args {
60542441Smckusick 		char	*fname;
6066254Sroot 		int	fmode;
6076254Sroot 		int	dev;
60842441Smckusick 	} *uap;
60942441Smckusick 	int *retval;
61042441Smckusick {
61142441Smckusick 	register struct nameidata *ndp = &u.u_nd;
61237741Smckusick 	register struct vnode *vp;
61337741Smckusick 	struct vattr vattr;
61437741Smckusick 	int error;
6156254Sroot 
61642441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
61737741Smckusick 		RETURN (error);
61837741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
61916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
62016694Smckusick 	ndp->ni_dirp = uap->fname;
62137741Smckusick 	if (error = namei(ndp))
62237741Smckusick 		RETURN (error);
62337741Smckusick 	vp = ndp->ni_vp;
62437741Smckusick 	if (vp != NULL) {
62537741Smckusick 		error = EEXIST;
62612756Ssam 		goto out;
6276254Sroot 	}
62841362Smckusick 	VATTR_NULL(&vattr);
62940635Smckusick 	switch (uap->fmode & S_IFMT) {
63012756Ssam 
63140635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
63237741Smckusick 		vattr.va_type = VBAD;
63337741Smckusick 		break;
63440635Smckusick 	case S_IFCHR:
63537741Smckusick 		vattr.va_type = VCHR;
63637741Smckusick 		break;
63740635Smckusick 	case S_IFBLK:
63837741Smckusick 		vattr.va_type = VBLK;
63937741Smckusick 		break;
64037741Smckusick 	default:
64137741Smckusick 		error = EINVAL;
64237741Smckusick 		goto out;
6436254Sroot 	}
64442441Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask;
64537741Smckusick 	vattr.va_rdev = uap->dev;
6466254Sroot out:
64742465Smckusick 	if (!error) {
64842465Smckusick 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
64942465Smckusick 	} else {
65037741Smckusick 		VOP_ABORTOP(ndp);
65143344Smckusick 		if (ndp->ni_dvp == vp)
65243344Smckusick 			vrele(ndp->ni_dvp);
65343344Smckusick 		else
65443344Smckusick 			vput(ndp->ni_dvp);
65542465Smckusick 		if (vp)
65642465Smckusick 			vrele(vp);
65742465Smckusick 	}
65837741Smckusick 	RETURN (error);
6596254Sroot }
6606254Sroot 
6616254Sroot /*
66240285Smckusick  * Mkfifo system call
66340285Smckusick  */
66442441Smckusick /* ARGSUSED */
66542441Smckusick mkfifo(p, uap, retval)
66642441Smckusick 	register struct proc *p;
66742441Smckusick 	register struct args {
66840285Smckusick 		char	*fname;
66940285Smckusick 		int	fmode;
67042441Smckusick 	} *uap;
67142441Smckusick 	int *retval;
67242441Smckusick {
67342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
67440285Smckusick 	struct vattr vattr;
67540285Smckusick 	int error;
67640285Smckusick 
67740285Smckusick #ifndef FIFO
67840285Smckusick 	RETURN (EOPNOTSUPP);
67940285Smckusick #else
68040285Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
68140285Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
68240285Smckusick 	ndp->ni_dirp = uap->fname;
68340285Smckusick 	if (error = namei(ndp))
68440285Smckusick 		RETURN (error);
68540285Smckusick 	if (ndp->ni_vp != NULL) {
68640285Smckusick 		VOP_ABORTOP(ndp);
68743344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
68843344Smckusick 			vrele(ndp->ni_dvp);
68943344Smckusick 		else
69043344Smckusick 			vput(ndp->ni_dvp);
69142465Smckusick 		vrele(ndp->ni_vp);
69240285Smckusick 		RETURN (EEXIST);
69340285Smckusick 	} else {
69441362Smckusick 		VATTR_NULL(&vattr);
69540285Smckusick 		vattr.va_type = VFIFO;
69642441Smckusick 		vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask;
69740285Smckusick 	}
69840285Smckusick 	RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred));
69940285Smckusick #endif /* FIFO */
70040285Smckusick }
70140285Smckusick 
70240285Smckusick /*
7036254Sroot  * link system call
7046254Sroot  */
70542441Smckusick /* ARGSUSED */
70642441Smckusick link(p, uap, retval)
70742441Smckusick 	register struct proc *p;
70842441Smckusick 	register struct args {
7096254Sroot 		char	*target;
7106254Sroot 		char	*linkname;
71142441Smckusick 	} *uap;
71242441Smckusick 	int *retval;
71342441Smckusick {
71442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
71537741Smckusick 	register struct vnode *vp, *xp;
71637741Smckusick 	int error;
7176254Sroot 
71816694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
71916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
72016694Smckusick 	ndp->ni_dirp = uap->target;
72137741Smckusick 	if (error = namei(ndp))
72237741Smckusick 		RETURN (error);
72337741Smckusick 	vp = ndp->ni_vp;
72437741Smckusick 	if (vp->v_type == VDIR &&
72542441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
72637741Smckusick 		goto out1;
72737741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
72816694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
72937741Smckusick 	if (error = namei(ndp))
73037741Smckusick 		goto out1;
73137741Smckusick 	xp = ndp->ni_vp;
7326254Sroot 	if (xp != NULL) {
73337741Smckusick 		error = EEXIST;
7346254Sroot 		goto out;
7356254Sroot 	}
73637741Smckusick 	xp = ndp->ni_dvp;
73737741Smckusick 	if (vp->v_mount != xp->v_mount)
73837741Smckusick 		error = EXDEV;
7396254Sroot out:
74042465Smckusick 	if (!error) {
74142465Smckusick 		error = VOP_LINK(vp, ndp);
74242465Smckusick 	} else {
74337741Smckusick 		VOP_ABORTOP(ndp);
74443344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
74543344Smckusick 			vrele(ndp->ni_dvp);
74643344Smckusick 		else
74743344Smckusick 			vput(ndp->ni_dvp);
74842465Smckusick 		if (ndp->ni_vp)
74942465Smckusick 			vrele(ndp->ni_vp);
75042465Smckusick 	}
75137741Smckusick out1:
75237741Smckusick 	vrele(vp);
75337741Smckusick 	RETURN (error);
7546254Sroot }
7556254Sroot 
7566254Sroot /*
7576254Sroot  * symlink -- make a symbolic link
7586254Sroot  */
75942441Smckusick /* ARGSUSED */
76042441Smckusick symlink(p, uap, retval)
76142441Smckusick 	register struct proc *p;
76242441Smckusick 	register struct args {
7636254Sroot 		char	*target;
7646254Sroot 		char	*linkname;
76542441Smckusick 	} *uap;
76642441Smckusick 	int *retval;
76742441Smckusick {
76842441Smckusick 	register struct nameidata *ndp = &u.u_nd;
76937741Smckusick 	struct vattr vattr;
77037741Smckusick 	char *target;
77137741Smckusick 	int error;
7726254Sroot 
77316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
77416694Smckusick 	ndp->ni_dirp = uap->linkname;
77537741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
77637741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
77742465Smckusick 		goto out;
77837741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
77937741Smckusick 	if (error = namei(ndp))
78042465Smckusick 		goto out;
78142465Smckusick 	if (ndp->ni_vp) {
78242465Smckusick 		VOP_ABORTOP(ndp);
78343344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
78443344Smckusick 			vrele(ndp->ni_dvp);
78543344Smckusick 		else
78643344Smckusick 			vput(ndp->ni_dvp);
78742465Smckusick 		vrele(ndp->ni_vp);
78837741Smckusick 		error = EEXIST;
78937741Smckusick 		goto out;
7906254Sroot 	}
79141362Smckusick 	VATTR_NULL(&vattr);
79242441Smckusick 	vattr.va_mode = 0777 &~ u.u_cmask;
79342465Smckusick 	error = VOP_SYMLINK(ndp, &vattr, target);
79437741Smckusick out:
79537741Smckusick 	FREE(target, M_NAMEI);
79637741Smckusick 	RETURN (error);
7976254Sroot }
7986254Sroot 
7996254Sroot /*
8006254Sroot  * Unlink system call.
8016254Sroot  * Hard to avoid races here, especially
8026254Sroot  * in unlinking directories.
8036254Sroot  */
80442441Smckusick /* ARGSUSED */
80542441Smckusick unlink(p, uap, retval)
80642441Smckusick 	register struct proc *p;
80742441Smckusick 	struct args {
80842441Smckusick 		char	*fname;
80942441Smckusick 	} *uap;
81042441Smckusick 	int *retval;
8116254Sroot {
81242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
81337741Smckusick 	register struct vnode *vp;
81437741Smckusick 	int error;
8156254Sroot 
81637741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
81716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
81816694Smckusick 	ndp->ni_dirp = uap->fname;
81937741Smckusick 	if (error = namei(ndp))
82037741Smckusick 		RETURN (error);
82137741Smckusick 	vp = ndp->ni_vp;
82237741Smckusick 	if (vp->v_type == VDIR &&
82342441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
8246254Sroot 		goto out;
8256254Sroot 	/*
8266254Sroot 	 * Don't unlink a mounted file.
8276254Sroot 	 */
82837741Smckusick 	if (vp->v_flag & VROOT) {
82937741Smckusick 		error = EBUSY;
8306254Sroot 		goto out;
8316254Sroot 	}
83237741Smckusick 	if (vp->v_flag & VTEXT)
83337741Smckusick 		xrele(vp);	/* try once to free text */
8346254Sroot out:
83542465Smckusick 	if (!error) {
83642465Smckusick 		error = VOP_REMOVE(ndp);
83742465Smckusick 	} else {
83837741Smckusick 		VOP_ABORTOP(ndp);
83943344Smckusick 		if (ndp->ni_dvp == vp)
84043344Smckusick 			vrele(ndp->ni_dvp);
84143344Smckusick 		else
84243344Smckusick 			vput(ndp->ni_dvp);
84342465Smckusick 		vput(vp);
84442465Smckusick 	}
84537741Smckusick 	RETURN (error);
8466254Sroot }
8476254Sroot 
8486254Sroot /*
8496254Sroot  * Seek system call
8506254Sroot  */
85142441Smckusick lseek(p, uap, retval)
85242441Smckusick 	register struct proc *p;
85342441Smckusick 	register struct args {
85437741Smckusick 		int	fdes;
8556254Sroot 		off_t	off;
8566254Sroot 		int	sbase;
85742441Smckusick 	} *uap;
85842441Smckusick 	off_t *retval;
85942441Smckusick {
86042441Smckusick 	struct ucred *cred = u.u_nd.ni_cred;
86142441Smckusick 	register struct file *fp;
86237741Smckusick 	struct vattr vattr;
86337741Smckusick 	int error;
8646254Sroot 
86537741Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
86642441Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
86737741Smckusick 		RETURN (EBADF);
86837741Smckusick 	if (fp->f_type != DTYPE_VNODE)
86937741Smckusick 		RETURN (ESPIPE);
87013878Ssam 	switch (uap->sbase) {
87113878Ssam 
87213878Ssam 	case L_INCR:
87313878Ssam 		fp->f_offset += uap->off;
87413878Ssam 		break;
87513878Ssam 
87613878Ssam 	case L_XTND:
87737741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
87842441Smckusick 		    &vattr, cred))
87937741Smckusick 			RETURN (error);
88037741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
88113878Ssam 		break;
88213878Ssam 
88313878Ssam 	case L_SET:
88413878Ssam 		fp->f_offset = uap->off;
88513878Ssam 		break;
88613878Ssam 
88713878Ssam 	default:
88837741Smckusick 		RETURN (EINVAL);
88913878Ssam 	}
89042441Smckusick 	*retval = fp->f_offset;
89137741Smckusick 	RETURN (0);
8926254Sroot }
8936254Sroot 
8946254Sroot /*
8956254Sroot  * Access system call
8966254Sroot  */
89742441Smckusick /* ARGSUSED */
89842441Smckusick saccess(p, uap, retval)
89942441Smckusick 	register struct proc *p;
90042441Smckusick 	register struct args {
9016254Sroot 		char	*fname;
9026254Sroot 		int	fmode;
90342441Smckusick 	} *uap;
90442441Smckusick 	int *retval;
90542441Smckusick {
90642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
90742441Smckusick 	register struct ucred *cred = ndp->ni_cred;
90837741Smckusick 	register struct vnode *vp;
90937741Smckusick 	int error, mode, svuid, svgid;
9106254Sroot 
91142441Smckusick 	svuid = cred->cr_uid;
91242441Smckusick 	svgid = cred->cr_groups[0];
91342441Smckusick 	cred->cr_uid = p->p_ruid;
91442441Smckusick 	cred->cr_groups[0] = p->p_rgid;
91537741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
91616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
91716694Smckusick 	ndp->ni_dirp = uap->fname;
91837741Smckusick 	if (error = namei(ndp))
91937741Smckusick 		goto out1;
92037741Smckusick 	vp = ndp->ni_vp;
92137741Smckusick 	/*
92237741Smckusick 	 * fmode == 0 means only check for exist
92337741Smckusick 	 */
92437741Smckusick 	if (uap->fmode) {
92537741Smckusick 		mode = 0;
92637741Smckusick 		if (uap->fmode & R_OK)
92737741Smckusick 			mode |= VREAD;
92837741Smckusick 		if (uap->fmode & W_OK)
92937741Smckusick 			mode |= VWRITE;
93037741Smckusick 		if (uap->fmode & X_OK)
93137741Smckusick 			mode |= VEXEC;
93239543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
93338399Smckusick 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
9346254Sroot 	}
93537741Smckusick 	vput(vp);
93637741Smckusick out1:
93742441Smckusick 	cred->cr_uid = svuid;
93842441Smckusick 	cred->cr_groups[0] = svgid;
93937741Smckusick 	RETURN (error);
9406254Sroot }
9416254Sroot 
9426254Sroot /*
9436574Smckusic  * Stat system call.  This version follows links.
94437Sbill  */
94542441Smckusick /* ARGSUSED */
94642441Smckusick stat(p, uap, retval)
94742441Smckusick 	register struct proc *p;
94842441Smckusick 	register struct args {
94942441Smckusick 		char	*fname;
95042441Smckusick 		struct stat *ub;
95142441Smckusick 	} *uap;
95242441Smckusick 	int *retval;
95337Sbill {
95442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
95542441Smckusick 	struct stat sb;
95642441Smckusick 	int error;
95737Sbill 
95842441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
95942441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
96042441Smckusick 	ndp->ni_dirp = uap->fname;
96142441Smckusick 	if (error = namei(ndp))
96242441Smckusick 		RETURN (error);
96342441Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
96442441Smckusick 	vput(ndp->ni_vp);
96542441Smckusick 	if (error)
96642441Smckusick 		RETURN (error);
96742441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
96842441Smckusick 	RETURN (error);
96937Sbill }
97037Sbill 
97137Sbill /*
9726574Smckusic  * Lstat system call.  This version does not follow links.
9735992Swnj  */
97442441Smckusick /* ARGSUSED */
97542441Smckusick lstat(p, uap, retval)
97642441Smckusick 	register struct proc *p;
97742441Smckusick 	register struct args {
9785992Swnj 		char	*fname;
97912756Ssam 		struct stat *ub;
98042441Smckusick 	} *uap;
98142441Smckusick 	int *retval;
98242441Smckusick {
98342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
98412756Ssam 	struct stat sb;
98537741Smckusick 	int error;
9865992Swnj 
98742441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW;
98816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
98916694Smckusick 	ndp->ni_dirp = uap->fname;
99037741Smckusick 	if (error = namei(ndp))
99137741Smckusick 		RETURN (error);
99237741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
99337741Smckusick 	vput(ndp->ni_vp);
99437741Smckusick 	if (error)
99537741Smckusick 		RETURN (error);
99637741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
99737741Smckusick 	RETURN (error);
9985992Swnj }
9995992Swnj 
10005992Swnj /*
10015992Swnj  * Return target name of a symbolic link
100237Sbill  */
100342441Smckusick /* ARGSUSED */
100442441Smckusick readlink(p, uap, retval)
100542441Smckusick 	register struct proc *p;
100642441Smckusick 	register struct args {
10075992Swnj 		char	*name;
10085992Swnj 		char	*buf;
10095992Swnj 		int	count;
101042441Smckusick 	} *uap;
101142441Smckusick 	int *retval;
101242441Smckusick {
101342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
101437741Smckusick 	register struct vnode *vp;
101537741Smckusick 	struct iovec aiov;
101637741Smckusick 	struct uio auio;
101737741Smckusick 	int error;
10185992Swnj 
101937741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
102016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
102116694Smckusick 	ndp->ni_dirp = uap->name;
102237741Smckusick 	if (error = namei(ndp))
102337741Smckusick 		RETURN (error);
102437741Smckusick 	vp = ndp->ni_vp;
102537741Smckusick 	if (vp->v_type != VLNK) {
102637741Smckusick 		error = EINVAL;
10275992Swnj 		goto out;
10285992Swnj 	}
102937741Smckusick 	aiov.iov_base = uap->buf;
103037741Smckusick 	aiov.iov_len = uap->count;
103137741Smckusick 	auio.uio_iov = &aiov;
103237741Smckusick 	auio.uio_iovcnt = 1;
103337741Smckusick 	auio.uio_offset = 0;
103437741Smckusick 	auio.uio_rw = UIO_READ;
103537741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
103637741Smckusick 	auio.uio_resid = uap->count;
103737741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
10385992Swnj out:
103937741Smckusick 	vput(vp);
104042441Smckusick 	*retval = uap->count - auio.uio_resid;
104137741Smckusick 	RETURN (error);
10425992Swnj }
10435992Swnj 
10449167Ssam /*
104538259Smckusick  * Change flags of a file given path name.
104638259Smckusick  */
104742441Smckusick /* ARGSUSED */
104842441Smckusick chflags(p, uap, retval)
104942441Smckusick 	register struct proc *p;
105042441Smckusick 	register struct args {
105138259Smckusick 		char	*fname;
105238259Smckusick 		int	flags;
105342441Smckusick 	} *uap;
105442441Smckusick 	int *retval;
105542441Smckusick {
105642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
105738259Smckusick 	register struct vnode *vp;
105838259Smckusick 	struct vattr vattr;
105938259Smckusick 	int error;
106038259Smckusick 
106138259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
106238259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
106338259Smckusick 	ndp->ni_dirp = uap->fname;
106441362Smckusick 	VATTR_NULL(&vattr);
106538259Smckusick 	vattr.va_flags = uap->flags;
106638259Smckusick 	if (error = namei(ndp))
106738259Smckusick 		RETURN (error);
106838259Smckusick 	vp = ndp->ni_vp;
106941400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
107038259Smckusick 		error = EROFS;
107138259Smckusick 		goto out;
107238259Smckusick 	}
107338259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
107438259Smckusick out:
107538259Smckusick 	vput(vp);
107638259Smckusick 	RETURN (error);
107738259Smckusick }
107838259Smckusick 
107938259Smckusick /*
108038259Smckusick  * Change flags of a file given a file descriptor.
108138259Smckusick  */
108242441Smckusick /* ARGSUSED */
108342441Smckusick fchflags(p, uap, retval)
108442441Smckusick 	register struct proc *p;
108542441Smckusick 	register struct args {
108638259Smckusick 		int	fd;
108738259Smckusick 		int	flags;
108842441Smckusick 	} *uap;
108942441Smckusick 	int *retval;
109042441Smckusick {
109138259Smckusick 	struct vattr vattr;
109238259Smckusick 	struct vnode *vp;
109338259Smckusick 	struct file *fp;
109438259Smckusick 	int error;
109538259Smckusick 
109642441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
109738259Smckusick 		RETURN (error);
109841362Smckusick 	VATTR_NULL(&vattr);
109938259Smckusick 	vattr.va_flags = uap->flags;
110038259Smckusick 	vp = (struct vnode *)fp->f_data;
110138259Smckusick 	VOP_LOCK(vp);
110241400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
110338259Smckusick 		error = EROFS;
110438259Smckusick 		goto out;
110538259Smckusick 	}
110638259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
110738259Smckusick out:
110838259Smckusick 	VOP_UNLOCK(vp);
110938259Smckusick 	RETURN (error);
111038259Smckusick }
111138259Smckusick 
111238259Smckusick /*
11139167Ssam  * Change mode of a file given path name.
11149167Ssam  */
111542441Smckusick /* ARGSUSED */
111642441Smckusick chmod(p, uap, retval)
111742441Smckusick 	register struct proc *p;
111842441Smckusick 	register struct args {
11196254Sroot 		char	*fname;
11206254Sroot 		int	fmode;
112142441Smckusick 	} *uap;
112242441Smckusick 	int *retval;
112342441Smckusick {
112442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
112537741Smckusick 	register struct vnode *vp;
112637741Smckusick 	struct vattr vattr;
112737741Smckusick 	int error;
11285992Swnj 
112937741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
113037741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
113137741Smckusick 	ndp->ni_dirp = uap->fname;
113241362Smckusick 	VATTR_NULL(&vattr);
113337741Smckusick 	vattr.va_mode = uap->fmode & 07777;
113437741Smckusick 	if (error = namei(ndp))
113537741Smckusick 		RETURN (error);
113637741Smckusick 	vp = ndp->ni_vp;
113741400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
113837741Smckusick 		error = EROFS;
113937741Smckusick 		goto out;
114037741Smckusick 	}
114137741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
114237741Smckusick out:
114337741Smckusick 	vput(vp);
114437741Smckusick 	RETURN (error);
11457701Ssam }
11467439Sroot 
11479167Ssam /*
11489167Ssam  * Change mode of a file given a file descriptor.
11499167Ssam  */
115042441Smckusick /* ARGSUSED */
115142441Smckusick fchmod(p, uap, retval)
115242441Smckusick 	register struct proc *p;
115342441Smckusick 	register struct args {
11547701Ssam 		int	fd;
11557701Ssam 		int	fmode;
115642441Smckusick 	} *uap;
115742441Smckusick 	int *retval;
115842441Smckusick {
115937741Smckusick 	struct vattr vattr;
116037741Smckusick 	struct vnode *vp;
116137741Smckusick 	struct file *fp;
116237741Smckusick 	int error;
11637701Ssam 
116442441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
116537741Smckusick 		RETURN (error);
116641362Smckusick 	VATTR_NULL(&vattr);
116737741Smckusick 	vattr.va_mode = uap->fmode & 07777;
116837741Smckusick 	vp = (struct vnode *)fp->f_data;
116937741Smckusick 	VOP_LOCK(vp);
117041400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
117137741Smckusick 		error = EROFS;
117237741Smckusick 		goto out;
11737439Sroot 	}
117437741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
117537741Smckusick out:
117637741Smckusick 	VOP_UNLOCK(vp);
117737741Smckusick 	RETURN (error);
11785992Swnj }
11795992Swnj 
11809167Ssam /*
11819167Ssam  * Set ownership given a path name.
11829167Ssam  */
118342441Smckusick /* ARGSUSED */
118442441Smckusick chown(p, uap, retval)
118542441Smckusick 	register struct proc *p;
118642441Smckusick 	register struct args {
11876254Sroot 		char	*fname;
11886254Sroot 		int	uid;
11896254Sroot 		int	gid;
119042441Smckusick 	} *uap;
119142441Smckusick 	int *retval;
119242441Smckusick {
119342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
119437741Smckusick 	register struct vnode *vp;
119537741Smckusick 	struct vattr vattr;
119637741Smckusick 	int error;
119737Sbill 
119837741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
119936614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
120036614Sbostic 	ndp->ni_dirp = uap->fname;
120141362Smckusick 	VATTR_NULL(&vattr);
120237741Smckusick 	vattr.va_uid = uap->uid;
120337741Smckusick 	vattr.va_gid = uap->gid;
120437741Smckusick 	if (error = namei(ndp))
120537741Smckusick 		RETURN (error);
120637741Smckusick 	vp = ndp->ni_vp;
120741400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
120837741Smckusick 		error = EROFS;
120937741Smckusick 		goto out;
121037741Smckusick 	}
121137741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
121237741Smckusick out:
121337741Smckusick 	vput(vp);
121437741Smckusick 	RETURN (error);
12157701Ssam }
12167439Sroot 
12179167Ssam /*
12189167Ssam  * Set ownership given a file descriptor.
12199167Ssam  */
122042441Smckusick /* ARGSUSED */
122142441Smckusick fchown(p, uap, retval)
122242441Smckusick 	register struct proc *p;
122342441Smckusick 	register struct args {
12247701Ssam 		int	fd;
12257701Ssam 		int	uid;
12267701Ssam 		int	gid;
122742441Smckusick 	} *uap;
122842441Smckusick 	int *retval;
122942441Smckusick {
123037741Smckusick 	struct vattr vattr;
123137741Smckusick 	struct vnode *vp;
123237741Smckusick 	struct file *fp;
123337741Smckusick 	int error;
12347701Ssam 
123542441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
123637741Smckusick 		RETURN (error);
123741362Smckusick 	VATTR_NULL(&vattr);
123837741Smckusick 	vattr.va_uid = uap->uid;
123937741Smckusick 	vattr.va_gid = uap->gid;
124037741Smckusick 	vp = (struct vnode *)fp->f_data;
124137741Smckusick 	VOP_LOCK(vp);
124241400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
124337741Smckusick 		error = EROFS;
124437741Smckusick 		goto out;
124537741Smckusick 	}
124637741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
124737741Smckusick out:
124837741Smckusick 	VOP_UNLOCK(vp);
124937741Smckusick 	RETURN (error);
12507701Ssam }
12517701Ssam 
125242441Smckusick /*
125342441Smckusick  * Set the access and modification times of a file.
125442441Smckusick  */
125542441Smckusick /* ARGSUSED */
125642441Smckusick utimes(p, uap, retval)
125742441Smckusick 	register struct proc *p;
125842441Smckusick 	register struct args {
125911811Ssam 		char	*fname;
126011811Ssam 		struct	timeval *tptr;
126142441Smckusick 	} *uap;
126242441Smckusick 	int *retval;
126342441Smckusick {
126442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
126537741Smckusick 	register struct vnode *vp;
126611811Ssam 	struct timeval tv[2];
126737741Smckusick 	struct vattr vattr;
126837741Smckusick 	int error;
126911811Ssam 
127037741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
127137741Smckusick 		RETURN (error);
127237741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
127337741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
127437741Smckusick 	ndp->ni_dirp = uap->fname;
127541362Smckusick 	VATTR_NULL(&vattr);
127637741Smckusick 	vattr.va_atime = tv[0];
127737741Smckusick 	vattr.va_mtime = tv[1];
127837741Smckusick 	if (error = namei(ndp))
127937741Smckusick 		RETURN (error);
128037741Smckusick 	vp = ndp->ni_vp;
128141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
128237741Smckusick 		error = EROFS;
128337741Smckusick 		goto out;
128421015Smckusick 	}
128537741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
128637741Smckusick out:
128737741Smckusick 	vput(vp);
128837741Smckusick 	RETURN (error);
128911811Ssam }
129011811Ssam 
12919167Ssam /*
12929167Ssam  * Truncate a file given its path name.
12939167Ssam  */
129442441Smckusick /* ARGSUSED */
129542441Smckusick truncate(p, uap, retval)
129642441Smckusick 	register struct proc *p;
129742441Smckusick 	register struct args {
12987701Ssam 		char	*fname;
129926473Skarels 		off_t	length;
130042441Smckusick 	} *uap;
130142441Smckusick 	int *retval;
130242441Smckusick {
130342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
130437741Smckusick 	register struct vnode *vp;
130537741Smckusick 	struct vattr vattr;
130637741Smckusick 	int error;
13077701Ssam 
130837741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
130916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
131016694Smckusick 	ndp->ni_dirp = uap->fname;
131141362Smckusick 	VATTR_NULL(&vattr);
131237741Smckusick 	vattr.va_size = uap->length;
131337741Smckusick 	if (error = namei(ndp))
131437741Smckusick 		RETURN (error);
131537741Smckusick 	vp = ndp->ni_vp;
131637741Smckusick 	if (vp->v_type == VDIR) {
131737741Smckusick 		error = EISDIR;
131837741Smckusick 		goto out;
13197701Ssam 	}
132038399Smckusick 	if ((error = vn_writechk(vp)) ||
132138399Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
132237741Smckusick 		goto out;
132337741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
132437741Smckusick out:
132537741Smckusick 	vput(vp);
132637741Smckusick 	RETURN (error);
13277701Ssam }
13287701Ssam 
13299167Ssam /*
13309167Ssam  * Truncate a file given a file descriptor.
13319167Ssam  */
133242441Smckusick /* ARGSUSED */
133342441Smckusick ftruncate(p, uap, retval)
133442441Smckusick 	register struct proc *p;
133542441Smckusick 	register struct args {
13367701Ssam 		int	fd;
133726473Skarels 		off_t	length;
133842441Smckusick 	} *uap;
133942441Smckusick 	int *retval;
134042441Smckusick {
134137741Smckusick 	struct vattr vattr;
134237741Smckusick 	struct vnode *vp;
13437701Ssam 	struct file *fp;
134437741Smckusick 	int error;
13457701Ssam 
134642441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
134737741Smckusick 		RETURN (error);
134837741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
134937741Smckusick 		RETURN (EINVAL);
135041362Smckusick 	VATTR_NULL(&vattr);
135137741Smckusick 	vattr.va_size = uap->length;
135237741Smckusick 	vp = (struct vnode *)fp->f_data;
135337741Smckusick 	VOP_LOCK(vp);
135437741Smckusick 	if (vp->v_type == VDIR) {
135537741Smckusick 		error = EISDIR;
135637741Smckusick 		goto out;
13577701Ssam 	}
135838399Smckusick 	if (error = vn_writechk(vp))
135937741Smckusick 		goto out;
136037741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
136137741Smckusick out:
136237741Smckusick 	VOP_UNLOCK(vp);
136337741Smckusick 	RETURN (error);
13647701Ssam }
13657701Ssam 
13669167Ssam /*
13679167Ssam  * Synch an open file.
13689167Ssam  */
136942441Smckusick /* ARGSUSED */
137042441Smckusick fsync(p, uap, retval)
137142441Smckusick 	register struct proc *p;
137242441Smckusick 	struct args {
137342441Smckusick 		int	fd;
137442441Smckusick 	} *uap;
137542441Smckusick 	int *retval;
13769167Ssam {
137739592Smckusick 	register struct vnode *vp;
13789167Ssam 	struct file *fp;
137937741Smckusick 	int error;
13809167Ssam 
138142441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
138237741Smckusick 		RETURN (error);
138339592Smckusick 	vp = (struct vnode *)fp->f_data;
138439592Smckusick 	VOP_LOCK(vp);
138539592Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT);
138639592Smckusick 	VOP_UNLOCK(vp);
138737741Smckusick 	RETURN (error);
13889167Ssam }
13899167Ssam 
13909167Ssam /*
13919167Ssam  * Rename system call.
13929167Ssam  *
13939167Ssam  * Source and destination must either both be directories, or both
13949167Ssam  * not be directories.  If target is a directory, it must be empty.
13959167Ssam  */
139642441Smckusick /* ARGSUSED */
139742441Smckusick rename(p, uap, retval)
139842441Smckusick 	register struct proc *p;
139942441Smckusick 	register struct args {
14007701Ssam 		char	*from;
14017701Ssam 		char	*to;
140242441Smckusick 	} *uap;
140342441Smckusick 	int *retval;
140442441Smckusick {
140537741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
140642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
140737741Smckusick 	struct nameidata tond;
140837741Smckusick 	int error;
14097701Ssam 
141037741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
141116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
141216694Smckusick 	ndp->ni_dirp = uap->from;
141337741Smckusick 	if (error = namei(ndp))
141437741Smckusick 		RETURN (error);
141537741Smckusick 	fvp = ndp->ni_vp;
141638266Smckusick 	nddup(ndp, &tond);
141737741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
141837741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
141937741Smckusick 	tond.ni_dirp = uap->to;
142042465Smckusick 	if (error = namei(&tond)) {
142142465Smckusick 		VOP_ABORTOP(ndp);
142242465Smckusick 		vrele(ndp->ni_dvp);
142342465Smckusick 		vrele(fvp);
142442465Smckusick 		goto out1;
142542465Smckusick 	}
142637741Smckusick 	tdvp = tond.ni_dvp;
142737741Smckusick 	tvp = tond.ni_vp;
142837741Smckusick 	if (tvp != NULL) {
142937741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
143039242Sbostic 			error = ENOTDIR;
143137741Smckusick 			goto out;
143237741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
143339242Sbostic 			error = EISDIR;
143437741Smckusick 			goto out;
14359167Ssam 		}
14369167Ssam 	}
143737741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
143837741Smckusick 		error = EXDEV;
14399167Ssam 		goto out;
144010051Ssam 	}
144139286Smckusick 	if (fvp == tdvp)
144237741Smckusick 		error = EINVAL;
144339286Smckusick 	/*
144439286Smckusick 	 * If source is the same as the destination,
144539286Smckusick 	 * then there is nothing to do.
144639286Smckusick 	 */
144739286Smckusick 	if (fvp == tvp)
144839286Smckusick 		error = -1;
144937741Smckusick out:
145042465Smckusick 	if (!error) {
145142465Smckusick 		error = VOP_RENAME(ndp, &tond);
145242465Smckusick 	} else {
145337741Smckusick 		VOP_ABORTOP(&tond);
145443344Smckusick 		if (tdvp == tvp)
145543344Smckusick 			vrele(tdvp);
145643344Smckusick 		else
145743344Smckusick 			vput(tdvp);
145842465Smckusick 		if (tvp)
145942465Smckusick 			vput(tvp);
146037741Smckusick 		VOP_ABORTOP(ndp);
146142465Smckusick 		vrele(ndp->ni_dvp);
146242465Smckusick 		vrele(fvp);
14639167Ssam 	}
146437741Smckusick out1:
146538266Smckusick 	ndrele(&tond);
146639286Smckusick 	if (error == -1)
146739286Smckusick 		RETURN (0);
146837741Smckusick 	RETURN (error);
14697701Ssam }
14707701Ssam 
14717535Sroot /*
147212756Ssam  * Mkdir system call
147312756Ssam  */
147442441Smckusick /* ARGSUSED */
147542441Smckusick mkdir(p, uap, retval)
147642441Smckusick 	register struct proc *p;
147742441Smckusick 	register struct args {
147812756Ssam 		char	*name;
147912756Ssam 		int	dmode;
148042441Smckusick 	} *uap;
148142441Smckusick 	int *retval;
148242441Smckusick {
148342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
148437741Smckusick 	register struct vnode *vp;
148537741Smckusick 	struct vattr vattr;
148637741Smckusick 	int error;
148712756Ssam 
148837741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
148916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
149016694Smckusick 	ndp->ni_dirp = uap->name;
149137741Smckusick 	if (error = namei(ndp))
149237741Smckusick 		RETURN (error);
149337741Smckusick 	vp = ndp->ni_vp;
149437741Smckusick 	if (vp != NULL) {
149537741Smckusick 		VOP_ABORTOP(ndp);
149643344Smckusick 		if (ndp->ni_dvp == vp)
149743344Smckusick 			vrele(ndp->ni_dvp);
149843344Smckusick 		else
149943344Smckusick 			vput(ndp->ni_dvp);
150042465Smckusick 		vrele(vp);
150137741Smckusick 		RETURN (EEXIST);
150212756Ssam 	}
150341362Smckusick 	VATTR_NULL(&vattr);
150437741Smckusick 	vattr.va_type = VDIR;
150542441Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask;
150637741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
150738145Smckusick 	if (!error)
150838145Smckusick 		vput(ndp->ni_vp);
150937741Smckusick 	RETURN (error);
151012756Ssam }
151112756Ssam 
151212756Ssam /*
151312756Ssam  * Rmdir system call.
151412756Ssam  */
151542441Smckusick /* ARGSUSED */
151642441Smckusick rmdir(p, uap, retval)
151742441Smckusick 	register struct proc *p;
151842441Smckusick 	struct args {
151942441Smckusick 		char	*name;
152042441Smckusick 	} *uap;
152142441Smckusick 	int *retval;
152212756Ssam {
152342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
152437741Smckusick 	register struct vnode *vp;
152537741Smckusick 	int error;
152612756Ssam 
152737741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
152816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
152916694Smckusick 	ndp->ni_dirp = uap->name;
153037741Smckusick 	if (error = namei(ndp))
153137741Smckusick 		RETURN (error);
153237741Smckusick 	vp = ndp->ni_vp;
153337741Smckusick 	if (vp->v_type != VDIR) {
153437741Smckusick 		error = ENOTDIR;
153512756Ssam 		goto out;
153612756Ssam 	}
153712756Ssam 	/*
153837741Smckusick 	 * No rmdir "." please.
153912756Ssam 	 */
154037741Smckusick 	if (ndp->ni_dvp == vp) {
154137741Smckusick 		error = EINVAL;
154212756Ssam 		goto out;
154312756Ssam 	}
154412756Ssam 	/*
154537741Smckusick 	 * Don't unlink a mounted file.
154612756Ssam 	 */
154737741Smckusick 	if (vp->v_flag & VROOT)
154837741Smckusick 		error = EBUSY;
154912756Ssam out:
155042465Smckusick 	if (!error) {
155142465Smckusick 		error = VOP_RMDIR(ndp);
155242465Smckusick 	} else {
155337741Smckusick 		VOP_ABORTOP(ndp);
155443344Smckusick 		if (ndp->ni_dvp == vp)
155543344Smckusick 			vrele(ndp->ni_dvp);
155643344Smckusick 		else
155743344Smckusick 			vput(ndp->ni_dvp);
155842465Smckusick 		vput(vp);
155942465Smckusick 	}
156037741Smckusick 	RETURN (error);
156112756Ssam }
156212756Ssam 
156337741Smckusick /*
156437741Smckusick  * Read a block of directory entries in a file system independent format
156537741Smckusick  */
156642441Smckusick getdirentries(p, uap, retval)
156742441Smckusick 	register struct proc *p;
156842441Smckusick 	register struct args {
156937741Smckusick 		int	fd;
157037741Smckusick 		char	*buf;
157137741Smckusick 		unsigned count;
157237741Smckusick 		long	*basep;
157342441Smckusick 	} *uap;
157442441Smckusick 	int *retval;
157542441Smckusick {
157639592Smckusick 	register struct vnode *vp;
157716540Ssam 	struct file *fp;
157837741Smckusick 	struct uio auio;
157937741Smckusick 	struct iovec aiov;
158038129Smckusick 	off_t off;
158140321Smckusick 	int error, eofflag;
158212756Ssam 
158342441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
158437741Smckusick 		RETURN (error);
158537741Smckusick 	if ((fp->f_flag & FREAD) == 0)
158637741Smckusick 		RETURN (EBADF);
158739592Smckusick 	vp = (struct vnode *)fp->f_data;
158839592Smckusick 	if (vp->v_type != VDIR)
158939592Smckusick 		RETURN (EINVAL);
159037741Smckusick 	aiov.iov_base = uap->buf;
159137741Smckusick 	aiov.iov_len = uap->count;
159237741Smckusick 	auio.uio_iov = &aiov;
159337741Smckusick 	auio.uio_iovcnt = 1;
159437741Smckusick 	auio.uio_rw = UIO_READ;
159537741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
159637741Smckusick 	auio.uio_resid = uap->count;
159739592Smckusick 	VOP_LOCK(vp);
159839592Smckusick 	auio.uio_offset = off = fp->f_offset;
159940321Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
160039592Smckusick 	fp->f_offset = auio.uio_offset;
160139592Smckusick 	VOP_UNLOCK(vp);
160239592Smckusick 	if (error)
160337741Smckusick 		RETURN (error);
160439592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
160542441Smckusick 	*retval = uap->count - auio.uio_resid;
160637741Smckusick 	RETURN (error);
160712756Ssam }
160812756Ssam 
160912756Ssam /*
161012756Ssam  * mode mask for creation of files
161112756Ssam  */
161242441Smckusick mode_t
161342441Smckusick umask(p, uap, retval)
161442441Smckusick 	register struct proc *p;
161542441Smckusick 	struct args {
161642441Smckusick 		int	mask;
161742441Smckusick 	} *uap;
161842441Smckusick 	int *retval;
161912756Ssam {
162012756Ssam 
162142441Smckusick 	*retval = u.u_cmask;
162242441Smckusick 	u.u_cmask = uap->mask & 07777;
162337741Smckusick 	RETURN (0);
162412756Ssam }
162537741Smckusick 
162639566Smarc /*
162739566Smarc  * Void all references to file by ripping underlying filesystem
162839566Smarc  * away from vnode.
162939566Smarc  */
163042441Smckusick /* ARGSUSED */
163142441Smckusick revoke(p, uap, retval)
163242441Smckusick 	register struct proc *p;
163342441Smckusick 	register struct args {
163439566Smarc 		char	*fname;
163542441Smckusick 	} *uap;
163642441Smckusick 	int *retval;
163742441Smckusick {
163842441Smckusick 	register struct nameidata *ndp = &u.u_nd;
163939566Smarc 	register struct vnode *vp;
164039566Smarc 	struct vattr vattr;
164139566Smarc 	int error;
164239566Smarc 
164339566Smarc 	ndp->ni_nameiop = LOOKUP | FOLLOW;
164439566Smarc 	ndp->ni_segflg = UIO_USERSPACE;
164539566Smarc 	ndp->ni_dirp = uap->fname;
164639566Smarc 	if (error = namei(ndp))
164739566Smarc 		RETURN (error);
164839566Smarc 	vp = ndp->ni_vp;
164939566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
165039566Smarc 		error = EINVAL;
165139566Smarc 		goto out;
165239566Smarc 	}
165342441Smckusick 	if (error = VOP_GETATTR(vp, &vattr, ndp->ni_cred))
165439566Smarc 		goto out;
165542955Smckusick 	if (ndp->ni_cred->cr_uid != vattr.va_uid &&
165642441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
165739566Smarc 		goto out;
165839805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
165939632Smckusick 		vgoneall(vp);
166039566Smarc out:
166139566Smarc 	vrele(vp);
166239566Smarc 	RETURN (error);
166339566Smarc }
166439566Smarc 
166538408Smckusick getvnode(ofile, fdes, fpp)
166638408Smckusick 	struct file *ofile[];
166737741Smckusick 	struct file **fpp;
166837741Smckusick 	int fdes;
166937741Smckusick {
167037741Smckusick 	struct file *fp;
167137741Smckusick 
167238408Smckusick 	if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
167337741Smckusick 		return (EBADF);
167437741Smckusick 	if (fp->f_type != DTYPE_VNODE)
167537741Smckusick 		return (EINVAL);
167637741Smckusick 	*fpp = fp;
167737741Smckusick 	return (0);
167837741Smckusick }
1679