xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 42955)
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*42955Smckusick  *	@(#)vfs_syscalls.c	7.50 (Berkeley) 06/06/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 
582*42955Smckusick #ifdef COMPAT_43
5836254Sroot /*
58442441Smckusick  * Creat system call.
5856254Sroot  */
586*42955Smckusick 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 }
605*42955Smckusick #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);
66042465Smckusick 		vput(ndp->ni_dvp);
66142465Smckusick 		if (vp)
66242465Smckusick 			vrele(vp);
66342465Smckusick 	}
66437741Smckusick 	RETURN (error);
6656254Sroot }
6666254Sroot 
6676254Sroot /*
66840285Smckusick  * Mkfifo system call
66940285Smckusick  */
67042441Smckusick /* ARGSUSED */
67142441Smckusick mkfifo(p, uap, retval)
67242441Smckusick 	register struct proc *p;
67342441Smckusick 	register struct args {
67440285Smckusick 		char	*fname;
67540285Smckusick 		int	fmode;
67642441Smckusick 	} *uap;
67742441Smckusick 	int *retval;
67842441Smckusick {
67942441Smckusick 	register struct nameidata *ndp = &u.u_nd;
68040285Smckusick 	struct vattr vattr;
68140285Smckusick 	int error;
68240285Smckusick 
68340285Smckusick #ifndef FIFO
68440285Smckusick 	RETURN (EOPNOTSUPP);
68540285Smckusick #else
68640285Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
68740285Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
68840285Smckusick 	ndp->ni_dirp = uap->fname;
68940285Smckusick 	if (error = namei(ndp))
69040285Smckusick 		RETURN (error);
69140285Smckusick 	if (ndp->ni_vp != NULL) {
69240285Smckusick 		VOP_ABORTOP(ndp);
69342465Smckusick 		vput(ndp->ni_dvp);
69442465Smckusick 		vrele(ndp->ni_vp);
69540285Smckusick 		RETURN (EEXIST);
69640285Smckusick 	} else {
69741362Smckusick 		VATTR_NULL(&vattr);
69840285Smckusick 		vattr.va_type = VFIFO;
69942441Smckusick 		vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask;
70040285Smckusick 	}
70140285Smckusick 	RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred));
70240285Smckusick #endif /* FIFO */
70340285Smckusick }
70440285Smckusick 
70540285Smckusick /*
7066254Sroot  * link system call
7076254Sroot  */
70842441Smckusick /* ARGSUSED */
70942441Smckusick link(p, uap, retval)
71042441Smckusick 	register struct proc *p;
71142441Smckusick 	register struct args {
7126254Sroot 		char	*target;
7136254Sroot 		char	*linkname;
71442441Smckusick 	} *uap;
71542441Smckusick 	int *retval;
71642441Smckusick {
71742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
71837741Smckusick 	register struct vnode *vp, *xp;
71937741Smckusick 	int error;
7206254Sroot 
72116694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
72216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
72316694Smckusick 	ndp->ni_dirp = uap->target;
72437741Smckusick 	if (error = namei(ndp))
72537741Smckusick 		RETURN (error);
72637741Smckusick 	vp = ndp->ni_vp;
72737741Smckusick 	if (vp->v_type == VDIR &&
72842441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
72937741Smckusick 		goto out1;
73037741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
73116694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
73237741Smckusick 	if (error = namei(ndp))
73337741Smckusick 		goto out1;
73437741Smckusick 	xp = ndp->ni_vp;
7356254Sroot 	if (xp != NULL) {
73637741Smckusick 		error = EEXIST;
7376254Sroot 		goto out;
7386254Sroot 	}
73937741Smckusick 	xp = ndp->ni_dvp;
74037741Smckusick 	if (vp->v_mount != xp->v_mount)
74137741Smckusick 		error = EXDEV;
7426254Sroot out:
74342465Smckusick 	if (!error) {
74442465Smckusick 		error = VOP_LINK(vp, ndp);
74542465Smckusick 	} else {
74637741Smckusick 		VOP_ABORTOP(ndp);
74742465Smckusick 		vput(ndp->ni_dvp);
74842465Smckusick 		if (ndp->ni_vp)
74942465Smckusick 			vrele(ndp->ni_vp);
75042465Smckusick 	}
75137741Smckusick out1:
75237741Smckusick 	vrele(vp);
75337741Smckusick 	RETURN (error);
7546254Sroot }
7556254Sroot 
7566254Sroot /*
7576254Sroot  * symlink -- make a symbolic link
7586254Sroot  */
75942441Smckusick /* ARGSUSED */
76042441Smckusick symlink(p, uap, retval)
76142441Smckusick 	register struct proc *p;
76242441Smckusick 	register struct args {
7636254Sroot 		char	*target;
7646254Sroot 		char	*linkname;
76542441Smckusick 	} *uap;
76642441Smckusick 	int *retval;
76742441Smckusick {
76842441Smckusick 	register struct nameidata *ndp = &u.u_nd;
76937741Smckusick 	struct vattr vattr;
77037741Smckusick 	char *target;
77137741Smckusick 	int error;
7726254Sroot 
77316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
77416694Smckusick 	ndp->ni_dirp = uap->linkname;
77537741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
77637741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
77742465Smckusick 		goto out;
77837741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
77937741Smckusick 	if (error = namei(ndp))
78042465Smckusick 		goto out;
78142465Smckusick 	if (ndp->ni_vp) {
78242465Smckusick 		VOP_ABORTOP(ndp);
78342465Smckusick 		vput(ndp->ni_dvp);
78442465Smckusick 		vrele(ndp->ni_vp);
78537741Smckusick 		error = EEXIST;
78637741Smckusick 		goto out;
7876254Sroot 	}
78841362Smckusick 	VATTR_NULL(&vattr);
78942441Smckusick 	vattr.va_mode = 0777 &~ u.u_cmask;
79042465Smckusick 	error = VOP_SYMLINK(ndp, &vattr, target);
79137741Smckusick out:
79237741Smckusick 	FREE(target, M_NAMEI);
79337741Smckusick 	RETURN (error);
7946254Sroot }
7956254Sroot 
7966254Sroot /*
7976254Sroot  * Unlink system call.
7986254Sroot  * Hard to avoid races here, especially
7996254Sroot  * in unlinking directories.
8006254Sroot  */
80142441Smckusick /* ARGSUSED */
80242441Smckusick unlink(p, uap, retval)
80342441Smckusick 	register struct proc *p;
80442441Smckusick 	struct args {
80542441Smckusick 		char	*fname;
80642441Smckusick 	} *uap;
80742441Smckusick 	int *retval;
8086254Sroot {
80942441Smckusick 	register struct nameidata *ndp = &u.u_nd;
81037741Smckusick 	register struct vnode *vp;
81137741Smckusick 	int error;
8126254Sroot 
81337741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
81416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
81516694Smckusick 	ndp->ni_dirp = uap->fname;
81637741Smckusick 	if (error = namei(ndp))
81737741Smckusick 		RETURN (error);
81837741Smckusick 	vp = ndp->ni_vp;
81937741Smckusick 	if (vp->v_type == VDIR &&
82042441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
8216254Sroot 		goto out;
8226254Sroot 	/*
8236254Sroot 	 * Don't unlink a mounted file.
8246254Sroot 	 */
82537741Smckusick 	if (vp->v_flag & VROOT) {
82637741Smckusick 		error = EBUSY;
8276254Sroot 		goto out;
8286254Sroot 	}
82937741Smckusick 	if (vp->v_flag & VTEXT)
83037741Smckusick 		xrele(vp);	/* try once to free text */
8316254Sroot out:
83242465Smckusick 	if (!error) {
83342465Smckusick 		error = VOP_REMOVE(ndp);
83442465Smckusick 	} else {
83537741Smckusick 		VOP_ABORTOP(ndp);
83642465Smckusick 		vput(ndp->ni_dvp);
83742465Smckusick 		vput(vp);
83842465Smckusick 	}
83937741Smckusick 	RETURN (error);
8406254Sroot }
8416254Sroot 
8426254Sroot /*
8436254Sroot  * Seek system call
8446254Sroot  */
84542441Smckusick lseek(p, uap, retval)
84642441Smckusick 	register struct proc *p;
84742441Smckusick 	register struct args {
84837741Smckusick 		int	fdes;
8496254Sroot 		off_t	off;
8506254Sroot 		int	sbase;
85142441Smckusick 	} *uap;
85242441Smckusick 	off_t *retval;
85342441Smckusick {
85442441Smckusick 	struct ucred *cred = u.u_nd.ni_cred;
85542441Smckusick 	register struct file *fp;
85637741Smckusick 	struct vattr vattr;
85737741Smckusick 	int error;
8586254Sroot 
85937741Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
86042441Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
86137741Smckusick 		RETURN (EBADF);
86237741Smckusick 	if (fp->f_type != DTYPE_VNODE)
86337741Smckusick 		RETURN (ESPIPE);
86413878Ssam 	switch (uap->sbase) {
86513878Ssam 
86613878Ssam 	case L_INCR:
86713878Ssam 		fp->f_offset += uap->off;
86813878Ssam 		break;
86913878Ssam 
87013878Ssam 	case L_XTND:
87137741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
87242441Smckusick 		    &vattr, cred))
87337741Smckusick 			RETURN (error);
87437741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
87513878Ssam 		break;
87613878Ssam 
87713878Ssam 	case L_SET:
87813878Ssam 		fp->f_offset = uap->off;
87913878Ssam 		break;
88013878Ssam 
88113878Ssam 	default:
88237741Smckusick 		RETURN (EINVAL);
88313878Ssam 	}
88442441Smckusick 	*retval = fp->f_offset;
88537741Smckusick 	RETURN (0);
8866254Sroot }
8876254Sroot 
8886254Sroot /*
8896254Sroot  * Access system call
8906254Sroot  */
89142441Smckusick /* ARGSUSED */
89242441Smckusick saccess(p, uap, retval)
89342441Smckusick 	register struct proc *p;
89442441Smckusick 	register struct args {
8956254Sroot 		char	*fname;
8966254Sroot 		int	fmode;
89742441Smckusick 	} *uap;
89842441Smckusick 	int *retval;
89942441Smckusick {
90042441Smckusick 	register struct nameidata *ndp = &u.u_nd;
90142441Smckusick 	register struct ucred *cred = ndp->ni_cred;
90237741Smckusick 	register struct vnode *vp;
90337741Smckusick 	int error, mode, svuid, svgid;
9046254Sroot 
90542441Smckusick 	svuid = cred->cr_uid;
90642441Smckusick 	svgid = cred->cr_groups[0];
90742441Smckusick 	cred->cr_uid = p->p_ruid;
90842441Smckusick 	cred->cr_groups[0] = p->p_rgid;
90937741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
91016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
91116694Smckusick 	ndp->ni_dirp = uap->fname;
91237741Smckusick 	if (error = namei(ndp))
91337741Smckusick 		goto out1;
91437741Smckusick 	vp = ndp->ni_vp;
91537741Smckusick 	/*
91637741Smckusick 	 * fmode == 0 means only check for exist
91737741Smckusick 	 */
91837741Smckusick 	if (uap->fmode) {
91937741Smckusick 		mode = 0;
92037741Smckusick 		if (uap->fmode & R_OK)
92137741Smckusick 			mode |= VREAD;
92237741Smckusick 		if (uap->fmode & W_OK)
92337741Smckusick 			mode |= VWRITE;
92437741Smckusick 		if (uap->fmode & X_OK)
92537741Smckusick 			mode |= VEXEC;
92639543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
92738399Smckusick 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
9286254Sroot 	}
92937741Smckusick 	vput(vp);
93037741Smckusick out1:
93142441Smckusick 	cred->cr_uid = svuid;
93242441Smckusick 	cred->cr_groups[0] = svgid;
93337741Smckusick 	RETURN (error);
9346254Sroot }
9356254Sroot 
9366254Sroot /*
9376574Smckusic  * Stat system call.  This version follows links.
93837Sbill  */
93942441Smckusick /* ARGSUSED */
94042441Smckusick stat(p, uap, retval)
94142441Smckusick 	register struct proc *p;
94242441Smckusick 	register struct args {
94342441Smckusick 		char	*fname;
94442441Smckusick 		struct stat *ub;
94542441Smckusick 	} *uap;
94642441Smckusick 	int *retval;
94737Sbill {
94842441Smckusick 	register struct nameidata *ndp = &u.u_nd;
94942441Smckusick 	struct stat sb;
95042441Smckusick 	int error;
95137Sbill 
95242441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
95342441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
95442441Smckusick 	ndp->ni_dirp = uap->fname;
95542441Smckusick 	if (error = namei(ndp))
95642441Smckusick 		RETURN (error);
95742441Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
95842441Smckusick 	vput(ndp->ni_vp);
95942441Smckusick 	if (error)
96042441Smckusick 		RETURN (error);
96142441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
96242441Smckusick 	RETURN (error);
96337Sbill }
96437Sbill 
96537Sbill /*
9666574Smckusic  * Lstat system call.  This version does not follow links.
9675992Swnj  */
96842441Smckusick /* ARGSUSED */
96942441Smckusick lstat(p, uap, retval)
97042441Smckusick 	register struct proc *p;
97142441Smckusick 	register struct args {
9725992Swnj 		char	*fname;
97312756Ssam 		struct stat *ub;
97442441Smckusick 	} *uap;
97542441Smckusick 	int *retval;
97642441Smckusick {
97742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
97812756Ssam 	struct stat sb;
97937741Smckusick 	int error;
9805992Swnj 
98142441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW;
98216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
98316694Smckusick 	ndp->ni_dirp = uap->fname;
98437741Smckusick 	if (error = namei(ndp))
98537741Smckusick 		RETURN (error);
98637741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
98737741Smckusick 	vput(ndp->ni_vp);
98837741Smckusick 	if (error)
98937741Smckusick 		RETURN (error);
99037741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
99137741Smckusick 	RETURN (error);
9925992Swnj }
9935992Swnj 
9945992Swnj /*
9955992Swnj  * Return target name of a symbolic link
99637Sbill  */
99742441Smckusick /* ARGSUSED */
99842441Smckusick readlink(p, uap, retval)
99942441Smckusick 	register struct proc *p;
100042441Smckusick 	register struct args {
10015992Swnj 		char	*name;
10025992Swnj 		char	*buf;
10035992Swnj 		int	count;
100442441Smckusick 	} *uap;
100542441Smckusick 	int *retval;
100642441Smckusick {
100742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
100837741Smckusick 	register struct vnode *vp;
100937741Smckusick 	struct iovec aiov;
101037741Smckusick 	struct uio auio;
101137741Smckusick 	int error;
10125992Swnj 
101337741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
101416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
101516694Smckusick 	ndp->ni_dirp = uap->name;
101637741Smckusick 	if (error = namei(ndp))
101737741Smckusick 		RETURN (error);
101837741Smckusick 	vp = ndp->ni_vp;
101937741Smckusick 	if (vp->v_type != VLNK) {
102037741Smckusick 		error = EINVAL;
10215992Swnj 		goto out;
10225992Swnj 	}
102337741Smckusick 	aiov.iov_base = uap->buf;
102437741Smckusick 	aiov.iov_len = uap->count;
102537741Smckusick 	auio.uio_iov = &aiov;
102637741Smckusick 	auio.uio_iovcnt = 1;
102737741Smckusick 	auio.uio_offset = 0;
102837741Smckusick 	auio.uio_rw = UIO_READ;
102937741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
103037741Smckusick 	auio.uio_resid = uap->count;
103137741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
10325992Swnj out:
103337741Smckusick 	vput(vp);
103442441Smckusick 	*retval = uap->count - auio.uio_resid;
103537741Smckusick 	RETURN (error);
10365992Swnj }
10375992Swnj 
10389167Ssam /*
103938259Smckusick  * Change flags of a file given path name.
104038259Smckusick  */
104142441Smckusick /* ARGSUSED */
104242441Smckusick chflags(p, uap, retval)
104342441Smckusick 	register struct proc *p;
104442441Smckusick 	register struct args {
104538259Smckusick 		char	*fname;
104638259Smckusick 		int	flags;
104742441Smckusick 	} *uap;
104842441Smckusick 	int *retval;
104942441Smckusick {
105042441Smckusick 	register struct nameidata *ndp = &u.u_nd;
105138259Smckusick 	register struct vnode *vp;
105238259Smckusick 	struct vattr vattr;
105338259Smckusick 	int error;
105438259Smckusick 
105538259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
105638259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
105738259Smckusick 	ndp->ni_dirp = uap->fname;
105841362Smckusick 	VATTR_NULL(&vattr);
105938259Smckusick 	vattr.va_flags = uap->flags;
106038259Smckusick 	if (error = namei(ndp))
106138259Smckusick 		RETURN (error);
106238259Smckusick 	vp = ndp->ni_vp;
106341400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
106438259Smckusick 		error = EROFS;
106538259Smckusick 		goto out;
106638259Smckusick 	}
106738259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
106838259Smckusick out:
106938259Smckusick 	vput(vp);
107038259Smckusick 	RETURN (error);
107138259Smckusick }
107238259Smckusick 
107338259Smckusick /*
107438259Smckusick  * Change flags of a file given a file descriptor.
107538259Smckusick  */
107642441Smckusick /* ARGSUSED */
107742441Smckusick fchflags(p, uap, retval)
107842441Smckusick 	register struct proc *p;
107942441Smckusick 	register struct args {
108038259Smckusick 		int	fd;
108138259Smckusick 		int	flags;
108242441Smckusick 	} *uap;
108342441Smckusick 	int *retval;
108442441Smckusick {
108538259Smckusick 	struct vattr vattr;
108638259Smckusick 	struct vnode *vp;
108738259Smckusick 	struct file *fp;
108838259Smckusick 	int error;
108938259Smckusick 
109042441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
109138259Smckusick 		RETURN (error);
109241362Smckusick 	VATTR_NULL(&vattr);
109338259Smckusick 	vattr.va_flags = uap->flags;
109438259Smckusick 	vp = (struct vnode *)fp->f_data;
109538259Smckusick 	VOP_LOCK(vp);
109641400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
109738259Smckusick 		error = EROFS;
109838259Smckusick 		goto out;
109938259Smckusick 	}
110038259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
110138259Smckusick out:
110238259Smckusick 	VOP_UNLOCK(vp);
110338259Smckusick 	RETURN (error);
110438259Smckusick }
110538259Smckusick 
110638259Smckusick /*
11079167Ssam  * Change mode of a file given path name.
11089167Ssam  */
110942441Smckusick /* ARGSUSED */
111042441Smckusick chmod(p, uap, retval)
111142441Smckusick 	register struct proc *p;
111242441Smckusick 	register struct args {
11136254Sroot 		char	*fname;
11146254Sroot 		int	fmode;
111542441Smckusick 	} *uap;
111642441Smckusick 	int *retval;
111742441Smckusick {
111842441Smckusick 	register struct nameidata *ndp = &u.u_nd;
111937741Smckusick 	register struct vnode *vp;
112037741Smckusick 	struct vattr vattr;
112137741Smckusick 	int error;
11225992Swnj 
112337741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
112437741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
112537741Smckusick 	ndp->ni_dirp = uap->fname;
112641362Smckusick 	VATTR_NULL(&vattr);
112737741Smckusick 	vattr.va_mode = uap->fmode & 07777;
112837741Smckusick 	if (error = namei(ndp))
112937741Smckusick 		RETURN (error);
113037741Smckusick 	vp = ndp->ni_vp;
113141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
113237741Smckusick 		error = EROFS;
113337741Smckusick 		goto out;
113437741Smckusick 	}
113537741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
113637741Smckusick out:
113737741Smckusick 	vput(vp);
113837741Smckusick 	RETURN (error);
11397701Ssam }
11407439Sroot 
11419167Ssam /*
11429167Ssam  * Change mode of a file given a file descriptor.
11439167Ssam  */
114442441Smckusick /* ARGSUSED */
114542441Smckusick fchmod(p, uap, retval)
114642441Smckusick 	register struct proc *p;
114742441Smckusick 	register struct args {
11487701Ssam 		int	fd;
11497701Ssam 		int	fmode;
115042441Smckusick 	} *uap;
115142441Smckusick 	int *retval;
115242441Smckusick {
115337741Smckusick 	struct vattr vattr;
115437741Smckusick 	struct vnode *vp;
115537741Smckusick 	struct file *fp;
115637741Smckusick 	int error;
11577701Ssam 
115842441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
115937741Smckusick 		RETURN (error);
116041362Smckusick 	VATTR_NULL(&vattr);
116137741Smckusick 	vattr.va_mode = uap->fmode & 07777;
116237741Smckusick 	vp = (struct vnode *)fp->f_data;
116337741Smckusick 	VOP_LOCK(vp);
116441400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
116537741Smckusick 		error = EROFS;
116637741Smckusick 		goto out;
11677439Sroot 	}
116837741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
116937741Smckusick out:
117037741Smckusick 	VOP_UNLOCK(vp);
117137741Smckusick 	RETURN (error);
11725992Swnj }
11735992Swnj 
11749167Ssam /*
11759167Ssam  * Set ownership given a path name.
11769167Ssam  */
117742441Smckusick /* ARGSUSED */
117842441Smckusick chown(p, uap, retval)
117942441Smckusick 	register struct proc *p;
118042441Smckusick 	register struct args {
11816254Sroot 		char	*fname;
11826254Sroot 		int	uid;
11836254Sroot 		int	gid;
118442441Smckusick 	} *uap;
118542441Smckusick 	int *retval;
118642441Smckusick {
118742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
118837741Smckusick 	register struct vnode *vp;
118937741Smckusick 	struct vattr vattr;
119037741Smckusick 	int error;
119137Sbill 
119237741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
119336614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
119436614Sbostic 	ndp->ni_dirp = uap->fname;
119541362Smckusick 	VATTR_NULL(&vattr);
119637741Smckusick 	vattr.va_uid = uap->uid;
119737741Smckusick 	vattr.va_gid = uap->gid;
119837741Smckusick 	if (error = namei(ndp))
119937741Smckusick 		RETURN (error);
120037741Smckusick 	vp = ndp->ni_vp;
120141400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
120237741Smckusick 		error = EROFS;
120337741Smckusick 		goto out;
120437741Smckusick 	}
120537741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
120637741Smckusick out:
120737741Smckusick 	vput(vp);
120837741Smckusick 	RETURN (error);
12097701Ssam }
12107439Sroot 
12119167Ssam /*
12129167Ssam  * Set ownership given a file descriptor.
12139167Ssam  */
121442441Smckusick /* ARGSUSED */
121542441Smckusick fchown(p, uap, retval)
121642441Smckusick 	register struct proc *p;
121742441Smckusick 	register struct args {
12187701Ssam 		int	fd;
12197701Ssam 		int	uid;
12207701Ssam 		int	gid;
122142441Smckusick 	} *uap;
122242441Smckusick 	int *retval;
122342441Smckusick {
122437741Smckusick 	struct vattr vattr;
122537741Smckusick 	struct vnode *vp;
122637741Smckusick 	struct file *fp;
122737741Smckusick 	int error;
12287701Ssam 
122942441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
123037741Smckusick 		RETURN (error);
123141362Smckusick 	VATTR_NULL(&vattr);
123237741Smckusick 	vattr.va_uid = uap->uid;
123337741Smckusick 	vattr.va_gid = uap->gid;
123437741Smckusick 	vp = (struct vnode *)fp->f_data;
123537741Smckusick 	VOP_LOCK(vp);
123641400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
123737741Smckusick 		error = EROFS;
123837741Smckusick 		goto out;
123937741Smckusick 	}
124037741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
124137741Smckusick out:
124237741Smckusick 	VOP_UNLOCK(vp);
124337741Smckusick 	RETURN (error);
12447701Ssam }
12457701Ssam 
124642441Smckusick /*
124742441Smckusick  * Set the access and modification times of a file.
124842441Smckusick  */
124942441Smckusick /* ARGSUSED */
125042441Smckusick utimes(p, uap, retval)
125142441Smckusick 	register struct proc *p;
125242441Smckusick 	register struct args {
125311811Ssam 		char	*fname;
125411811Ssam 		struct	timeval *tptr;
125542441Smckusick 	} *uap;
125642441Smckusick 	int *retval;
125742441Smckusick {
125842441Smckusick 	register struct nameidata *ndp = &u.u_nd;
125937741Smckusick 	register struct vnode *vp;
126011811Ssam 	struct timeval tv[2];
126137741Smckusick 	struct vattr vattr;
126237741Smckusick 	int error;
126311811Ssam 
126437741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
126537741Smckusick 		RETURN (error);
126637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
126737741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
126837741Smckusick 	ndp->ni_dirp = uap->fname;
126941362Smckusick 	VATTR_NULL(&vattr);
127037741Smckusick 	vattr.va_atime = tv[0];
127137741Smckusick 	vattr.va_mtime = tv[1];
127237741Smckusick 	if (error = namei(ndp))
127337741Smckusick 		RETURN (error);
127437741Smckusick 	vp = ndp->ni_vp;
127541400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
127637741Smckusick 		error = EROFS;
127737741Smckusick 		goto out;
127821015Smckusick 	}
127937741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
128037741Smckusick out:
128137741Smckusick 	vput(vp);
128237741Smckusick 	RETURN (error);
128311811Ssam }
128411811Ssam 
12859167Ssam /*
12869167Ssam  * Truncate a file given its path name.
12879167Ssam  */
128842441Smckusick /* ARGSUSED */
128942441Smckusick truncate(p, uap, retval)
129042441Smckusick 	register struct proc *p;
129142441Smckusick 	register struct args {
12927701Ssam 		char	*fname;
129326473Skarels 		off_t	length;
129442441Smckusick 	} *uap;
129542441Smckusick 	int *retval;
129642441Smckusick {
129742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
129837741Smckusick 	register struct vnode *vp;
129937741Smckusick 	struct vattr vattr;
130037741Smckusick 	int error;
13017701Ssam 
130237741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
130316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
130416694Smckusick 	ndp->ni_dirp = uap->fname;
130541362Smckusick 	VATTR_NULL(&vattr);
130637741Smckusick 	vattr.va_size = uap->length;
130737741Smckusick 	if (error = namei(ndp))
130837741Smckusick 		RETURN (error);
130937741Smckusick 	vp = ndp->ni_vp;
131037741Smckusick 	if (vp->v_type == VDIR) {
131137741Smckusick 		error = EISDIR;
131237741Smckusick 		goto out;
13137701Ssam 	}
131438399Smckusick 	if ((error = vn_writechk(vp)) ||
131538399Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
131637741Smckusick 		goto out;
131737741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
131837741Smckusick out:
131937741Smckusick 	vput(vp);
132037741Smckusick 	RETURN (error);
13217701Ssam }
13227701Ssam 
13239167Ssam /*
13249167Ssam  * Truncate a file given a file descriptor.
13259167Ssam  */
132642441Smckusick /* ARGSUSED */
132742441Smckusick ftruncate(p, uap, retval)
132842441Smckusick 	register struct proc *p;
132942441Smckusick 	register struct args {
13307701Ssam 		int	fd;
133126473Skarels 		off_t	length;
133242441Smckusick 	} *uap;
133342441Smckusick 	int *retval;
133442441Smckusick {
133537741Smckusick 	struct vattr vattr;
133637741Smckusick 	struct vnode *vp;
13377701Ssam 	struct file *fp;
133837741Smckusick 	int error;
13397701Ssam 
134042441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
134137741Smckusick 		RETURN (error);
134237741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
134337741Smckusick 		RETURN (EINVAL);
134441362Smckusick 	VATTR_NULL(&vattr);
134537741Smckusick 	vattr.va_size = uap->length;
134637741Smckusick 	vp = (struct vnode *)fp->f_data;
134737741Smckusick 	VOP_LOCK(vp);
134837741Smckusick 	if (vp->v_type == VDIR) {
134937741Smckusick 		error = EISDIR;
135037741Smckusick 		goto out;
13517701Ssam 	}
135238399Smckusick 	if (error = vn_writechk(vp))
135337741Smckusick 		goto out;
135437741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
135537741Smckusick out:
135637741Smckusick 	VOP_UNLOCK(vp);
135737741Smckusick 	RETURN (error);
13587701Ssam }
13597701Ssam 
13609167Ssam /*
13619167Ssam  * Synch an open file.
13629167Ssam  */
136342441Smckusick /* ARGSUSED */
136442441Smckusick fsync(p, uap, retval)
136542441Smckusick 	register struct proc *p;
136642441Smckusick 	struct args {
136742441Smckusick 		int	fd;
136842441Smckusick 	} *uap;
136942441Smckusick 	int *retval;
13709167Ssam {
137139592Smckusick 	register struct vnode *vp;
13729167Ssam 	struct file *fp;
137337741Smckusick 	int error;
13749167Ssam 
137542441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
137637741Smckusick 		RETURN (error);
137739592Smckusick 	vp = (struct vnode *)fp->f_data;
137839592Smckusick 	VOP_LOCK(vp);
137939592Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT);
138039592Smckusick 	VOP_UNLOCK(vp);
138137741Smckusick 	RETURN (error);
13829167Ssam }
13839167Ssam 
13849167Ssam /*
13859167Ssam  * Rename system call.
13869167Ssam  *
13879167Ssam  * Source and destination must either both be directories, or both
13889167Ssam  * not be directories.  If target is a directory, it must be empty.
13899167Ssam  */
139042441Smckusick /* ARGSUSED */
139142441Smckusick rename(p, uap, retval)
139242441Smckusick 	register struct proc *p;
139342441Smckusick 	register struct args {
13947701Ssam 		char	*from;
13957701Ssam 		char	*to;
139642441Smckusick 	} *uap;
139742441Smckusick 	int *retval;
139842441Smckusick {
139937741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
140042441Smckusick 	register struct nameidata *ndp = &u.u_nd;
140137741Smckusick 	struct nameidata tond;
140237741Smckusick 	int error;
14037701Ssam 
140437741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
140516694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
140616694Smckusick 	ndp->ni_dirp = uap->from;
140737741Smckusick 	if (error = namei(ndp))
140837741Smckusick 		RETURN (error);
140937741Smckusick 	fvp = ndp->ni_vp;
141038266Smckusick 	nddup(ndp, &tond);
141137741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
141237741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
141337741Smckusick 	tond.ni_dirp = uap->to;
141442465Smckusick 	if (error = namei(&tond)) {
141542465Smckusick 		VOP_ABORTOP(ndp);
141642465Smckusick 		vrele(ndp->ni_dvp);
141742465Smckusick 		vrele(fvp);
141842465Smckusick 		goto out1;
141942465Smckusick 	}
142037741Smckusick 	tdvp = tond.ni_dvp;
142137741Smckusick 	tvp = tond.ni_vp;
142237741Smckusick 	if (tvp != NULL) {
142337741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
142439242Sbostic 			error = ENOTDIR;
142537741Smckusick 			goto out;
142637741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
142739242Sbostic 			error = EISDIR;
142837741Smckusick 			goto out;
14299167Ssam 		}
14309167Ssam 	}
143137741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
143237741Smckusick 		error = EXDEV;
14339167Ssam 		goto out;
143410051Ssam 	}
143539286Smckusick 	if (fvp == tdvp)
143637741Smckusick 		error = EINVAL;
143739286Smckusick 	/*
143839286Smckusick 	 * If source is the same as the destination,
143939286Smckusick 	 * then there is nothing to do.
144039286Smckusick 	 */
144139286Smckusick 	if (fvp == tvp)
144239286Smckusick 		error = -1;
144337741Smckusick out:
144442465Smckusick 	if (!error) {
144542465Smckusick 		error = VOP_RENAME(ndp, &tond);
144642465Smckusick 	} else {
144737741Smckusick 		VOP_ABORTOP(&tond);
144842465Smckusick 		vput(tdvp);
144942465Smckusick 		if (tvp)
145042465Smckusick 			vput(tvp);
145137741Smckusick 		VOP_ABORTOP(ndp);
145242465Smckusick 		vrele(ndp->ni_dvp);
145342465Smckusick 		vrele(fvp);
14549167Ssam 	}
145537741Smckusick out1:
145638266Smckusick 	ndrele(&tond);
145739286Smckusick 	if (error == -1)
145839286Smckusick 		RETURN (0);
145937741Smckusick 	RETURN (error);
14607701Ssam }
14617701Ssam 
14627535Sroot /*
146312756Ssam  * Mkdir system call
146412756Ssam  */
146542441Smckusick /* ARGSUSED */
146642441Smckusick mkdir(p, uap, retval)
146742441Smckusick 	register struct proc *p;
146842441Smckusick 	register struct args {
146912756Ssam 		char	*name;
147012756Ssam 		int	dmode;
147142441Smckusick 	} *uap;
147242441Smckusick 	int *retval;
147342441Smckusick {
147442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
147537741Smckusick 	register struct vnode *vp;
147637741Smckusick 	struct vattr vattr;
147737741Smckusick 	int error;
147812756Ssam 
147937741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
148016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
148116694Smckusick 	ndp->ni_dirp = uap->name;
148237741Smckusick 	if (error = namei(ndp))
148337741Smckusick 		RETURN (error);
148437741Smckusick 	vp = ndp->ni_vp;
148537741Smckusick 	if (vp != NULL) {
148637741Smckusick 		VOP_ABORTOP(ndp);
148742465Smckusick 		vput(ndp->ni_dvp);
148842465Smckusick 		vrele(vp);
148937741Smckusick 		RETURN (EEXIST);
149012756Ssam 	}
149141362Smckusick 	VATTR_NULL(&vattr);
149237741Smckusick 	vattr.va_type = VDIR;
149342441Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask;
149437741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
149538145Smckusick 	if (!error)
149638145Smckusick 		vput(ndp->ni_vp);
149737741Smckusick 	RETURN (error);
149812756Ssam }
149912756Ssam 
150012756Ssam /*
150112756Ssam  * Rmdir system call.
150212756Ssam  */
150342441Smckusick /* ARGSUSED */
150442441Smckusick rmdir(p, uap, retval)
150542441Smckusick 	register struct proc *p;
150642441Smckusick 	struct args {
150742441Smckusick 		char	*name;
150842441Smckusick 	} *uap;
150942441Smckusick 	int *retval;
151012756Ssam {
151142441Smckusick 	register struct nameidata *ndp = &u.u_nd;
151237741Smckusick 	register struct vnode *vp;
151337741Smckusick 	int error;
151412756Ssam 
151537741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
151616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
151716694Smckusick 	ndp->ni_dirp = uap->name;
151837741Smckusick 	if (error = namei(ndp))
151937741Smckusick 		RETURN (error);
152037741Smckusick 	vp = ndp->ni_vp;
152137741Smckusick 	if (vp->v_type != VDIR) {
152237741Smckusick 		error = ENOTDIR;
152312756Ssam 		goto out;
152412756Ssam 	}
152512756Ssam 	/*
152637741Smckusick 	 * No rmdir "." please.
152712756Ssam 	 */
152837741Smckusick 	if (ndp->ni_dvp == vp) {
152937741Smckusick 		error = EINVAL;
153012756Ssam 		goto out;
153112756Ssam 	}
153212756Ssam 	/*
153337741Smckusick 	 * Don't unlink a mounted file.
153412756Ssam 	 */
153537741Smckusick 	if (vp->v_flag & VROOT)
153637741Smckusick 		error = EBUSY;
153712756Ssam out:
153842465Smckusick 	if (!error) {
153942465Smckusick 		error = VOP_RMDIR(ndp);
154042465Smckusick 	} else {
154137741Smckusick 		VOP_ABORTOP(ndp);
154242465Smckusick 		vput(ndp->ni_dvp);
154342465Smckusick 		vput(vp);
154442465Smckusick 	}
154537741Smckusick 	RETURN (error);
154612756Ssam }
154712756Ssam 
154837741Smckusick /*
154937741Smckusick  * Read a block of directory entries in a file system independent format
155037741Smckusick  */
155142441Smckusick getdirentries(p, uap, retval)
155242441Smckusick 	register struct proc *p;
155342441Smckusick 	register struct args {
155437741Smckusick 		int	fd;
155537741Smckusick 		char	*buf;
155637741Smckusick 		unsigned count;
155737741Smckusick 		long	*basep;
155842441Smckusick 	} *uap;
155942441Smckusick 	int *retval;
156042441Smckusick {
156139592Smckusick 	register struct vnode *vp;
156216540Ssam 	struct file *fp;
156337741Smckusick 	struct uio auio;
156437741Smckusick 	struct iovec aiov;
156538129Smckusick 	off_t off;
156640321Smckusick 	int error, eofflag;
156712756Ssam 
156842441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
156937741Smckusick 		RETURN (error);
157037741Smckusick 	if ((fp->f_flag & FREAD) == 0)
157137741Smckusick 		RETURN (EBADF);
157239592Smckusick 	vp = (struct vnode *)fp->f_data;
157339592Smckusick 	if (vp->v_type != VDIR)
157439592Smckusick 		RETURN (EINVAL);
157537741Smckusick 	aiov.iov_base = uap->buf;
157637741Smckusick 	aiov.iov_len = uap->count;
157737741Smckusick 	auio.uio_iov = &aiov;
157837741Smckusick 	auio.uio_iovcnt = 1;
157937741Smckusick 	auio.uio_rw = UIO_READ;
158037741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
158137741Smckusick 	auio.uio_resid = uap->count;
158239592Smckusick 	VOP_LOCK(vp);
158339592Smckusick 	auio.uio_offset = off = fp->f_offset;
158440321Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
158539592Smckusick 	fp->f_offset = auio.uio_offset;
158639592Smckusick 	VOP_UNLOCK(vp);
158739592Smckusick 	if (error)
158837741Smckusick 		RETURN (error);
158939592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
159042441Smckusick 	*retval = uap->count - auio.uio_resid;
159137741Smckusick 	RETURN (error);
159212756Ssam }
159312756Ssam 
159412756Ssam /*
159512756Ssam  * mode mask for creation of files
159612756Ssam  */
159742441Smckusick mode_t
159842441Smckusick umask(p, uap, retval)
159942441Smckusick 	register struct proc *p;
160042441Smckusick 	struct args {
160142441Smckusick 		int	mask;
160242441Smckusick 	} *uap;
160342441Smckusick 	int *retval;
160412756Ssam {
160512756Ssam 
160642441Smckusick 	*retval = u.u_cmask;
160742441Smckusick 	u.u_cmask = uap->mask & 07777;
160837741Smckusick 	RETURN (0);
160912756Ssam }
161037741Smckusick 
161139566Smarc /*
161239566Smarc  * Void all references to file by ripping underlying filesystem
161339566Smarc  * away from vnode.
161439566Smarc  */
161542441Smckusick /* ARGSUSED */
161642441Smckusick revoke(p, uap, retval)
161742441Smckusick 	register struct proc *p;
161842441Smckusick 	register struct args {
161939566Smarc 		char	*fname;
162041676Smckusick 		int	flags;
162142441Smckusick 	} *uap;
162242441Smckusick 	int *retval;
162342441Smckusick {
162442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
162539566Smarc 	register struct vnode *vp;
162639566Smarc 	struct vattr vattr;
162739566Smarc 	int error;
162839566Smarc 
162939566Smarc 	ndp->ni_nameiop = LOOKUP | FOLLOW;
163039566Smarc 	ndp->ni_segflg = UIO_USERSPACE;
163139566Smarc 	ndp->ni_dirp = uap->fname;
163239566Smarc 	if (error = namei(ndp))
163339566Smarc 		RETURN (error);
163439566Smarc 	vp = ndp->ni_vp;
163539566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
163639566Smarc 		error = EINVAL;
163739566Smarc 		goto out;
163839566Smarc 	}
163942441Smckusick 	if (error = VOP_GETATTR(vp, &vattr, ndp->ni_cred))
164039566Smarc 		goto out;
1641*42955Smckusick 	if (ndp->ni_cred->cr_uid != vattr.va_uid &&
164242441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
164339566Smarc 		goto out;
164439805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
164539632Smckusick 		vgoneall(vp);
164639566Smarc out:
164739566Smarc 	vrele(vp);
164839566Smarc 	RETURN (error);
164939566Smarc }
165039566Smarc 
165138408Smckusick getvnode(ofile, fdes, fpp)
165238408Smckusick 	struct file *ofile[];
165337741Smckusick 	struct file **fpp;
165437741Smckusick 	int fdes;
165537741Smckusick {
165637741Smckusick 	struct file *fp;
165737741Smckusick 
165838408Smckusick 	if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
165937741Smckusick 		return (EBADF);
166037741Smckusick 	if (fp->f_type != DTYPE_VNODE)
166137741Smckusick 		return (EINVAL);
166237741Smckusick 	*fpp = fp;
166337741Smckusick 	return (0);
166437741Smckusick }
1665