xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 43450)
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*43450Smckusick  *	@(#)vfs_syscalls.c	7.54 (Berkeley) 06/22/90
1823405Smckusick  */
1937Sbill 
2017101Sbloom #include "param.h"
2117101Sbloom #include "systm.h"
2237741Smckusick #include "syscontext.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 
3239797Smckusick #undef RETURN
33*43450Smckusick #define RETURN(val) {if (u.u_spare[0] != 0) panic("lock count"); return (val);}
3439797Smckusick 
3537741Smckusick /*
3637741Smckusick  * Virtual File System System Calls
3737741Smckusick  */
3812756Ssam 
399167Ssam /*
4037741Smckusick  * mount system call
419167Ssam  */
4242441Smckusick /* ARGSUSED */
4342441Smckusick mount(p, uap, retval)
4442441Smckusick 	register struct proc *p;
4542441Smckusick 	register struct args {
4637741Smckusick 		int	type;
4737741Smckusick 		char	*dir;
4837741Smckusick 		int	flags;
4937741Smckusick 		caddr_t	data;
5042441Smckusick 	} *uap;
5142441Smckusick 	int *retval;
5242441Smckusick {
5342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
5439335Smckusick 	register struct vnode *vp;
5539335Smckusick 	register struct mount *mp;
5640111Smckusick 	int error, flag;
576254Sroot 
5837741Smckusick 	/*
5937741Smckusick 	 * Must be super user
6037741Smckusick 	 */
6142441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
6237741Smckusick 		RETURN (error);
6337741Smckusick 	/*
6437741Smckusick 	 * Get vnode to be covered
6537741Smckusick 	 */
6637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
6737741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
6837741Smckusick 	ndp->ni_dirp = uap->dir;
6937741Smckusick 	if (error = namei(ndp))
7037741Smckusick 		RETURN (error);
7137741Smckusick 	vp = ndp->ni_vp;
7241400Smckusick 	if (uap->flags & MNT_UPDATE) {
7339335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
7439335Smckusick 			vput(vp);
7539335Smckusick 			RETURN (EINVAL);
7639335Smckusick 		}
7739335Smckusick 		mp = vp->v_mount;
7839335Smckusick 		/*
7939335Smckusick 		 * We allow going from read-only to read-write,
8039335Smckusick 		 * but not from read-write to read-only.
8139335Smckusick 		 */
8241400Smckusick 		if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
8341400Smckusick 		    (uap->flags & MNT_RDONLY) != 0) {
8439335Smckusick 			vput(vp);
8539335Smckusick 			RETURN (EOPNOTSUPP);	/* Needs translation */
8639335Smckusick 		}
8741400Smckusick 		flag = mp->mnt_flag;
8841400Smckusick 		mp->mnt_flag |= MNT_UPDATE;
8939335Smckusick 		VOP_UNLOCK(vp);
9039335Smckusick 		goto update;
9139335Smckusick 	}
9239665Smckusick 	vinvalbuf(vp, 1);
9339805Smckusick 	if (vp->v_usecount != 1) {
9437741Smckusick 		vput(vp);
9537741Smckusick 		RETURN (EBUSY);
9637741Smckusick 	}
9737741Smckusick 	if (vp->v_type != VDIR) {
9837741Smckusick 		vput(vp);
9937741Smckusick 		RETURN (ENOTDIR);
10037741Smckusick 	}
10139741Smckusick 	if ((unsigned long)uap->type > MOUNT_MAXTYPE ||
10237741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
10337741Smckusick 		vput(vp);
10437741Smckusick 		RETURN (ENODEV);
10537741Smckusick 	}
10637741Smckusick 
10737741Smckusick 	/*
10839335Smckusick 	 * Allocate and initialize the file system.
10937741Smckusick 	 */
11037741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
11137741Smckusick 		M_MOUNT, M_WAITOK);
11241400Smckusick 	mp->mnt_op = vfssw[uap->type];
11341400Smckusick 	mp->mnt_flag = 0;
11441400Smckusick 	mp->mnt_exroot = 0;
11541400Smckusick 	mp->mnt_mounth = NULLVP;
11639335Smckusick 	if (error = vfs_lock(mp)) {
11739335Smckusick 		free((caddr_t)mp, M_MOUNT);
11839335Smckusick 		vput(vp);
11939335Smckusick 		RETURN (error);
12039335Smckusick 	}
12139335Smckusick 	if (vp->v_mountedhere != (struct mount *)0) {
12239335Smckusick 		vfs_unlock(mp);
12339335Smckusick 		free((caddr_t)mp, M_MOUNT);
12439335Smckusick 		vput(vp);
12539335Smckusick 		RETURN (EBUSY);
12639335Smckusick 	}
12739335Smckusick 	vp->v_mountedhere = mp;
12841400Smckusick 	mp->mnt_vnodecovered = vp;
12939335Smckusick update:
13039335Smckusick 	/*
13139335Smckusick 	 * Set the mount level flags.
13239335Smckusick 	 */
13341400Smckusick 	if (uap->flags & MNT_RDONLY)
13441400Smckusick 		mp->mnt_flag |= MNT_RDONLY;
13539335Smckusick 	else
13641400Smckusick 		mp->mnt_flag &= ~MNT_RDONLY;
13741400Smckusick 	if (uap->flags & MNT_NOSUID)
13841400Smckusick 		mp->mnt_flag |= MNT_NOSUID;
13939335Smckusick 	else
14041400Smckusick 		mp->mnt_flag &= ~MNT_NOSUID;
14141400Smckusick 	if (uap->flags & MNT_NOEXEC)
14241400Smckusick 		mp->mnt_flag |= MNT_NOEXEC;
14339335Smckusick 	else
14441400Smckusick 		mp->mnt_flag &= ~MNT_NOEXEC;
14541400Smckusick 	if (uap->flags & MNT_NODEV)
14641400Smckusick 		mp->mnt_flag |= MNT_NODEV;
14739335Smckusick 	else
14841400Smckusick 		mp->mnt_flag &= ~MNT_NODEV;
14941400Smckusick 	if (uap->flags & MNT_SYNCHRONOUS)
15041400Smckusick 		mp->mnt_flag |= MNT_SYNCHRONOUS;
15139335Smckusick 	else
15241400Smckusick 		mp->mnt_flag &= ~MNT_SYNCHRONOUS;
15339335Smckusick 	/*
15439335Smckusick 	 * Mount the filesystem.
15539335Smckusick 	 */
15639335Smckusick 	error = VFS_MOUNT(mp, uap->dir, uap->data, ndp);
15741400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
15841400Smckusick 		mp->mnt_flag &= ~MNT_UPDATE;
15939335Smckusick 		vrele(vp);
16040111Smckusick 		if (error)
16141400Smckusick 			mp->mnt_flag = flag;
16239335Smckusick 		RETURN (error);
16339335Smckusick 	}
16440110Smckusick 	/*
16540110Smckusick 	 * Put the new filesystem on the mount list after root.
16640110Smckusick 	 */
16741400Smckusick 	mp->mnt_next = rootfs->mnt_next;
16841400Smckusick 	mp->mnt_prev = rootfs;
16941400Smckusick 	rootfs->mnt_next = mp;
17041400Smckusick 	mp->mnt_next->mnt_prev = mp;
17137741Smckusick 	cache_purge(vp);
17237741Smckusick 	if (!error) {
17339335Smckusick 		VOP_UNLOCK(vp);
17437741Smckusick 		vfs_unlock(mp);
17539044Smckusick 		error = VFS_START(mp, 0);
17637741Smckusick 	} else {
17737741Smckusick 		vfs_remove(mp);
17837741Smckusick 		free((caddr_t)mp, M_MOUNT);
17939335Smckusick 		vput(vp);
18037741Smckusick 	}
18137741Smckusick 	RETURN (error);
1826254Sroot }
1836254Sroot 
1849167Ssam /*
18537741Smckusick  * Unmount system call.
18637741Smckusick  *
18737741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
18837741Smckusick  * not special file (as before).
1899167Ssam  */
19042441Smckusick /* ARGSUSED */
19142441Smckusick unmount(p, uap, retval)
19242441Smckusick 	register struct proc *p;
19342441Smckusick 	register struct args {
19437741Smckusick 		char	*pathp;
19537741Smckusick 		int	flags;
19642441Smckusick 	} *uap;
19742441Smckusick 	int *retval;
19842441Smckusick {
19937741Smckusick 	register struct vnode *vp;
20042441Smckusick 	register struct nameidata *ndp = &u.u_nd;
20139356Smckusick 	struct mount *mp;
20237741Smckusick 	int error;
2036254Sroot 
20437741Smckusick 	/*
20537741Smckusick 	 * Must be super user
20637741Smckusick 	 */
20742441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
20837741Smckusick 		RETURN (error);
20937741Smckusick 
21037741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
21137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
21237741Smckusick 	ndp->ni_dirp = uap->pathp;
21337741Smckusick 	if (error = namei(ndp))
21437741Smckusick 		RETURN (error);
21537741Smckusick 	vp = ndp->ni_vp;
21637741Smckusick 	/*
21737741Smckusick 	 * Must be the root of the filesystem
21837741Smckusick 	 */
21937741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
22037741Smckusick 		vput(vp);
22137741Smckusick 		RETURN (EINVAL);
22237741Smckusick 	}
22337741Smckusick 	mp = vp->v_mount;
22437741Smckusick 	vput(vp);
22539356Smckusick 	RETURN (dounmount(mp, uap->flags));
22639356Smckusick }
22739356Smckusick 
22839356Smckusick /*
22939356Smckusick  * Do an unmount.
23039356Smckusick  */
23139356Smckusick dounmount(mp, flags)
23239356Smckusick 	register struct mount *mp;
23339356Smckusick 	int flags;
23439356Smckusick {
23539356Smckusick 	struct vnode *coveredvp;
23639356Smckusick 	int error;
23739356Smckusick 
23841400Smckusick 	coveredvp = mp->mnt_vnodecovered;
23941298Smckusick 	if (vfs_busy(mp))
24041298Smckusick 		return (EBUSY);
24141400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
24237741Smckusick 	if (error = vfs_lock(mp))
24339356Smckusick 		return (error);
24437741Smckusick 
24537741Smckusick 	xumount(mp);		/* remove unused sticky files from text table */
24637741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
24741676Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE))
24841676Smckusick 		error = VFS_UNMOUNT(mp, flags);
24941400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
25041298Smckusick 	vfs_unbusy(mp);
25137741Smckusick 	if (error) {
25237741Smckusick 		vfs_unlock(mp);
25337741Smckusick 	} else {
25437741Smckusick 		vrele(coveredvp);
25537741Smckusick 		vfs_remove(mp);
25637741Smckusick 		free((caddr_t)mp, M_MOUNT);
25737741Smckusick 	}
25839356Smckusick 	return (error);
2596254Sroot }
2606254Sroot 
2619167Ssam /*
26237741Smckusick  * Sync system call.
26337741Smckusick  * Sync each mounted filesystem.
2649167Ssam  */
26539491Smckusick /* ARGSUSED */
26642441Smckusick sync(p, uap, retval)
26742441Smckusick 	register struct proc *p;
26842441Smckusick 	struct args *uap;
26942441Smckusick 	int *retval;
2706254Sroot {
27137741Smckusick 	register struct mount *mp;
27241298Smckusick 	struct mount *omp;
27337741Smckusick 
27437741Smckusick 	mp = rootfs;
27537741Smckusick 	do {
27640343Smckusick 		/*
27740343Smckusick 		 * The lock check below is to avoid races with mount
27840343Smckusick 		 * and unmount.
27940343Smckusick 		 */
28041400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
28141298Smckusick 		    !vfs_busy(mp)) {
28237741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
28341298Smckusick 			omp = mp;
28441400Smckusick 			mp = mp->mnt_next;
28541298Smckusick 			vfs_unbusy(omp);
28641298Smckusick 		} else
28741400Smckusick 			mp = mp->mnt_next;
28837741Smckusick 	} while (mp != rootfs);
28937741Smckusick }
29037741Smckusick 
29137741Smckusick /*
29241298Smckusick  * operate on filesystem quotas
29341298Smckusick  */
29442441Smckusick /* ARGSUSED */
29542441Smckusick quotactl(p, uap, retval)
29642441Smckusick 	register struct proc *p;
29742441Smckusick 	register struct args {
29841298Smckusick 		char *path;
29941298Smckusick 		int cmd;
30041298Smckusick 		int uid;
30141298Smckusick 		caddr_t arg;
30242441Smckusick 	} *uap;
30342441Smckusick 	int *retval;
30442441Smckusick {
30541298Smckusick 	register struct mount *mp;
30642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
30741298Smckusick 	int error;
30841298Smckusick 
30941298Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
31041298Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
31141298Smckusick 	ndp->ni_dirp = uap->path;
31241298Smckusick 	if (error = namei(ndp))
31341298Smckusick 		RETURN (error);
31441298Smckusick 	mp = ndp->ni_vp->v_mount;
31541298Smckusick 	vrele(ndp->ni_vp);
31641298Smckusick 	RETURN (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg));
31741298Smckusick }
31841298Smckusick 
31941298Smckusick /*
32037741Smckusick  * get filesystem statistics
32137741Smckusick  */
32242441Smckusick /* ARGSUSED */
32342441Smckusick statfs(p, uap, retval)
32442441Smckusick 	register struct proc *p;
32542441Smckusick 	register struct args {
32637741Smckusick 		char *path;
32737741Smckusick 		struct statfs *buf;
32842441Smckusick 	} *uap;
32942441Smckusick 	int *retval;
33042441Smckusick {
33139464Smckusick 	register struct mount *mp;
33242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
33340343Smckusick 	register struct statfs *sp;
33437741Smckusick 	int error;
33537741Smckusick 
33639544Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
33737741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
33837741Smckusick 	ndp->ni_dirp = uap->path;
33937741Smckusick 	if (error = namei(ndp))
34037741Smckusick 		RETURN (error);
34139544Smckusick 	mp = ndp->ni_vp->v_mount;
34241400Smckusick 	sp = &mp->mnt_stat;
34339544Smckusick 	vrele(ndp->ni_vp);
34440343Smckusick 	if (error = VFS_STATFS(mp, sp))
34539544Smckusick 		RETURN (error);
34641400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
34740343Smckusick 	RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
34837741Smckusick }
34937741Smckusick 
35042441Smckusick /*
35142441Smckusick  * get filesystem statistics
35242441Smckusick  */
35342441Smckusick /* ARGSUSED */
35442441Smckusick fstatfs(p, uap, retval)
35542441Smckusick 	register struct proc *p;
35642441Smckusick 	register struct args {
35737741Smckusick 		int fd;
35837741Smckusick 		struct statfs *buf;
35942441Smckusick 	} *uap;
36042441Smckusick 	int *retval;
36142441Smckusick {
36237741Smckusick 	struct file *fp;
36339464Smckusick 	struct mount *mp;
36440343Smckusick 	register struct statfs *sp;
36537741Smckusick 	int error;
36637741Smckusick 
36742441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
36837741Smckusick 		RETURN (error);
36939464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
37041400Smckusick 	sp = &mp->mnt_stat;
37140343Smckusick 	if (error = VFS_STATFS(mp, sp))
37237741Smckusick 		RETURN (error);
37341400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
37440343Smckusick 	RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
37537741Smckusick }
37637741Smckusick 
37737741Smckusick /*
37838270Smckusick  * get statistics on all filesystems
37938270Smckusick  */
38042441Smckusick getfsstat(p, uap, retval)
38142441Smckusick 	register struct proc *p;
38242441Smckusick 	register struct args {
38338270Smckusick 		struct statfs *buf;
38438270Smckusick 		long bufsize;
38540343Smckusick 		int flags;
38642441Smckusick 	} *uap;
38742441Smckusick 	int *retval;
38842441Smckusick {
38938270Smckusick 	register struct mount *mp;
39040343Smckusick 	register struct statfs *sp;
39139606Smckusick 	caddr_t sfsp;
39238270Smckusick 	long count, maxcount, error;
39338270Smckusick 
39438270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
39539606Smckusick 	sfsp = (caddr_t)uap->buf;
39638270Smckusick 	mp = rootfs;
39738270Smckusick 	count = 0;
39838270Smckusick 	do {
39941400Smckusick 		if (sfsp && count < maxcount &&
40041400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
40141400Smckusick 			sp = &mp->mnt_stat;
40240343Smckusick 			/*
40340343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
40440343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
40540343Smckusick 			 */
40640343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
40740343Smckusick 			    (uap->flags & MNT_WAIT)) &&
40840343Smckusick 			    (error = VFS_STATFS(mp, sp))) {
40941400Smckusick 				mp = mp->mnt_prev;
41039607Smckusick 				continue;
41139607Smckusick 			}
41241400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
41340343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
41439606Smckusick 				RETURN (error);
41540343Smckusick 			sfsp += sizeof(*sp);
41638270Smckusick 		}
41739606Smckusick 		count++;
41841400Smckusick 		mp = mp->mnt_prev;
41938270Smckusick 	} while (mp != rootfs);
42038270Smckusick 	if (sfsp && count > maxcount)
42142441Smckusick 		*retval = maxcount;
42238270Smckusick 	else
42342441Smckusick 		*retval = count;
42438270Smckusick 	RETURN (0);
42538270Smckusick }
42638270Smckusick 
42738270Smckusick /*
42838259Smckusick  * Change current working directory to a given file descriptor.
42938259Smckusick  */
43042441Smckusick /* ARGSUSED */
43142441Smckusick fchdir(p, uap, retval)
43242441Smckusick 	register struct proc *p;
43342441Smckusick 	struct args {
43442441Smckusick 		int	fd;
43542441Smckusick 	} *uap;
43642441Smckusick 	int *retval;
43738259Smckusick {
43842441Smckusick 	register struct nameidata *ndp = &u.u_nd;
43938259Smckusick 	register struct vnode *vp;
44038259Smckusick 	struct file *fp;
44138259Smckusick 	int error;
44238259Smckusick 
44342441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
44438259Smckusick 		RETURN (error);
44538259Smckusick 	vp = (struct vnode *)fp->f_data;
44638259Smckusick 	VOP_LOCK(vp);
44738259Smckusick 	if (vp->v_type != VDIR)
44838259Smckusick 		error = ENOTDIR;
44938259Smckusick 	else
45042441Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
45138259Smckusick 	VOP_UNLOCK(vp);
45239860Smckusick 	if (error)
45339860Smckusick 		RETURN (error);
45439860Smckusick 	VREF(vp);
45542441Smckusick 	vrele(ndp->ni_cdir);
45642441Smckusick 	ndp->ni_cdir = vp;
45739860Smckusick 	RETURN (0);
45838259Smckusick }
45938259Smckusick 
46038259Smckusick /*
46137741Smckusick  * Change current working directory (``.'').
46237741Smckusick  */
46342441Smckusick /* ARGSUSED */
46442441Smckusick chdir(p, uap, retval)
46542441Smckusick 	register struct proc *p;
46642441Smckusick 	struct args {
46742441Smckusick 		char	*fname;
46842441Smckusick 	} *uap;
46942441Smckusick 	int *retval;
47037741Smckusick {
47142441Smckusick 	register struct nameidata *ndp = &u.u_nd;
47237741Smckusick 	int error;
4736254Sroot 
47437741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
47516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
47616694Smckusick 	ndp->ni_dirp = uap->fname;
47737741Smckusick 	if (error = chdirec(ndp))
47837741Smckusick 		RETURN (error);
47942441Smckusick 	vrele(ndp->ni_cdir);
48042441Smckusick 	ndp->ni_cdir = ndp->ni_vp;
48137741Smckusick 	RETURN (0);
48237741Smckusick }
4836254Sroot 
48437741Smckusick /*
48537741Smckusick  * Change notion of root (``/'') directory.
48637741Smckusick  */
48742441Smckusick /* ARGSUSED */
48842441Smckusick chroot(p, uap, retval)
48942441Smckusick 	register struct proc *p;
49042441Smckusick 	struct args {
49142441Smckusick 		char	*fname;
49242441Smckusick 	} *uap;
49342441Smckusick 	int *retval;
49437741Smckusick {
49542441Smckusick 	register struct nameidata *ndp = &u.u_nd;
49637741Smckusick 	int error;
49737741Smckusick 
49842441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
49937741Smckusick 		RETURN (error);
50037741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
50137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
50237741Smckusick 	ndp->ni_dirp = uap->fname;
50337741Smckusick 	if (error = chdirec(ndp))
50437741Smckusick 		RETURN (error);
50542441Smckusick 	if (ndp->ni_rdir != NULL)
50642441Smckusick 		vrele(ndp->ni_rdir);
50742441Smckusick 	ndp->ni_rdir = ndp->ni_vp;
50837741Smckusick 	RETURN (0);
5096254Sroot }
5106254Sroot 
51137Sbill /*
51237741Smckusick  * Common routine for chroot and chdir.
51337741Smckusick  */
51437741Smckusick chdirec(ndp)
51537741Smckusick 	register struct nameidata *ndp;
51637741Smckusick {
51737741Smckusick 	struct vnode *vp;
51837741Smckusick 	int error;
51937741Smckusick 
52037741Smckusick 	if (error = namei(ndp))
52137741Smckusick 		return (error);
52237741Smckusick 	vp = ndp->ni_vp;
52337741Smckusick 	if (vp->v_type != VDIR)
52437741Smckusick 		error = ENOTDIR;
52537741Smckusick 	else
52638399Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
52737741Smckusick 	VOP_UNLOCK(vp);
52837741Smckusick 	if (error)
52937741Smckusick 		vrele(vp);
53037741Smckusick 	return (error);
53137741Smckusick }
53237741Smckusick 
53337741Smckusick /*
5346254Sroot  * Open system call.
53542441Smckusick  * Check permissions, allocate an open file structure,
53642441Smckusick  * and call the device open routine if any.
5376254Sroot  */
53842441Smckusick open(p, uap, retval)
53942441Smckusick 	register struct proc *p;
54042441Smckusick 	register struct args {
5416254Sroot 		char	*fname;
5427701Ssam 		int	mode;
54312756Ssam 		int	crtmode;
54442441Smckusick 	} *uap;
54542441Smckusick 	int *retval;
5466254Sroot {
54742441Smckusick 	struct nameidata *ndp = &u.u_nd;
54842441Smckusick 	register struct file *fp;
54937741Smckusick 	int fmode, cmode;
55037741Smckusick 	struct file *nfp;
55137741Smckusick 	int indx, error;
55237741Smckusick 	extern struct fileops vnops;
5536254Sroot 
55437741Smckusick 	if (error = falloc(&nfp, &indx))
55542441Smckusick 		RETURN (error);
55637741Smckusick 	fp = nfp;
55742441Smckusick 	fmode = uap->mode - FOPEN;
55842441Smckusick 	cmode = ((uap->crtmode &~ u.u_cmask) & 07777) &~ S_ISVTX;
55942441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
56042441Smckusick 	ndp->ni_dirp = uap->fname;
561*43450Smckusick 	p->p_dupfd = -1;			/* XXX check for fdopen */
56242441Smckusick 	if (error = vn_open(ndp, fmode, cmode)) {
56337741Smckusick 		crfree(fp->f_cred);
56437741Smckusick 		fp->f_count--;
56543405Smckusick 		if (error == ENODEV &&		/* XXX from fdopen */
566*43450Smckusick 		    p->p_dupfd >= 0 &&
567*43450Smckusick 		    (error = dupfdopen(indx, p->p_dupfd, fmode)) == 0) {
56842441Smckusick 			*retval = indx;
56942441Smckusick 			RETURN (0);
57042441Smckusick 		}
57140884Smckusick 		if (error == ERESTART)
57240884Smckusick 			error = EINTR;
57342441Smckusick 		u.u_ofile[indx] = NULL;
57442441Smckusick 		RETURN (error);
57512756Ssam 	}
57637741Smckusick 	fp->f_flag = fmode & FMASK;
57737741Smckusick 	fp->f_type = DTYPE_VNODE;
57837741Smckusick 	fp->f_ops = &vnops;
57937741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
58042441Smckusick 	*retval = indx;
58142441Smckusick 	RETURN (0);
5826254Sroot }
5836254Sroot 
58442955Smckusick #ifdef COMPAT_43
5856254Sroot /*
58642441Smckusick  * Creat system call.
5876254Sroot  */
58842955Smckusick ocreat(p, uap, retval)
58942441Smckusick 	struct proc *p;
59042441Smckusick 	register struct args {
59142441Smckusick 		char	*fname;
59242441Smckusick 		int	fmode;
59342441Smckusick 	} *uap;
59442441Smckusick 	int *retval;
5956254Sroot {
59642441Smckusick 	struct args {
5976254Sroot 		char	*fname;
59842441Smckusick 		int	mode;
59942441Smckusick 		int	crtmode;
60042441Smckusick 	} openuap;
60142441Smckusick 
60242441Smckusick 	openuap.fname = uap->fname;
60342441Smckusick 	openuap.crtmode = uap->fmode;
60442441Smckusick 	openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
60542441Smckusick 	RETURN (open(p, &openuap, retval));
60642441Smckusick }
60742955Smckusick #endif /* COMPAT_43 */
60842441Smckusick 
60942441Smckusick /*
61042441Smckusick  * Mknod system call
61142441Smckusick  */
61242441Smckusick /* ARGSUSED */
61342441Smckusick mknod(p, uap, retval)
61442441Smckusick 	register struct proc *p;
61542441Smckusick 	register struct args {
61642441Smckusick 		char	*fname;
6176254Sroot 		int	fmode;
6186254Sroot 		int	dev;
61942441Smckusick 	} *uap;
62042441Smckusick 	int *retval;
62142441Smckusick {
62242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
62337741Smckusick 	register struct vnode *vp;
62437741Smckusick 	struct vattr vattr;
62537741Smckusick 	int error;
6266254Sroot 
62742441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
62837741Smckusick 		RETURN (error);
62937741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
63016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
63116694Smckusick 	ndp->ni_dirp = uap->fname;
63237741Smckusick 	if (error = namei(ndp))
63337741Smckusick 		RETURN (error);
63437741Smckusick 	vp = ndp->ni_vp;
63537741Smckusick 	if (vp != NULL) {
63637741Smckusick 		error = EEXIST;
63712756Ssam 		goto out;
6386254Sroot 	}
63941362Smckusick 	VATTR_NULL(&vattr);
64040635Smckusick 	switch (uap->fmode & S_IFMT) {
64112756Ssam 
64240635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
64337741Smckusick 		vattr.va_type = VBAD;
64437741Smckusick 		break;
64540635Smckusick 	case S_IFCHR:
64637741Smckusick 		vattr.va_type = VCHR;
64737741Smckusick 		break;
64840635Smckusick 	case S_IFBLK:
64937741Smckusick 		vattr.va_type = VBLK;
65037741Smckusick 		break;
65137741Smckusick 	default:
65237741Smckusick 		error = EINVAL;
65337741Smckusick 		goto out;
6546254Sroot 	}
65542441Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask;
65637741Smckusick 	vattr.va_rdev = uap->dev;
6576254Sroot out:
65842465Smckusick 	if (!error) {
65942465Smckusick 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
66042465Smckusick 	} else {
66137741Smckusick 		VOP_ABORTOP(ndp);
66243344Smckusick 		if (ndp->ni_dvp == vp)
66343344Smckusick 			vrele(ndp->ni_dvp);
66443344Smckusick 		else
66543344Smckusick 			vput(ndp->ni_dvp);
66642465Smckusick 		if (vp)
66742465Smckusick 			vrele(vp);
66842465Smckusick 	}
66937741Smckusick 	RETURN (error);
6706254Sroot }
6716254Sroot 
6726254Sroot /*
67340285Smckusick  * Mkfifo system call
67440285Smckusick  */
67542441Smckusick /* ARGSUSED */
67642441Smckusick mkfifo(p, uap, retval)
67742441Smckusick 	register struct proc *p;
67842441Smckusick 	register struct args {
67940285Smckusick 		char	*fname;
68040285Smckusick 		int	fmode;
68142441Smckusick 	} *uap;
68242441Smckusick 	int *retval;
68342441Smckusick {
68442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
68540285Smckusick 	struct vattr vattr;
68640285Smckusick 	int error;
68740285Smckusick 
68840285Smckusick #ifndef FIFO
68940285Smckusick 	RETURN (EOPNOTSUPP);
69040285Smckusick #else
69140285Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
69240285Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
69340285Smckusick 	ndp->ni_dirp = uap->fname;
69440285Smckusick 	if (error = namei(ndp))
69540285Smckusick 		RETURN (error);
69640285Smckusick 	if (ndp->ni_vp != NULL) {
69740285Smckusick 		VOP_ABORTOP(ndp);
69843344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
69943344Smckusick 			vrele(ndp->ni_dvp);
70043344Smckusick 		else
70143344Smckusick 			vput(ndp->ni_dvp);
70242465Smckusick 		vrele(ndp->ni_vp);
70340285Smckusick 		RETURN (EEXIST);
70440285Smckusick 	} else {
70541362Smckusick 		VATTR_NULL(&vattr);
70640285Smckusick 		vattr.va_type = VFIFO;
70742441Smckusick 		vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask;
70840285Smckusick 	}
70940285Smckusick 	RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred));
71040285Smckusick #endif /* FIFO */
71140285Smckusick }
71240285Smckusick 
71340285Smckusick /*
7146254Sroot  * link system call
7156254Sroot  */
71642441Smckusick /* ARGSUSED */
71742441Smckusick link(p, uap, retval)
71842441Smckusick 	register struct proc *p;
71942441Smckusick 	register struct args {
7206254Sroot 		char	*target;
7216254Sroot 		char	*linkname;
72242441Smckusick 	} *uap;
72342441Smckusick 	int *retval;
72442441Smckusick {
72542441Smckusick 	register struct nameidata *ndp = &u.u_nd;
72637741Smckusick 	register struct vnode *vp, *xp;
72737741Smckusick 	int error;
7286254Sroot 
72916694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
73016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
73116694Smckusick 	ndp->ni_dirp = uap->target;
73237741Smckusick 	if (error = namei(ndp))
73337741Smckusick 		RETURN (error);
73437741Smckusick 	vp = ndp->ni_vp;
73537741Smckusick 	if (vp->v_type == VDIR &&
73642441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
73737741Smckusick 		goto out1;
73837741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
73916694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
74037741Smckusick 	if (error = namei(ndp))
74137741Smckusick 		goto out1;
74237741Smckusick 	xp = ndp->ni_vp;
7436254Sroot 	if (xp != NULL) {
74437741Smckusick 		error = EEXIST;
7456254Sroot 		goto out;
7466254Sroot 	}
74737741Smckusick 	xp = ndp->ni_dvp;
74837741Smckusick 	if (vp->v_mount != xp->v_mount)
74937741Smckusick 		error = EXDEV;
7506254Sroot out:
75142465Smckusick 	if (!error) {
75242465Smckusick 		error = VOP_LINK(vp, ndp);
75342465Smckusick 	} else {
75437741Smckusick 		VOP_ABORTOP(ndp);
75543344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
75643344Smckusick 			vrele(ndp->ni_dvp);
75743344Smckusick 		else
75843344Smckusick 			vput(ndp->ni_dvp);
75942465Smckusick 		if (ndp->ni_vp)
76042465Smckusick 			vrele(ndp->ni_vp);
76142465Smckusick 	}
76237741Smckusick out1:
76337741Smckusick 	vrele(vp);
76437741Smckusick 	RETURN (error);
7656254Sroot }
7666254Sroot 
7676254Sroot /*
7686254Sroot  * symlink -- make a symbolic link
7696254Sroot  */
77042441Smckusick /* ARGSUSED */
77142441Smckusick symlink(p, uap, retval)
77242441Smckusick 	register struct proc *p;
77342441Smckusick 	register struct args {
7746254Sroot 		char	*target;
7756254Sroot 		char	*linkname;
77642441Smckusick 	} *uap;
77742441Smckusick 	int *retval;
77842441Smckusick {
77942441Smckusick 	register struct nameidata *ndp = &u.u_nd;
78037741Smckusick 	struct vattr vattr;
78137741Smckusick 	char *target;
78237741Smckusick 	int error;
7836254Sroot 
78416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
78516694Smckusick 	ndp->ni_dirp = uap->linkname;
78637741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
78737741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
78842465Smckusick 		goto out;
78937741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
79037741Smckusick 	if (error = namei(ndp))
79142465Smckusick 		goto out;
79242465Smckusick 	if (ndp->ni_vp) {
79342465Smckusick 		VOP_ABORTOP(ndp);
79443344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
79543344Smckusick 			vrele(ndp->ni_dvp);
79643344Smckusick 		else
79743344Smckusick 			vput(ndp->ni_dvp);
79842465Smckusick 		vrele(ndp->ni_vp);
79937741Smckusick 		error = EEXIST;
80037741Smckusick 		goto out;
8016254Sroot 	}
80241362Smckusick 	VATTR_NULL(&vattr);
80342441Smckusick 	vattr.va_mode = 0777 &~ u.u_cmask;
80442465Smckusick 	error = VOP_SYMLINK(ndp, &vattr, target);
80537741Smckusick out:
80637741Smckusick 	FREE(target, M_NAMEI);
80737741Smckusick 	RETURN (error);
8086254Sroot }
8096254Sroot 
8106254Sroot /*
8116254Sroot  * Unlink system call.
8126254Sroot  * Hard to avoid races here, especially
8136254Sroot  * in unlinking directories.
8146254Sroot  */
81542441Smckusick /* ARGSUSED */
81642441Smckusick unlink(p, uap, retval)
81742441Smckusick 	register struct proc *p;
81842441Smckusick 	struct args {
81942441Smckusick 		char	*fname;
82042441Smckusick 	} *uap;
82142441Smckusick 	int *retval;
8226254Sroot {
82342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
82437741Smckusick 	register struct vnode *vp;
82537741Smckusick 	int error;
8266254Sroot 
82737741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
82816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
82916694Smckusick 	ndp->ni_dirp = uap->fname;
83037741Smckusick 	if (error = namei(ndp))
83137741Smckusick 		RETURN (error);
83237741Smckusick 	vp = ndp->ni_vp;
83337741Smckusick 	if (vp->v_type == VDIR &&
83442441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
8356254Sroot 		goto out;
8366254Sroot 	/*
8376254Sroot 	 * Don't unlink a mounted file.
8386254Sroot 	 */
83937741Smckusick 	if (vp->v_flag & VROOT) {
84037741Smckusick 		error = EBUSY;
8416254Sroot 		goto out;
8426254Sroot 	}
84337741Smckusick 	if (vp->v_flag & VTEXT)
84437741Smckusick 		xrele(vp);	/* try once to free text */
8456254Sroot out:
84642465Smckusick 	if (!error) {
84742465Smckusick 		error = VOP_REMOVE(ndp);
84842465Smckusick 	} else {
84937741Smckusick 		VOP_ABORTOP(ndp);
85043344Smckusick 		if (ndp->ni_dvp == vp)
85143344Smckusick 			vrele(ndp->ni_dvp);
85243344Smckusick 		else
85343344Smckusick 			vput(ndp->ni_dvp);
85442465Smckusick 		vput(vp);
85542465Smckusick 	}
85637741Smckusick 	RETURN (error);
8576254Sroot }
8586254Sroot 
8596254Sroot /*
8606254Sroot  * Seek system call
8616254Sroot  */
86242441Smckusick lseek(p, uap, retval)
86342441Smckusick 	register struct proc *p;
86442441Smckusick 	register struct args {
86537741Smckusick 		int	fdes;
8666254Sroot 		off_t	off;
8676254Sroot 		int	sbase;
86842441Smckusick 	} *uap;
86942441Smckusick 	off_t *retval;
87042441Smckusick {
87142441Smckusick 	struct ucred *cred = u.u_nd.ni_cred;
87242441Smckusick 	register struct file *fp;
87337741Smckusick 	struct vattr vattr;
87437741Smckusick 	int error;
8756254Sroot 
87637741Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
87742441Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
87837741Smckusick 		RETURN (EBADF);
87937741Smckusick 	if (fp->f_type != DTYPE_VNODE)
88037741Smckusick 		RETURN (ESPIPE);
88113878Ssam 	switch (uap->sbase) {
88213878Ssam 
88313878Ssam 	case L_INCR:
88413878Ssam 		fp->f_offset += uap->off;
88513878Ssam 		break;
88613878Ssam 
88713878Ssam 	case L_XTND:
88837741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
88942441Smckusick 		    &vattr, cred))
89037741Smckusick 			RETURN (error);
89137741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
89213878Ssam 		break;
89313878Ssam 
89413878Ssam 	case L_SET:
89513878Ssam 		fp->f_offset = uap->off;
89613878Ssam 		break;
89713878Ssam 
89813878Ssam 	default:
89937741Smckusick 		RETURN (EINVAL);
90013878Ssam 	}
90142441Smckusick 	*retval = fp->f_offset;
90237741Smckusick 	RETURN (0);
9036254Sroot }
9046254Sroot 
9056254Sroot /*
9066254Sroot  * Access system call
9076254Sroot  */
90842441Smckusick /* ARGSUSED */
90942441Smckusick saccess(p, uap, retval)
91042441Smckusick 	register struct proc *p;
91142441Smckusick 	register struct args {
9126254Sroot 		char	*fname;
9136254Sroot 		int	fmode;
91442441Smckusick 	} *uap;
91542441Smckusick 	int *retval;
91642441Smckusick {
91742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
91842441Smckusick 	register struct ucred *cred = ndp->ni_cred;
91937741Smckusick 	register struct vnode *vp;
92037741Smckusick 	int error, mode, svuid, svgid;
9216254Sroot 
92242441Smckusick 	svuid = cred->cr_uid;
92342441Smckusick 	svgid = cred->cr_groups[0];
92442441Smckusick 	cred->cr_uid = p->p_ruid;
92542441Smckusick 	cred->cr_groups[0] = p->p_rgid;
92637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
92716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
92816694Smckusick 	ndp->ni_dirp = uap->fname;
92937741Smckusick 	if (error = namei(ndp))
93037741Smckusick 		goto out1;
93137741Smckusick 	vp = ndp->ni_vp;
93237741Smckusick 	/*
93337741Smckusick 	 * fmode == 0 means only check for exist
93437741Smckusick 	 */
93537741Smckusick 	if (uap->fmode) {
93637741Smckusick 		mode = 0;
93737741Smckusick 		if (uap->fmode & R_OK)
93837741Smckusick 			mode |= VREAD;
93937741Smckusick 		if (uap->fmode & W_OK)
94037741Smckusick 			mode |= VWRITE;
94137741Smckusick 		if (uap->fmode & X_OK)
94237741Smckusick 			mode |= VEXEC;
94339543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
94438399Smckusick 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
9456254Sroot 	}
94637741Smckusick 	vput(vp);
94737741Smckusick out1:
94842441Smckusick 	cred->cr_uid = svuid;
94942441Smckusick 	cred->cr_groups[0] = svgid;
95037741Smckusick 	RETURN (error);
9516254Sroot }
9526254Sroot 
9536254Sroot /*
9546574Smckusic  * Stat system call.  This version follows links.
95537Sbill  */
95642441Smckusick /* ARGSUSED */
95742441Smckusick stat(p, uap, retval)
95842441Smckusick 	register struct proc *p;
95942441Smckusick 	register struct args {
96042441Smckusick 		char	*fname;
96142441Smckusick 		struct stat *ub;
96242441Smckusick 	} *uap;
96342441Smckusick 	int *retval;
96437Sbill {
96542441Smckusick 	register struct nameidata *ndp = &u.u_nd;
96642441Smckusick 	struct stat sb;
96742441Smckusick 	int error;
96837Sbill 
96942441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
97042441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
97142441Smckusick 	ndp->ni_dirp = uap->fname;
97242441Smckusick 	if (error = namei(ndp))
97342441Smckusick 		RETURN (error);
97442441Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
97542441Smckusick 	vput(ndp->ni_vp);
97642441Smckusick 	if (error)
97742441Smckusick 		RETURN (error);
97842441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
97942441Smckusick 	RETURN (error);
98037Sbill }
98137Sbill 
98237Sbill /*
9836574Smckusic  * Lstat system call.  This version does not follow links.
9845992Swnj  */
98542441Smckusick /* ARGSUSED */
98642441Smckusick lstat(p, uap, retval)
98742441Smckusick 	register struct proc *p;
98842441Smckusick 	register struct args {
9895992Swnj 		char	*fname;
99012756Ssam 		struct stat *ub;
99142441Smckusick 	} *uap;
99242441Smckusick 	int *retval;
99342441Smckusick {
99442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
99512756Ssam 	struct stat sb;
99637741Smckusick 	int error;
9975992Swnj 
99842441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW;
99916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
100016694Smckusick 	ndp->ni_dirp = uap->fname;
100137741Smckusick 	if (error = namei(ndp))
100237741Smckusick 		RETURN (error);
100337741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
100437741Smckusick 	vput(ndp->ni_vp);
100537741Smckusick 	if (error)
100637741Smckusick 		RETURN (error);
100737741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
100837741Smckusick 	RETURN (error);
10095992Swnj }
10105992Swnj 
10115992Swnj /*
10125992Swnj  * Return target name of a symbolic link
101337Sbill  */
101442441Smckusick /* ARGSUSED */
101542441Smckusick readlink(p, uap, retval)
101642441Smckusick 	register struct proc *p;
101742441Smckusick 	register struct args {
10185992Swnj 		char	*name;
10195992Swnj 		char	*buf;
10205992Swnj 		int	count;
102142441Smckusick 	} *uap;
102242441Smckusick 	int *retval;
102342441Smckusick {
102442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
102537741Smckusick 	register struct vnode *vp;
102637741Smckusick 	struct iovec aiov;
102737741Smckusick 	struct uio auio;
102837741Smckusick 	int error;
10295992Swnj 
103037741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
103116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
103216694Smckusick 	ndp->ni_dirp = uap->name;
103337741Smckusick 	if (error = namei(ndp))
103437741Smckusick 		RETURN (error);
103537741Smckusick 	vp = ndp->ni_vp;
103637741Smckusick 	if (vp->v_type != VLNK) {
103737741Smckusick 		error = EINVAL;
10385992Swnj 		goto out;
10395992Swnj 	}
104037741Smckusick 	aiov.iov_base = uap->buf;
104137741Smckusick 	aiov.iov_len = uap->count;
104237741Smckusick 	auio.uio_iov = &aiov;
104337741Smckusick 	auio.uio_iovcnt = 1;
104437741Smckusick 	auio.uio_offset = 0;
104537741Smckusick 	auio.uio_rw = UIO_READ;
104637741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
104737741Smckusick 	auio.uio_resid = uap->count;
104837741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
10495992Swnj out:
105037741Smckusick 	vput(vp);
105142441Smckusick 	*retval = uap->count - auio.uio_resid;
105237741Smckusick 	RETURN (error);
10535992Swnj }
10545992Swnj 
10559167Ssam /*
105638259Smckusick  * Change flags of a file given path name.
105738259Smckusick  */
105842441Smckusick /* ARGSUSED */
105942441Smckusick chflags(p, uap, retval)
106042441Smckusick 	register struct proc *p;
106142441Smckusick 	register struct args {
106238259Smckusick 		char	*fname;
106338259Smckusick 		int	flags;
106442441Smckusick 	} *uap;
106542441Smckusick 	int *retval;
106642441Smckusick {
106742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
106838259Smckusick 	register struct vnode *vp;
106938259Smckusick 	struct vattr vattr;
107038259Smckusick 	int error;
107138259Smckusick 
107238259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
107338259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
107438259Smckusick 	ndp->ni_dirp = uap->fname;
107541362Smckusick 	VATTR_NULL(&vattr);
107638259Smckusick 	vattr.va_flags = uap->flags;
107738259Smckusick 	if (error = namei(ndp))
107838259Smckusick 		RETURN (error);
107938259Smckusick 	vp = ndp->ni_vp;
108041400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
108138259Smckusick 		error = EROFS;
108238259Smckusick 		goto out;
108338259Smckusick 	}
108438259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
108538259Smckusick out:
108638259Smckusick 	vput(vp);
108738259Smckusick 	RETURN (error);
108838259Smckusick }
108938259Smckusick 
109038259Smckusick /*
109138259Smckusick  * Change flags of a file given a file descriptor.
109238259Smckusick  */
109342441Smckusick /* ARGSUSED */
109442441Smckusick fchflags(p, uap, retval)
109542441Smckusick 	register struct proc *p;
109642441Smckusick 	register struct args {
109738259Smckusick 		int	fd;
109838259Smckusick 		int	flags;
109942441Smckusick 	} *uap;
110042441Smckusick 	int *retval;
110142441Smckusick {
110238259Smckusick 	struct vattr vattr;
110338259Smckusick 	struct vnode *vp;
110438259Smckusick 	struct file *fp;
110538259Smckusick 	int error;
110638259Smckusick 
110742441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
110838259Smckusick 		RETURN (error);
110941362Smckusick 	VATTR_NULL(&vattr);
111038259Smckusick 	vattr.va_flags = uap->flags;
111138259Smckusick 	vp = (struct vnode *)fp->f_data;
111238259Smckusick 	VOP_LOCK(vp);
111341400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
111438259Smckusick 		error = EROFS;
111538259Smckusick 		goto out;
111638259Smckusick 	}
111738259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
111838259Smckusick out:
111938259Smckusick 	VOP_UNLOCK(vp);
112038259Smckusick 	RETURN (error);
112138259Smckusick }
112238259Smckusick 
112338259Smckusick /*
11249167Ssam  * Change mode of a file given path name.
11259167Ssam  */
112642441Smckusick /* ARGSUSED */
112742441Smckusick chmod(p, uap, retval)
112842441Smckusick 	register struct proc *p;
112942441Smckusick 	register struct args {
11306254Sroot 		char	*fname;
11316254Sroot 		int	fmode;
113242441Smckusick 	} *uap;
113342441Smckusick 	int *retval;
113442441Smckusick {
113542441Smckusick 	register struct nameidata *ndp = &u.u_nd;
113637741Smckusick 	register struct vnode *vp;
113737741Smckusick 	struct vattr vattr;
113837741Smckusick 	int error;
11395992Swnj 
114037741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
114137741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
114237741Smckusick 	ndp->ni_dirp = uap->fname;
114341362Smckusick 	VATTR_NULL(&vattr);
114437741Smckusick 	vattr.va_mode = uap->fmode & 07777;
114537741Smckusick 	if (error = namei(ndp))
114637741Smckusick 		RETURN (error);
114737741Smckusick 	vp = ndp->ni_vp;
114841400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
114937741Smckusick 		error = EROFS;
115037741Smckusick 		goto out;
115137741Smckusick 	}
115237741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
115337741Smckusick out:
115437741Smckusick 	vput(vp);
115537741Smckusick 	RETURN (error);
11567701Ssam }
11577439Sroot 
11589167Ssam /*
11599167Ssam  * Change mode of a file given a file descriptor.
11609167Ssam  */
116142441Smckusick /* ARGSUSED */
116242441Smckusick fchmod(p, uap, retval)
116342441Smckusick 	register struct proc *p;
116442441Smckusick 	register struct args {
11657701Ssam 		int	fd;
11667701Ssam 		int	fmode;
116742441Smckusick 	} *uap;
116842441Smckusick 	int *retval;
116942441Smckusick {
117037741Smckusick 	struct vattr vattr;
117137741Smckusick 	struct vnode *vp;
117237741Smckusick 	struct file *fp;
117337741Smckusick 	int error;
11747701Ssam 
117542441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
117637741Smckusick 		RETURN (error);
117741362Smckusick 	VATTR_NULL(&vattr);
117837741Smckusick 	vattr.va_mode = uap->fmode & 07777;
117937741Smckusick 	vp = (struct vnode *)fp->f_data;
118037741Smckusick 	VOP_LOCK(vp);
118141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
118237741Smckusick 		error = EROFS;
118337741Smckusick 		goto out;
11847439Sroot 	}
118537741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
118637741Smckusick out:
118737741Smckusick 	VOP_UNLOCK(vp);
118837741Smckusick 	RETURN (error);
11895992Swnj }
11905992Swnj 
11919167Ssam /*
11929167Ssam  * Set ownership given a path name.
11939167Ssam  */
119442441Smckusick /* ARGSUSED */
119542441Smckusick chown(p, uap, retval)
119642441Smckusick 	register struct proc *p;
119742441Smckusick 	register struct args {
11986254Sroot 		char	*fname;
11996254Sroot 		int	uid;
12006254Sroot 		int	gid;
120142441Smckusick 	} *uap;
120242441Smckusick 	int *retval;
120342441Smckusick {
120442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
120537741Smckusick 	register struct vnode *vp;
120637741Smckusick 	struct vattr vattr;
120737741Smckusick 	int error;
120837Sbill 
120937741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
121036614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
121136614Sbostic 	ndp->ni_dirp = uap->fname;
121241362Smckusick 	VATTR_NULL(&vattr);
121337741Smckusick 	vattr.va_uid = uap->uid;
121437741Smckusick 	vattr.va_gid = uap->gid;
121537741Smckusick 	if (error = namei(ndp))
121637741Smckusick 		RETURN (error);
121737741Smckusick 	vp = ndp->ni_vp;
121841400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
121937741Smckusick 		error = EROFS;
122037741Smckusick 		goto out;
122137741Smckusick 	}
122237741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
122337741Smckusick out:
122437741Smckusick 	vput(vp);
122537741Smckusick 	RETURN (error);
12267701Ssam }
12277439Sroot 
12289167Ssam /*
12299167Ssam  * Set ownership given a file descriptor.
12309167Ssam  */
123142441Smckusick /* ARGSUSED */
123242441Smckusick fchown(p, uap, retval)
123342441Smckusick 	register struct proc *p;
123442441Smckusick 	register struct args {
12357701Ssam 		int	fd;
12367701Ssam 		int	uid;
12377701Ssam 		int	gid;
123842441Smckusick 	} *uap;
123942441Smckusick 	int *retval;
124042441Smckusick {
124137741Smckusick 	struct vattr vattr;
124237741Smckusick 	struct vnode *vp;
124337741Smckusick 	struct file *fp;
124437741Smckusick 	int error;
12457701Ssam 
124642441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
124737741Smckusick 		RETURN (error);
124841362Smckusick 	VATTR_NULL(&vattr);
124937741Smckusick 	vattr.va_uid = uap->uid;
125037741Smckusick 	vattr.va_gid = uap->gid;
125137741Smckusick 	vp = (struct vnode *)fp->f_data;
125237741Smckusick 	VOP_LOCK(vp);
125341400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
125437741Smckusick 		error = EROFS;
125537741Smckusick 		goto out;
125637741Smckusick 	}
125737741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
125837741Smckusick out:
125937741Smckusick 	VOP_UNLOCK(vp);
126037741Smckusick 	RETURN (error);
12617701Ssam }
12627701Ssam 
126342441Smckusick /*
126442441Smckusick  * Set the access and modification times of a file.
126542441Smckusick  */
126642441Smckusick /* ARGSUSED */
126742441Smckusick utimes(p, uap, retval)
126842441Smckusick 	register struct proc *p;
126942441Smckusick 	register struct args {
127011811Ssam 		char	*fname;
127111811Ssam 		struct	timeval *tptr;
127242441Smckusick 	} *uap;
127342441Smckusick 	int *retval;
127442441Smckusick {
127542441Smckusick 	register struct nameidata *ndp = &u.u_nd;
127637741Smckusick 	register struct vnode *vp;
127711811Ssam 	struct timeval tv[2];
127837741Smckusick 	struct vattr vattr;
127937741Smckusick 	int error;
128011811Ssam 
128137741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
128237741Smckusick 		RETURN (error);
128337741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
128437741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
128537741Smckusick 	ndp->ni_dirp = uap->fname;
128641362Smckusick 	VATTR_NULL(&vattr);
128737741Smckusick 	vattr.va_atime = tv[0];
128837741Smckusick 	vattr.va_mtime = tv[1];
128937741Smckusick 	if (error = namei(ndp))
129037741Smckusick 		RETURN (error);
129137741Smckusick 	vp = ndp->ni_vp;
129241400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
129337741Smckusick 		error = EROFS;
129437741Smckusick 		goto out;
129521015Smckusick 	}
129637741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
129737741Smckusick out:
129837741Smckusick 	vput(vp);
129937741Smckusick 	RETURN (error);
130011811Ssam }
130111811Ssam 
13029167Ssam /*
13039167Ssam  * Truncate a file given its path name.
13049167Ssam  */
130542441Smckusick /* ARGSUSED */
130642441Smckusick truncate(p, uap, retval)
130742441Smckusick 	register struct proc *p;
130842441Smckusick 	register struct args {
13097701Ssam 		char	*fname;
131026473Skarels 		off_t	length;
131142441Smckusick 	} *uap;
131242441Smckusick 	int *retval;
131342441Smckusick {
131442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
131537741Smckusick 	register struct vnode *vp;
131637741Smckusick 	struct vattr vattr;
131737741Smckusick 	int error;
13187701Ssam 
131937741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
132016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
132116694Smckusick 	ndp->ni_dirp = uap->fname;
132241362Smckusick 	VATTR_NULL(&vattr);
132337741Smckusick 	vattr.va_size = uap->length;
132437741Smckusick 	if (error = namei(ndp))
132537741Smckusick 		RETURN (error);
132637741Smckusick 	vp = ndp->ni_vp;
132737741Smckusick 	if (vp->v_type == VDIR) {
132837741Smckusick 		error = EISDIR;
132937741Smckusick 		goto out;
13307701Ssam 	}
133138399Smckusick 	if ((error = vn_writechk(vp)) ||
133238399Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
133337741Smckusick 		goto out;
133437741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
133537741Smckusick out:
133637741Smckusick 	vput(vp);
133737741Smckusick 	RETURN (error);
13387701Ssam }
13397701Ssam 
13409167Ssam /*
13419167Ssam  * Truncate a file given a file descriptor.
13429167Ssam  */
134342441Smckusick /* ARGSUSED */
134442441Smckusick ftruncate(p, uap, retval)
134542441Smckusick 	register struct proc *p;
134642441Smckusick 	register struct args {
13477701Ssam 		int	fd;
134826473Skarels 		off_t	length;
134942441Smckusick 	} *uap;
135042441Smckusick 	int *retval;
135142441Smckusick {
135237741Smckusick 	struct vattr vattr;
135337741Smckusick 	struct vnode *vp;
13547701Ssam 	struct file *fp;
135537741Smckusick 	int error;
13567701Ssam 
135742441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
135837741Smckusick 		RETURN (error);
135937741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
136037741Smckusick 		RETURN (EINVAL);
136141362Smckusick 	VATTR_NULL(&vattr);
136237741Smckusick 	vattr.va_size = uap->length;
136337741Smckusick 	vp = (struct vnode *)fp->f_data;
136437741Smckusick 	VOP_LOCK(vp);
136537741Smckusick 	if (vp->v_type == VDIR) {
136637741Smckusick 		error = EISDIR;
136737741Smckusick 		goto out;
13687701Ssam 	}
136938399Smckusick 	if (error = vn_writechk(vp))
137037741Smckusick 		goto out;
137137741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
137237741Smckusick out:
137337741Smckusick 	VOP_UNLOCK(vp);
137437741Smckusick 	RETURN (error);
13757701Ssam }
13767701Ssam 
13779167Ssam /*
13789167Ssam  * Synch an open file.
13799167Ssam  */
138042441Smckusick /* ARGSUSED */
138142441Smckusick fsync(p, uap, retval)
138242441Smckusick 	register struct proc *p;
138342441Smckusick 	struct args {
138442441Smckusick 		int	fd;
138542441Smckusick 	} *uap;
138642441Smckusick 	int *retval;
13879167Ssam {
138839592Smckusick 	register struct vnode *vp;
13899167Ssam 	struct file *fp;
139037741Smckusick 	int error;
13919167Ssam 
139242441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
139337741Smckusick 		RETURN (error);
139439592Smckusick 	vp = (struct vnode *)fp->f_data;
139539592Smckusick 	VOP_LOCK(vp);
139639592Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT);
139739592Smckusick 	VOP_UNLOCK(vp);
139837741Smckusick 	RETURN (error);
13999167Ssam }
14009167Ssam 
14019167Ssam /*
14029167Ssam  * Rename system call.
14039167Ssam  *
14049167Ssam  * Source and destination must either both be directories, or both
14059167Ssam  * not be directories.  If target is a directory, it must be empty.
14069167Ssam  */
140742441Smckusick /* ARGSUSED */
140842441Smckusick rename(p, uap, retval)
140942441Smckusick 	register struct proc *p;
141042441Smckusick 	register struct args {
14117701Ssam 		char	*from;
14127701Ssam 		char	*to;
141342441Smckusick 	} *uap;
141442441Smckusick 	int *retval;
141542441Smckusick {
141637741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
141742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
141837741Smckusick 	struct nameidata tond;
141937741Smckusick 	int error;
14207701Ssam 
142137741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
142216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
142316694Smckusick 	ndp->ni_dirp = uap->from;
142437741Smckusick 	if (error = namei(ndp))
142537741Smckusick 		RETURN (error);
142637741Smckusick 	fvp = ndp->ni_vp;
142738266Smckusick 	nddup(ndp, &tond);
142837741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
142937741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
143037741Smckusick 	tond.ni_dirp = uap->to;
143142465Smckusick 	if (error = namei(&tond)) {
143242465Smckusick 		VOP_ABORTOP(ndp);
143342465Smckusick 		vrele(ndp->ni_dvp);
143442465Smckusick 		vrele(fvp);
143542465Smckusick 		goto out1;
143642465Smckusick 	}
143737741Smckusick 	tdvp = tond.ni_dvp;
143837741Smckusick 	tvp = tond.ni_vp;
143937741Smckusick 	if (tvp != NULL) {
144037741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
144139242Sbostic 			error = ENOTDIR;
144237741Smckusick 			goto out;
144337741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
144439242Sbostic 			error = EISDIR;
144537741Smckusick 			goto out;
14469167Ssam 		}
14479167Ssam 	}
144837741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
144937741Smckusick 		error = EXDEV;
14509167Ssam 		goto out;
145110051Ssam 	}
145239286Smckusick 	if (fvp == tdvp)
145337741Smckusick 		error = EINVAL;
145439286Smckusick 	/*
145539286Smckusick 	 * If source is the same as the destination,
145639286Smckusick 	 * then there is nothing to do.
145739286Smckusick 	 */
145839286Smckusick 	if (fvp == tvp)
145939286Smckusick 		error = -1;
146037741Smckusick out:
146142465Smckusick 	if (!error) {
146242465Smckusick 		error = VOP_RENAME(ndp, &tond);
146342465Smckusick 	} else {
146437741Smckusick 		VOP_ABORTOP(&tond);
146543344Smckusick 		if (tdvp == tvp)
146643344Smckusick 			vrele(tdvp);
146743344Smckusick 		else
146843344Smckusick 			vput(tdvp);
146942465Smckusick 		if (tvp)
147042465Smckusick 			vput(tvp);
147137741Smckusick 		VOP_ABORTOP(ndp);
147242465Smckusick 		vrele(ndp->ni_dvp);
147342465Smckusick 		vrele(fvp);
14749167Ssam 	}
147537741Smckusick out1:
147638266Smckusick 	ndrele(&tond);
147739286Smckusick 	if (error == -1)
147839286Smckusick 		RETURN (0);
147937741Smckusick 	RETURN (error);
14807701Ssam }
14817701Ssam 
14827535Sroot /*
148312756Ssam  * Mkdir system call
148412756Ssam  */
148542441Smckusick /* ARGSUSED */
148642441Smckusick mkdir(p, uap, retval)
148742441Smckusick 	register struct proc *p;
148842441Smckusick 	register struct args {
148912756Ssam 		char	*name;
149012756Ssam 		int	dmode;
149142441Smckusick 	} *uap;
149242441Smckusick 	int *retval;
149342441Smckusick {
149442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
149537741Smckusick 	register struct vnode *vp;
149637741Smckusick 	struct vattr vattr;
149737741Smckusick 	int error;
149812756Ssam 
149937741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
150016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
150116694Smckusick 	ndp->ni_dirp = uap->name;
150237741Smckusick 	if (error = namei(ndp))
150337741Smckusick 		RETURN (error);
150437741Smckusick 	vp = ndp->ni_vp;
150537741Smckusick 	if (vp != NULL) {
150637741Smckusick 		VOP_ABORTOP(ndp);
150743344Smckusick 		if (ndp->ni_dvp == vp)
150843344Smckusick 			vrele(ndp->ni_dvp);
150943344Smckusick 		else
151043344Smckusick 			vput(ndp->ni_dvp);
151142465Smckusick 		vrele(vp);
151237741Smckusick 		RETURN (EEXIST);
151312756Ssam 	}
151441362Smckusick 	VATTR_NULL(&vattr);
151537741Smckusick 	vattr.va_type = VDIR;
151642441Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask;
151737741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
151838145Smckusick 	if (!error)
151938145Smckusick 		vput(ndp->ni_vp);
152037741Smckusick 	RETURN (error);
152112756Ssam }
152212756Ssam 
152312756Ssam /*
152412756Ssam  * Rmdir system call.
152512756Ssam  */
152642441Smckusick /* ARGSUSED */
152742441Smckusick rmdir(p, uap, retval)
152842441Smckusick 	register struct proc *p;
152942441Smckusick 	struct args {
153042441Smckusick 		char	*name;
153142441Smckusick 	} *uap;
153242441Smckusick 	int *retval;
153312756Ssam {
153442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
153537741Smckusick 	register struct vnode *vp;
153637741Smckusick 	int error;
153712756Ssam 
153837741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
153916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
154016694Smckusick 	ndp->ni_dirp = uap->name;
154137741Smckusick 	if (error = namei(ndp))
154237741Smckusick 		RETURN (error);
154337741Smckusick 	vp = ndp->ni_vp;
154437741Smckusick 	if (vp->v_type != VDIR) {
154537741Smckusick 		error = ENOTDIR;
154612756Ssam 		goto out;
154712756Ssam 	}
154812756Ssam 	/*
154937741Smckusick 	 * No rmdir "." please.
155012756Ssam 	 */
155137741Smckusick 	if (ndp->ni_dvp == vp) {
155237741Smckusick 		error = EINVAL;
155312756Ssam 		goto out;
155412756Ssam 	}
155512756Ssam 	/*
155637741Smckusick 	 * Don't unlink a mounted file.
155712756Ssam 	 */
155837741Smckusick 	if (vp->v_flag & VROOT)
155937741Smckusick 		error = EBUSY;
156012756Ssam out:
156142465Smckusick 	if (!error) {
156242465Smckusick 		error = VOP_RMDIR(ndp);
156342465Smckusick 	} else {
156437741Smckusick 		VOP_ABORTOP(ndp);
156543344Smckusick 		if (ndp->ni_dvp == vp)
156643344Smckusick 			vrele(ndp->ni_dvp);
156743344Smckusick 		else
156843344Smckusick 			vput(ndp->ni_dvp);
156942465Smckusick 		vput(vp);
157042465Smckusick 	}
157137741Smckusick 	RETURN (error);
157212756Ssam }
157312756Ssam 
157437741Smckusick /*
157537741Smckusick  * Read a block of directory entries in a file system independent format
157637741Smckusick  */
157742441Smckusick getdirentries(p, uap, retval)
157842441Smckusick 	register struct proc *p;
157942441Smckusick 	register struct args {
158037741Smckusick 		int	fd;
158137741Smckusick 		char	*buf;
158237741Smckusick 		unsigned count;
158337741Smckusick 		long	*basep;
158442441Smckusick 	} *uap;
158542441Smckusick 	int *retval;
158642441Smckusick {
158739592Smckusick 	register struct vnode *vp;
158816540Ssam 	struct file *fp;
158937741Smckusick 	struct uio auio;
159037741Smckusick 	struct iovec aiov;
159138129Smckusick 	off_t off;
159240321Smckusick 	int error, eofflag;
159312756Ssam 
159442441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
159537741Smckusick 		RETURN (error);
159637741Smckusick 	if ((fp->f_flag & FREAD) == 0)
159737741Smckusick 		RETURN (EBADF);
159839592Smckusick 	vp = (struct vnode *)fp->f_data;
159939592Smckusick 	if (vp->v_type != VDIR)
160039592Smckusick 		RETURN (EINVAL);
160137741Smckusick 	aiov.iov_base = uap->buf;
160237741Smckusick 	aiov.iov_len = uap->count;
160337741Smckusick 	auio.uio_iov = &aiov;
160437741Smckusick 	auio.uio_iovcnt = 1;
160537741Smckusick 	auio.uio_rw = UIO_READ;
160637741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
160737741Smckusick 	auio.uio_resid = uap->count;
160839592Smckusick 	VOP_LOCK(vp);
160939592Smckusick 	auio.uio_offset = off = fp->f_offset;
161040321Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
161139592Smckusick 	fp->f_offset = auio.uio_offset;
161239592Smckusick 	VOP_UNLOCK(vp);
161339592Smckusick 	if (error)
161437741Smckusick 		RETURN (error);
161539592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
161642441Smckusick 	*retval = uap->count - auio.uio_resid;
161737741Smckusick 	RETURN (error);
161812756Ssam }
161912756Ssam 
162012756Ssam /*
162112756Ssam  * mode mask for creation of files
162212756Ssam  */
162342441Smckusick mode_t
162442441Smckusick umask(p, uap, retval)
162542441Smckusick 	register struct proc *p;
162642441Smckusick 	struct args {
162742441Smckusick 		int	mask;
162842441Smckusick 	} *uap;
162942441Smckusick 	int *retval;
163012756Ssam {
163112756Ssam 
163242441Smckusick 	*retval = u.u_cmask;
163342441Smckusick 	u.u_cmask = uap->mask & 07777;
163437741Smckusick 	RETURN (0);
163512756Ssam }
163637741Smckusick 
163739566Smarc /*
163839566Smarc  * Void all references to file by ripping underlying filesystem
163939566Smarc  * away from vnode.
164039566Smarc  */
164142441Smckusick /* ARGSUSED */
164242441Smckusick revoke(p, uap, retval)
164342441Smckusick 	register struct proc *p;
164442441Smckusick 	register struct args {
164539566Smarc 		char	*fname;
164642441Smckusick 	} *uap;
164742441Smckusick 	int *retval;
164842441Smckusick {
164942441Smckusick 	register struct nameidata *ndp = &u.u_nd;
165039566Smarc 	register struct vnode *vp;
165139566Smarc 	struct vattr vattr;
165239566Smarc 	int error;
165339566Smarc 
165439566Smarc 	ndp->ni_nameiop = LOOKUP | FOLLOW;
165539566Smarc 	ndp->ni_segflg = UIO_USERSPACE;
165639566Smarc 	ndp->ni_dirp = uap->fname;
165739566Smarc 	if (error = namei(ndp))
165839566Smarc 		RETURN (error);
165939566Smarc 	vp = ndp->ni_vp;
166039566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
166139566Smarc 		error = EINVAL;
166239566Smarc 		goto out;
166339566Smarc 	}
166442441Smckusick 	if (error = VOP_GETATTR(vp, &vattr, ndp->ni_cred))
166539566Smarc 		goto out;
166642955Smckusick 	if (ndp->ni_cred->cr_uid != vattr.va_uid &&
166742441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
166839566Smarc 		goto out;
166939805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
167039632Smckusick 		vgoneall(vp);
167139566Smarc out:
167239566Smarc 	vrele(vp);
167339566Smarc 	RETURN (error);
167439566Smarc }
167539566Smarc 
167638408Smckusick getvnode(ofile, fdes, fpp)
167738408Smckusick 	struct file *ofile[];
167837741Smckusick 	struct file **fpp;
167937741Smckusick 	int fdes;
168037741Smckusick {
168137741Smckusick 	struct file *fp;
168237741Smckusick 
168338408Smckusick 	if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
168437741Smckusick 		return (EBADF);
168537741Smckusick 	if (fp->f_type != DTYPE_VNODE)
168637741Smckusick 		return (EINVAL);
168737741Smckusick 	*fpp = fp;
168837741Smckusick 	return (0);
168937741Smckusick }
1690