xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 43344)
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*43344Smckusick  *	@(#)vfs_syscalls.c	7.51 (Berkeley) 06/21/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
3342441Smckusick #define RETURN(val)	{ u.u_error = (val); if (u.u_spare[0] != 0) panic("lock count"); return (u.u_error); }
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;
56142441Smckusick 	u.u_r.u_rv.R_val1 = indx;		/* XXX for fdopen() */
56242441Smckusick 	if (error = vn_open(ndp, fmode, cmode)) {
56337741Smckusick 		crfree(fp->f_cred);
56437741Smckusick 		fp->f_count--;
56542441Smckusick 		if (error == EJUSTRETURN) {	/* XXX from fdopen */
56642441Smckusick 			*retval = indx;
56742441Smckusick 			RETURN (0);
56842441Smckusick 		}
56940884Smckusick 		if (error == ERESTART)
57040884Smckusick 			error = EINTR;
57142441Smckusick 		u.u_ofile[indx] = NULL;
57242441Smckusick 		RETURN (error);
57312756Ssam 	}
57437741Smckusick 	fp->f_flag = fmode & FMASK;
57537741Smckusick 	fp->f_type = DTYPE_VNODE;
57637741Smckusick 	fp->f_ops = &vnops;
57737741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
57842441Smckusick 	*retval = indx;
57942441Smckusick 	RETURN (0);
5806254Sroot }
5816254Sroot 
58242955Smckusick #ifdef COMPAT_43
5836254Sroot /*
58442441Smckusick  * Creat system call.
5856254Sroot  */
58642955Smckusick ocreat(p, uap, retval)
58742441Smckusick 	struct proc *p;
58842441Smckusick 	register struct args {
58942441Smckusick 		char	*fname;
59042441Smckusick 		int	fmode;
59142441Smckusick 	} *uap;
59242441Smckusick 	int *retval;
5936254Sroot {
59442441Smckusick 	struct args {
5956254Sroot 		char	*fname;
59642441Smckusick 		int	mode;
59742441Smckusick 		int	crtmode;
59842441Smckusick 	} openuap;
59942441Smckusick 
60042441Smckusick 	openuap.fname = uap->fname;
60142441Smckusick 	openuap.crtmode = uap->fmode;
60242441Smckusick 	openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
60342441Smckusick 	RETURN (open(p, &openuap, retval));
60442441Smckusick }
60542955Smckusick #endif /* COMPAT_43 */
60642441Smckusick 
60742441Smckusick /*
60842441Smckusick  * Mknod system call
60942441Smckusick  */
61042441Smckusick /* ARGSUSED */
61142441Smckusick mknod(p, uap, retval)
61242441Smckusick 	register struct proc *p;
61342441Smckusick 	register struct args {
61442441Smckusick 		char	*fname;
6156254Sroot 		int	fmode;
6166254Sroot 		int	dev;
61742441Smckusick 	} *uap;
61842441Smckusick 	int *retval;
61942441Smckusick {
62042441Smckusick 	register struct nameidata *ndp = &u.u_nd;
62137741Smckusick 	register struct vnode *vp;
62237741Smckusick 	struct vattr vattr;
62337741Smckusick 	int error;
6246254Sroot 
62542441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
62637741Smckusick 		RETURN (error);
62737741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
62816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
62916694Smckusick 	ndp->ni_dirp = uap->fname;
63037741Smckusick 	if (error = namei(ndp))
63137741Smckusick 		RETURN (error);
63237741Smckusick 	vp = ndp->ni_vp;
63337741Smckusick 	if (vp != NULL) {
63437741Smckusick 		error = EEXIST;
63512756Ssam 		goto out;
6366254Sroot 	}
63741362Smckusick 	VATTR_NULL(&vattr);
63840635Smckusick 	switch (uap->fmode & S_IFMT) {
63912756Ssam 
64040635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
64137741Smckusick 		vattr.va_type = VBAD;
64237741Smckusick 		break;
64340635Smckusick 	case S_IFCHR:
64437741Smckusick 		vattr.va_type = VCHR;
64537741Smckusick 		break;
64640635Smckusick 	case S_IFBLK:
64737741Smckusick 		vattr.va_type = VBLK;
64837741Smckusick 		break;
64937741Smckusick 	default:
65037741Smckusick 		error = EINVAL;
65137741Smckusick 		goto out;
6526254Sroot 	}
65342441Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask;
65437741Smckusick 	vattr.va_rdev = uap->dev;
6556254Sroot out:
65642465Smckusick 	if (!error) {
65742465Smckusick 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
65842465Smckusick 	} else {
65937741Smckusick 		VOP_ABORTOP(ndp);
660*43344Smckusick 		if (ndp->ni_dvp == vp)
661*43344Smckusick 			vrele(ndp->ni_dvp);
662*43344Smckusick 		else
663*43344Smckusick 			vput(ndp->ni_dvp);
66442465Smckusick 		if (vp)
66542465Smckusick 			vrele(vp);
66642465Smckusick 	}
66737741Smckusick 	RETURN (error);
6686254Sroot }
6696254Sroot 
6706254Sroot /*
67140285Smckusick  * Mkfifo system call
67240285Smckusick  */
67342441Smckusick /* ARGSUSED */
67442441Smckusick mkfifo(p, uap, retval)
67542441Smckusick 	register struct proc *p;
67642441Smckusick 	register struct args {
67740285Smckusick 		char	*fname;
67840285Smckusick 		int	fmode;
67942441Smckusick 	} *uap;
68042441Smckusick 	int *retval;
68142441Smckusick {
68242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
68340285Smckusick 	struct vattr vattr;
68440285Smckusick 	int error;
68540285Smckusick 
68640285Smckusick #ifndef FIFO
68740285Smckusick 	RETURN (EOPNOTSUPP);
68840285Smckusick #else
68940285Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
69040285Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
69140285Smckusick 	ndp->ni_dirp = uap->fname;
69240285Smckusick 	if (error = namei(ndp))
69340285Smckusick 		RETURN (error);
69440285Smckusick 	if (ndp->ni_vp != NULL) {
69540285Smckusick 		VOP_ABORTOP(ndp);
696*43344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
697*43344Smckusick 			vrele(ndp->ni_dvp);
698*43344Smckusick 		else
699*43344Smckusick 			vput(ndp->ni_dvp);
70042465Smckusick 		vrele(ndp->ni_vp);
70140285Smckusick 		RETURN (EEXIST);
70240285Smckusick 	} else {
70341362Smckusick 		VATTR_NULL(&vattr);
70440285Smckusick 		vattr.va_type = VFIFO;
70542441Smckusick 		vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask;
70640285Smckusick 	}
70740285Smckusick 	RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred));
70840285Smckusick #endif /* FIFO */
70940285Smckusick }
71040285Smckusick 
71140285Smckusick /*
7126254Sroot  * link system call
7136254Sroot  */
71442441Smckusick /* ARGSUSED */
71542441Smckusick link(p, uap, retval)
71642441Smckusick 	register struct proc *p;
71742441Smckusick 	register struct args {
7186254Sroot 		char	*target;
7196254Sroot 		char	*linkname;
72042441Smckusick 	} *uap;
72142441Smckusick 	int *retval;
72242441Smckusick {
72342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
72437741Smckusick 	register struct vnode *vp, *xp;
72537741Smckusick 	int error;
7266254Sroot 
72716694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
72816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
72916694Smckusick 	ndp->ni_dirp = uap->target;
73037741Smckusick 	if (error = namei(ndp))
73137741Smckusick 		RETURN (error);
73237741Smckusick 	vp = ndp->ni_vp;
73337741Smckusick 	if (vp->v_type == VDIR &&
73442441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
73537741Smckusick 		goto out1;
73637741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
73716694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
73837741Smckusick 	if (error = namei(ndp))
73937741Smckusick 		goto out1;
74037741Smckusick 	xp = ndp->ni_vp;
7416254Sroot 	if (xp != NULL) {
74237741Smckusick 		error = EEXIST;
7436254Sroot 		goto out;
7446254Sroot 	}
74537741Smckusick 	xp = ndp->ni_dvp;
74637741Smckusick 	if (vp->v_mount != xp->v_mount)
74737741Smckusick 		error = EXDEV;
7486254Sroot out:
74942465Smckusick 	if (!error) {
75042465Smckusick 		error = VOP_LINK(vp, ndp);
75142465Smckusick 	} else {
75237741Smckusick 		VOP_ABORTOP(ndp);
753*43344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
754*43344Smckusick 			vrele(ndp->ni_dvp);
755*43344Smckusick 		else
756*43344Smckusick 			vput(ndp->ni_dvp);
75742465Smckusick 		if (ndp->ni_vp)
75842465Smckusick 			vrele(ndp->ni_vp);
75942465Smckusick 	}
76037741Smckusick out1:
76137741Smckusick 	vrele(vp);
76237741Smckusick 	RETURN (error);
7636254Sroot }
7646254Sroot 
7656254Sroot /*
7666254Sroot  * symlink -- make a symbolic link
7676254Sroot  */
76842441Smckusick /* ARGSUSED */
76942441Smckusick symlink(p, uap, retval)
77042441Smckusick 	register struct proc *p;
77142441Smckusick 	register struct args {
7726254Sroot 		char	*target;
7736254Sroot 		char	*linkname;
77442441Smckusick 	} *uap;
77542441Smckusick 	int *retval;
77642441Smckusick {
77742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
77837741Smckusick 	struct vattr vattr;
77937741Smckusick 	char *target;
78037741Smckusick 	int error;
7816254Sroot 
78216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
78316694Smckusick 	ndp->ni_dirp = uap->linkname;
78437741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
78537741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
78642465Smckusick 		goto out;
78737741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
78837741Smckusick 	if (error = namei(ndp))
78942465Smckusick 		goto out;
79042465Smckusick 	if (ndp->ni_vp) {
79142465Smckusick 		VOP_ABORTOP(ndp);
792*43344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
793*43344Smckusick 			vrele(ndp->ni_dvp);
794*43344Smckusick 		else
795*43344Smckusick 			vput(ndp->ni_dvp);
79642465Smckusick 		vrele(ndp->ni_vp);
79737741Smckusick 		error = EEXIST;
79837741Smckusick 		goto out;
7996254Sroot 	}
80041362Smckusick 	VATTR_NULL(&vattr);
80142441Smckusick 	vattr.va_mode = 0777 &~ u.u_cmask;
80242465Smckusick 	error = VOP_SYMLINK(ndp, &vattr, target);
80337741Smckusick out:
80437741Smckusick 	FREE(target, M_NAMEI);
80537741Smckusick 	RETURN (error);
8066254Sroot }
8076254Sroot 
8086254Sroot /*
8096254Sroot  * Unlink system call.
8106254Sroot  * Hard to avoid races here, especially
8116254Sroot  * in unlinking directories.
8126254Sroot  */
81342441Smckusick /* ARGSUSED */
81442441Smckusick unlink(p, uap, retval)
81542441Smckusick 	register struct proc *p;
81642441Smckusick 	struct args {
81742441Smckusick 		char	*fname;
81842441Smckusick 	} *uap;
81942441Smckusick 	int *retval;
8206254Sroot {
82142441Smckusick 	register struct nameidata *ndp = &u.u_nd;
82237741Smckusick 	register struct vnode *vp;
82337741Smckusick 	int error;
8246254Sroot 
82537741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
82616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
82716694Smckusick 	ndp->ni_dirp = uap->fname;
82837741Smckusick 	if (error = namei(ndp))
82937741Smckusick 		RETURN (error);
83037741Smckusick 	vp = ndp->ni_vp;
83137741Smckusick 	if (vp->v_type == VDIR &&
83242441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
8336254Sroot 		goto out;
8346254Sroot 	/*
8356254Sroot 	 * Don't unlink a mounted file.
8366254Sroot 	 */
83737741Smckusick 	if (vp->v_flag & VROOT) {
83837741Smckusick 		error = EBUSY;
8396254Sroot 		goto out;
8406254Sroot 	}
84137741Smckusick 	if (vp->v_flag & VTEXT)
84237741Smckusick 		xrele(vp);	/* try once to free text */
8436254Sroot out:
84442465Smckusick 	if (!error) {
84542465Smckusick 		error = VOP_REMOVE(ndp);
84642465Smckusick 	} else {
84737741Smckusick 		VOP_ABORTOP(ndp);
848*43344Smckusick 		if (ndp->ni_dvp == vp)
849*43344Smckusick 			vrele(ndp->ni_dvp);
850*43344Smckusick 		else
851*43344Smckusick 			vput(ndp->ni_dvp);
85242465Smckusick 		vput(vp);
85342465Smckusick 	}
85437741Smckusick 	RETURN (error);
8556254Sroot }
8566254Sroot 
8576254Sroot /*
8586254Sroot  * Seek system call
8596254Sroot  */
86042441Smckusick lseek(p, uap, retval)
86142441Smckusick 	register struct proc *p;
86242441Smckusick 	register struct args {
86337741Smckusick 		int	fdes;
8646254Sroot 		off_t	off;
8656254Sroot 		int	sbase;
86642441Smckusick 	} *uap;
86742441Smckusick 	off_t *retval;
86842441Smckusick {
86942441Smckusick 	struct ucred *cred = u.u_nd.ni_cred;
87042441Smckusick 	register struct file *fp;
87137741Smckusick 	struct vattr vattr;
87237741Smckusick 	int error;
8736254Sroot 
87437741Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
87542441Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
87637741Smckusick 		RETURN (EBADF);
87737741Smckusick 	if (fp->f_type != DTYPE_VNODE)
87837741Smckusick 		RETURN (ESPIPE);
87913878Ssam 	switch (uap->sbase) {
88013878Ssam 
88113878Ssam 	case L_INCR:
88213878Ssam 		fp->f_offset += uap->off;
88313878Ssam 		break;
88413878Ssam 
88513878Ssam 	case L_XTND:
88637741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
88742441Smckusick 		    &vattr, cred))
88837741Smckusick 			RETURN (error);
88937741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
89013878Ssam 		break;
89113878Ssam 
89213878Ssam 	case L_SET:
89313878Ssam 		fp->f_offset = uap->off;
89413878Ssam 		break;
89513878Ssam 
89613878Ssam 	default:
89737741Smckusick 		RETURN (EINVAL);
89813878Ssam 	}
89942441Smckusick 	*retval = fp->f_offset;
90037741Smckusick 	RETURN (0);
9016254Sroot }
9026254Sroot 
9036254Sroot /*
9046254Sroot  * Access system call
9056254Sroot  */
90642441Smckusick /* ARGSUSED */
90742441Smckusick saccess(p, uap, retval)
90842441Smckusick 	register struct proc *p;
90942441Smckusick 	register struct args {
9106254Sroot 		char	*fname;
9116254Sroot 		int	fmode;
91242441Smckusick 	} *uap;
91342441Smckusick 	int *retval;
91442441Smckusick {
91542441Smckusick 	register struct nameidata *ndp = &u.u_nd;
91642441Smckusick 	register struct ucred *cred = ndp->ni_cred;
91737741Smckusick 	register struct vnode *vp;
91837741Smckusick 	int error, mode, svuid, svgid;
9196254Sroot 
92042441Smckusick 	svuid = cred->cr_uid;
92142441Smckusick 	svgid = cred->cr_groups[0];
92242441Smckusick 	cred->cr_uid = p->p_ruid;
92342441Smckusick 	cred->cr_groups[0] = p->p_rgid;
92437741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
92516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
92616694Smckusick 	ndp->ni_dirp = uap->fname;
92737741Smckusick 	if (error = namei(ndp))
92837741Smckusick 		goto out1;
92937741Smckusick 	vp = ndp->ni_vp;
93037741Smckusick 	/*
93137741Smckusick 	 * fmode == 0 means only check for exist
93237741Smckusick 	 */
93337741Smckusick 	if (uap->fmode) {
93437741Smckusick 		mode = 0;
93537741Smckusick 		if (uap->fmode & R_OK)
93637741Smckusick 			mode |= VREAD;
93737741Smckusick 		if (uap->fmode & W_OK)
93837741Smckusick 			mode |= VWRITE;
93937741Smckusick 		if (uap->fmode & X_OK)
94037741Smckusick 			mode |= VEXEC;
94139543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
94238399Smckusick 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
9436254Sroot 	}
94437741Smckusick 	vput(vp);
94537741Smckusick out1:
94642441Smckusick 	cred->cr_uid = svuid;
94742441Smckusick 	cred->cr_groups[0] = svgid;
94837741Smckusick 	RETURN (error);
9496254Sroot }
9506254Sroot 
9516254Sroot /*
9526574Smckusic  * Stat system call.  This version follows links.
95337Sbill  */
95442441Smckusick /* ARGSUSED */
95542441Smckusick stat(p, uap, retval)
95642441Smckusick 	register struct proc *p;
95742441Smckusick 	register struct args {
95842441Smckusick 		char	*fname;
95942441Smckusick 		struct stat *ub;
96042441Smckusick 	} *uap;
96142441Smckusick 	int *retval;
96237Sbill {
96342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
96442441Smckusick 	struct stat sb;
96542441Smckusick 	int error;
96637Sbill 
96742441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
96842441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
96942441Smckusick 	ndp->ni_dirp = uap->fname;
97042441Smckusick 	if (error = namei(ndp))
97142441Smckusick 		RETURN (error);
97242441Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
97342441Smckusick 	vput(ndp->ni_vp);
97442441Smckusick 	if (error)
97542441Smckusick 		RETURN (error);
97642441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
97742441Smckusick 	RETURN (error);
97837Sbill }
97937Sbill 
98037Sbill /*
9816574Smckusic  * Lstat system call.  This version does not follow links.
9825992Swnj  */
98342441Smckusick /* ARGSUSED */
98442441Smckusick lstat(p, uap, retval)
98542441Smckusick 	register struct proc *p;
98642441Smckusick 	register struct args {
9875992Swnj 		char	*fname;
98812756Ssam 		struct stat *ub;
98942441Smckusick 	} *uap;
99042441Smckusick 	int *retval;
99142441Smckusick {
99242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
99312756Ssam 	struct stat sb;
99437741Smckusick 	int error;
9955992Swnj 
99642441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW;
99716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
99816694Smckusick 	ndp->ni_dirp = uap->fname;
99937741Smckusick 	if (error = namei(ndp))
100037741Smckusick 		RETURN (error);
100137741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
100237741Smckusick 	vput(ndp->ni_vp);
100337741Smckusick 	if (error)
100437741Smckusick 		RETURN (error);
100537741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
100637741Smckusick 	RETURN (error);
10075992Swnj }
10085992Swnj 
10095992Swnj /*
10105992Swnj  * Return target name of a symbolic link
101137Sbill  */
101242441Smckusick /* ARGSUSED */
101342441Smckusick readlink(p, uap, retval)
101442441Smckusick 	register struct proc *p;
101542441Smckusick 	register struct args {
10165992Swnj 		char	*name;
10175992Swnj 		char	*buf;
10185992Swnj 		int	count;
101942441Smckusick 	} *uap;
102042441Smckusick 	int *retval;
102142441Smckusick {
102242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
102337741Smckusick 	register struct vnode *vp;
102437741Smckusick 	struct iovec aiov;
102537741Smckusick 	struct uio auio;
102637741Smckusick 	int error;
10275992Swnj 
102837741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
102916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
103016694Smckusick 	ndp->ni_dirp = uap->name;
103137741Smckusick 	if (error = namei(ndp))
103237741Smckusick 		RETURN (error);
103337741Smckusick 	vp = ndp->ni_vp;
103437741Smckusick 	if (vp->v_type != VLNK) {
103537741Smckusick 		error = EINVAL;
10365992Swnj 		goto out;
10375992Swnj 	}
103837741Smckusick 	aiov.iov_base = uap->buf;
103937741Smckusick 	aiov.iov_len = uap->count;
104037741Smckusick 	auio.uio_iov = &aiov;
104137741Smckusick 	auio.uio_iovcnt = 1;
104237741Smckusick 	auio.uio_offset = 0;
104337741Smckusick 	auio.uio_rw = UIO_READ;
104437741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
104537741Smckusick 	auio.uio_resid = uap->count;
104637741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
10475992Swnj out:
104837741Smckusick 	vput(vp);
104942441Smckusick 	*retval = uap->count - auio.uio_resid;
105037741Smckusick 	RETURN (error);
10515992Swnj }
10525992Swnj 
10539167Ssam /*
105438259Smckusick  * Change flags of a file given path name.
105538259Smckusick  */
105642441Smckusick /* ARGSUSED */
105742441Smckusick chflags(p, uap, retval)
105842441Smckusick 	register struct proc *p;
105942441Smckusick 	register struct args {
106038259Smckusick 		char	*fname;
106138259Smckusick 		int	flags;
106242441Smckusick 	} *uap;
106342441Smckusick 	int *retval;
106442441Smckusick {
106542441Smckusick 	register struct nameidata *ndp = &u.u_nd;
106638259Smckusick 	register struct vnode *vp;
106738259Smckusick 	struct vattr vattr;
106838259Smckusick 	int error;
106938259Smckusick 
107038259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
107138259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
107238259Smckusick 	ndp->ni_dirp = uap->fname;
107341362Smckusick 	VATTR_NULL(&vattr);
107438259Smckusick 	vattr.va_flags = uap->flags;
107538259Smckusick 	if (error = namei(ndp))
107638259Smckusick 		RETURN (error);
107738259Smckusick 	vp = ndp->ni_vp;
107841400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
107938259Smckusick 		error = EROFS;
108038259Smckusick 		goto out;
108138259Smckusick 	}
108238259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
108338259Smckusick out:
108438259Smckusick 	vput(vp);
108538259Smckusick 	RETURN (error);
108638259Smckusick }
108738259Smckusick 
108838259Smckusick /*
108938259Smckusick  * Change flags of a file given a file descriptor.
109038259Smckusick  */
109142441Smckusick /* ARGSUSED */
109242441Smckusick fchflags(p, uap, retval)
109342441Smckusick 	register struct proc *p;
109442441Smckusick 	register struct args {
109538259Smckusick 		int	fd;
109638259Smckusick 		int	flags;
109742441Smckusick 	} *uap;
109842441Smckusick 	int *retval;
109942441Smckusick {
110038259Smckusick 	struct vattr vattr;
110138259Smckusick 	struct vnode *vp;
110238259Smckusick 	struct file *fp;
110338259Smckusick 	int error;
110438259Smckusick 
110542441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
110638259Smckusick 		RETURN (error);
110741362Smckusick 	VATTR_NULL(&vattr);
110838259Smckusick 	vattr.va_flags = uap->flags;
110938259Smckusick 	vp = (struct vnode *)fp->f_data;
111038259Smckusick 	VOP_LOCK(vp);
111141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
111238259Smckusick 		error = EROFS;
111338259Smckusick 		goto out;
111438259Smckusick 	}
111538259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
111638259Smckusick out:
111738259Smckusick 	VOP_UNLOCK(vp);
111838259Smckusick 	RETURN (error);
111938259Smckusick }
112038259Smckusick 
112138259Smckusick /*
11229167Ssam  * Change mode of a file given path name.
11239167Ssam  */
112442441Smckusick /* ARGSUSED */
112542441Smckusick chmod(p, uap, retval)
112642441Smckusick 	register struct proc *p;
112742441Smckusick 	register struct args {
11286254Sroot 		char	*fname;
11296254Sroot 		int	fmode;
113042441Smckusick 	} *uap;
113142441Smckusick 	int *retval;
113242441Smckusick {
113342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
113437741Smckusick 	register struct vnode *vp;
113537741Smckusick 	struct vattr vattr;
113637741Smckusick 	int error;
11375992Swnj 
113837741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
113937741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
114037741Smckusick 	ndp->ni_dirp = uap->fname;
114141362Smckusick 	VATTR_NULL(&vattr);
114237741Smckusick 	vattr.va_mode = uap->fmode & 07777;
114337741Smckusick 	if (error = namei(ndp))
114437741Smckusick 		RETURN (error);
114537741Smckusick 	vp = ndp->ni_vp;
114641400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
114737741Smckusick 		error = EROFS;
114837741Smckusick 		goto out;
114937741Smckusick 	}
115037741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
115137741Smckusick out:
115237741Smckusick 	vput(vp);
115337741Smckusick 	RETURN (error);
11547701Ssam }
11557439Sroot 
11569167Ssam /*
11579167Ssam  * Change mode of a file given a file descriptor.
11589167Ssam  */
115942441Smckusick /* ARGSUSED */
116042441Smckusick fchmod(p, uap, retval)
116142441Smckusick 	register struct proc *p;
116242441Smckusick 	register struct args {
11637701Ssam 		int	fd;
11647701Ssam 		int	fmode;
116542441Smckusick 	} *uap;
116642441Smckusick 	int *retval;
116742441Smckusick {
116837741Smckusick 	struct vattr vattr;
116937741Smckusick 	struct vnode *vp;
117037741Smckusick 	struct file *fp;
117137741Smckusick 	int error;
11727701Ssam 
117342441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
117437741Smckusick 		RETURN (error);
117541362Smckusick 	VATTR_NULL(&vattr);
117637741Smckusick 	vattr.va_mode = uap->fmode & 07777;
117737741Smckusick 	vp = (struct vnode *)fp->f_data;
117837741Smckusick 	VOP_LOCK(vp);
117941400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
118037741Smckusick 		error = EROFS;
118137741Smckusick 		goto out;
11827439Sroot 	}
118337741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
118437741Smckusick out:
118537741Smckusick 	VOP_UNLOCK(vp);
118637741Smckusick 	RETURN (error);
11875992Swnj }
11885992Swnj 
11899167Ssam /*
11909167Ssam  * Set ownership given a path name.
11919167Ssam  */
119242441Smckusick /* ARGSUSED */
119342441Smckusick chown(p, uap, retval)
119442441Smckusick 	register struct proc *p;
119542441Smckusick 	register struct args {
11966254Sroot 		char	*fname;
11976254Sroot 		int	uid;
11986254Sroot 		int	gid;
119942441Smckusick 	} *uap;
120042441Smckusick 	int *retval;
120142441Smckusick {
120242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
120337741Smckusick 	register struct vnode *vp;
120437741Smckusick 	struct vattr vattr;
120537741Smckusick 	int error;
120637Sbill 
120737741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
120836614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
120936614Sbostic 	ndp->ni_dirp = uap->fname;
121041362Smckusick 	VATTR_NULL(&vattr);
121137741Smckusick 	vattr.va_uid = uap->uid;
121237741Smckusick 	vattr.va_gid = uap->gid;
121337741Smckusick 	if (error = namei(ndp))
121437741Smckusick 		RETURN (error);
121537741Smckusick 	vp = ndp->ni_vp;
121641400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
121737741Smckusick 		error = EROFS;
121837741Smckusick 		goto out;
121937741Smckusick 	}
122037741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
122137741Smckusick out:
122237741Smckusick 	vput(vp);
122337741Smckusick 	RETURN (error);
12247701Ssam }
12257439Sroot 
12269167Ssam /*
12279167Ssam  * Set ownership given a file descriptor.
12289167Ssam  */
122942441Smckusick /* ARGSUSED */
123042441Smckusick fchown(p, uap, retval)
123142441Smckusick 	register struct proc *p;
123242441Smckusick 	register struct args {
12337701Ssam 		int	fd;
12347701Ssam 		int	uid;
12357701Ssam 		int	gid;
123642441Smckusick 	} *uap;
123742441Smckusick 	int *retval;
123842441Smckusick {
123937741Smckusick 	struct vattr vattr;
124037741Smckusick 	struct vnode *vp;
124137741Smckusick 	struct file *fp;
124237741Smckusick 	int error;
12437701Ssam 
124442441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
124537741Smckusick 		RETURN (error);
124641362Smckusick 	VATTR_NULL(&vattr);
124737741Smckusick 	vattr.va_uid = uap->uid;
124837741Smckusick 	vattr.va_gid = uap->gid;
124937741Smckusick 	vp = (struct vnode *)fp->f_data;
125037741Smckusick 	VOP_LOCK(vp);
125141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
125237741Smckusick 		error = EROFS;
125337741Smckusick 		goto out;
125437741Smckusick 	}
125537741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
125637741Smckusick out:
125737741Smckusick 	VOP_UNLOCK(vp);
125837741Smckusick 	RETURN (error);
12597701Ssam }
12607701Ssam 
126142441Smckusick /*
126242441Smckusick  * Set the access and modification times of a file.
126342441Smckusick  */
126442441Smckusick /* ARGSUSED */
126542441Smckusick utimes(p, uap, retval)
126642441Smckusick 	register struct proc *p;
126742441Smckusick 	register struct args {
126811811Ssam 		char	*fname;
126911811Ssam 		struct	timeval *tptr;
127042441Smckusick 	} *uap;
127142441Smckusick 	int *retval;
127242441Smckusick {
127342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
127437741Smckusick 	register struct vnode *vp;
127511811Ssam 	struct timeval tv[2];
127637741Smckusick 	struct vattr vattr;
127737741Smckusick 	int error;
127811811Ssam 
127937741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
128037741Smckusick 		RETURN (error);
128137741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
128237741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
128337741Smckusick 	ndp->ni_dirp = uap->fname;
128441362Smckusick 	VATTR_NULL(&vattr);
128537741Smckusick 	vattr.va_atime = tv[0];
128637741Smckusick 	vattr.va_mtime = tv[1];
128737741Smckusick 	if (error = namei(ndp))
128837741Smckusick 		RETURN (error);
128937741Smckusick 	vp = ndp->ni_vp;
129041400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
129137741Smckusick 		error = EROFS;
129237741Smckusick 		goto out;
129321015Smckusick 	}
129437741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
129537741Smckusick out:
129637741Smckusick 	vput(vp);
129737741Smckusick 	RETURN (error);
129811811Ssam }
129911811Ssam 
13009167Ssam /*
13019167Ssam  * Truncate a file given its path name.
13029167Ssam  */
130342441Smckusick /* ARGSUSED */
130442441Smckusick truncate(p, uap, retval)
130542441Smckusick 	register struct proc *p;
130642441Smckusick 	register struct args {
13077701Ssam 		char	*fname;
130826473Skarels 		off_t	length;
130942441Smckusick 	} *uap;
131042441Smckusick 	int *retval;
131142441Smckusick {
131242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
131337741Smckusick 	register struct vnode *vp;
131437741Smckusick 	struct vattr vattr;
131537741Smckusick 	int error;
13167701Ssam 
131737741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
131816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
131916694Smckusick 	ndp->ni_dirp = uap->fname;
132041362Smckusick 	VATTR_NULL(&vattr);
132137741Smckusick 	vattr.va_size = uap->length;
132237741Smckusick 	if (error = namei(ndp))
132337741Smckusick 		RETURN (error);
132437741Smckusick 	vp = ndp->ni_vp;
132537741Smckusick 	if (vp->v_type == VDIR) {
132637741Smckusick 		error = EISDIR;
132737741Smckusick 		goto out;
13287701Ssam 	}
132938399Smckusick 	if ((error = vn_writechk(vp)) ||
133038399Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
133137741Smckusick 		goto out;
133237741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
133337741Smckusick out:
133437741Smckusick 	vput(vp);
133537741Smckusick 	RETURN (error);
13367701Ssam }
13377701Ssam 
13389167Ssam /*
13399167Ssam  * Truncate a file given a file descriptor.
13409167Ssam  */
134142441Smckusick /* ARGSUSED */
134242441Smckusick ftruncate(p, uap, retval)
134342441Smckusick 	register struct proc *p;
134442441Smckusick 	register struct args {
13457701Ssam 		int	fd;
134626473Skarels 		off_t	length;
134742441Smckusick 	} *uap;
134842441Smckusick 	int *retval;
134942441Smckusick {
135037741Smckusick 	struct vattr vattr;
135137741Smckusick 	struct vnode *vp;
13527701Ssam 	struct file *fp;
135337741Smckusick 	int error;
13547701Ssam 
135542441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
135637741Smckusick 		RETURN (error);
135737741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
135837741Smckusick 		RETURN (EINVAL);
135941362Smckusick 	VATTR_NULL(&vattr);
136037741Smckusick 	vattr.va_size = uap->length;
136137741Smckusick 	vp = (struct vnode *)fp->f_data;
136237741Smckusick 	VOP_LOCK(vp);
136337741Smckusick 	if (vp->v_type == VDIR) {
136437741Smckusick 		error = EISDIR;
136537741Smckusick 		goto out;
13667701Ssam 	}
136738399Smckusick 	if (error = vn_writechk(vp))
136837741Smckusick 		goto out;
136937741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
137037741Smckusick out:
137137741Smckusick 	VOP_UNLOCK(vp);
137237741Smckusick 	RETURN (error);
13737701Ssam }
13747701Ssam 
13759167Ssam /*
13769167Ssam  * Synch an open file.
13779167Ssam  */
137842441Smckusick /* ARGSUSED */
137942441Smckusick fsync(p, uap, retval)
138042441Smckusick 	register struct proc *p;
138142441Smckusick 	struct args {
138242441Smckusick 		int	fd;
138342441Smckusick 	} *uap;
138442441Smckusick 	int *retval;
13859167Ssam {
138639592Smckusick 	register struct vnode *vp;
13879167Ssam 	struct file *fp;
138837741Smckusick 	int error;
13899167Ssam 
139042441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
139137741Smckusick 		RETURN (error);
139239592Smckusick 	vp = (struct vnode *)fp->f_data;
139339592Smckusick 	VOP_LOCK(vp);
139439592Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT);
139539592Smckusick 	VOP_UNLOCK(vp);
139637741Smckusick 	RETURN (error);
13979167Ssam }
13989167Ssam 
13999167Ssam /*
14009167Ssam  * Rename system call.
14019167Ssam  *
14029167Ssam  * Source and destination must either both be directories, or both
14039167Ssam  * not be directories.  If target is a directory, it must be empty.
14049167Ssam  */
140542441Smckusick /* ARGSUSED */
140642441Smckusick rename(p, uap, retval)
140742441Smckusick 	register struct proc *p;
140842441Smckusick 	register struct args {
14097701Ssam 		char	*from;
14107701Ssam 		char	*to;
141142441Smckusick 	} *uap;
141242441Smckusick 	int *retval;
141342441Smckusick {
141437741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
141542441Smckusick 	register struct nameidata *ndp = &u.u_nd;
141637741Smckusick 	struct nameidata tond;
141737741Smckusick 	int error;
14187701Ssam 
141937741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
142016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
142116694Smckusick 	ndp->ni_dirp = uap->from;
142237741Smckusick 	if (error = namei(ndp))
142337741Smckusick 		RETURN (error);
142437741Smckusick 	fvp = ndp->ni_vp;
142538266Smckusick 	nddup(ndp, &tond);
142637741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
142737741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
142837741Smckusick 	tond.ni_dirp = uap->to;
142942465Smckusick 	if (error = namei(&tond)) {
143042465Smckusick 		VOP_ABORTOP(ndp);
143142465Smckusick 		vrele(ndp->ni_dvp);
143242465Smckusick 		vrele(fvp);
143342465Smckusick 		goto out1;
143442465Smckusick 	}
143537741Smckusick 	tdvp = tond.ni_dvp;
143637741Smckusick 	tvp = tond.ni_vp;
143737741Smckusick 	if (tvp != NULL) {
143837741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
143939242Sbostic 			error = ENOTDIR;
144037741Smckusick 			goto out;
144137741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
144239242Sbostic 			error = EISDIR;
144337741Smckusick 			goto out;
14449167Ssam 		}
14459167Ssam 	}
144637741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
144737741Smckusick 		error = EXDEV;
14489167Ssam 		goto out;
144910051Ssam 	}
145039286Smckusick 	if (fvp == tdvp)
145137741Smckusick 		error = EINVAL;
145239286Smckusick 	/*
145339286Smckusick 	 * If source is the same as the destination,
145439286Smckusick 	 * then there is nothing to do.
145539286Smckusick 	 */
145639286Smckusick 	if (fvp == tvp)
145739286Smckusick 		error = -1;
145837741Smckusick out:
145942465Smckusick 	if (!error) {
146042465Smckusick 		error = VOP_RENAME(ndp, &tond);
146142465Smckusick 	} else {
146237741Smckusick 		VOP_ABORTOP(&tond);
1463*43344Smckusick 		if (tdvp == tvp)
1464*43344Smckusick 			vrele(tdvp);
1465*43344Smckusick 		else
1466*43344Smckusick 			vput(tdvp);
146742465Smckusick 		if (tvp)
146842465Smckusick 			vput(tvp);
146937741Smckusick 		VOP_ABORTOP(ndp);
147042465Smckusick 		vrele(ndp->ni_dvp);
147142465Smckusick 		vrele(fvp);
14729167Ssam 	}
147337741Smckusick out1:
147438266Smckusick 	ndrele(&tond);
147539286Smckusick 	if (error == -1)
147639286Smckusick 		RETURN (0);
147737741Smckusick 	RETURN (error);
14787701Ssam }
14797701Ssam 
14807535Sroot /*
148112756Ssam  * Mkdir system call
148212756Ssam  */
148342441Smckusick /* ARGSUSED */
148442441Smckusick mkdir(p, uap, retval)
148542441Smckusick 	register struct proc *p;
148642441Smckusick 	register struct args {
148712756Ssam 		char	*name;
148812756Ssam 		int	dmode;
148942441Smckusick 	} *uap;
149042441Smckusick 	int *retval;
149142441Smckusick {
149242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
149337741Smckusick 	register struct vnode *vp;
149437741Smckusick 	struct vattr vattr;
149537741Smckusick 	int error;
149612756Ssam 
149737741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
149816694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
149916694Smckusick 	ndp->ni_dirp = uap->name;
150037741Smckusick 	if (error = namei(ndp))
150137741Smckusick 		RETURN (error);
150237741Smckusick 	vp = ndp->ni_vp;
150337741Smckusick 	if (vp != NULL) {
150437741Smckusick 		VOP_ABORTOP(ndp);
1505*43344Smckusick 		if (ndp->ni_dvp == vp)
1506*43344Smckusick 			vrele(ndp->ni_dvp);
1507*43344Smckusick 		else
1508*43344Smckusick 			vput(ndp->ni_dvp);
150942465Smckusick 		vrele(vp);
151037741Smckusick 		RETURN (EEXIST);
151112756Ssam 	}
151241362Smckusick 	VATTR_NULL(&vattr);
151337741Smckusick 	vattr.va_type = VDIR;
151442441Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask;
151537741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
151638145Smckusick 	if (!error)
151738145Smckusick 		vput(ndp->ni_vp);
151837741Smckusick 	RETURN (error);
151912756Ssam }
152012756Ssam 
152112756Ssam /*
152212756Ssam  * Rmdir system call.
152312756Ssam  */
152442441Smckusick /* ARGSUSED */
152542441Smckusick rmdir(p, uap, retval)
152642441Smckusick 	register struct proc *p;
152742441Smckusick 	struct args {
152842441Smckusick 		char	*name;
152942441Smckusick 	} *uap;
153042441Smckusick 	int *retval;
153112756Ssam {
153242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
153337741Smckusick 	register struct vnode *vp;
153437741Smckusick 	int error;
153512756Ssam 
153637741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
153716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
153816694Smckusick 	ndp->ni_dirp = uap->name;
153937741Smckusick 	if (error = namei(ndp))
154037741Smckusick 		RETURN (error);
154137741Smckusick 	vp = ndp->ni_vp;
154237741Smckusick 	if (vp->v_type != VDIR) {
154337741Smckusick 		error = ENOTDIR;
154412756Ssam 		goto out;
154512756Ssam 	}
154612756Ssam 	/*
154737741Smckusick 	 * No rmdir "." please.
154812756Ssam 	 */
154937741Smckusick 	if (ndp->ni_dvp == vp) {
155037741Smckusick 		error = EINVAL;
155112756Ssam 		goto out;
155212756Ssam 	}
155312756Ssam 	/*
155437741Smckusick 	 * Don't unlink a mounted file.
155512756Ssam 	 */
155637741Smckusick 	if (vp->v_flag & VROOT)
155737741Smckusick 		error = EBUSY;
155812756Ssam out:
155942465Smckusick 	if (!error) {
156042465Smckusick 		error = VOP_RMDIR(ndp);
156142465Smckusick 	} else {
156237741Smckusick 		VOP_ABORTOP(ndp);
1563*43344Smckusick 		if (ndp->ni_dvp == vp)
1564*43344Smckusick 			vrele(ndp->ni_dvp);
1565*43344Smckusick 		else
1566*43344Smckusick 			vput(ndp->ni_dvp);
156742465Smckusick 		vput(vp);
156842465Smckusick 	}
156937741Smckusick 	RETURN (error);
157012756Ssam }
157112756Ssam 
157237741Smckusick /*
157337741Smckusick  * Read a block of directory entries in a file system independent format
157437741Smckusick  */
157542441Smckusick getdirentries(p, uap, retval)
157642441Smckusick 	register struct proc *p;
157742441Smckusick 	register struct args {
157837741Smckusick 		int	fd;
157937741Smckusick 		char	*buf;
158037741Smckusick 		unsigned count;
158137741Smckusick 		long	*basep;
158242441Smckusick 	} *uap;
158342441Smckusick 	int *retval;
158442441Smckusick {
158539592Smckusick 	register struct vnode *vp;
158616540Ssam 	struct file *fp;
158737741Smckusick 	struct uio auio;
158837741Smckusick 	struct iovec aiov;
158938129Smckusick 	off_t off;
159040321Smckusick 	int error, eofflag;
159112756Ssam 
159242441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
159337741Smckusick 		RETURN (error);
159437741Smckusick 	if ((fp->f_flag & FREAD) == 0)
159537741Smckusick 		RETURN (EBADF);
159639592Smckusick 	vp = (struct vnode *)fp->f_data;
159739592Smckusick 	if (vp->v_type != VDIR)
159839592Smckusick 		RETURN (EINVAL);
159937741Smckusick 	aiov.iov_base = uap->buf;
160037741Smckusick 	aiov.iov_len = uap->count;
160137741Smckusick 	auio.uio_iov = &aiov;
160237741Smckusick 	auio.uio_iovcnt = 1;
160337741Smckusick 	auio.uio_rw = UIO_READ;
160437741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
160537741Smckusick 	auio.uio_resid = uap->count;
160639592Smckusick 	VOP_LOCK(vp);
160739592Smckusick 	auio.uio_offset = off = fp->f_offset;
160840321Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
160939592Smckusick 	fp->f_offset = auio.uio_offset;
161039592Smckusick 	VOP_UNLOCK(vp);
161139592Smckusick 	if (error)
161237741Smckusick 		RETURN (error);
161339592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
161442441Smckusick 	*retval = uap->count - auio.uio_resid;
161537741Smckusick 	RETURN (error);
161612756Ssam }
161712756Ssam 
161812756Ssam /*
161912756Ssam  * mode mask for creation of files
162012756Ssam  */
162142441Smckusick mode_t
162242441Smckusick umask(p, uap, retval)
162342441Smckusick 	register struct proc *p;
162442441Smckusick 	struct args {
162542441Smckusick 		int	mask;
162642441Smckusick 	} *uap;
162742441Smckusick 	int *retval;
162812756Ssam {
162912756Ssam 
163042441Smckusick 	*retval = u.u_cmask;
163142441Smckusick 	u.u_cmask = uap->mask & 07777;
163237741Smckusick 	RETURN (0);
163312756Ssam }
163437741Smckusick 
163539566Smarc /*
163639566Smarc  * Void all references to file by ripping underlying filesystem
163739566Smarc  * away from vnode.
163839566Smarc  */
163942441Smckusick /* ARGSUSED */
164042441Smckusick revoke(p, uap, retval)
164142441Smckusick 	register struct proc *p;
164242441Smckusick 	register struct args {
164339566Smarc 		char	*fname;
164441676Smckusick 		int	flags;
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