xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 45738)
123405Smckusick /*
237741Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337741Smckusick  * All rights reserved.
423405Smckusick  *
544459Sbostic  * %sccs.include.redist.c%
637741Smckusick  *
7*45738Smckusick  *	@(#)vfs_syscalls.c	7.60 (Berkeley) 12/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 
234*45738Smckusick 	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 	} 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 	}
832*45738Smckusick 	(void) vnode_pager_uncache(vp);
8336254Sroot out:
83442465Smckusick 	if (!error) {
83542465Smckusick 		error = VOP_REMOVE(ndp);
83642465Smckusick 	} else {
83737741Smckusick 		VOP_ABORTOP(ndp);
83843344Smckusick 		if (ndp->ni_dvp == vp)
83943344Smckusick 			vrele(ndp->ni_dvp);
84043344Smckusick 		else
84143344Smckusick 			vput(ndp->ni_dvp);
84242465Smckusick 		vput(vp);
84342465Smckusick 	}
84437741Smckusick 	RETURN (error);
8456254Sroot }
8466254Sroot 
8476254Sroot /*
8486254Sroot  * Seek system call
8496254Sroot  */
85042441Smckusick lseek(p, uap, retval)
85142441Smckusick 	register struct proc *p;
85242441Smckusick 	register struct args {
85337741Smckusick 		int	fdes;
8546254Sroot 		off_t	off;
8556254Sroot 		int	sbase;
85642441Smckusick 	} *uap;
85742441Smckusick 	off_t *retval;
85842441Smckusick {
85942441Smckusick 	struct ucred *cred = u.u_nd.ni_cred;
86042441Smckusick 	register struct file *fp;
86137741Smckusick 	struct vattr vattr;
86237741Smckusick 	int error;
8636254Sroot 
86437741Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
86542441Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
86637741Smckusick 		RETURN (EBADF);
86737741Smckusick 	if (fp->f_type != DTYPE_VNODE)
86837741Smckusick 		RETURN (ESPIPE);
86913878Ssam 	switch (uap->sbase) {
87013878Ssam 
87113878Ssam 	case L_INCR:
87213878Ssam 		fp->f_offset += uap->off;
87313878Ssam 		break;
87413878Ssam 
87513878Ssam 	case L_XTND:
87637741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
87742441Smckusick 		    &vattr, cred))
87837741Smckusick 			RETURN (error);
87937741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
88013878Ssam 		break;
88113878Ssam 
88213878Ssam 	case L_SET:
88313878Ssam 		fp->f_offset = uap->off;
88413878Ssam 		break;
88513878Ssam 
88613878Ssam 	default:
88737741Smckusick 		RETURN (EINVAL);
88813878Ssam 	}
88942441Smckusick 	*retval = fp->f_offset;
89037741Smckusick 	RETURN (0);
8916254Sroot }
8926254Sroot 
8936254Sroot /*
8946254Sroot  * Access system call
8956254Sroot  */
89642441Smckusick /* ARGSUSED */
89742441Smckusick saccess(p, uap, retval)
89842441Smckusick 	register struct proc *p;
89942441Smckusick 	register struct args {
9006254Sroot 		char	*fname;
9016254Sroot 		int	fmode;
90242441Smckusick 	} *uap;
90342441Smckusick 	int *retval;
90442441Smckusick {
90542441Smckusick 	register struct nameidata *ndp = &u.u_nd;
90642441Smckusick 	register struct ucred *cred = ndp->ni_cred;
90737741Smckusick 	register struct vnode *vp;
90837741Smckusick 	int error, mode, svuid, svgid;
9096254Sroot 
91042441Smckusick 	svuid = cred->cr_uid;
91142441Smckusick 	svgid = cred->cr_groups[0];
91242441Smckusick 	cred->cr_uid = p->p_ruid;
91342441Smckusick 	cred->cr_groups[0] = p->p_rgid;
91437741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
91516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
91616694Smckusick 	ndp->ni_dirp = uap->fname;
91737741Smckusick 	if (error = namei(ndp))
91837741Smckusick 		goto out1;
91937741Smckusick 	vp = ndp->ni_vp;
92037741Smckusick 	/*
92137741Smckusick 	 * fmode == 0 means only check for exist
92237741Smckusick 	 */
92337741Smckusick 	if (uap->fmode) {
92437741Smckusick 		mode = 0;
92537741Smckusick 		if (uap->fmode & R_OK)
92637741Smckusick 			mode |= VREAD;
92737741Smckusick 		if (uap->fmode & W_OK)
92837741Smckusick 			mode |= VWRITE;
92937741Smckusick 		if (uap->fmode & X_OK)
93037741Smckusick 			mode |= VEXEC;
93139543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
93238399Smckusick 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
9336254Sroot 	}
93437741Smckusick 	vput(vp);
93537741Smckusick out1:
93642441Smckusick 	cred->cr_uid = svuid;
93742441Smckusick 	cred->cr_groups[0] = svgid;
93837741Smckusick 	RETURN (error);
9396254Sroot }
9406254Sroot 
9416254Sroot /*
9426574Smckusic  * Stat system call.  This version follows links.
94337Sbill  */
94442441Smckusick /* ARGSUSED */
94542441Smckusick stat(p, uap, retval)
94642441Smckusick 	register struct proc *p;
94742441Smckusick 	register struct args {
94842441Smckusick 		char	*fname;
94942441Smckusick 		struct stat *ub;
95042441Smckusick 	} *uap;
95142441Smckusick 	int *retval;
95237Sbill {
95342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
95442441Smckusick 	struct stat sb;
95542441Smckusick 	int error;
95637Sbill 
95742441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
95842441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
95942441Smckusick 	ndp->ni_dirp = uap->fname;
96042441Smckusick 	if (error = namei(ndp))
96142441Smckusick 		RETURN (error);
96242441Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
96342441Smckusick 	vput(ndp->ni_vp);
96442441Smckusick 	if (error)
96542441Smckusick 		RETURN (error);
96642441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
96742441Smckusick 	RETURN (error);
96837Sbill }
96937Sbill 
97037Sbill /*
9716574Smckusic  * Lstat system call.  This version does not follow links.
9725992Swnj  */
97342441Smckusick /* ARGSUSED */
97442441Smckusick lstat(p, uap, retval)
97542441Smckusick 	register struct proc *p;
97642441Smckusick 	register struct args {
9775992Swnj 		char	*fname;
97812756Ssam 		struct stat *ub;
97942441Smckusick 	} *uap;
98042441Smckusick 	int *retval;
98142441Smckusick {
98242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
98312756Ssam 	struct stat sb;
98437741Smckusick 	int error;
9855992Swnj 
98642441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW;
98716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
98816694Smckusick 	ndp->ni_dirp = uap->fname;
98937741Smckusick 	if (error = namei(ndp))
99037741Smckusick 		RETURN (error);
99137741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
99237741Smckusick 	vput(ndp->ni_vp);
99337741Smckusick 	if (error)
99437741Smckusick 		RETURN (error);
99537741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
99637741Smckusick 	RETURN (error);
9975992Swnj }
9985992Swnj 
9995992Swnj /*
10005992Swnj  * Return target name of a symbolic link
100137Sbill  */
100242441Smckusick /* ARGSUSED */
100342441Smckusick readlink(p, uap, retval)
100442441Smckusick 	register struct proc *p;
100542441Smckusick 	register struct args {
10065992Swnj 		char	*name;
10075992Swnj 		char	*buf;
10085992Swnj 		int	count;
100942441Smckusick 	} *uap;
101042441Smckusick 	int *retval;
101142441Smckusick {
101242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
101337741Smckusick 	register struct vnode *vp;
101437741Smckusick 	struct iovec aiov;
101537741Smckusick 	struct uio auio;
101637741Smckusick 	int error;
10175992Swnj 
101837741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
101916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
102016694Smckusick 	ndp->ni_dirp = uap->name;
102137741Smckusick 	if (error = namei(ndp))
102237741Smckusick 		RETURN (error);
102337741Smckusick 	vp = ndp->ni_vp;
102437741Smckusick 	if (vp->v_type != VLNK) {
102537741Smckusick 		error = EINVAL;
10265992Swnj 		goto out;
10275992Swnj 	}
102837741Smckusick 	aiov.iov_base = uap->buf;
102937741Smckusick 	aiov.iov_len = uap->count;
103037741Smckusick 	auio.uio_iov = &aiov;
103137741Smckusick 	auio.uio_iovcnt = 1;
103237741Smckusick 	auio.uio_offset = 0;
103337741Smckusick 	auio.uio_rw = UIO_READ;
103437741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
103537741Smckusick 	auio.uio_resid = uap->count;
103637741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
10375992Swnj out:
103837741Smckusick 	vput(vp);
103942441Smckusick 	*retval = uap->count - auio.uio_resid;
104037741Smckusick 	RETURN (error);
10415992Swnj }
10425992Swnj 
10439167Ssam /*
104438259Smckusick  * Change flags of a file given path name.
104538259Smckusick  */
104642441Smckusick /* ARGSUSED */
104742441Smckusick chflags(p, uap, retval)
104842441Smckusick 	register struct proc *p;
104942441Smckusick 	register struct args {
105038259Smckusick 		char	*fname;
105138259Smckusick 		int	flags;
105242441Smckusick 	} *uap;
105342441Smckusick 	int *retval;
105442441Smckusick {
105542441Smckusick 	register struct nameidata *ndp = &u.u_nd;
105638259Smckusick 	register struct vnode *vp;
105738259Smckusick 	struct vattr vattr;
105838259Smckusick 	int error;
105938259Smckusick 
106038259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
106138259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
106238259Smckusick 	ndp->ni_dirp = uap->fname;
106341362Smckusick 	VATTR_NULL(&vattr);
106438259Smckusick 	vattr.va_flags = uap->flags;
106538259Smckusick 	if (error = namei(ndp))
106638259Smckusick 		RETURN (error);
106738259Smckusick 	vp = ndp->ni_vp;
106841400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
106938259Smckusick 		error = EROFS;
107038259Smckusick 		goto out;
107138259Smckusick 	}
107238259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
107338259Smckusick out:
107438259Smckusick 	vput(vp);
107538259Smckusick 	RETURN (error);
107638259Smckusick }
107738259Smckusick 
107838259Smckusick /*
107938259Smckusick  * Change flags of a file given a file descriptor.
108038259Smckusick  */
108142441Smckusick /* ARGSUSED */
108242441Smckusick fchflags(p, uap, retval)
108342441Smckusick 	register struct proc *p;
108442441Smckusick 	register struct args {
108538259Smckusick 		int	fd;
108638259Smckusick 		int	flags;
108742441Smckusick 	} *uap;
108842441Smckusick 	int *retval;
108942441Smckusick {
109038259Smckusick 	struct vattr vattr;
109138259Smckusick 	struct vnode *vp;
109238259Smckusick 	struct file *fp;
109338259Smckusick 	int error;
109438259Smckusick 
109542441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
109638259Smckusick 		RETURN (error);
109741362Smckusick 	VATTR_NULL(&vattr);
109838259Smckusick 	vattr.va_flags = uap->flags;
109938259Smckusick 	vp = (struct vnode *)fp->f_data;
110038259Smckusick 	VOP_LOCK(vp);
110141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
110238259Smckusick 		error = EROFS;
110338259Smckusick 		goto out;
110438259Smckusick 	}
110538259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
110638259Smckusick out:
110738259Smckusick 	VOP_UNLOCK(vp);
110838259Smckusick 	RETURN (error);
110938259Smckusick }
111038259Smckusick 
111138259Smckusick /*
11129167Ssam  * Change mode of a file given path name.
11139167Ssam  */
111442441Smckusick /* ARGSUSED */
111542441Smckusick chmod(p, uap, retval)
111642441Smckusick 	register struct proc *p;
111742441Smckusick 	register struct args {
11186254Sroot 		char	*fname;
11196254Sroot 		int	fmode;
112042441Smckusick 	} *uap;
112142441Smckusick 	int *retval;
112242441Smckusick {
112342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
112437741Smckusick 	register struct vnode *vp;
112537741Smckusick 	struct vattr vattr;
112637741Smckusick 	int error;
11275992Swnj 
112837741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
112937741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
113037741Smckusick 	ndp->ni_dirp = uap->fname;
113141362Smckusick 	VATTR_NULL(&vattr);
113237741Smckusick 	vattr.va_mode = uap->fmode & 07777;
113337741Smckusick 	if (error = namei(ndp))
113437741Smckusick 		RETURN (error);
113537741Smckusick 	vp = ndp->ni_vp;
113641400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
113737741Smckusick 		error = EROFS;
113837741Smckusick 		goto out;
113937741Smckusick 	}
114037741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
114137741Smckusick out:
114237741Smckusick 	vput(vp);
114337741Smckusick 	RETURN (error);
11447701Ssam }
11457439Sroot 
11469167Ssam /*
11479167Ssam  * Change mode of a file given a file descriptor.
11489167Ssam  */
114942441Smckusick /* ARGSUSED */
115042441Smckusick fchmod(p, uap, retval)
115142441Smckusick 	register struct proc *p;
115242441Smckusick 	register struct args {
11537701Ssam 		int	fd;
11547701Ssam 		int	fmode;
115542441Smckusick 	} *uap;
115642441Smckusick 	int *retval;
115742441Smckusick {
115837741Smckusick 	struct vattr vattr;
115937741Smckusick 	struct vnode *vp;
116037741Smckusick 	struct file *fp;
116137741Smckusick 	int error;
11627701Ssam 
116342441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
116437741Smckusick 		RETURN (error);
116541362Smckusick 	VATTR_NULL(&vattr);
116637741Smckusick 	vattr.va_mode = uap->fmode & 07777;
116737741Smckusick 	vp = (struct vnode *)fp->f_data;
116837741Smckusick 	VOP_LOCK(vp);
116941400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
117037741Smckusick 		error = EROFS;
117137741Smckusick 		goto out;
11727439Sroot 	}
117337741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
117437741Smckusick out:
117537741Smckusick 	VOP_UNLOCK(vp);
117637741Smckusick 	RETURN (error);
11775992Swnj }
11785992Swnj 
11799167Ssam /*
11809167Ssam  * Set ownership given a path name.
11819167Ssam  */
118242441Smckusick /* ARGSUSED */
118342441Smckusick chown(p, uap, retval)
118442441Smckusick 	register struct proc *p;
118542441Smckusick 	register struct args {
11866254Sroot 		char	*fname;
11876254Sroot 		int	uid;
11886254Sroot 		int	gid;
118942441Smckusick 	} *uap;
119042441Smckusick 	int *retval;
119142441Smckusick {
119242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
119337741Smckusick 	register struct vnode *vp;
119437741Smckusick 	struct vattr vattr;
119537741Smckusick 	int error;
119637Sbill 
119737741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
119836614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
119936614Sbostic 	ndp->ni_dirp = uap->fname;
120041362Smckusick 	VATTR_NULL(&vattr);
120137741Smckusick 	vattr.va_uid = uap->uid;
120237741Smckusick 	vattr.va_gid = uap->gid;
120337741Smckusick 	if (error = namei(ndp))
120437741Smckusick 		RETURN (error);
120537741Smckusick 	vp = ndp->ni_vp;
120641400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
120737741Smckusick 		error = EROFS;
120837741Smckusick 		goto out;
120937741Smckusick 	}
121037741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
121137741Smckusick out:
121237741Smckusick 	vput(vp);
121337741Smckusick 	RETURN (error);
12147701Ssam }
12157439Sroot 
12169167Ssam /*
12179167Ssam  * Set ownership given a file descriptor.
12189167Ssam  */
121942441Smckusick /* ARGSUSED */
122042441Smckusick fchown(p, uap, retval)
122142441Smckusick 	register struct proc *p;
122242441Smckusick 	register struct args {
12237701Ssam 		int	fd;
12247701Ssam 		int	uid;
12257701Ssam 		int	gid;
122642441Smckusick 	} *uap;
122742441Smckusick 	int *retval;
122842441Smckusick {
122937741Smckusick 	struct vattr vattr;
123037741Smckusick 	struct vnode *vp;
123137741Smckusick 	struct file *fp;
123237741Smckusick 	int error;
12337701Ssam 
123442441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
123537741Smckusick 		RETURN (error);
123641362Smckusick 	VATTR_NULL(&vattr);
123737741Smckusick 	vattr.va_uid = uap->uid;
123837741Smckusick 	vattr.va_gid = uap->gid;
123937741Smckusick 	vp = (struct vnode *)fp->f_data;
124037741Smckusick 	VOP_LOCK(vp);
124141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
124237741Smckusick 		error = EROFS;
124337741Smckusick 		goto out;
124437741Smckusick 	}
124537741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
124637741Smckusick out:
124737741Smckusick 	VOP_UNLOCK(vp);
124837741Smckusick 	RETURN (error);
12497701Ssam }
12507701Ssam 
125142441Smckusick /*
125242441Smckusick  * Set the access and modification times of a file.
125342441Smckusick  */
125442441Smckusick /* ARGSUSED */
125542441Smckusick utimes(p, uap, retval)
125642441Smckusick 	register struct proc *p;
125742441Smckusick 	register struct args {
125811811Ssam 		char	*fname;
125911811Ssam 		struct	timeval *tptr;
126042441Smckusick 	} *uap;
126142441Smckusick 	int *retval;
126242441Smckusick {
126342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
126437741Smckusick 	register struct vnode *vp;
126511811Ssam 	struct timeval tv[2];
126637741Smckusick 	struct vattr vattr;
126737741Smckusick 	int error;
126811811Ssam 
126937741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
127037741Smckusick 		RETURN (error);
127137741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
127237741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
127337741Smckusick 	ndp->ni_dirp = uap->fname;
127441362Smckusick 	VATTR_NULL(&vattr);
127537741Smckusick 	vattr.va_atime = tv[0];
127637741Smckusick 	vattr.va_mtime = tv[1];
127737741Smckusick 	if (error = namei(ndp))
127837741Smckusick 		RETURN (error);
127937741Smckusick 	vp = ndp->ni_vp;
128041400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
128137741Smckusick 		error = EROFS;
128237741Smckusick 		goto out;
128321015Smckusick 	}
128437741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
128537741Smckusick out:
128637741Smckusick 	vput(vp);
128737741Smckusick 	RETURN (error);
128811811Ssam }
128911811Ssam 
12909167Ssam /*
12919167Ssam  * Truncate a file given its path name.
12929167Ssam  */
129342441Smckusick /* ARGSUSED */
129442441Smckusick truncate(p, uap, retval)
129542441Smckusick 	register struct proc *p;
129642441Smckusick 	register struct args {
12977701Ssam 		char	*fname;
129826473Skarels 		off_t	length;
129942441Smckusick 	} *uap;
130042441Smckusick 	int *retval;
130142441Smckusick {
130242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
130337741Smckusick 	register struct vnode *vp;
130437741Smckusick 	struct vattr vattr;
130537741Smckusick 	int error;
13067701Ssam 
130737741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
130816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
130916694Smckusick 	ndp->ni_dirp = uap->fname;
131041362Smckusick 	VATTR_NULL(&vattr);
131137741Smckusick 	vattr.va_size = uap->length;
131237741Smckusick 	if (error = namei(ndp))
131337741Smckusick 		RETURN (error);
131437741Smckusick 	vp = ndp->ni_vp;
131537741Smckusick 	if (vp->v_type == VDIR) {
131637741Smckusick 		error = EISDIR;
131737741Smckusick 		goto out;
13187701Ssam 	}
131938399Smckusick 	if ((error = vn_writechk(vp)) ||
132038399Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
132137741Smckusick 		goto out;
132237741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
132337741Smckusick out:
132437741Smckusick 	vput(vp);
132537741Smckusick 	RETURN (error);
13267701Ssam }
13277701Ssam 
13289167Ssam /*
13299167Ssam  * Truncate a file given a file descriptor.
13309167Ssam  */
133142441Smckusick /* ARGSUSED */
133242441Smckusick ftruncate(p, uap, retval)
133342441Smckusick 	register struct proc *p;
133442441Smckusick 	register struct args {
13357701Ssam 		int	fd;
133626473Skarels 		off_t	length;
133742441Smckusick 	} *uap;
133842441Smckusick 	int *retval;
133942441Smckusick {
134037741Smckusick 	struct vattr vattr;
134137741Smckusick 	struct vnode *vp;
13427701Ssam 	struct file *fp;
134337741Smckusick 	int error;
13447701Ssam 
134542441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
134637741Smckusick 		RETURN (error);
134737741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
134837741Smckusick 		RETURN (EINVAL);
134941362Smckusick 	VATTR_NULL(&vattr);
135037741Smckusick 	vattr.va_size = uap->length;
135137741Smckusick 	vp = (struct vnode *)fp->f_data;
135237741Smckusick 	VOP_LOCK(vp);
135337741Smckusick 	if (vp->v_type == VDIR) {
135437741Smckusick 		error = EISDIR;
135537741Smckusick 		goto out;
13567701Ssam 	}
135738399Smckusick 	if (error = vn_writechk(vp))
135837741Smckusick 		goto out;
135937741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
136037741Smckusick out:
136137741Smckusick 	VOP_UNLOCK(vp);
136237741Smckusick 	RETURN (error);
13637701Ssam }
13647701Ssam 
13659167Ssam /*
13669167Ssam  * Synch an open file.
13679167Ssam  */
136842441Smckusick /* ARGSUSED */
136942441Smckusick fsync(p, uap, retval)
137042441Smckusick 	register struct proc *p;
137142441Smckusick 	struct args {
137242441Smckusick 		int	fd;
137342441Smckusick 	} *uap;
137442441Smckusick 	int *retval;
13759167Ssam {
137639592Smckusick 	register struct vnode *vp;
13779167Ssam 	struct file *fp;
137837741Smckusick 	int error;
13799167Ssam 
138042441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
138137741Smckusick 		RETURN (error);
138239592Smckusick 	vp = (struct vnode *)fp->f_data;
138339592Smckusick 	VOP_LOCK(vp);
138439592Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT);
138539592Smckusick 	VOP_UNLOCK(vp);
138637741Smckusick 	RETURN (error);
13879167Ssam }
13889167Ssam 
13899167Ssam /*
13909167Ssam  * Rename system call.
13919167Ssam  *
13929167Ssam  * Source and destination must either both be directories, or both
13939167Ssam  * not be directories.  If target is a directory, it must be empty.
13949167Ssam  */
139542441Smckusick /* ARGSUSED */
139642441Smckusick rename(p, uap, retval)
139742441Smckusick 	register struct proc *p;
139842441Smckusick 	register struct args {
13997701Ssam 		char	*from;
14007701Ssam 		char	*to;
140142441Smckusick 	} *uap;
140242441Smckusick 	int *retval;
140342441Smckusick {
140437741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
140542441Smckusick 	register struct nameidata *ndp = &u.u_nd;
140637741Smckusick 	struct nameidata tond;
140737741Smckusick 	int error;
14087701Ssam 
140937741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
141016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
141116694Smckusick 	ndp->ni_dirp = uap->from;
141237741Smckusick 	if (error = namei(ndp))
141337741Smckusick 		RETURN (error);
141437741Smckusick 	fvp = ndp->ni_vp;
141538266Smckusick 	nddup(ndp, &tond);
141637741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
141737741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
141837741Smckusick 	tond.ni_dirp = uap->to;
141942465Smckusick 	if (error = namei(&tond)) {
142042465Smckusick 		VOP_ABORTOP(ndp);
142142465Smckusick 		vrele(ndp->ni_dvp);
142242465Smckusick 		vrele(fvp);
142342465Smckusick 		goto out1;
142442465Smckusick 	}
142537741Smckusick 	tdvp = tond.ni_dvp;
142637741Smckusick 	tvp = tond.ni_vp;
142737741Smckusick 	if (tvp != NULL) {
142837741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
142939242Sbostic 			error = ENOTDIR;
143037741Smckusick 			goto out;
143137741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
143239242Sbostic 			error = EISDIR;
143337741Smckusick 			goto out;
14349167Ssam 		}
143545240Smckusick 		if (fvp->v_mount != tvp->v_mount) {
143645240Smckusick 			error = EXDEV;
143745240Smckusick 			goto out;
143845240Smckusick 		}
14399167Ssam 	}
144037741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
144137741Smckusick 		error = EXDEV;
14429167Ssam 		goto out;
144310051Ssam 	}
144439286Smckusick 	if (fvp == tdvp)
144537741Smckusick 		error = EINVAL;
144639286Smckusick 	/*
144739286Smckusick 	 * If source is the same as the destination,
144839286Smckusick 	 * then there is nothing to do.
144939286Smckusick 	 */
145039286Smckusick 	if (fvp == tvp)
145139286Smckusick 		error = -1;
145237741Smckusick out:
145342465Smckusick 	if (!error) {
145442465Smckusick 		error = VOP_RENAME(ndp, &tond);
145542465Smckusick 	} else {
145637741Smckusick 		VOP_ABORTOP(&tond);
145743344Smckusick 		if (tdvp == tvp)
145843344Smckusick 			vrele(tdvp);
145943344Smckusick 		else
146043344Smckusick 			vput(tdvp);
146142465Smckusick 		if (tvp)
146242465Smckusick 			vput(tvp);
146337741Smckusick 		VOP_ABORTOP(ndp);
146442465Smckusick 		vrele(ndp->ni_dvp);
146542465Smckusick 		vrele(fvp);
14669167Ssam 	}
146737741Smckusick out1:
146838266Smckusick 	ndrele(&tond);
146939286Smckusick 	if (error == -1)
147039286Smckusick 		RETURN (0);
147137741Smckusick 	RETURN (error);
14727701Ssam }
14737701Ssam 
14747535Sroot /*
147512756Ssam  * Mkdir system call
147612756Ssam  */
147742441Smckusick /* ARGSUSED */
147842441Smckusick mkdir(p, uap, retval)
147942441Smckusick 	register struct proc *p;
148042441Smckusick 	register struct args {
148112756Ssam 		char	*name;
148212756Ssam 		int	dmode;
148342441Smckusick 	} *uap;
148442441Smckusick 	int *retval;
148542441Smckusick {
148642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
148737741Smckusick 	register struct vnode *vp;
148837741Smckusick 	struct vattr vattr;
148937741Smckusick 	int error;
149012756Ssam 
149137741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
149216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
149316694Smckusick 	ndp->ni_dirp = uap->name;
149437741Smckusick 	if (error = namei(ndp))
149537741Smckusick 		RETURN (error);
149637741Smckusick 	vp = ndp->ni_vp;
149737741Smckusick 	if (vp != NULL) {
149837741Smckusick 		VOP_ABORTOP(ndp);
149943344Smckusick 		if (ndp->ni_dvp == vp)
150043344Smckusick 			vrele(ndp->ni_dvp);
150143344Smckusick 		else
150243344Smckusick 			vput(ndp->ni_dvp);
150342465Smckusick 		vrele(vp);
150437741Smckusick 		RETURN (EEXIST);
150512756Ssam 	}
150641362Smckusick 	VATTR_NULL(&vattr);
150737741Smckusick 	vattr.va_type = VDIR;
150842441Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask;
150937741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
151038145Smckusick 	if (!error)
151138145Smckusick 		vput(ndp->ni_vp);
151237741Smckusick 	RETURN (error);
151312756Ssam }
151412756Ssam 
151512756Ssam /*
151612756Ssam  * Rmdir system call.
151712756Ssam  */
151842441Smckusick /* ARGSUSED */
151942441Smckusick rmdir(p, uap, retval)
152042441Smckusick 	register struct proc *p;
152142441Smckusick 	struct args {
152242441Smckusick 		char	*name;
152342441Smckusick 	} *uap;
152442441Smckusick 	int *retval;
152512756Ssam {
152642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
152737741Smckusick 	register struct vnode *vp;
152837741Smckusick 	int error;
152912756Ssam 
153037741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
153116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
153216694Smckusick 	ndp->ni_dirp = uap->name;
153337741Smckusick 	if (error = namei(ndp))
153437741Smckusick 		RETURN (error);
153537741Smckusick 	vp = ndp->ni_vp;
153637741Smckusick 	if (vp->v_type != VDIR) {
153737741Smckusick 		error = ENOTDIR;
153812756Ssam 		goto out;
153912756Ssam 	}
154012756Ssam 	/*
154137741Smckusick 	 * No rmdir "." please.
154212756Ssam 	 */
154337741Smckusick 	if (ndp->ni_dvp == vp) {
154437741Smckusick 		error = EINVAL;
154512756Ssam 		goto out;
154612756Ssam 	}
154712756Ssam 	/*
154837741Smckusick 	 * Don't unlink a mounted file.
154912756Ssam 	 */
155037741Smckusick 	if (vp->v_flag & VROOT)
155137741Smckusick 		error = EBUSY;
155212756Ssam out:
155342465Smckusick 	if (!error) {
155442465Smckusick 		error = VOP_RMDIR(ndp);
155542465Smckusick 	} else {
155637741Smckusick 		VOP_ABORTOP(ndp);
155743344Smckusick 		if (ndp->ni_dvp == vp)
155843344Smckusick 			vrele(ndp->ni_dvp);
155943344Smckusick 		else
156043344Smckusick 			vput(ndp->ni_dvp);
156142465Smckusick 		vput(vp);
156242465Smckusick 	}
156337741Smckusick 	RETURN (error);
156412756Ssam }
156512756Ssam 
156637741Smckusick /*
156737741Smckusick  * Read a block of directory entries in a file system independent format
156837741Smckusick  */
156942441Smckusick getdirentries(p, uap, retval)
157042441Smckusick 	register struct proc *p;
157142441Smckusick 	register struct args {
157237741Smckusick 		int	fd;
157337741Smckusick 		char	*buf;
157437741Smckusick 		unsigned count;
157537741Smckusick 		long	*basep;
157642441Smckusick 	} *uap;
157742441Smckusick 	int *retval;
157842441Smckusick {
157939592Smckusick 	register struct vnode *vp;
158016540Ssam 	struct file *fp;
158137741Smckusick 	struct uio auio;
158237741Smckusick 	struct iovec aiov;
158338129Smckusick 	off_t off;
158440321Smckusick 	int error, eofflag;
158512756Ssam 
158642441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
158737741Smckusick 		RETURN (error);
158837741Smckusick 	if ((fp->f_flag & FREAD) == 0)
158937741Smckusick 		RETURN (EBADF);
159039592Smckusick 	vp = (struct vnode *)fp->f_data;
159139592Smckusick 	if (vp->v_type != VDIR)
159239592Smckusick 		RETURN (EINVAL);
159337741Smckusick 	aiov.iov_base = uap->buf;
159437741Smckusick 	aiov.iov_len = uap->count;
159537741Smckusick 	auio.uio_iov = &aiov;
159637741Smckusick 	auio.uio_iovcnt = 1;
159737741Smckusick 	auio.uio_rw = UIO_READ;
159837741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
159937741Smckusick 	auio.uio_resid = uap->count;
160039592Smckusick 	VOP_LOCK(vp);
160139592Smckusick 	auio.uio_offset = off = fp->f_offset;
160240321Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
160339592Smckusick 	fp->f_offset = auio.uio_offset;
160439592Smckusick 	VOP_UNLOCK(vp);
160539592Smckusick 	if (error)
160637741Smckusick 		RETURN (error);
160739592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
160842441Smckusick 	*retval = uap->count - auio.uio_resid;
160937741Smckusick 	RETURN (error);
161012756Ssam }
161112756Ssam 
161212756Ssam /*
161312756Ssam  * mode mask for creation of files
161412756Ssam  */
161542441Smckusick mode_t
161642441Smckusick umask(p, uap, retval)
161742441Smckusick 	register struct proc *p;
161842441Smckusick 	struct args {
161942441Smckusick 		int	mask;
162042441Smckusick 	} *uap;
162142441Smckusick 	int *retval;
162212756Ssam {
162312756Ssam 
162442441Smckusick 	*retval = u.u_cmask;
162542441Smckusick 	u.u_cmask = uap->mask & 07777;
162637741Smckusick 	RETURN (0);
162712756Ssam }
162837741Smckusick 
162939566Smarc /*
163039566Smarc  * Void all references to file by ripping underlying filesystem
163139566Smarc  * away from vnode.
163239566Smarc  */
163342441Smckusick /* ARGSUSED */
163442441Smckusick revoke(p, uap, retval)
163542441Smckusick 	register struct proc *p;
163642441Smckusick 	register struct args {
163739566Smarc 		char	*fname;
163842441Smckusick 	} *uap;
163942441Smckusick 	int *retval;
164042441Smckusick {
164142441Smckusick 	register struct nameidata *ndp = &u.u_nd;
164239566Smarc 	register struct vnode *vp;
164339566Smarc 	struct vattr vattr;
164439566Smarc 	int error;
164539566Smarc 
164639566Smarc 	ndp->ni_nameiop = LOOKUP | FOLLOW;
164739566Smarc 	ndp->ni_segflg = UIO_USERSPACE;
164839566Smarc 	ndp->ni_dirp = uap->fname;
164939566Smarc 	if (error = namei(ndp))
165039566Smarc 		RETURN (error);
165139566Smarc 	vp = ndp->ni_vp;
165239566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
165339566Smarc 		error = EINVAL;
165439566Smarc 		goto out;
165539566Smarc 	}
165642441Smckusick 	if (error = VOP_GETATTR(vp, &vattr, ndp->ni_cred))
165739566Smarc 		goto out;
165842955Smckusick 	if (ndp->ni_cred->cr_uid != vattr.va_uid &&
165942441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
166039566Smarc 		goto out;
166139805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
166239632Smckusick 		vgoneall(vp);
166339566Smarc out:
166439566Smarc 	vrele(vp);
166539566Smarc 	RETURN (error);
166639566Smarc }
166739566Smarc 
166838408Smckusick getvnode(ofile, fdes, fpp)
166938408Smckusick 	struct file *ofile[];
167037741Smckusick 	struct file **fpp;
167137741Smckusick 	int fdes;
167237741Smckusick {
167337741Smckusick 	struct file *fp;
167437741Smckusick 
167538408Smckusick 	if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
167637741Smckusick 		return (EBADF);
167737741Smckusick 	if (fp->f_type != DTYPE_VNODE)
167837741Smckusick 		return (EINVAL);
167937741Smckusick 	*fpp = fp;
168037741Smckusick 	return (0);
168137741Smckusick }
1682