xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 45785)
123405Smckusick /*
237741Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337741Smckusick  * All rights reserved.
423405Smckusick  *
544459Sbostic  * %sccs.include.redist.c%
637741Smckusick  *
7*45785Sbostic  *	@(#)vfs_syscalls.c	7.61 (Berkeley) 12/14/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 
23445738Smckusick 	vnode_pager_umount(mp);	/* release cached vnodes */
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;
55045202Smckusick 	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 */
55545202Smckusick 		    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 	}
694*45785Sbostic 	VATTR_NULL(&vattr);
695*45785Sbostic 	vattr.va_type = VFIFO;
696*45785Sbostic 	vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask;
69740285Smckusick 	RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred));
69840285Smckusick #endif /* FIFO */
69940285Smckusick }
70040285Smckusick 
70140285Smckusick /*
7026254Sroot  * link system call
7036254Sroot  */
70442441Smckusick /* ARGSUSED */
70542441Smckusick link(p, uap, retval)
70642441Smckusick 	register struct proc *p;
70742441Smckusick 	register struct args {
7086254Sroot 		char	*target;
7096254Sroot 		char	*linkname;
71042441Smckusick 	} *uap;
71142441Smckusick 	int *retval;
71242441Smckusick {
71342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
71437741Smckusick 	register struct vnode *vp, *xp;
71537741Smckusick 	int error;
7166254Sroot 
71716694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
71816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
71916694Smckusick 	ndp->ni_dirp = uap->target;
72037741Smckusick 	if (error = namei(ndp))
72137741Smckusick 		RETURN (error);
72237741Smckusick 	vp = ndp->ni_vp;
72337741Smckusick 	if (vp->v_type == VDIR &&
72442441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
72537741Smckusick 		goto out1;
72637741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
72716694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
72837741Smckusick 	if (error = namei(ndp))
72937741Smckusick 		goto out1;
73037741Smckusick 	xp = ndp->ni_vp;
7316254Sroot 	if (xp != NULL) {
73237741Smckusick 		error = EEXIST;
7336254Sroot 		goto out;
7346254Sroot 	}
73537741Smckusick 	xp = ndp->ni_dvp;
73637741Smckusick 	if (vp->v_mount != xp->v_mount)
73737741Smckusick 		error = EXDEV;
7386254Sroot out:
73942465Smckusick 	if (!error) {
74042465Smckusick 		error = VOP_LINK(vp, ndp);
74142465Smckusick 	} else {
74237741Smckusick 		VOP_ABORTOP(ndp);
74343344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
74443344Smckusick 			vrele(ndp->ni_dvp);
74543344Smckusick 		else
74643344Smckusick 			vput(ndp->ni_dvp);
74742465Smckusick 		if (ndp->ni_vp)
74842465Smckusick 			vrele(ndp->ni_vp);
74942465Smckusick 	}
75037741Smckusick out1:
75137741Smckusick 	vrele(vp);
75237741Smckusick 	RETURN (error);
7536254Sroot }
7546254Sroot 
7556254Sroot /*
7566254Sroot  * symlink -- make a symbolic link
7576254Sroot  */
75842441Smckusick /* ARGSUSED */
75942441Smckusick symlink(p, uap, retval)
76042441Smckusick 	register struct proc *p;
76142441Smckusick 	register struct args {
7626254Sroot 		char	*target;
7636254Sroot 		char	*linkname;
76442441Smckusick 	} *uap;
76542441Smckusick 	int *retval;
76642441Smckusick {
76742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
76837741Smckusick 	struct vattr vattr;
76937741Smckusick 	char *target;
77037741Smckusick 	int error;
7716254Sroot 
77216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
77316694Smckusick 	ndp->ni_dirp = uap->linkname;
77437741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
77537741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
77642465Smckusick 		goto out;
77737741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
77837741Smckusick 	if (error = namei(ndp))
77942465Smckusick 		goto out;
78042465Smckusick 	if (ndp->ni_vp) {
78142465Smckusick 		VOP_ABORTOP(ndp);
78243344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
78343344Smckusick 			vrele(ndp->ni_dvp);
78443344Smckusick 		else
78543344Smckusick 			vput(ndp->ni_dvp);
78642465Smckusick 		vrele(ndp->ni_vp);
78737741Smckusick 		error = EEXIST;
78837741Smckusick 		goto out;
7896254Sroot 	}
79041362Smckusick 	VATTR_NULL(&vattr);
79142441Smckusick 	vattr.va_mode = 0777 &~ u.u_cmask;
79242465Smckusick 	error = VOP_SYMLINK(ndp, &vattr, target);
79337741Smckusick out:
79437741Smckusick 	FREE(target, M_NAMEI);
79537741Smckusick 	RETURN (error);
7966254Sroot }
7976254Sroot 
7986254Sroot /*
7996254Sroot  * Unlink system call.
8006254Sroot  * Hard to avoid races here, especially
8016254Sroot  * in unlinking directories.
8026254Sroot  */
80342441Smckusick /* ARGSUSED */
80442441Smckusick unlink(p, uap, retval)
80542441Smckusick 	register struct proc *p;
80642441Smckusick 	struct args {
80742441Smckusick 		char	*fname;
80842441Smckusick 	} *uap;
80942441Smckusick 	int *retval;
8106254Sroot {
81142441Smckusick 	register struct nameidata *ndp = &u.u_nd;
81237741Smckusick 	register struct vnode *vp;
81337741Smckusick 	int error;
8146254Sroot 
81537741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
81616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
81716694Smckusick 	ndp->ni_dirp = uap->fname;
81837741Smckusick 	if (error = namei(ndp))
81937741Smckusick 		RETURN (error);
82037741Smckusick 	vp = ndp->ni_vp;
82137741Smckusick 	if (vp->v_type == VDIR &&
82242441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
8236254Sroot 		goto out;
8246254Sroot 	/*
8256254Sroot 	 * Don't unlink a mounted file.
8266254Sroot 	 */
82737741Smckusick 	if (vp->v_flag & VROOT) {
82837741Smckusick 		error = EBUSY;
8296254Sroot 		goto out;
8306254Sroot 	}
83145738Smckusick 	(void) vnode_pager_uncache(vp);
8326254Sroot out:
83342465Smckusick 	if (!error) {
83442465Smckusick 		error = VOP_REMOVE(ndp);
83542465Smckusick 	} else {
83637741Smckusick 		VOP_ABORTOP(ndp);
83743344Smckusick 		if (ndp->ni_dvp == vp)
83843344Smckusick 			vrele(ndp->ni_dvp);
83943344Smckusick 		else
84043344Smckusick 			vput(ndp->ni_dvp);
84142465Smckusick 		vput(vp);
84242465Smckusick 	}
84337741Smckusick 	RETURN (error);
8446254Sroot }
8456254Sroot 
8466254Sroot /*
8476254Sroot  * Seek system call
8486254Sroot  */
84942441Smckusick lseek(p, uap, retval)
85042441Smckusick 	register struct proc *p;
85142441Smckusick 	register struct args {
85237741Smckusick 		int	fdes;
8536254Sroot 		off_t	off;
8546254Sroot 		int	sbase;
85542441Smckusick 	} *uap;
85642441Smckusick 	off_t *retval;
85742441Smckusick {
85842441Smckusick 	struct ucred *cred = u.u_nd.ni_cred;
85942441Smckusick 	register struct file *fp;
86037741Smckusick 	struct vattr vattr;
86137741Smckusick 	int error;
8626254Sroot 
86337741Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
86442441Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
86537741Smckusick 		RETURN (EBADF);
86637741Smckusick 	if (fp->f_type != DTYPE_VNODE)
86737741Smckusick 		RETURN (ESPIPE);
86813878Ssam 	switch (uap->sbase) {
86913878Ssam 
87013878Ssam 	case L_INCR:
87113878Ssam 		fp->f_offset += uap->off;
87213878Ssam 		break;
87313878Ssam 
87413878Ssam 	case L_XTND:
87537741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
87642441Smckusick 		    &vattr, cred))
87737741Smckusick 			RETURN (error);
87837741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
87913878Ssam 		break;
88013878Ssam 
88113878Ssam 	case L_SET:
88213878Ssam 		fp->f_offset = uap->off;
88313878Ssam 		break;
88413878Ssam 
88513878Ssam 	default:
88637741Smckusick 		RETURN (EINVAL);
88713878Ssam 	}
88842441Smckusick 	*retval = fp->f_offset;
88937741Smckusick 	RETURN (0);
8906254Sroot }
8916254Sroot 
8926254Sroot /*
8936254Sroot  * Access system call
8946254Sroot  */
89542441Smckusick /* ARGSUSED */
89642441Smckusick saccess(p, uap, retval)
89742441Smckusick 	register struct proc *p;
89842441Smckusick 	register struct args {
8996254Sroot 		char	*fname;
9006254Sroot 		int	fmode;
90142441Smckusick 	} *uap;
90242441Smckusick 	int *retval;
90342441Smckusick {
90442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
90542441Smckusick 	register struct ucred *cred = ndp->ni_cred;
90637741Smckusick 	register struct vnode *vp;
90737741Smckusick 	int error, mode, svuid, svgid;
9086254Sroot 
90942441Smckusick 	svuid = cred->cr_uid;
91042441Smckusick 	svgid = cred->cr_groups[0];
91142441Smckusick 	cred->cr_uid = p->p_ruid;
91242441Smckusick 	cred->cr_groups[0] = p->p_rgid;
91337741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
91416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
91516694Smckusick 	ndp->ni_dirp = uap->fname;
91637741Smckusick 	if (error = namei(ndp))
91737741Smckusick 		goto out1;
91837741Smckusick 	vp = ndp->ni_vp;
91937741Smckusick 	/*
92037741Smckusick 	 * fmode == 0 means only check for exist
92137741Smckusick 	 */
92237741Smckusick 	if (uap->fmode) {
92337741Smckusick 		mode = 0;
92437741Smckusick 		if (uap->fmode & R_OK)
92537741Smckusick 			mode |= VREAD;
92637741Smckusick 		if (uap->fmode & W_OK)
92737741Smckusick 			mode |= VWRITE;
92837741Smckusick 		if (uap->fmode & X_OK)
92937741Smckusick 			mode |= VEXEC;
93039543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
93138399Smckusick 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
9326254Sroot 	}
93337741Smckusick 	vput(vp);
93437741Smckusick out1:
93542441Smckusick 	cred->cr_uid = svuid;
93642441Smckusick 	cred->cr_groups[0] = svgid;
93737741Smckusick 	RETURN (error);
9386254Sroot }
9396254Sroot 
9406254Sroot /*
9416574Smckusic  * Stat system call.  This version follows links.
94237Sbill  */
94342441Smckusick /* ARGSUSED */
94442441Smckusick stat(p, uap, retval)
94542441Smckusick 	register struct proc *p;
94642441Smckusick 	register struct args {
94742441Smckusick 		char	*fname;
94842441Smckusick 		struct stat *ub;
94942441Smckusick 	} *uap;
95042441Smckusick 	int *retval;
95137Sbill {
95242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
95342441Smckusick 	struct stat sb;
95442441Smckusick 	int error;
95537Sbill 
95642441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
95742441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
95842441Smckusick 	ndp->ni_dirp = uap->fname;
95942441Smckusick 	if (error = namei(ndp))
96042441Smckusick 		RETURN (error);
96142441Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
96242441Smckusick 	vput(ndp->ni_vp);
96342441Smckusick 	if (error)
96442441Smckusick 		RETURN (error);
96542441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
96642441Smckusick 	RETURN (error);
96737Sbill }
96837Sbill 
96937Sbill /*
9706574Smckusic  * Lstat system call.  This version does not follow links.
9715992Swnj  */
97242441Smckusick /* ARGSUSED */
97342441Smckusick lstat(p, uap, retval)
97442441Smckusick 	register struct proc *p;
97542441Smckusick 	register struct args {
9765992Swnj 		char	*fname;
97712756Ssam 		struct stat *ub;
97842441Smckusick 	} *uap;
97942441Smckusick 	int *retval;
98042441Smckusick {
98142441Smckusick 	register struct nameidata *ndp = &u.u_nd;
98212756Ssam 	struct stat sb;
98337741Smckusick 	int error;
9845992Swnj 
98542441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW;
98616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
98716694Smckusick 	ndp->ni_dirp = uap->fname;
98837741Smckusick 	if (error = namei(ndp))
98937741Smckusick 		RETURN (error);
99037741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
99137741Smckusick 	vput(ndp->ni_vp);
99237741Smckusick 	if (error)
99337741Smckusick 		RETURN (error);
99437741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
99537741Smckusick 	RETURN (error);
9965992Swnj }
9975992Swnj 
9985992Swnj /*
9995992Swnj  * Return target name of a symbolic link
100037Sbill  */
100142441Smckusick /* ARGSUSED */
100242441Smckusick readlink(p, uap, retval)
100342441Smckusick 	register struct proc *p;
100442441Smckusick 	register struct args {
10055992Swnj 		char	*name;
10065992Swnj 		char	*buf;
10075992Swnj 		int	count;
100842441Smckusick 	} *uap;
100942441Smckusick 	int *retval;
101042441Smckusick {
101142441Smckusick 	register struct nameidata *ndp = &u.u_nd;
101237741Smckusick 	register struct vnode *vp;
101337741Smckusick 	struct iovec aiov;
101437741Smckusick 	struct uio auio;
101537741Smckusick 	int error;
10165992Swnj 
101737741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
101816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
101916694Smckusick 	ndp->ni_dirp = uap->name;
102037741Smckusick 	if (error = namei(ndp))
102137741Smckusick 		RETURN (error);
102237741Smckusick 	vp = ndp->ni_vp;
102337741Smckusick 	if (vp->v_type != VLNK) {
102437741Smckusick 		error = EINVAL;
10255992Swnj 		goto out;
10265992Swnj 	}
102737741Smckusick 	aiov.iov_base = uap->buf;
102837741Smckusick 	aiov.iov_len = uap->count;
102937741Smckusick 	auio.uio_iov = &aiov;
103037741Smckusick 	auio.uio_iovcnt = 1;
103137741Smckusick 	auio.uio_offset = 0;
103237741Smckusick 	auio.uio_rw = UIO_READ;
103337741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
103437741Smckusick 	auio.uio_resid = uap->count;
103537741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
10365992Swnj out:
103737741Smckusick 	vput(vp);
103842441Smckusick 	*retval = uap->count - auio.uio_resid;
103937741Smckusick 	RETURN (error);
10405992Swnj }
10415992Swnj 
10429167Ssam /*
104338259Smckusick  * Change flags of a file given path name.
104438259Smckusick  */
104542441Smckusick /* ARGSUSED */
104642441Smckusick chflags(p, uap, retval)
104742441Smckusick 	register struct proc *p;
104842441Smckusick 	register struct args {
104938259Smckusick 		char	*fname;
105038259Smckusick 		int	flags;
105142441Smckusick 	} *uap;
105242441Smckusick 	int *retval;
105342441Smckusick {
105442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
105538259Smckusick 	register struct vnode *vp;
105638259Smckusick 	struct vattr vattr;
105738259Smckusick 	int error;
105838259Smckusick 
105938259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
106038259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
106138259Smckusick 	ndp->ni_dirp = uap->fname;
106238259Smckusick 	if (error = namei(ndp))
106338259Smckusick 		RETURN (error);
106438259Smckusick 	vp = ndp->ni_vp;
106541400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
106638259Smckusick 		error = EROFS;
106738259Smckusick 		goto out;
106838259Smckusick 	}
1069*45785Sbostic 	VATTR_NULL(&vattr);
1070*45785Sbostic 	vattr.va_flags = uap->flags;
107138259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
107238259Smckusick out:
107338259Smckusick 	vput(vp);
107438259Smckusick 	RETURN (error);
107538259Smckusick }
107638259Smckusick 
107738259Smckusick /*
107838259Smckusick  * Change flags of a file given a file descriptor.
107938259Smckusick  */
108042441Smckusick /* ARGSUSED */
108142441Smckusick fchflags(p, uap, retval)
108242441Smckusick 	register struct proc *p;
108342441Smckusick 	register struct args {
108438259Smckusick 		int	fd;
108538259Smckusick 		int	flags;
108642441Smckusick 	} *uap;
108742441Smckusick 	int *retval;
108842441Smckusick {
108938259Smckusick 	struct vattr vattr;
109038259Smckusick 	struct vnode *vp;
109138259Smckusick 	struct file *fp;
109238259Smckusick 	int error;
109338259Smckusick 
109442441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
109538259Smckusick 		RETURN (error);
109638259Smckusick 	vp = (struct vnode *)fp->f_data;
109738259Smckusick 	VOP_LOCK(vp);
109841400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
109938259Smckusick 		error = EROFS;
110038259Smckusick 		goto out;
110138259Smckusick 	}
1102*45785Sbostic 	VATTR_NULL(&vattr);
1103*45785Sbostic 	vattr.va_flags = uap->flags;
110438259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
110538259Smckusick out:
110638259Smckusick 	VOP_UNLOCK(vp);
110738259Smckusick 	RETURN (error);
110838259Smckusick }
110938259Smckusick 
111038259Smckusick /*
11119167Ssam  * Change mode of a file given path name.
11129167Ssam  */
111342441Smckusick /* ARGSUSED */
111442441Smckusick chmod(p, uap, retval)
111542441Smckusick 	register struct proc *p;
111642441Smckusick 	register struct args {
11176254Sroot 		char	*fname;
11186254Sroot 		int	fmode;
111942441Smckusick 	} *uap;
112042441Smckusick 	int *retval;
112142441Smckusick {
112242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
112337741Smckusick 	register struct vnode *vp;
112437741Smckusick 	struct vattr vattr;
112537741Smckusick 	int error;
11265992Swnj 
112737741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
112837741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
112937741Smckusick 	ndp->ni_dirp = uap->fname;
113037741Smckusick 	if (error = namei(ndp))
113137741Smckusick 		RETURN (error);
113237741Smckusick 	vp = ndp->ni_vp;
113341400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
113437741Smckusick 		error = EROFS;
113537741Smckusick 		goto out;
113637741Smckusick 	}
1137*45785Sbostic 	VATTR_NULL(&vattr);
1138*45785Sbostic 	vattr.va_mode = uap->fmode & 07777;
113937741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
114037741Smckusick out:
114137741Smckusick 	vput(vp);
114237741Smckusick 	RETURN (error);
11437701Ssam }
11447439Sroot 
11459167Ssam /*
11469167Ssam  * Change mode of a file given a file descriptor.
11479167Ssam  */
114842441Smckusick /* ARGSUSED */
114942441Smckusick fchmod(p, uap, retval)
115042441Smckusick 	register struct proc *p;
115142441Smckusick 	register struct args {
11527701Ssam 		int	fd;
11537701Ssam 		int	fmode;
115442441Smckusick 	} *uap;
115542441Smckusick 	int *retval;
115642441Smckusick {
115737741Smckusick 	struct vattr vattr;
115837741Smckusick 	struct vnode *vp;
115937741Smckusick 	struct file *fp;
116037741Smckusick 	int error;
11617701Ssam 
116242441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
116337741Smckusick 		RETURN (error);
116437741Smckusick 	vp = (struct vnode *)fp->f_data;
116537741Smckusick 	VOP_LOCK(vp);
116641400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
116737741Smckusick 		error = EROFS;
116837741Smckusick 		goto out;
11697439Sroot 	}
1170*45785Sbostic 	VATTR_NULL(&vattr);
1171*45785Sbostic 	vattr.va_mode = uap->fmode & 07777;
117237741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
117337741Smckusick out:
117437741Smckusick 	VOP_UNLOCK(vp);
117537741Smckusick 	RETURN (error);
11765992Swnj }
11775992Swnj 
11789167Ssam /*
11799167Ssam  * Set ownership given a path name.
11809167Ssam  */
118142441Smckusick /* ARGSUSED */
118242441Smckusick chown(p, uap, retval)
118342441Smckusick 	register struct proc *p;
118442441Smckusick 	register struct args {
11856254Sroot 		char	*fname;
11866254Sroot 		int	uid;
11876254Sroot 		int	gid;
118842441Smckusick 	} *uap;
118942441Smckusick 	int *retval;
119042441Smckusick {
119142441Smckusick 	register struct nameidata *ndp = &u.u_nd;
119237741Smckusick 	register struct vnode *vp;
119337741Smckusick 	struct vattr vattr;
119437741Smckusick 	int error;
119537Sbill 
119637741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
119736614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
119836614Sbostic 	ndp->ni_dirp = uap->fname;
119937741Smckusick 	if (error = namei(ndp))
120037741Smckusick 		RETURN (error);
120137741Smckusick 	vp = ndp->ni_vp;
120241400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
120337741Smckusick 		error = EROFS;
120437741Smckusick 		goto out;
120537741Smckusick 	}
1206*45785Sbostic 	VATTR_NULL(&vattr);
1207*45785Sbostic 	vattr.va_uid = uap->uid;
1208*45785Sbostic 	vattr.va_gid = uap->gid;
120937741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
121037741Smckusick out:
121137741Smckusick 	vput(vp);
121237741Smckusick 	RETURN (error);
12137701Ssam }
12147439Sroot 
12159167Ssam /*
12169167Ssam  * Set ownership given a file descriptor.
12179167Ssam  */
121842441Smckusick /* ARGSUSED */
121942441Smckusick fchown(p, uap, retval)
122042441Smckusick 	register struct proc *p;
122142441Smckusick 	register struct args {
12227701Ssam 		int	fd;
12237701Ssam 		int	uid;
12247701Ssam 		int	gid;
122542441Smckusick 	} *uap;
122642441Smckusick 	int *retval;
122742441Smckusick {
122837741Smckusick 	struct vattr vattr;
122937741Smckusick 	struct vnode *vp;
123037741Smckusick 	struct file *fp;
123137741Smckusick 	int error;
12327701Ssam 
123342441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
123437741Smckusick 		RETURN (error);
123537741Smckusick 	vp = (struct vnode *)fp->f_data;
123637741Smckusick 	VOP_LOCK(vp);
123741400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
123837741Smckusick 		error = EROFS;
123937741Smckusick 		goto out;
124037741Smckusick 	}
1241*45785Sbostic 	VATTR_NULL(&vattr);
1242*45785Sbostic 	vattr.va_uid = uap->uid;
1243*45785Sbostic 	vattr.va_gid = uap->gid;
124437741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
124537741Smckusick out:
124637741Smckusick 	VOP_UNLOCK(vp);
124737741Smckusick 	RETURN (error);
12487701Ssam }
12497701Ssam 
125042441Smckusick /*
125142441Smckusick  * Set the access and modification times of a file.
125242441Smckusick  */
125342441Smckusick /* ARGSUSED */
125442441Smckusick utimes(p, uap, retval)
125542441Smckusick 	register struct proc *p;
125642441Smckusick 	register struct args {
125711811Ssam 		char	*fname;
125811811Ssam 		struct	timeval *tptr;
125942441Smckusick 	} *uap;
126042441Smckusick 	int *retval;
126142441Smckusick {
126242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
126337741Smckusick 	register struct vnode *vp;
126411811Ssam 	struct timeval tv[2];
126537741Smckusick 	struct vattr vattr;
126637741Smckusick 	int error;
126711811Ssam 
126837741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
126937741Smckusick 		RETURN (error);
127037741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
127137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
127237741Smckusick 	ndp->ni_dirp = uap->fname;
127337741Smckusick 	if (error = namei(ndp))
127437741Smckusick 		RETURN (error);
127537741Smckusick 	vp = ndp->ni_vp;
127641400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
127737741Smckusick 		error = EROFS;
127837741Smckusick 		goto out;
127921015Smckusick 	}
1280*45785Sbostic 	VATTR_NULL(&vattr);
1281*45785Sbostic 	vattr.va_atime = tv[0];
1282*45785Sbostic 	vattr.va_mtime = tv[1];
128337741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
128437741Smckusick out:
128537741Smckusick 	vput(vp);
128637741Smckusick 	RETURN (error);
128711811Ssam }
128811811Ssam 
12899167Ssam /*
12909167Ssam  * Truncate a file given its path name.
12919167Ssam  */
129242441Smckusick /* ARGSUSED */
129342441Smckusick truncate(p, uap, retval)
129442441Smckusick 	register struct proc *p;
129542441Smckusick 	register struct args {
12967701Ssam 		char	*fname;
129726473Skarels 		off_t	length;
129842441Smckusick 	} *uap;
129942441Smckusick 	int *retval;
130042441Smckusick {
130142441Smckusick 	register struct nameidata *ndp = &u.u_nd;
130237741Smckusick 	register struct vnode *vp;
130337741Smckusick 	struct vattr vattr;
130437741Smckusick 	int error;
13057701Ssam 
130637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
130716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
130816694Smckusick 	ndp->ni_dirp = uap->fname;
130937741Smckusick 	if (error = namei(ndp))
131037741Smckusick 		RETURN (error);
131137741Smckusick 	vp = ndp->ni_vp;
131237741Smckusick 	if (vp->v_type == VDIR) {
131337741Smckusick 		error = EISDIR;
131437741Smckusick 		goto out;
13157701Ssam 	}
131638399Smckusick 	if ((error = vn_writechk(vp)) ||
131738399Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
131837741Smckusick 		goto out;
1319*45785Sbostic 	VATTR_NULL(&vattr);
1320*45785Sbostic 	vattr.va_size = uap->length;
132137741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
132237741Smckusick out:
132337741Smckusick 	vput(vp);
132437741Smckusick 	RETURN (error);
13257701Ssam }
13267701Ssam 
13279167Ssam /*
13289167Ssam  * Truncate a file given a file descriptor.
13299167Ssam  */
133042441Smckusick /* ARGSUSED */
133142441Smckusick ftruncate(p, uap, retval)
133242441Smckusick 	register struct proc *p;
133342441Smckusick 	register struct args {
13347701Ssam 		int	fd;
133526473Skarels 		off_t	length;
133642441Smckusick 	} *uap;
133742441Smckusick 	int *retval;
133842441Smckusick {
133937741Smckusick 	struct vattr vattr;
134037741Smckusick 	struct vnode *vp;
13417701Ssam 	struct file *fp;
134237741Smckusick 	int error;
13437701Ssam 
134442441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
134537741Smckusick 		RETURN (error);
134637741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
134737741Smckusick 		RETURN (EINVAL);
134837741Smckusick 	vp = (struct vnode *)fp->f_data;
134937741Smckusick 	VOP_LOCK(vp);
135037741Smckusick 	if (vp->v_type == VDIR) {
135137741Smckusick 		error = EISDIR;
135237741Smckusick 		goto out;
13537701Ssam 	}
135438399Smckusick 	if (error = vn_writechk(vp))
135537741Smckusick 		goto out;
1356*45785Sbostic 	VATTR_NULL(&vattr);
1357*45785Sbostic 	vattr.va_size = uap->length;
135837741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
135937741Smckusick out:
136037741Smckusick 	VOP_UNLOCK(vp);
136137741Smckusick 	RETURN (error);
13627701Ssam }
13637701Ssam 
13649167Ssam /*
13659167Ssam  * Synch an open file.
13669167Ssam  */
136742441Smckusick /* ARGSUSED */
136842441Smckusick fsync(p, uap, retval)
136942441Smckusick 	register struct proc *p;
137042441Smckusick 	struct args {
137142441Smckusick 		int	fd;
137242441Smckusick 	} *uap;
137342441Smckusick 	int *retval;
13749167Ssam {
137539592Smckusick 	register struct vnode *vp;
13769167Ssam 	struct file *fp;
137737741Smckusick 	int error;
13789167Ssam 
137942441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
138037741Smckusick 		RETURN (error);
138139592Smckusick 	vp = (struct vnode *)fp->f_data;
138239592Smckusick 	VOP_LOCK(vp);
138339592Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT);
138439592Smckusick 	VOP_UNLOCK(vp);
138537741Smckusick 	RETURN (error);
13869167Ssam }
13879167Ssam 
13889167Ssam /*
13899167Ssam  * Rename system call.
13909167Ssam  *
13919167Ssam  * Source and destination must either both be directories, or both
13929167Ssam  * not be directories.  If target is a directory, it must be empty.
13939167Ssam  */
139442441Smckusick /* ARGSUSED */
139542441Smckusick rename(p, uap, retval)
139642441Smckusick 	register struct proc *p;
139742441Smckusick 	register struct args {
13987701Ssam 		char	*from;
13997701Ssam 		char	*to;
140042441Smckusick 	} *uap;
140142441Smckusick 	int *retval;
140242441Smckusick {
140337741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
140442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
140537741Smckusick 	struct nameidata tond;
140637741Smckusick 	int error;
14077701Ssam 
140837741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
140916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
141016694Smckusick 	ndp->ni_dirp = uap->from;
141137741Smckusick 	if (error = namei(ndp))
141237741Smckusick 		RETURN (error);
141337741Smckusick 	fvp = ndp->ni_vp;
141438266Smckusick 	nddup(ndp, &tond);
141537741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
141637741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
141737741Smckusick 	tond.ni_dirp = uap->to;
141842465Smckusick 	if (error = namei(&tond)) {
141942465Smckusick 		VOP_ABORTOP(ndp);
142042465Smckusick 		vrele(ndp->ni_dvp);
142142465Smckusick 		vrele(fvp);
142242465Smckusick 		goto out1;
142342465Smckusick 	}
142437741Smckusick 	tdvp = tond.ni_dvp;
142537741Smckusick 	tvp = tond.ni_vp;
142637741Smckusick 	if (tvp != NULL) {
142737741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
142839242Sbostic 			error = ENOTDIR;
142937741Smckusick 			goto out;
143037741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
143139242Sbostic 			error = EISDIR;
143237741Smckusick 			goto out;
14339167Ssam 		}
143445240Smckusick 		if (fvp->v_mount != tvp->v_mount) {
143545240Smckusick 			error = EXDEV;
143645240Smckusick 			goto out;
143745240Smckusick 		}
14389167Ssam 	}
143937741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
144037741Smckusick 		error = EXDEV;
14419167Ssam 		goto out;
144210051Ssam 	}
144339286Smckusick 	if (fvp == tdvp)
144437741Smckusick 		error = EINVAL;
144539286Smckusick 	/*
144639286Smckusick 	 * If source is the same as the destination,
144739286Smckusick 	 * then there is nothing to do.
144839286Smckusick 	 */
144939286Smckusick 	if (fvp == tvp)
145039286Smckusick 		error = -1;
145137741Smckusick out:
145242465Smckusick 	if (!error) {
145342465Smckusick 		error = VOP_RENAME(ndp, &tond);
145442465Smckusick 	} else {
145537741Smckusick 		VOP_ABORTOP(&tond);
145643344Smckusick 		if (tdvp == tvp)
145743344Smckusick 			vrele(tdvp);
145843344Smckusick 		else
145943344Smckusick 			vput(tdvp);
146042465Smckusick 		if (tvp)
146142465Smckusick 			vput(tvp);
146237741Smckusick 		VOP_ABORTOP(ndp);
146342465Smckusick 		vrele(ndp->ni_dvp);
146442465Smckusick 		vrele(fvp);
14659167Ssam 	}
146637741Smckusick out1:
146738266Smckusick 	ndrele(&tond);
146839286Smckusick 	if (error == -1)
146939286Smckusick 		RETURN (0);
147037741Smckusick 	RETURN (error);
14717701Ssam }
14727701Ssam 
14737535Sroot /*
147412756Ssam  * Mkdir system call
147512756Ssam  */
147642441Smckusick /* ARGSUSED */
147742441Smckusick mkdir(p, uap, retval)
147842441Smckusick 	register struct proc *p;
147942441Smckusick 	register struct args {
148012756Ssam 		char	*name;
148112756Ssam 		int	dmode;
148242441Smckusick 	} *uap;
148342441Smckusick 	int *retval;
148442441Smckusick {
148542441Smckusick 	register struct nameidata *ndp = &u.u_nd;
148637741Smckusick 	register struct vnode *vp;
148737741Smckusick 	struct vattr vattr;
148837741Smckusick 	int error;
148912756Ssam 
149037741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
149116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
149216694Smckusick 	ndp->ni_dirp = uap->name;
149337741Smckusick 	if (error = namei(ndp))
149437741Smckusick 		RETURN (error);
149537741Smckusick 	vp = ndp->ni_vp;
149637741Smckusick 	if (vp != NULL) {
149737741Smckusick 		VOP_ABORTOP(ndp);
149843344Smckusick 		if (ndp->ni_dvp == vp)
149943344Smckusick 			vrele(ndp->ni_dvp);
150043344Smckusick 		else
150143344Smckusick 			vput(ndp->ni_dvp);
150242465Smckusick 		vrele(vp);
150337741Smckusick 		RETURN (EEXIST);
150412756Ssam 	}
150541362Smckusick 	VATTR_NULL(&vattr);
150637741Smckusick 	vattr.va_type = VDIR;
150742441Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask;
150837741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
150938145Smckusick 	if (!error)
151038145Smckusick 		vput(ndp->ni_vp);
151137741Smckusick 	RETURN (error);
151212756Ssam }
151312756Ssam 
151412756Ssam /*
151512756Ssam  * Rmdir system call.
151612756Ssam  */
151742441Smckusick /* ARGSUSED */
151842441Smckusick rmdir(p, uap, retval)
151942441Smckusick 	register struct proc *p;
152042441Smckusick 	struct args {
152142441Smckusick 		char	*name;
152242441Smckusick 	} *uap;
152342441Smckusick 	int *retval;
152412756Ssam {
152542441Smckusick 	register struct nameidata *ndp = &u.u_nd;
152637741Smckusick 	register struct vnode *vp;
152737741Smckusick 	int error;
152812756Ssam 
152937741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
153016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
153116694Smckusick 	ndp->ni_dirp = uap->name;
153237741Smckusick 	if (error = namei(ndp))
153337741Smckusick 		RETURN (error);
153437741Smckusick 	vp = ndp->ni_vp;
153537741Smckusick 	if (vp->v_type != VDIR) {
153637741Smckusick 		error = ENOTDIR;
153712756Ssam 		goto out;
153812756Ssam 	}
153912756Ssam 	/*
154037741Smckusick 	 * No rmdir "." please.
154112756Ssam 	 */
154237741Smckusick 	if (ndp->ni_dvp == vp) {
154337741Smckusick 		error = EINVAL;
154412756Ssam 		goto out;
154512756Ssam 	}
154612756Ssam 	/*
154737741Smckusick 	 * Don't unlink a mounted file.
154812756Ssam 	 */
154937741Smckusick 	if (vp->v_flag & VROOT)
155037741Smckusick 		error = EBUSY;
155112756Ssam out:
155242465Smckusick 	if (!error) {
155342465Smckusick 		error = VOP_RMDIR(ndp);
155442465Smckusick 	} else {
155537741Smckusick 		VOP_ABORTOP(ndp);
155643344Smckusick 		if (ndp->ni_dvp == vp)
155743344Smckusick 			vrele(ndp->ni_dvp);
155843344Smckusick 		else
155943344Smckusick 			vput(ndp->ni_dvp);
156042465Smckusick 		vput(vp);
156142465Smckusick 	}
156237741Smckusick 	RETURN (error);
156312756Ssam }
156412756Ssam 
156537741Smckusick /*
156637741Smckusick  * Read a block of directory entries in a file system independent format
156737741Smckusick  */
156842441Smckusick getdirentries(p, uap, retval)
156942441Smckusick 	register struct proc *p;
157042441Smckusick 	register struct args {
157137741Smckusick 		int	fd;
157237741Smckusick 		char	*buf;
157337741Smckusick 		unsigned count;
157437741Smckusick 		long	*basep;
157542441Smckusick 	} *uap;
157642441Smckusick 	int *retval;
157742441Smckusick {
157839592Smckusick 	register struct vnode *vp;
157916540Ssam 	struct file *fp;
158037741Smckusick 	struct uio auio;
158137741Smckusick 	struct iovec aiov;
158238129Smckusick 	off_t off;
158340321Smckusick 	int error, eofflag;
158412756Ssam 
158542441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
158637741Smckusick 		RETURN (error);
158737741Smckusick 	if ((fp->f_flag & FREAD) == 0)
158837741Smckusick 		RETURN (EBADF);
158939592Smckusick 	vp = (struct vnode *)fp->f_data;
159039592Smckusick 	if (vp->v_type != VDIR)
159139592Smckusick 		RETURN (EINVAL);
159237741Smckusick 	aiov.iov_base = uap->buf;
159337741Smckusick 	aiov.iov_len = uap->count;
159437741Smckusick 	auio.uio_iov = &aiov;
159537741Smckusick 	auio.uio_iovcnt = 1;
159637741Smckusick 	auio.uio_rw = UIO_READ;
159737741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
159837741Smckusick 	auio.uio_resid = uap->count;
159939592Smckusick 	VOP_LOCK(vp);
160039592Smckusick 	auio.uio_offset = off = fp->f_offset;
160140321Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
160239592Smckusick 	fp->f_offset = auio.uio_offset;
160339592Smckusick 	VOP_UNLOCK(vp);
160439592Smckusick 	if (error)
160537741Smckusick 		RETURN (error);
160639592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
160742441Smckusick 	*retval = uap->count - auio.uio_resid;
160837741Smckusick 	RETURN (error);
160912756Ssam }
161012756Ssam 
161112756Ssam /*
161212756Ssam  * mode mask for creation of files
161312756Ssam  */
161442441Smckusick mode_t
161542441Smckusick umask(p, uap, retval)
161642441Smckusick 	register struct proc *p;
161742441Smckusick 	struct args {
161842441Smckusick 		int	mask;
161942441Smckusick 	} *uap;
162042441Smckusick 	int *retval;
162112756Ssam {
162212756Ssam 
162342441Smckusick 	*retval = u.u_cmask;
162442441Smckusick 	u.u_cmask = uap->mask & 07777;
162537741Smckusick 	RETURN (0);
162612756Ssam }
162737741Smckusick 
162839566Smarc /*
162939566Smarc  * Void all references to file by ripping underlying filesystem
163039566Smarc  * away from vnode.
163139566Smarc  */
163242441Smckusick /* ARGSUSED */
163342441Smckusick revoke(p, uap, retval)
163442441Smckusick 	register struct proc *p;
163542441Smckusick 	register struct args {
163639566Smarc 		char	*fname;
163742441Smckusick 	} *uap;
163842441Smckusick 	int *retval;
163942441Smckusick {
164042441Smckusick 	register struct nameidata *ndp = &u.u_nd;
164139566Smarc 	register struct vnode *vp;
164239566Smarc 	struct vattr vattr;
164339566Smarc 	int error;
164439566Smarc 
164539566Smarc 	ndp->ni_nameiop = LOOKUP | FOLLOW;
164639566Smarc 	ndp->ni_segflg = UIO_USERSPACE;
164739566Smarc 	ndp->ni_dirp = uap->fname;
164839566Smarc 	if (error = namei(ndp))
164939566Smarc 		RETURN (error);
165039566Smarc 	vp = ndp->ni_vp;
165139566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
165239566Smarc 		error = EINVAL;
165339566Smarc 		goto out;
165439566Smarc 	}
165542441Smckusick 	if (error = VOP_GETATTR(vp, &vattr, ndp->ni_cred))
165639566Smarc 		goto out;
165742955Smckusick 	if (ndp->ni_cred->cr_uid != vattr.va_uid &&
165842441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
165939566Smarc 		goto out;
166039805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
166139632Smckusick 		vgoneall(vp);
166239566Smarc out:
166339566Smarc 	vrele(vp);
166439566Smarc 	RETURN (error);
166539566Smarc }
166639566Smarc 
166738408Smckusick getvnode(ofile, fdes, fpp)
166838408Smckusick 	struct file *ofile[];
166937741Smckusick 	struct file **fpp;
167037741Smckusick 	int fdes;
167137741Smckusick {
167237741Smckusick 	struct file *fp;
167337741Smckusick 
167438408Smckusick 	if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
167537741Smckusick 		return (EBADF);
167637741Smckusick 	if (fp->f_type != DTYPE_VNODE)
167737741Smckusick 		return (EINVAL);
167837741Smckusick 	*fpp = fp;
167937741Smckusick 	return (0);
168037741Smckusick }
1681