xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 44407)
123405Smckusick /*
237741Smckusick  * Copyright (c) 1989 The Regents of the University of California.
337741Smckusick  * All rights reserved.
423405Smckusick  *
537741Smckusick  * Redistribution and use in source and binary forms are permitted
637741Smckusick  * provided that the above copyright notice and this paragraph are
737741Smckusick  * duplicated in all such forms and that any documentation,
837741Smckusick  * advertising materials, and other materials related to such
937741Smckusick  * distribution and use acknowledge that the software was developed
1037741Smckusick  * by the University of California, Berkeley.  The name of the
1137741Smckusick  * University may not be used to endorse or promote products derived
1237741Smckusick  * from this software without specific prior written permission.
1337741Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1437741Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1537741Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1637741Smckusick  *
17*44407Skarels  *	@(#)vfs_syscalls.c	7.55 (Berkeley) 06/28/90
1823405Smckusick  */
1937Sbill 
2017101Sbloom #include "param.h"
2117101Sbloom #include "systm.h"
22*44407Skarels #include "user.h"
2317101Sbloom #include "kernel.h"
2417101Sbloom #include "file.h"
2517101Sbloom #include "stat.h"
2637741Smckusick #include "vnode.h"
2737741Smckusick #include "mount.h"
2817101Sbloom #include "proc.h"
2917101Sbloom #include "uio.h"
3037741Smckusick #include "malloc.h"
3137Sbill 
3243450Smckusick #define RETURN(val) {if (u.u_spare[0] != 0) panic("lock count"); return (val);}
3339797Smckusick 
3437741Smckusick /*
3537741Smckusick  * Virtual File System System Calls
3637741Smckusick  */
3712756Ssam 
389167Ssam /*
3937741Smckusick  * mount system call
409167Ssam  */
4142441Smckusick /* ARGSUSED */
4242441Smckusick mount(p, uap, retval)
4342441Smckusick 	register struct proc *p;
4442441Smckusick 	register struct args {
4537741Smckusick 		int	type;
4637741Smckusick 		char	*dir;
4737741Smckusick 		int	flags;
4837741Smckusick 		caddr_t	data;
4942441Smckusick 	} *uap;
5042441Smckusick 	int *retval;
5142441Smckusick {
5242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
5339335Smckusick 	register struct vnode *vp;
5439335Smckusick 	register struct mount *mp;
5540111Smckusick 	int error, flag;
566254Sroot 
5737741Smckusick 	/*
5837741Smckusick 	 * Must be super user
5937741Smckusick 	 */
6042441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
6137741Smckusick 		RETURN (error);
6237741Smckusick 	/*
6337741Smckusick 	 * Get vnode to be covered
6437741Smckusick 	 */
6537741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
6637741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
6737741Smckusick 	ndp->ni_dirp = uap->dir;
6837741Smckusick 	if (error = namei(ndp))
6937741Smckusick 		RETURN (error);
7037741Smckusick 	vp = ndp->ni_vp;
7141400Smckusick 	if (uap->flags & MNT_UPDATE) {
7239335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
7339335Smckusick 			vput(vp);
7439335Smckusick 			RETURN (EINVAL);
7539335Smckusick 		}
7639335Smckusick 		mp = vp->v_mount;
7739335Smckusick 		/*
7839335Smckusick 		 * We allow going from read-only to read-write,
7939335Smckusick 		 * but not from read-write to read-only.
8039335Smckusick 		 */
8141400Smckusick 		if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
8241400Smckusick 		    (uap->flags & MNT_RDONLY) != 0) {
8339335Smckusick 			vput(vp);
8439335Smckusick 			RETURN (EOPNOTSUPP);	/* Needs translation */
8539335Smckusick 		}
8641400Smckusick 		flag = mp->mnt_flag;
8741400Smckusick 		mp->mnt_flag |= MNT_UPDATE;
8839335Smckusick 		VOP_UNLOCK(vp);
8939335Smckusick 		goto update;
9039335Smckusick 	}
9139665Smckusick 	vinvalbuf(vp, 1);
9239805Smckusick 	if (vp->v_usecount != 1) {
9337741Smckusick 		vput(vp);
9437741Smckusick 		RETURN (EBUSY);
9537741Smckusick 	}
9637741Smckusick 	if (vp->v_type != VDIR) {
9737741Smckusick 		vput(vp);
9837741Smckusick 		RETURN (ENOTDIR);
9937741Smckusick 	}
10039741Smckusick 	if ((unsigned long)uap->type > MOUNT_MAXTYPE ||
10137741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
10237741Smckusick 		vput(vp);
10337741Smckusick 		RETURN (ENODEV);
10437741Smckusick 	}
10537741Smckusick 
10637741Smckusick 	/*
10739335Smckusick 	 * Allocate and initialize the file system.
10837741Smckusick 	 */
10937741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
11037741Smckusick 		M_MOUNT, M_WAITOK);
11141400Smckusick 	mp->mnt_op = vfssw[uap->type];
11241400Smckusick 	mp->mnt_flag = 0;
11341400Smckusick 	mp->mnt_exroot = 0;
11441400Smckusick 	mp->mnt_mounth = NULLVP;
11539335Smckusick 	if (error = vfs_lock(mp)) {
11639335Smckusick 		free((caddr_t)mp, M_MOUNT);
11739335Smckusick 		vput(vp);
11839335Smckusick 		RETURN (error);
11939335Smckusick 	}
12039335Smckusick 	if (vp->v_mountedhere != (struct mount *)0) {
12139335Smckusick 		vfs_unlock(mp);
12239335Smckusick 		free((caddr_t)mp, M_MOUNT);
12339335Smckusick 		vput(vp);
12439335Smckusick 		RETURN (EBUSY);
12539335Smckusick 	}
12639335Smckusick 	vp->v_mountedhere = mp;
12741400Smckusick 	mp->mnt_vnodecovered = vp;
12839335Smckusick update:
12939335Smckusick 	/*
13039335Smckusick 	 * Set the mount level flags.
13139335Smckusick 	 */
13241400Smckusick 	if (uap->flags & MNT_RDONLY)
13341400Smckusick 		mp->mnt_flag |= MNT_RDONLY;
13439335Smckusick 	else
13541400Smckusick 		mp->mnt_flag &= ~MNT_RDONLY;
13641400Smckusick 	if (uap->flags & MNT_NOSUID)
13741400Smckusick 		mp->mnt_flag |= MNT_NOSUID;
13839335Smckusick 	else
13941400Smckusick 		mp->mnt_flag &= ~MNT_NOSUID;
14041400Smckusick 	if (uap->flags & MNT_NOEXEC)
14141400Smckusick 		mp->mnt_flag |= MNT_NOEXEC;
14239335Smckusick 	else
14341400Smckusick 		mp->mnt_flag &= ~MNT_NOEXEC;
14441400Smckusick 	if (uap->flags & MNT_NODEV)
14541400Smckusick 		mp->mnt_flag |= MNT_NODEV;
14639335Smckusick 	else
14741400Smckusick 		mp->mnt_flag &= ~MNT_NODEV;
14841400Smckusick 	if (uap->flags & MNT_SYNCHRONOUS)
14941400Smckusick 		mp->mnt_flag |= MNT_SYNCHRONOUS;
15039335Smckusick 	else
15141400Smckusick 		mp->mnt_flag &= ~MNT_SYNCHRONOUS;
15239335Smckusick 	/*
15339335Smckusick 	 * Mount the filesystem.
15439335Smckusick 	 */
15539335Smckusick 	error = VFS_MOUNT(mp, uap->dir, uap->data, ndp);
15641400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
15741400Smckusick 		mp->mnt_flag &= ~MNT_UPDATE;
15839335Smckusick 		vrele(vp);
15940111Smckusick 		if (error)
16041400Smckusick 			mp->mnt_flag = flag;
16139335Smckusick 		RETURN (error);
16239335Smckusick 	}
16340110Smckusick 	/*
16440110Smckusick 	 * Put the new filesystem on the mount list after root.
16540110Smckusick 	 */
16641400Smckusick 	mp->mnt_next = rootfs->mnt_next;
16741400Smckusick 	mp->mnt_prev = rootfs;
16841400Smckusick 	rootfs->mnt_next = mp;
16941400Smckusick 	mp->mnt_next->mnt_prev = mp;
17037741Smckusick 	cache_purge(vp);
17137741Smckusick 	if (!error) {
17239335Smckusick 		VOP_UNLOCK(vp);
17337741Smckusick 		vfs_unlock(mp);
17439044Smckusick 		error = VFS_START(mp, 0);
17537741Smckusick 	} else {
17637741Smckusick 		vfs_remove(mp);
17737741Smckusick 		free((caddr_t)mp, M_MOUNT);
17839335Smckusick 		vput(vp);
17937741Smckusick 	}
18037741Smckusick 	RETURN (error);
1816254Sroot }
1826254Sroot 
1839167Ssam /*
18437741Smckusick  * Unmount system call.
18537741Smckusick  *
18637741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
18737741Smckusick  * not special file (as before).
1889167Ssam  */
18942441Smckusick /* ARGSUSED */
19042441Smckusick unmount(p, uap, retval)
19142441Smckusick 	register struct proc *p;
19242441Smckusick 	register struct args {
19337741Smckusick 		char	*pathp;
19437741Smckusick 		int	flags;
19542441Smckusick 	} *uap;
19642441Smckusick 	int *retval;
19742441Smckusick {
19837741Smckusick 	register struct vnode *vp;
19942441Smckusick 	register struct nameidata *ndp = &u.u_nd;
20039356Smckusick 	struct mount *mp;
20137741Smckusick 	int error;
2026254Sroot 
20337741Smckusick 	/*
20437741Smckusick 	 * Must be super user
20537741Smckusick 	 */
20642441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
20737741Smckusick 		RETURN (error);
20837741Smckusick 
20937741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
21037741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
21137741Smckusick 	ndp->ni_dirp = uap->pathp;
21237741Smckusick 	if (error = namei(ndp))
21337741Smckusick 		RETURN (error);
21437741Smckusick 	vp = ndp->ni_vp;
21537741Smckusick 	/*
21637741Smckusick 	 * Must be the root of the filesystem
21737741Smckusick 	 */
21837741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
21937741Smckusick 		vput(vp);
22037741Smckusick 		RETURN (EINVAL);
22137741Smckusick 	}
22237741Smckusick 	mp = vp->v_mount;
22337741Smckusick 	vput(vp);
22439356Smckusick 	RETURN (dounmount(mp, uap->flags));
22539356Smckusick }
22639356Smckusick 
22739356Smckusick /*
22839356Smckusick  * Do an unmount.
22939356Smckusick  */
23039356Smckusick dounmount(mp, flags)
23139356Smckusick 	register struct mount *mp;
23239356Smckusick 	int flags;
23339356Smckusick {
23439356Smckusick 	struct vnode *coveredvp;
23539356Smckusick 	int error;
23639356Smckusick 
23741400Smckusick 	coveredvp = mp->mnt_vnodecovered;
23841298Smckusick 	if (vfs_busy(mp))
23941298Smckusick 		return (EBUSY);
24041400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
24137741Smckusick 	if (error = vfs_lock(mp))
24239356Smckusick 		return (error);
24337741Smckusick 
24437741Smckusick 	xumount(mp);		/* remove unused sticky files from text table */
24537741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
24641676Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE))
24741676Smckusick 		error = VFS_UNMOUNT(mp, flags);
24841400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
24941298Smckusick 	vfs_unbusy(mp);
25037741Smckusick 	if (error) {
25137741Smckusick 		vfs_unlock(mp);
25237741Smckusick 	} else {
25337741Smckusick 		vrele(coveredvp);
25437741Smckusick 		vfs_remove(mp);
25537741Smckusick 		free((caddr_t)mp, M_MOUNT);
25637741Smckusick 	}
25739356Smckusick 	return (error);
2586254Sroot }
2596254Sroot 
2609167Ssam /*
26137741Smckusick  * Sync system call.
26237741Smckusick  * Sync each mounted filesystem.
2639167Ssam  */
26439491Smckusick /* ARGSUSED */
26542441Smckusick sync(p, uap, retval)
26642441Smckusick 	register struct proc *p;
26742441Smckusick 	struct args *uap;
26842441Smckusick 	int *retval;
2696254Sroot {
27037741Smckusick 	register struct mount *mp;
27141298Smckusick 	struct mount *omp;
27237741Smckusick 
27337741Smckusick 	mp = rootfs;
27437741Smckusick 	do {
27540343Smckusick 		/*
27640343Smckusick 		 * The lock check below is to avoid races with mount
27740343Smckusick 		 * and unmount.
27840343Smckusick 		 */
27941400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
28041298Smckusick 		    !vfs_busy(mp)) {
28137741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
28241298Smckusick 			omp = mp;
28341400Smckusick 			mp = mp->mnt_next;
28441298Smckusick 			vfs_unbusy(omp);
28541298Smckusick 		} else
28641400Smckusick 			mp = mp->mnt_next;
28737741Smckusick 	} while (mp != rootfs);
28837741Smckusick }
28937741Smckusick 
29037741Smckusick /*
29141298Smckusick  * operate on filesystem quotas
29241298Smckusick  */
29342441Smckusick /* ARGSUSED */
29442441Smckusick quotactl(p, uap, retval)
29542441Smckusick 	register struct proc *p;
29642441Smckusick 	register struct args {
29741298Smckusick 		char *path;
29841298Smckusick 		int cmd;
29941298Smckusick 		int uid;
30041298Smckusick 		caddr_t arg;
30142441Smckusick 	} *uap;
30242441Smckusick 	int *retval;
30342441Smckusick {
30441298Smckusick 	register struct mount *mp;
30542441Smckusick 	register struct nameidata *ndp = &u.u_nd;
30641298Smckusick 	int error;
30741298Smckusick 
30841298Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
30941298Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
31041298Smckusick 	ndp->ni_dirp = uap->path;
31141298Smckusick 	if (error = namei(ndp))
31241298Smckusick 		RETURN (error);
31341298Smckusick 	mp = ndp->ni_vp->v_mount;
31441298Smckusick 	vrele(ndp->ni_vp);
31541298Smckusick 	RETURN (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg));
31641298Smckusick }
31741298Smckusick 
31841298Smckusick /*
31937741Smckusick  * get filesystem statistics
32037741Smckusick  */
32142441Smckusick /* ARGSUSED */
32242441Smckusick statfs(p, uap, retval)
32342441Smckusick 	register struct proc *p;
32442441Smckusick 	register struct args {
32537741Smckusick 		char *path;
32637741Smckusick 		struct statfs *buf;
32742441Smckusick 	} *uap;
32842441Smckusick 	int *retval;
32942441Smckusick {
33039464Smckusick 	register struct mount *mp;
33142441Smckusick 	register struct nameidata *ndp = &u.u_nd;
33240343Smckusick 	register struct statfs *sp;
33337741Smckusick 	int error;
33437741Smckusick 
33539544Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
33637741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
33737741Smckusick 	ndp->ni_dirp = uap->path;
33837741Smckusick 	if (error = namei(ndp))
33937741Smckusick 		RETURN (error);
34039544Smckusick 	mp = ndp->ni_vp->v_mount;
34141400Smckusick 	sp = &mp->mnt_stat;
34239544Smckusick 	vrele(ndp->ni_vp);
34340343Smckusick 	if (error = VFS_STATFS(mp, sp))
34439544Smckusick 		RETURN (error);
34541400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
34640343Smckusick 	RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
34737741Smckusick }
34837741Smckusick 
34942441Smckusick /*
35042441Smckusick  * get filesystem statistics
35142441Smckusick  */
35242441Smckusick /* ARGSUSED */
35342441Smckusick fstatfs(p, uap, retval)
35442441Smckusick 	register struct proc *p;
35542441Smckusick 	register struct args {
35637741Smckusick 		int fd;
35737741Smckusick 		struct statfs *buf;
35842441Smckusick 	} *uap;
35942441Smckusick 	int *retval;
36042441Smckusick {
36137741Smckusick 	struct file *fp;
36239464Smckusick 	struct mount *mp;
36340343Smckusick 	register struct statfs *sp;
36437741Smckusick 	int error;
36537741Smckusick 
36642441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
36737741Smckusick 		RETURN (error);
36839464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
36941400Smckusick 	sp = &mp->mnt_stat;
37040343Smckusick 	if (error = VFS_STATFS(mp, sp))
37137741Smckusick 		RETURN (error);
37241400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
37340343Smckusick 	RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
37437741Smckusick }
37537741Smckusick 
37637741Smckusick /*
37738270Smckusick  * get statistics on all filesystems
37838270Smckusick  */
37942441Smckusick getfsstat(p, uap, retval)
38042441Smckusick 	register struct proc *p;
38142441Smckusick 	register struct args {
38238270Smckusick 		struct statfs *buf;
38338270Smckusick 		long bufsize;
38440343Smckusick 		int flags;
38542441Smckusick 	} *uap;
38642441Smckusick 	int *retval;
38742441Smckusick {
38838270Smckusick 	register struct mount *mp;
38940343Smckusick 	register struct statfs *sp;
39039606Smckusick 	caddr_t sfsp;
39138270Smckusick 	long count, maxcount, error;
39238270Smckusick 
39338270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
39439606Smckusick 	sfsp = (caddr_t)uap->buf;
39538270Smckusick 	mp = rootfs;
39638270Smckusick 	count = 0;
39738270Smckusick 	do {
39841400Smckusick 		if (sfsp && count < maxcount &&
39941400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
40041400Smckusick 			sp = &mp->mnt_stat;
40140343Smckusick 			/*
40240343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
40340343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
40440343Smckusick 			 */
40540343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
40640343Smckusick 			    (uap->flags & MNT_WAIT)) &&
40740343Smckusick 			    (error = VFS_STATFS(mp, sp))) {
40841400Smckusick 				mp = mp->mnt_prev;
40939607Smckusick 				continue;
41039607Smckusick 			}
41141400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
41240343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
41339606Smckusick 				RETURN (error);
41440343Smckusick 			sfsp += sizeof(*sp);
41538270Smckusick 		}
41639606Smckusick 		count++;
41741400Smckusick 		mp = mp->mnt_prev;
41838270Smckusick 	} while (mp != rootfs);
41938270Smckusick 	if (sfsp && count > maxcount)
42042441Smckusick 		*retval = maxcount;
42138270Smckusick 	else
42242441Smckusick 		*retval = count;
42338270Smckusick 	RETURN (0);
42438270Smckusick }
42538270Smckusick 
42638270Smckusick /*
42738259Smckusick  * Change current working directory to a given file descriptor.
42838259Smckusick  */
42942441Smckusick /* ARGSUSED */
43042441Smckusick fchdir(p, uap, retval)
43142441Smckusick 	register struct proc *p;
43242441Smckusick 	struct args {
43342441Smckusick 		int	fd;
43442441Smckusick 	} *uap;
43542441Smckusick 	int *retval;
43638259Smckusick {
43742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
43838259Smckusick 	register struct vnode *vp;
43938259Smckusick 	struct file *fp;
44038259Smckusick 	int error;
44138259Smckusick 
44242441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
44338259Smckusick 		RETURN (error);
44438259Smckusick 	vp = (struct vnode *)fp->f_data;
44538259Smckusick 	VOP_LOCK(vp);
44638259Smckusick 	if (vp->v_type != VDIR)
44738259Smckusick 		error = ENOTDIR;
44838259Smckusick 	else
44942441Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
45038259Smckusick 	VOP_UNLOCK(vp);
45139860Smckusick 	if (error)
45239860Smckusick 		RETURN (error);
45339860Smckusick 	VREF(vp);
45442441Smckusick 	vrele(ndp->ni_cdir);
45542441Smckusick 	ndp->ni_cdir = vp;
45639860Smckusick 	RETURN (0);
45738259Smckusick }
45838259Smckusick 
45938259Smckusick /*
46037741Smckusick  * Change current working directory (``.'').
46137741Smckusick  */
46242441Smckusick /* ARGSUSED */
46342441Smckusick chdir(p, uap, retval)
46442441Smckusick 	register struct proc *p;
46542441Smckusick 	struct args {
46642441Smckusick 		char	*fname;
46742441Smckusick 	} *uap;
46842441Smckusick 	int *retval;
46937741Smckusick {
47042441Smckusick 	register struct nameidata *ndp = &u.u_nd;
47137741Smckusick 	int error;
4726254Sroot 
47337741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
47416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
47516694Smckusick 	ndp->ni_dirp = uap->fname;
47637741Smckusick 	if (error = chdirec(ndp))
47737741Smckusick 		RETURN (error);
47842441Smckusick 	vrele(ndp->ni_cdir);
47942441Smckusick 	ndp->ni_cdir = ndp->ni_vp;
48037741Smckusick 	RETURN (0);
48137741Smckusick }
4826254Sroot 
48337741Smckusick /*
48437741Smckusick  * Change notion of root (``/'') directory.
48537741Smckusick  */
48642441Smckusick /* ARGSUSED */
48742441Smckusick chroot(p, uap, retval)
48842441Smckusick 	register struct proc *p;
48942441Smckusick 	struct args {
49042441Smckusick 		char	*fname;
49142441Smckusick 	} *uap;
49242441Smckusick 	int *retval;
49337741Smckusick {
49442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
49537741Smckusick 	int error;
49637741Smckusick 
49742441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
49837741Smckusick 		RETURN (error);
49937741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
50037741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
50137741Smckusick 	ndp->ni_dirp = uap->fname;
50237741Smckusick 	if (error = chdirec(ndp))
50337741Smckusick 		RETURN (error);
50442441Smckusick 	if (ndp->ni_rdir != NULL)
50542441Smckusick 		vrele(ndp->ni_rdir);
50642441Smckusick 	ndp->ni_rdir = ndp->ni_vp;
50737741Smckusick 	RETURN (0);
5086254Sroot }
5096254Sroot 
51037Sbill /*
51137741Smckusick  * Common routine for chroot and chdir.
51237741Smckusick  */
51337741Smckusick chdirec(ndp)
51437741Smckusick 	register struct nameidata *ndp;
51537741Smckusick {
51637741Smckusick 	struct vnode *vp;
51737741Smckusick 	int error;
51837741Smckusick 
51937741Smckusick 	if (error = namei(ndp))
52037741Smckusick 		return (error);
52137741Smckusick 	vp = ndp->ni_vp;
52237741Smckusick 	if (vp->v_type != VDIR)
52337741Smckusick 		error = ENOTDIR;
52437741Smckusick 	else
52538399Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
52637741Smckusick 	VOP_UNLOCK(vp);
52737741Smckusick 	if (error)
52837741Smckusick 		vrele(vp);
52937741Smckusick 	return (error);
53037741Smckusick }
53137741Smckusick 
53237741Smckusick /*
5336254Sroot  * Open system call.
53442441Smckusick  * Check permissions, allocate an open file structure,
53542441Smckusick  * and call the device open routine if any.
5366254Sroot  */
53742441Smckusick open(p, uap, retval)
53842441Smckusick 	register struct proc *p;
53942441Smckusick 	register struct args {
5406254Sroot 		char	*fname;
5417701Ssam 		int	mode;
54212756Ssam 		int	crtmode;
54342441Smckusick 	} *uap;
54442441Smckusick 	int *retval;
5456254Sroot {
54642441Smckusick 	struct nameidata *ndp = &u.u_nd;
54742441Smckusick 	register struct file *fp;
54837741Smckusick 	int fmode, cmode;
54937741Smckusick 	struct file *nfp;
55037741Smckusick 	int indx, error;
55137741Smckusick 	extern struct fileops vnops;
5526254Sroot 
55337741Smckusick 	if (error = falloc(&nfp, &indx))
55442441Smckusick 		RETURN (error);
55537741Smckusick 	fp = nfp;
55642441Smckusick 	fmode = uap->mode - FOPEN;
55742441Smckusick 	cmode = ((uap->crtmode &~ u.u_cmask) & 07777) &~ S_ISVTX;
55842441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
55942441Smckusick 	ndp->ni_dirp = uap->fname;
56043450Smckusick 	p->p_dupfd = -1;			/* XXX check for fdopen */
56142441Smckusick 	if (error = vn_open(ndp, fmode, cmode)) {
56237741Smckusick 		crfree(fp->f_cred);
56337741Smckusick 		fp->f_count--;
56443405Smckusick 		if (error == ENODEV &&		/* XXX from fdopen */
56543450Smckusick 		    p->p_dupfd >= 0 &&
56643450Smckusick 		    (error = dupfdopen(indx, p->p_dupfd, fmode)) == 0) {
56742441Smckusick 			*retval = indx;
56842441Smckusick 			RETURN (0);
56942441Smckusick 		}
57040884Smckusick 		if (error == ERESTART)
57140884Smckusick 			error = EINTR;
57242441Smckusick 		u.u_ofile[indx] = NULL;
57342441Smckusick 		RETURN (error);
57412756Ssam 	}
57537741Smckusick 	fp->f_flag = fmode & FMASK;
57637741Smckusick 	fp->f_type = DTYPE_VNODE;
57737741Smckusick 	fp->f_ops = &vnops;
57837741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
57942441Smckusick 	*retval = indx;
58042441Smckusick 	RETURN (0);
5816254Sroot }
5826254Sroot 
58342955Smckusick #ifdef COMPAT_43
5846254Sroot /*
58542441Smckusick  * Creat system call.
5866254Sroot  */
58742955Smckusick ocreat(p, uap, retval)
58842441Smckusick 	struct proc *p;
58942441Smckusick 	register struct args {
59042441Smckusick 		char	*fname;
59142441Smckusick 		int	fmode;
59242441Smckusick 	} *uap;
59342441Smckusick 	int *retval;
5946254Sroot {
59542441Smckusick 	struct args {
5966254Sroot 		char	*fname;
59742441Smckusick 		int	mode;
59842441Smckusick 		int	crtmode;
59942441Smckusick 	} openuap;
60042441Smckusick 
60142441Smckusick 	openuap.fname = uap->fname;
60242441Smckusick 	openuap.crtmode = uap->fmode;
60342441Smckusick 	openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
60442441Smckusick 	RETURN (open(p, &openuap, retval));
60542441Smckusick }
60642955Smckusick #endif /* COMPAT_43 */
60742441Smckusick 
60842441Smckusick /*
60942441Smckusick  * Mknod system call
61042441Smckusick  */
61142441Smckusick /* ARGSUSED */
61242441Smckusick mknod(p, uap, retval)
61342441Smckusick 	register struct proc *p;
61442441Smckusick 	register struct args {
61542441Smckusick 		char	*fname;
6166254Sroot 		int	fmode;
6176254Sroot 		int	dev;
61842441Smckusick 	} *uap;
61942441Smckusick 	int *retval;
62042441Smckusick {
62142441Smckusick 	register struct nameidata *ndp = &u.u_nd;
62237741Smckusick 	register struct vnode *vp;
62337741Smckusick 	struct vattr vattr;
62437741Smckusick 	int error;
6256254Sroot 
62642441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
62737741Smckusick 		RETURN (error);
62837741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
62916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
63016694Smckusick 	ndp->ni_dirp = uap->fname;
63137741Smckusick 	if (error = namei(ndp))
63237741Smckusick 		RETURN (error);
63337741Smckusick 	vp = ndp->ni_vp;
63437741Smckusick 	if (vp != NULL) {
63537741Smckusick 		error = EEXIST;
63612756Ssam 		goto out;
6376254Sroot 	}
63841362Smckusick 	VATTR_NULL(&vattr);
63940635Smckusick 	switch (uap->fmode & S_IFMT) {
64012756Ssam 
64140635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
64237741Smckusick 		vattr.va_type = VBAD;
64337741Smckusick 		break;
64440635Smckusick 	case S_IFCHR:
64537741Smckusick 		vattr.va_type = VCHR;
64637741Smckusick 		break;
64740635Smckusick 	case S_IFBLK:
64837741Smckusick 		vattr.va_type = VBLK;
64937741Smckusick 		break;
65037741Smckusick 	default:
65137741Smckusick 		error = EINVAL;
65237741Smckusick 		goto out;
6536254Sroot 	}
65442441Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask;
65537741Smckusick 	vattr.va_rdev = uap->dev;
6566254Sroot out:
65742465Smckusick 	if (!error) {
65842465Smckusick 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
65942465Smckusick 	} else {
66037741Smckusick 		VOP_ABORTOP(ndp);
66143344Smckusick 		if (ndp->ni_dvp == vp)
66243344Smckusick 			vrele(ndp->ni_dvp);
66343344Smckusick 		else
66443344Smckusick 			vput(ndp->ni_dvp);
66542465Smckusick 		if (vp)
66642465Smckusick 			vrele(vp);
66742465Smckusick 	}
66837741Smckusick 	RETURN (error);
6696254Sroot }
6706254Sroot 
6716254Sroot /*
67240285Smckusick  * Mkfifo system call
67340285Smckusick  */
67442441Smckusick /* ARGSUSED */
67542441Smckusick mkfifo(p, uap, retval)
67642441Smckusick 	register struct proc *p;
67742441Smckusick 	register struct args {
67840285Smckusick 		char	*fname;
67940285Smckusick 		int	fmode;
68042441Smckusick 	} *uap;
68142441Smckusick 	int *retval;
68242441Smckusick {
68342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
68440285Smckusick 	struct vattr vattr;
68540285Smckusick 	int error;
68640285Smckusick 
68740285Smckusick #ifndef FIFO
68840285Smckusick 	RETURN (EOPNOTSUPP);
68940285Smckusick #else
69040285Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
69140285Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
69240285Smckusick 	ndp->ni_dirp = uap->fname;
69340285Smckusick 	if (error = namei(ndp))
69440285Smckusick 		RETURN (error);
69540285Smckusick 	if (ndp->ni_vp != NULL) {
69640285Smckusick 		VOP_ABORTOP(ndp);
69743344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
69843344Smckusick 			vrele(ndp->ni_dvp);
69943344Smckusick 		else
70043344Smckusick 			vput(ndp->ni_dvp);
70142465Smckusick 		vrele(ndp->ni_vp);
70240285Smckusick 		RETURN (EEXIST);
70340285Smckusick 	} else {
70441362Smckusick 		VATTR_NULL(&vattr);
70540285Smckusick 		vattr.va_type = VFIFO;
70642441Smckusick 		vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask;
70740285Smckusick 	}
70840285Smckusick 	RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred));
70940285Smckusick #endif /* FIFO */
71040285Smckusick }
71140285Smckusick 
71240285Smckusick /*
7136254Sroot  * link system call
7146254Sroot  */
71542441Smckusick /* ARGSUSED */
71642441Smckusick link(p, uap, retval)
71742441Smckusick 	register struct proc *p;
71842441Smckusick 	register struct args {
7196254Sroot 		char	*target;
7206254Sroot 		char	*linkname;
72142441Smckusick 	} *uap;
72242441Smckusick 	int *retval;
72342441Smckusick {
72442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
72537741Smckusick 	register struct vnode *vp, *xp;
72637741Smckusick 	int error;
7276254Sroot 
72816694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
72916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
73016694Smckusick 	ndp->ni_dirp = uap->target;
73137741Smckusick 	if (error = namei(ndp))
73237741Smckusick 		RETURN (error);
73337741Smckusick 	vp = ndp->ni_vp;
73437741Smckusick 	if (vp->v_type == VDIR &&
73542441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
73637741Smckusick 		goto out1;
73737741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
73816694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
73937741Smckusick 	if (error = namei(ndp))
74037741Smckusick 		goto out1;
74137741Smckusick 	xp = ndp->ni_vp;
7426254Sroot 	if (xp != NULL) {
74337741Smckusick 		error = EEXIST;
7446254Sroot 		goto out;
7456254Sroot 	}
74637741Smckusick 	xp = ndp->ni_dvp;
74737741Smckusick 	if (vp->v_mount != xp->v_mount)
74837741Smckusick 		error = EXDEV;
7496254Sroot out:
75042465Smckusick 	if (!error) {
75142465Smckusick 		error = VOP_LINK(vp, ndp);
75242465Smckusick 	} else {
75337741Smckusick 		VOP_ABORTOP(ndp);
75443344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
75543344Smckusick 			vrele(ndp->ni_dvp);
75643344Smckusick 		else
75743344Smckusick 			vput(ndp->ni_dvp);
75842465Smckusick 		if (ndp->ni_vp)
75942465Smckusick 			vrele(ndp->ni_vp);
76042465Smckusick 	}
76137741Smckusick out1:
76237741Smckusick 	vrele(vp);
76337741Smckusick 	RETURN (error);
7646254Sroot }
7656254Sroot 
7666254Sroot /*
7676254Sroot  * symlink -- make a symbolic link
7686254Sroot  */
76942441Smckusick /* ARGSUSED */
77042441Smckusick symlink(p, uap, retval)
77142441Smckusick 	register struct proc *p;
77242441Smckusick 	register struct args {
7736254Sroot 		char	*target;
7746254Sroot 		char	*linkname;
77542441Smckusick 	} *uap;
77642441Smckusick 	int *retval;
77742441Smckusick {
77842441Smckusick 	register struct nameidata *ndp = &u.u_nd;
77937741Smckusick 	struct vattr vattr;
78037741Smckusick 	char *target;
78137741Smckusick 	int error;
7826254Sroot 
78316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
78416694Smckusick 	ndp->ni_dirp = uap->linkname;
78537741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
78637741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
78742465Smckusick 		goto out;
78837741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
78937741Smckusick 	if (error = namei(ndp))
79042465Smckusick 		goto out;
79142465Smckusick 	if (ndp->ni_vp) {
79242465Smckusick 		VOP_ABORTOP(ndp);
79343344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
79443344Smckusick 			vrele(ndp->ni_dvp);
79543344Smckusick 		else
79643344Smckusick 			vput(ndp->ni_dvp);
79742465Smckusick 		vrele(ndp->ni_vp);
79837741Smckusick 		error = EEXIST;
79937741Smckusick 		goto out;
8006254Sroot 	}
80141362Smckusick 	VATTR_NULL(&vattr);
80242441Smckusick 	vattr.va_mode = 0777 &~ u.u_cmask;
80342465Smckusick 	error = VOP_SYMLINK(ndp, &vattr, target);
80437741Smckusick out:
80537741Smckusick 	FREE(target, M_NAMEI);
80637741Smckusick 	RETURN (error);
8076254Sroot }
8086254Sroot 
8096254Sroot /*
8106254Sroot  * Unlink system call.
8116254Sroot  * Hard to avoid races here, especially
8126254Sroot  * in unlinking directories.
8136254Sroot  */
81442441Smckusick /* ARGSUSED */
81542441Smckusick unlink(p, uap, retval)
81642441Smckusick 	register struct proc *p;
81742441Smckusick 	struct args {
81842441Smckusick 		char	*fname;
81942441Smckusick 	} *uap;
82042441Smckusick 	int *retval;
8216254Sroot {
82242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
82337741Smckusick 	register struct vnode *vp;
82437741Smckusick 	int error;
8256254Sroot 
82637741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
82716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
82816694Smckusick 	ndp->ni_dirp = uap->fname;
82937741Smckusick 	if (error = namei(ndp))
83037741Smckusick 		RETURN (error);
83137741Smckusick 	vp = ndp->ni_vp;
83237741Smckusick 	if (vp->v_type == VDIR &&
83342441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
8346254Sroot 		goto out;
8356254Sroot 	/*
8366254Sroot 	 * Don't unlink a mounted file.
8376254Sroot 	 */
83837741Smckusick 	if (vp->v_flag & VROOT) {
83937741Smckusick 		error = EBUSY;
8406254Sroot 		goto out;
8416254Sroot 	}
84237741Smckusick 	if (vp->v_flag & VTEXT)
84337741Smckusick 		xrele(vp);	/* try once to free text */
8446254Sroot out:
84542465Smckusick 	if (!error) {
84642465Smckusick 		error = VOP_REMOVE(ndp);
84742465Smckusick 	} else {
84837741Smckusick 		VOP_ABORTOP(ndp);
84943344Smckusick 		if (ndp->ni_dvp == vp)
85043344Smckusick 			vrele(ndp->ni_dvp);
85143344Smckusick 		else
85243344Smckusick 			vput(ndp->ni_dvp);
85342465Smckusick 		vput(vp);
85442465Smckusick 	}
85537741Smckusick 	RETURN (error);
8566254Sroot }
8576254Sroot 
8586254Sroot /*
8596254Sroot  * Seek system call
8606254Sroot  */
86142441Smckusick lseek(p, uap, retval)
86242441Smckusick 	register struct proc *p;
86342441Smckusick 	register struct args {
86437741Smckusick 		int	fdes;
8656254Sroot 		off_t	off;
8666254Sroot 		int	sbase;
86742441Smckusick 	} *uap;
86842441Smckusick 	off_t *retval;
86942441Smckusick {
87042441Smckusick 	struct ucred *cred = u.u_nd.ni_cred;
87142441Smckusick 	register struct file *fp;
87237741Smckusick 	struct vattr vattr;
87337741Smckusick 	int error;
8746254Sroot 
87537741Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
87642441Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
87737741Smckusick 		RETURN (EBADF);
87837741Smckusick 	if (fp->f_type != DTYPE_VNODE)
87937741Smckusick 		RETURN (ESPIPE);
88013878Ssam 	switch (uap->sbase) {
88113878Ssam 
88213878Ssam 	case L_INCR:
88313878Ssam 		fp->f_offset += uap->off;
88413878Ssam 		break;
88513878Ssam 
88613878Ssam 	case L_XTND:
88737741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
88842441Smckusick 		    &vattr, cred))
88937741Smckusick 			RETURN (error);
89037741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
89113878Ssam 		break;
89213878Ssam 
89313878Ssam 	case L_SET:
89413878Ssam 		fp->f_offset = uap->off;
89513878Ssam 		break;
89613878Ssam 
89713878Ssam 	default:
89837741Smckusick 		RETURN (EINVAL);
89913878Ssam 	}
90042441Smckusick 	*retval = fp->f_offset;
90137741Smckusick 	RETURN (0);
9026254Sroot }
9036254Sroot 
9046254Sroot /*
9056254Sroot  * Access system call
9066254Sroot  */
90742441Smckusick /* ARGSUSED */
90842441Smckusick saccess(p, uap, retval)
90942441Smckusick 	register struct proc *p;
91042441Smckusick 	register struct args {
9116254Sroot 		char	*fname;
9126254Sroot 		int	fmode;
91342441Smckusick 	} *uap;
91442441Smckusick 	int *retval;
91542441Smckusick {
91642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
91742441Smckusick 	register struct ucred *cred = ndp->ni_cred;
91837741Smckusick 	register struct vnode *vp;
91937741Smckusick 	int error, mode, svuid, svgid;
9206254Sroot 
92142441Smckusick 	svuid = cred->cr_uid;
92242441Smckusick 	svgid = cred->cr_groups[0];
92342441Smckusick 	cred->cr_uid = p->p_ruid;
92442441Smckusick 	cred->cr_groups[0] = p->p_rgid;
92537741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
92616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
92716694Smckusick 	ndp->ni_dirp = uap->fname;
92837741Smckusick 	if (error = namei(ndp))
92937741Smckusick 		goto out1;
93037741Smckusick 	vp = ndp->ni_vp;
93137741Smckusick 	/*
93237741Smckusick 	 * fmode == 0 means only check for exist
93337741Smckusick 	 */
93437741Smckusick 	if (uap->fmode) {
93537741Smckusick 		mode = 0;
93637741Smckusick 		if (uap->fmode & R_OK)
93737741Smckusick 			mode |= VREAD;
93837741Smckusick 		if (uap->fmode & W_OK)
93937741Smckusick 			mode |= VWRITE;
94037741Smckusick 		if (uap->fmode & X_OK)
94137741Smckusick 			mode |= VEXEC;
94239543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
94338399Smckusick 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
9446254Sroot 	}
94537741Smckusick 	vput(vp);
94637741Smckusick out1:
94742441Smckusick 	cred->cr_uid = svuid;
94842441Smckusick 	cred->cr_groups[0] = svgid;
94937741Smckusick 	RETURN (error);
9506254Sroot }
9516254Sroot 
9526254Sroot /*
9536574Smckusic  * Stat system call.  This version follows links.
95437Sbill  */
95542441Smckusick /* ARGSUSED */
95642441Smckusick stat(p, uap, retval)
95742441Smckusick 	register struct proc *p;
95842441Smckusick 	register struct args {
95942441Smckusick 		char	*fname;
96042441Smckusick 		struct stat *ub;
96142441Smckusick 	} *uap;
96242441Smckusick 	int *retval;
96337Sbill {
96442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
96542441Smckusick 	struct stat sb;
96642441Smckusick 	int error;
96737Sbill 
96842441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
96942441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
97042441Smckusick 	ndp->ni_dirp = uap->fname;
97142441Smckusick 	if (error = namei(ndp))
97242441Smckusick 		RETURN (error);
97342441Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
97442441Smckusick 	vput(ndp->ni_vp);
97542441Smckusick 	if (error)
97642441Smckusick 		RETURN (error);
97742441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
97842441Smckusick 	RETURN (error);
97937Sbill }
98037Sbill 
98137Sbill /*
9826574Smckusic  * Lstat system call.  This version does not follow links.
9835992Swnj  */
98442441Smckusick /* ARGSUSED */
98542441Smckusick lstat(p, uap, retval)
98642441Smckusick 	register struct proc *p;
98742441Smckusick 	register struct args {
9885992Swnj 		char	*fname;
98912756Ssam 		struct stat *ub;
99042441Smckusick 	} *uap;
99142441Smckusick 	int *retval;
99242441Smckusick {
99342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
99412756Ssam 	struct stat sb;
99537741Smckusick 	int error;
9965992Swnj 
99742441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW;
99816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
99916694Smckusick 	ndp->ni_dirp = uap->fname;
100037741Smckusick 	if (error = namei(ndp))
100137741Smckusick 		RETURN (error);
100237741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
100337741Smckusick 	vput(ndp->ni_vp);
100437741Smckusick 	if (error)
100537741Smckusick 		RETURN (error);
100637741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
100737741Smckusick 	RETURN (error);
10085992Swnj }
10095992Swnj 
10105992Swnj /*
10115992Swnj  * Return target name of a symbolic link
101237Sbill  */
101342441Smckusick /* ARGSUSED */
101442441Smckusick readlink(p, uap, retval)
101542441Smckusick 	register struct proc *p;
101642441Smckusick 	register struct args {
10175992Swnj 		char	*name;
10185992Swnj 		char	*buf;
10195992Swnj 		int	count;
102042441Smckusick 	} *uap;
102142441Smckusick 	int *retval;
102242441Smckusick {
102342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
102437741Smckusick 	register struct vnode *vp;
102537741Smckusick 	struct iovec aiov;
102637741Smckusick 	struct uio auio;
102737741Smckusick 	int error;
10285992Swnj 
102937741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
103016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
103116694Smckusick 	ndp->ni_dirp = uap->name;
103237741Smckusick 	if (error = namei(ndp))
103337741Smckusick 		RETURN (error);
103437741Smckusick 	vp = ndp->ni_vp;
103537741Smckusick 	if (vp->v_type != VLNK) {
103637741Smckusick 		error = EINVAL;
10375992Swnj 		goto out;
10385992Swnj 	}
103937741Smckusick 	aiov.iov_base = uap->buf;
104037741Smckusick 	aiov.iov_len = uap->count;
104137741Smckusick 	auio.uio_iov = &aiov;
104237741Smckusick 	auio.uio_iovcnt = 1;
104337741Smckusick 	auio.uio_offset = 0;
104437741Smckusick 	auio.uio_rw = UIO_READ;
104537741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
104637741Smckusick 	auio.uio_resid = uap->count;
104737741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
10485992Swnj out:
104937741Smckusick 	vput(vp);
105042441Smckusick 	*retval = uap->count - auio.uio_resid;
105137741Smckusick 	RETURN (error);
10525992Swnj }
10535992Swnj 
10549167Ssam /*
105538259Smckusick  * Change flags of a file given path name.
105638259Smckusick  */
105742441Smckusick /* ARGSUSED */
105842441Smckusick chflags(p, uap, retval)
105942441Smckusick 	register struct proc *p;
106042441Smckusick 	register struct args {
106138259Smckusick 		char	*fname;
106238259Smckusick 		int	flags;
106342441Smckusick 	} *uap;
106442441Smckusick 	int *retval;
106542441Smckusick {
106642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
106738259Smckusick 	register struct vnode *vp;
106838259Smckusick 	struct vattr vattr;
106938259Smckusick 	int error;
107038259Smckusick 
107138259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
107238259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
107338259Smckusick 	ndp->ni_dirp = uap->fname;
107441362Smckusick 	VATTR_NULL(&vattr);
107538259Smckusick 	vattr.va_flags = uap->flags;
107638259Smckusick 	if (error = namei(ndp))
107738259Smckusick 		RETURN (error);
107838259Smckusick 	vp = ndp->ni_vp;
107941400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
108038259Smckusick 		error = EROFS;
108138259Smckusick 		goto out;
108238259Smckusick 	}
108338259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
108438259Smckusick out:
108538259Smckusick 	vput(vp);
108638259Smckusick 	RETURN (error);
108738259Smckusick }
108838259Smckusick 
108938259Smckusick /*
109038259Smckusick  * Change flags of a file given a file descriptor.
109138259Smckusick  */
109242441Smckusick /* ARGSUSED */
109342441Smckusick fchflags(p, uap, retval)
109442441Smckusick 	register struct proc *p;
109542441Smckusick 	register struct args {
109638259Smckusick 		int	fd;
109738259Smckusick 		int	flags;
109842441Smckusick 	} *uap;
109942441Smckusick 	int *retval;
110042441Smckusick {
110138259Smckusick 	struct vattr vattr;
110238259Smckusick 	struct vnode *vp;
110338259Smckusick 	struct file *fp;
110438259Smckusick 	int error;
110538259Smckusick 
110642441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
110738259Smckusick 		RETURN (error);
110841362Smckusick 	VATTR_NULL(&vattr);
110938259Smckusick 	vattr.va_flags = uap->flags;
111038259Smckusick 	vp = (struct vnode *)fp->f_data;
111138259Smckusick 	VOP_LOCK(vp);
111241400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
111338259Smckusick 		error = EROFS;
111438259Smckusick 		goto out;
111538259Smckusick 	}
111638259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
111738259Smckusick out:
111838259Smckusick 	VOP_UNLOCK(vp);
111938259Smckusick 	RETURN (error);
112038259Smckusick }
112138259Smckusick 
112238259Smckusick /*
11239167Ssam  * Change mode of a file given path name.
11249167Ssam  */
112542441Smckusick /* ARGSUSED */
112642441Smckusick chmod(p, uap, retval)
112742441Smckusick 	register struct proc *p;
112842441Smckusick 	register struct args {
11296254Sroot 		char	*fname;
11306254Sroot 		int	fmode;
113142441Smckusick 	} *uap;
113242441Smckusick 	int *retval;
113342441Smckusick {
113442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
113537741Smckusick 	register struct vnode *vp;
113637741Smckusick 	struct vattr vattr;
113737741Smckusick 	int error;
11385992Swnj 
113937741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
114037741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
114137741Smckusick 	ndp->ni_dirp = uap->fname;
114241362Smckusick 	VATTR_NULL(&vattr);
114337741Smckusick 	vattr.va_mode = uap->fmode & 07777;
114437741Smckusick 	if (error = namei(ndp))
114537741Smckusick 		RETURN (error);
114637741Smckusick 	vp = ndp->ni_vp;
114741400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
114837741Smckusick 		error = EROFS;
114937741Smckusick 		goto out;
115037741Smckusick 	}
115137741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
115237741Smckusick out:
115337741Smckusick 	vput(vp);
115437741Smckusick 	RETURN (error);
11557701Ssam }
11567439Sroot 
11579167Ssam /*
11589167Ssam  * Change mode of a file given a file descriptor.
11599167Ssam  */
116042441Smckusick /* ARGSUSED */
116142441Smckusick fchmod(p, uap, retval)
116242441Smckusick 	register struct proc *p;
116342441Smckusick 	register struct args {
11647701Ssam 		int	fd;
11657701Ssam 		int	fmode;
116642441Smckusick 	} *uap;
116742441Smckusick 	int *retval;
116842441Smckusick {
116937741Smckusick 	struct vattr vattr;
117037741Smckusick 	struct vnode *vp;
117137741Smckusick 	struct file *fp;
117237741Smckusick 	int error;
11737701Ssam 
117442441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
117537741Smckusick 		RETURN (error);
117641362Smckusick 	VATTR_NULL(&vattr);
117737741Smckusick 	vattr.va_mode = uap->fmode & 07777;
117837741Smckusick 	vp = (struct vnode *)fp->f_data;
117937741Smckusick 	VOP_LOCK(vp);
118041400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
118137741Smckusick 		error = EROFS;
118237741Smckusick 		goto out;
11837439Sroot 	}
118437741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
118537741Smckusick out:
118637741Smckusick 	VOP_UNLOCK(vp);
118737741Smckusick 	RETURN (error);
11885992Swnj }
11895992Swnj 
11909167Ssam /*
11919167Ssam  * Set ownership given a path name.
11929167Ssam  */
119342441Smckusick /* ARGSUSED */
119442441Smckusick chown(p, uap, retval)
119542441Smckusick 	register struct proc *p;
119642441Smckusick 	register struct args {
11976254Sroot 		char	*fname;
11986254Sroot 		int	uid;
11996254Sroot 		int	gid;
120042441Smckusick 	} *uap;
120142441Smckusick 	int *retval;
120242441Smckusick {
120342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
120437741Smckusick 	register struct vnode *vp;
120537741Smckusick 	struct vattr vattr;
120637741Smckusick 	int error;
120737Sbill 
120837741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
120936614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
121036614Sbostic 	ndp->ni_dirp = uap->fname;
121141362Smckusick 	VATTR_NULL(&vattr);
121237741Smckusick 	vattr.va_uid = uap->uid;
121337741Smckusick 	vattr.va_gid = uap->gid;
121437741Smckusick 	if (error = namei(ndp))
121537741Smckusick 		RETURN (error);
121637741Smckusick 	vp = ndp->ni_vp;
121741400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
121837741Smckusick 		error = EROFS;
121937741Smckusick 		goto out;
122037741Smckusick 	}
122137741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
122237741Smckusick out:
122337741Smckusick 	vput(vp);
122437741Smckusick 	RETURN (error);
12257701Ssam }
12267439Sroot 
12279167Ssam /*
12289167Ssam  * Set ownership given a file descriptor.
12299167Ssam  */
123042441Smckusick /* ARGSUSED */
123142441Smckusick fchown(p, uap, retval)
123242441Smckusick 	register struct proc *p;
123342441Smckusick 	register struct args {
12347701Ssam 		int	fd;
12357701Ssam 		int	uid;
12367701Ssam 		int	gid;
123742441Smckusick 	} *uap;
123842441Smckusick 	int *retval;
123942441Smckusick {
124037741Smckusick 	struct vattr vattr;
124137741Smckusick 	struct vnode *vp;
124237741Smckusick 	struct file *fp;
124337741Smckusick 	int error;
12447701Ssam 
124542441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
124637741Smckusick 		RETURN (error);
124741362Smckusick 	VATTR_NULL(&vattr);
124837741Smckusick 	vattr.va_uid = uap->uid;
124937741Smckusick 	vattr.va_gid = uap->gid;
125037741Smckusick 	vp = (struct vnode *)fp->f_data;
125137741Smckusick 	VOP_LOCK(vp);
125241400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
125337741Smckusick 		error = EROFS;
125437741Smckusick 		goto out;
125537741Smckusick 	}
125637741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
125737741Smckusick out:
125837741Smckusick 	VOP_UNLOCK(vp);
125937741Smckusick 	RETURN (error);
12607701Ssam }
12617701Ssam 
126242441Smckusick /*
126342441Smckusick  * Set the access and modification times of a file.
126442441Smckusick  */
126542441Smckusick /* ARGSUSED */
126642441Smckusick utimes(p, uap, retval)
126742441Smckusick 	register struct proc *p;
126842441Smckusick 	register struct args {
126911811Ssam 		char	*fname;
127011811Ssam 		struct	timeval *tptr;
127142441Smckusick 	} *uap;
127242441Smckusick 	int *retval;
127342441Smckusick {
127442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
127537741Smckusick 	register struct vnode *vp;
127611811Ssam 	struct timeval tv[2];
127737741Smckusick 	struct vattr vattr;
127837741Smckusick 	int error;
127911811Ssam 
128037741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
128137741Smckusick 		RETURN (error);
128237741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
128337741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
128437741Smckusick 	ndp->ni_dirp = uap->fname;
128541362Smckusick 	VATTR_NULL(&vattr);
128637741Smckusick 	vattr.va_atime = tv[0];
128737741Smckusick 	vattr.va_mtime = tv[1];
128837741Smckusick 	if (error = namei(ndp))
128937741Smckusick 		RETURN (error);
129037741Smckusick 	vp = ndp->ni_vp;
129141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
129237741Smckusick 		error = EROFS;
129337741Smckusick 		goto out;
129421015Smckusick 	}
129537741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
129637741Smckusick out:
129737741Smckusick 	vput(vp);
129837741Smckusick 	RETURN (error);
129911811Ssam }
130011811Ssam 
13019167Ssam /*
13029167Ssam  * Truncate a file given its path name.
13039167Ssam  */
130442441Smckusick /* ARGSUSED */
130542441Smckusick truncate(p, uap, retval)
130642441Smckusick 	register struct proc *p;
130742441Smckusick 	register struct args {
13087701Ssam 		char	*fname;
130926473Skarels 		off_t	length;
131042441Smckusick 	} *uap;
131142441Smckusick 	int *retval;
131242441Smckusick {
131342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
131437741Smckusick 	register struct vnode *vp;
131537741Smckusick 	struct vattr vattr;
131637741Smckusick 	int error;
13177701Ssam 
131837741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
131916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
132016694Smckusick 	ndp->ni_dirp = uap->fname;
132141362Smckusick 	VATTR_NULL(&vattr);
132237741Smckusick 	vattr.va_size = uap->length;
132337741Smckusick 	if (error = namei(ndp))
132437741Smckusick 		RETURN (error);
132537741Smckusick 	vp = ndp->ni_vp;
132637741Smckusick 	if (vp->v_type == VDIR) {
132737741Smckusick 		error = EISDIR;
132837741Smckusick 		goto out;
13297701Ssam 	}
133038399Smckusick 	if ((error = vn_writechk(vp)) ||
133138399Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
133237741Smckusick 		goto out;
133337741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
133437741Smckusick out:
133537741Smckusick 	vput(vp);
133637741Smckusick 	RETURN (error);
13377701Ssam }
13387701Ssam 
13399167Ssam /*
13409167Ssam  * Truncate a file given a file descriptor.
13419167Ssam  */
134242441Smckusick /* ARGSUSED */
134342441Smckusick ftruncate(p, uap, retval)
134442441Smckusick 	register struct proc *p;
134542441Smckusick 	register struct args {
13467701Ssam 		int	fd;
134726473Skarels 		off_t	length;
134842441Smckusick 	} *uap;
134942441Smckusick 	int *retval;
135042441Smckusick {
135137741Smckusick 	struct vattr vattr;
135237741Smckusick 	struct vnode *vp;
13537701Ssam 	struct file *fp;
135437741Smckusick 	int error;
13557701Ssam 
135642441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
135737741Smckusick 		RETURN (error);
135837741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
135937741Smckusick 		RETURN (EINVAL);
136041362Smckusick 	VATTR_NULL(&vattr);
136137741Smckusick 	vattr.va_size = uap->length;
136237741Smckusick 	vp = (struct vnode *)fp->f_data;
136337741Smckusick 	VOP_LOCK(vp);
136437741Smckusick 	if (vp->v_type == VDIR) {
136537741Smckusick 		error = EISDIR;
136637741Smckusick 		goto out;
13677701Ssam 	}
136838399Smckusick 	if (error = vn_writechk(vp))
136937741Smckusick 		goto out;
137037741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
137137741Smckusick out:
137237741Smckusick 	VOP_UNLOCK(vp);
137337741Smckusick 	RETURN (error);
13747701Ssam }
13757701Ssam 
13769167Ssam /*
13779167Ssam  * Synch an open file.
13789167Ssam  */
137942441Smckusick /* ARGSUSED */
138042441Smckusick fsync(p, uap, retval)
138142441Smckusick 	register struct proc *p;
138242441Smckusick 	struct args {
138342441Smckusick 		int	fd;
138442441Smckusick 	} *uap;
138542441Smckusick 	int *retval;
13869167Ssam {
138739592Smckusick 	register struct vnode *vp;
13889167Ssam 	struct file *fp;
138937741Smckusick 	int error;
13909167Ssam 
139142441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
139237741Smckusick 		RETURN (error);
139339592Smckusick 	vp = (struct vnode *)fp->f_data;
139439592Smckusick 	VOP_LOCK(vp);
139539592Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT);
139639592Smckusick 	VOP_UNLOCK(vp);
139737741Smckusick 	RETURN (error);
13989167Ssam }
13999167Ssam 
14009167Ssam /*
14019167Ssam  * Rename system call.
14029167Ssam  *
14039167Ssam  * Source and destination must either both be directories, or both
14049167Ssam  * not be directories.  If target is a directory, it must be empty.
14059167Ssam  */
140642441Smckusick /* ARGSUSED */
140742441Smckusick rename(p, uap, retval)
140842441Smckusick 	register struct proc *p;
140942441Smckusick 	register struct args {
14107701Ssam 		char	*from;
14117701Ssam 		char	*to;
141242441Smckusick 	} *uap;
141342441Smckusick 	int *retval;
141442441Smckusick {
141537741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
141642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
141737741Smckusick 	struct nameidata tond;
141837741Smckusick 	int error;
14197701Ssam 
142037741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
142116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
142216694Smckusick 	ndp->ni_dirp = uap->from;
142337741Smckusick 	if (error = namei(ndp))
142437741Smckusick 		RETURN (error);
142537741Smckusick 	fvp = ndp->ni_vp;
142638266Smckusick 	nddup(ndp, &tond);
142737741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
142837741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
142937741Smckusick 	tond.ni_dirp = uap->to;
143042465Smckusick 	if (error = namei(&tond)) {
143142465Smckusick 		VOP_ABORTOP(ndp);
143242465Smckusick 		vrele(ndp->ni_dvp);
143342465Smckusick 		vrele(fvp);
143442465Smckusick 		goto out1;
143542465Smckusick 	}
143637741Smckusick 	tdvp = tond.ni_dvp;
143737741Smckusick 	tvp = tond.ni_vp;
143837741Smckusick 	if (tvp != NULL) {
143937741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
144039242Sbostic 			error = ENOTDIR;
144137741Smckusick 			goto out;
144237741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
144339242Sbostic 			error = EISDIR;
144437741Smckusick 			goto out;
14459167Ssam 		}
14469167Ssam 	}
144737741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
144837741Smckusick 		error = EXDEV;
14499167Ssam 		goto out;
145010051Ssam 	}
145139286Smckusick 	if (fvp == tdvp)
145237741Smckusick 		error = EINVAL;
145339286Smckusick 	/*
145439286Smckusick 	 * If source is the same as the destination,
145539286Smckusick 	 * then there is nothing to do.
145639286Smckusick 	 */
145739286Smckusick 	if (fvp == tvp)
145839286Smckusick 		error = -1;
145937741Smckusick out:
146042465Smckusick 	if (!error) {
146142465Smckusick 		error = VOP_RENAME(ndp, &tond);
146242465Smckusick 	} else {
146337741Smckusick 		VOP_ABORTOP(&tond);
146443344Smckusick 		if (tdvp == tvp)
146543344Smckusick 			vrele(tdvp);
146643344Smckusick 		else
146743344Smckusick 			vput(tdvp);
146842465Smckusick 		if (tvp)
146942465Smckusick 			vput(tvp);
147037741Smckusick 		VOP_ABORTOP(ndp);
147142465Smckusick 		vrele(ndp->ni_dvp);
147242465Smckusick 		vrele(fvp);
14739167Ssam 	}
147437741Smckusick out1:
147538266Smckusick 	ndrele(&tond);
147639286Smckusick 	if (error == -1)
147739286Smckusick 		RETURN (0);
147837741Smckusick 	RETURN (error);
14797701Ssam }
14807701Ssam 
14817535Sroot /*
148212756Ssam  * Mkdir system call
148312756Ssam  */
148442441Smckusick /* ARGSUSED */
148542441Smckusick mkdir(p, uap, retval)
148642441Smckusick 	register struct proc *p;
148742441Smckusick 	register struct args {
148812756Ssam 		char	*name;
148912756Ssam 		int	dmode;
149042441Smckusick 	} *uap;
149142441Smckusick 	int *retval;
149242441Smckusick {
149342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
149437741Smckusick 	register struct vnode *vp;
149537741Smckusick 	struct vattr vattr;
149637741Smckusick 	int error;
149712756Ssam 
149837741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
149916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
150016694Smckusick 	ndp->ni_dirp = uap->name;
150137741Smckusick 	if (error = namei(ndp))
150237741Smckusick 		RETURN (error);
150337741Smckusick 	vp = ndp->ni_vp;
150437741Smckusick 	if (vp != NULL) {
150537741Smckusick 		VOP_ABORTOP(ndp);
150643344Smckusick 		if (ndp->ni_dvp == vp)
150743344Smckusick 			vrele(ndp->ni_dvp);
150843344Smckusick 		else
150943344Smckusick 			vput(ndp->ni_dvp);
151042465Smckusick 		vrele(vp);
151137741Smckusick 		RETURN (EEXIST);
151212756Ssam 	}
151341362Smckusick 	VATTR_NULL(&vattr);
151437741Smckusick 	vattr.va_type = VDIR;
151542441Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask;
151637741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
151738145Smckusick 	if (!error)
151838145Smckusick 		vput(ndp->ni_vp);
151937741Smckusick 	RETURN (error);
152012756Ssam }
152112756Ssam 
152212756Ssam /*
152312756Ssam  * Rmdir system call.
152412756Ssam  */
152542441Smckusick /* ARGSUSED */
152642441Smckusick rmdir(p, uap, retval)
152742441Smckusick 	register struct proc *p;
152842441Smckusick 	struct args {
152942441Smckusick 		char	*name;
153042441Smckusick 	} *uap;
153142441Smckusick 	int *retval;
153212756Ssam {
153342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
153437741Smckusick 	register struct vnode *vp;
153537741Smckusick 	int error;
153612756Ssam 
153737741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
153816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
153916694Smckusick 	ndp->ni_dirp = uap->name;
154037741Smckusick 	if (error = namei(ndp))
154137741Smckusick 		RETURN (error);
154237741Smckusick 	vp = ndp->ni_vp;
154337741Smckusick 	if (vp->v_type != VDIR) {
154437741Smckusick 		error = ENOTDIR;
154512756Ssam 		goto out;
154612756Ssam 	}
154712756Ssam 	/*
154837741Smckusick 	 * No rmdir "." please.
154912756Ssam 	 */
155037741Smckusick 	if (ndp->ni_dvp == vp) {
155137741Smckusick 		error = EINVAL;
155212756Ssam 		goto out;
155312756Ssam 	}
155412756Ssam 	/*
155537741Smckusick 	 * Don't unlink a mounted file.
155612756Ssam 	 */
155737741Smckusick 	if (vp->v_flag & VROOT)
155837741Smckusick 		error = EBUSY;
155912756Ssam out:
156042465Smckusick 	if (!error) {
156142465Smckusick 		error = VOP_RMDIR(ndp);
156242465Smckusick 	} else {
156337741Smckusick 		VOP_ABORTOP(ndp);
156443344Smckusick 		if (ndp->ni_dvp == vp)
156543344Smckusick 			vrele(ndp->ni_dvp);
156643344Smckusick 		else
156743344Smckusick 			vput(ndp->ni_dvp);
156842465Smckusick 		vput(vp);
156942465Smckusick 	}
157037741Smckusick 	RETURN (error);
157112756Ssam }
157212756Ssam 
157337741Smckusick /*
157437741Smckusick  * Read a block of directory entries in a file system independent format
157537741Smckusick  */
157642441Smckusick getdirentries(p, uap, retval)
157742441Smckusick 	register struct proc *p;
157842441Smckusick 	register struct args {
157937741Smckusick 		int	fd;
158037741Smckusick 		char	*buf;
158137741Smckusick 		unsigned count;
158237741Smckusick 		long	*basep;
158342441Smckusick 	} *uap;
158442441Smckusick 	int *retval;
158542441Smckusick {
158639592Smckusick 	register struct vnode *vp;
158716540Ssam 	struct file *fp;
158837741Smckusick 	struct uio auio;
158937741Smckusick 	struct iovec aiov;
159038129Smckusick 	off_t off;
159140321Smckusick 	int error, eofflag;
159212756Ssam 
159342441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
159437741Smckusick 		RETURN (error);
159537741Smckusick 	if ((fp->f_flag & FREAD) == 0)
159637741Smckusick 		RETURN (EBADF);
159739592Smckusick 	vp = (struct vnode *)fp->f_data;
159839592Smckusick 	if (vp->v_type != VDIR)
159939592Smckusick 		RETURN (EINVAL);
160037741Smckusick 	aiov.iov_base = uap->buf;
160137741Smckusick 	aiov.iov_len = uap->count;
160237741Smckusick 	auio.uio_iov = &aiov;
160337741Smckusick 	auio.uio_iovcnt = 1;
160437741Smckusick 	auio.uio_rw = UIO_READ;
160537741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
160637741Smckusick 	auio.uio_resid = uap->count;
160739592Smckusick 	VOP_LOCK(vp);
160839592Smckusick 	auio.uio_offset = off = fp->f_offset;
160940321Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
161039592Smckusick 	fp->f_offset = auio.uio_offset;
161139592Smckusick 	VOP_UNLOCK(vp);
161239592Smckusick 	if (error)
161337741Smckusick 		RETURN (error);
161439592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
161542441Smckusick 	*retval = uap->count - auio.uio_resid;
161637741Smckusick 	RETURN (error);
161712756Ssam }
161812756Ssam 
161912756Ssam /*
162012756Ssam  * mode mask for creation of files
162112756Ssam  */
162242441Smckusick mode_t
162342441Smckusick umask(p, uap, retval)
162442441Smckusick 	register struct proc *p;
162542441Smckusick 	struct args {
162642441Smckusick 		int	mask;
162742441Smckusick 	} *uap;
162842441Smckusick 	int *retval;
162912756Ssam {
163012756Ssam 
163142441Smckusick 	*retval = u.u_cmask;
163242441Smckusick 	u.u_cmask = uap->mask & 07777;
163337741Smckusick 	RETURN (0);
163412756Ssam }
163537741Smckusick 
163639566Smarc /*
163739566Smarc  * Void all references to file by ripping underlying filesystem
163839566Smarc  * away from vnode.
163939566Smarc  */
164042441Smckusick /* ARGSUSED */
164142441Smckusick revoke(p, uap, retval)
164242441Smckusick 	register struct proc *p;
164342441Smckusick 	register struct args {
164439566Smarc 		char	*fname;
164542441Smckusick 	} *uap;
164642441Smckusick 	int *retval;
164742441Smckusick {
164842441Smckusick 	register struct nameidata *ndp = &u.u_nd;
164939566Smarc 	register struct vnode *vp;
165039566Smarc 	struct vattr vattr;
165139566Smarc 	int error;
165239566Smarc 
165339566Smarc 	ndp->ni_nameiop = LOOKUP | FOLLOW;
165439566Smarc 	ndp->ni_segflg = UIO_USERSPACE;
165539566Smarc 	ndp->ni_dirp = uap->fname;
165639566Smarc 	if (error = namei(ndp))
165739566Smarc 		RETURN (error);
165839566Smarc 	vp = ndp->ni_vp;
165939566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
166039566Smarc 		error = EINVAL;
166139566Smarc 		goto out;
166239566Smarc 	}
166342441Smckusick 	if (error = VOP_GETATTR(vp, &vattr, ndp->ni_cred))
166439566Smarc 		goto out;
166542955Smckusick 	if (ndp->ni_cred->cr_uid != vattr.va_uid &&
166642441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
166739566Smarc 		goto out;
166839805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
166939632Smckusick 		vgoneall(vp);
167039566Smarc out:
167139566Smarc 	vrele(vp);
167239566Smarc 	RETURN (error);
167339566Smarc }
167439566Smarc 
167538408Smckusick getvnode(ofile, fdes, fpp)
167638408Smckusick 	struct file *ofile[];
167737741Smckusick 	struct file **fpp;
167837741Smckusick 	int fdes;
167937741Smckusick {
168037741Smckusick 	struct file *fp;
168137741Smckusick 
168238408Smckusick 	if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
168337741Smckusick 		return (EBADF);
168437741Smckusick 	if (fp->f_type != DTYPE_VNODE)
168537741Smckusick 		return (EINVAL);
168637741Smckusick 	*fpp = fp;
168737741Smckusick 	return (0);
168837741Smckusick }
1689