xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 43405)
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*43405Smckusick  *	@(#)vfs_syscalls.c	7.53 (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 
32*43405Smckusick #define	p_devtmp	p_logname[11]
33*43405Smckusick 
3439797Smckusick #undef RETURN
3542441Smckusick #define RETURN(val)	{ u.u_error = (val); if (u.u_spare[0] != 0) panic("lock count"); return (u.u_error); }
3639797Smckusick 
3737741Smckusick /*
3837741Smckusick  * Virtual File System System Calls
3937741Smckusick  */
4012756Ssam 
419167Ssam /*
4237741Smckusick  * mount system call
439167Ssam  */
4442441Smckusick /* ARGSUSED */
4542441Smckusick mount(p, uap, retval)
4642441Smckusick 	register struct proc *p;
4742441Smckusick 	register struct args {
4837741Smckusick 		int	type;
4937741Smckusick 		char	*dir;
5037741Smckusick 		int	flags;
5137741Smckusick 		caddr_t	data;
5242441Smckusick 	} *uap;
5342441Smckusick 	int *retval;
5442441Smckusick {
5542441Smckusick 	register struct nameidata *ndp = &u.u_nd;
5639335Smckusick 	register struct vnode *vp;
5739335Smckusick 	register struct mount *mp;
5840111Smckusick 	int error, flag;
596254Sroot 
6037741Smckusick 	/*
6137741Smckusick 	 * Must be super user
6237741Smckusick 	 */
6342441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
6437741Smckusick 		RETURN (error);
6537741Smckusick 	/*
6637741Smckusick 	 * Get vnode to be covered
6737741Smckusick 	 */
6837741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
6937741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
7037741Smckusick 	ndp->ni_dirp = uap->dir;
7137741Smckusick 	if (error = namei(ndp))
7237741Smckusick 		RETURN (error);
7337741Smckusick 	vp = ndp->ni_vp;
7441400Smckusick 	if (uap->flags & MNT_UPDATE) {
7539335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
7639335Smckusick 			vput(vp);
7739335Smckusick 			RETURN (EINVAL);
7839335Smckusick 		}
7939335Smckusick 		mp = vp->v_mount;
8039335Smckusick 		/*
8139335Smckusick 		 * We allow going from read-only to read-write,
8239335Smckusick 		 * but not from read-write to read-only.
8339335Smckusick 		 */
8441400Smckusick 		if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
8541400Smckusick 		    (uap->flags & MNT_RDONLY) != 0) {
8639335Smckusick 			vput(vp);
8739335Smckusick 			RETURN (EOPNOTSUPP);	/* Needs translation */
8839335Smckusick 		}
8941400Smckusick 		flag = mp->mnt_flag;
9041400Smckusick 		mp->mnt_flag |= MNT_UPDATE;
9139335Smckusick 		VOP_UNLOCK(vp);
9239335Smckusick 		goto update;
9339335Smckusick 	}
9439665Smckusick 	vinvalbuf(vp, 1);
9539805Smckusick 	if (vp->v_usecount != 1) {
9637741Smckusick 		vput(vp);
9737741Smckusick 		RETURN (EBUSY);
9837741Smckusick 	}
9937741Smckusick 	if (vp->v_type != VDIR) {
10037741Smckusick 		vput(vp);
10137741Smckusick 		RETURN (ENOTDIR);
10237741Smckusick 	}
10339741Smckusick 	if ((unsigned long)uap->type > MOUNT_MAXTYPE ||
10437741Smckusick 	    vfssw[uap->type] == (struct vfsops *)0) {
10537741Smckusick 		vput(vp);
10637741Smckusick 		RETURN (ENODEV);
10737741Smckusick 	}
10837741Smckusick 
10937741Smckusick 	/*
11039335Smckusick 	 * Allocate and initialize the file system.
11137741Smckusick 	 */
11237741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
11337741Smckusick 		M_MOUNT, M_WAITOK);
11441400Smckusick 	mp->mnt_op = vfssw[uap->type];
11541400Smckusick 	mp->mnt_flag = 0;
11641400Smckusick 	mp->mnt_exroot = 0;
11741400Smckusick 	mp->mnt_mounth = NULLVP;
11839335Smckusick 	if (error = vfs_lock(mp)) {
11939335Smckusick 		free((caddr_t)mp, M_MOUNT);
12039335Smckusick 		vput(vp);
12139335Smckusick 		RETURN (error);
12239335Smckusick 	}
12339335Smckusick 	if (vp->v_mountedhere != (struct mount *)0) {
12439335Smckusick 		vfs_unlock(mp);
12539335Smckusick 		free((caddr_t)mp, M_MOUNT);
12639335Smckusick 		vput(vp);
12739335Smckusick 		RETURN (EBUSY);
12839335Smckusick 	}
12939335Smckusick 	vp->v_mountedhere = mp;
13041400Smckusick 	mp->mnt_vnodecovered = vp;
13139335Smckusick update:
13239335Smckusick 	/*
13339335Smckusick 	 * Set the mount level flags.
13439335Smckusick 	 */
13541400Smckusick 	if (uap->flags & MNT_RDONLY)
13641400Smckusick 		mp->mnt_flag |= MNT_RDONLY;
13739335Smckusick 	else
13841400Smckusick 		mp->mnt_flag &= ~MNT_RDONLY;
13941400Smckusick 	if (uap->flags & MNT_NOSUID)
14041400Smckusick 		mp->mnt_flag |= MNT_NOSUID;
14139335Smckusick 	else
14241400Smckusick 		mp->mnt_flag &= ~MNT_NOSUID;
14341400Smckusick 	if (uap->flags & MNT_NOEXEC)
14441400Smckusick 		mp->mnt_flag |= MNT_NOEXEC;
14539335Smckusick 	else
14641400Smckusick 		mp->mnt_flag &= ~MNT_NOEXEC;
14741400Smckusick 	if (uap->flags & MNT_NODEV)
14841400Smckusick 		mp->mnt_flag |= MNT_NODEV;
14939335Smckusick 	else
15041400Smckusick 		mp->mnt_flag &= ~MNT_NODEV;
15141400Smckusick 	if (uap->flags & MNT_SYNCHRONOUS)
15241400Smckusick 		mp->mnt_flag |= MNT_SYNCHRONOUS;
15339335Smckusick 	else
15441400Smckusick 		mp->mnt_flag &= ~MNT_SYNCHRONOUS;
15539335Smckusick 	/*
15639335Smckusick 	 * Mount the filesystem.
15739335Smckusick 	 */
15839335Smckusick 	error = VFS_MOUNT(mp, uap->dir, uap->data, ndp);
15941400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
16041400Smckusick 		mp->mnt_flag &= ~MNT_UPDATE;
16139335Smckusick 		vrele(vp);
16240111Smckusick 		if (error)
16341400Smckusick 			mp->mnt_flag = flag;
16439335Smckusick 		RETURN (error);
16539335Smckusick 	}
16640110Smckusick 	/*
16740110Smckusick 	 * Put the new filesystem on the mount list after root.
16840110Smckusick 	 */
16941400Smckusick 	mp->mnt_next = rootfs->mnt_next;
17041400Smckusick 	mp->mnt_prev = rootfs;
17141400Smckusick 	rootfs->mnt_next = mp;
17241400Smckusick 	mp->mnt_next->mnt_prev = mp;
17337741Smckusick 	cache_purge(vp);
17437741Smckusick 	if (!error) {
17539335Smckusick 		VOP_UNLOCK(vp);
17637741Smckusick 		vfs_unlock(mp);
17739044Smckusick 		error = VFS_START(mp, 0);
17837741Smckusick 	} else {
17937741Smckusick 		vfs_remove(mp);
18037741Smckusick 		free((caddr_t)mp, M_MOUNT);
18139335Smckusick 		vput(vp);
18237741Smckusick 	}
18337741Smckusick 	RETURN (error);
1846254Sroot }
1856254Sroot 
1869167Ssam /*
18737741Smckusick  * Unmount system call.
18837741Smckusick  *
18937741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
19037741Smckusick  * not special file (as before).
1919167Ssam  */
19242441Smckusick /* ARGSUSED */
19342441Smckusick unmount(p, uap, retval)
19442441Smckusick 	register struct proc *p;
19542441Smckusick 	register struct args {
19637741Smckusick 		char	*pathp;
19737741Smckusick 		int	flags;
19842441Smckusick 	} *uap;
19942441Smckusick 	int *retval;
20042441Smckusick {
20137741Smckusick 	register struct vnode *vp;
20242441Smckusick 	register struct nameidata *ndp = &u.u_nd;
20339356Smckusick 	struct mount *mp;
20437741Smckusick 	int error;
2056254Sroot 
20637741Smckusick 	/*
20737741Smckusick 	 * Must be super user
20837741Smckusick 	 */
20942441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
21037741Smckusick 		RETURN (error);
21137741Smckusick 
21237741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
21337741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
21437741Smckusick 	ndp->ni_dirp = uap->pathp;
21537741Smckusick 	if (error = namei(ndp))
21637741Smckusick 		RETURN (error);
21737741Smckusick 	vp = ndp->ni_vp;
21837741Smckusick 	/*
21937741Smckusick 	 * Must be the root of the filesystem
22037741Smckusick 	 */
22137741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
22237741Smckusick 		vput(vp);
22337741Smckusick 		RETURN (EINVAL);
22437741Smckusick 	}
22537741Smckusick 	mp = vp->v_mount;
22637741Smckusick 	vput(vp);
22739356Smckusick 	RETURN (dounmount(mp, uap->flags));
22839356Smckusick }
22939356Smckusick 
23039356Smckusick /*
23139356Smckusick  * Do an unmount.
23239356Smckusick  */
23339356Smckusick dounmount(mp, flags)
23439356Smckusick 	register struct mount *mp;
23539356Smckusick 	int flags;
23639356Smckusick {
23739356Smckusick 	struct vnode *coveredvp;
23839356Smckusick 	int error;
23939356Smckusick 
24041400Smckusick 	coveredvp = mp->mnt_vnodecovered;
24141298Smckusick 	if (vfs_busy(mp))
24241298Smckusick 		return (EBUSY);
24341400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
24437741Smckusick 	if (error = vfs_lock(mp))
24539356Smckusick 		return (error);
24637741Smckusick 
24737741Smckusick 	xumount(mp);		/* remove unused sticky files from text table */
24837741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
24941676Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE))
25041676Smckusick 		error = VFS_UNMOUNT(mp, flags);
25141400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
25241298Smckusick 	vfs_unbusy(mp);
25337741Smckusick 	if (error) {
25437741Smckusick 		vfs_unlock(mp);
25537741Smckusick 	} else {
25637741Smckusick 		vrele(coveredvp);
25737741Smckusick 		vfs_remove(mp);
25837741Smckusick 		free((caddr_t)mp, M_MOUNT);
25937741Smckusick 	}
26039356Smckusick 	return (error);
2616254Sroot }
2626254Sroot 
2639167Ssam /*
26437741Smckusick  * Sync system call.
26537741Smckusick  * Sync each mounted filesystem.
2669167Ssam  */
26739491Smckusick /* ARGSUSED */
26842441Smckusick sync(p, uap, retval)
26942441Smckusick 	register struct proc *p;
27042441Smckusick 	struct args *uap;
27142441Smckusick 	int *retval;
2726254Sroot {
27337741Smckusick 	register struct mount *mp;
27441298Smckusick 	struct mount *omp;
27537741Smckusick 
27637741Smckusick 	mp = rootfs;
27737741Smckusick 	do {
27840343Smckusick 		/*
27940343Smckusick 		 * The lock check below is to avoid races with mount
28040343Smckusick 		 * and unmount.
28140343Smckusick 		 */
28241400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
28341298Smckusick 		    !vfs_busy(mp)) {
28437741Smckusick 			VFS_SYNC(mp, MNT_NOWAIT);
28541298Smckusick 			omp = mp;
28641400Smckusick 			mp = mp->mnt_next;
28741298Smckusick 			vfs_unbusy(omp);
28841298Smckusick 		} else
28941400Smckusick 			mp = mp->mnt_next;
29037741Smckusick 	} while (mp != rootfs);
29137741Smckusick }
29237741Smckusick 
29337741Smckusick /*
29441298Smckusick  * operate on filesystem quotas
29541298Smckusick  */
29642441Smckusick /* ARGSUSED */
29742441Smckusick quotactl(p, uap, retval)
29842441Smckusick 	register struct proc *p;
29942441Smckusick 	register struct args {
30041298Smckusick 		char *path;
30141298Smckusick 		int cmd;
30241298Smckusick 		int uid;
30341298Smckusick 		caddr_t arg;
30442441Smckusick 	} *uap;
30542441Smckusick 	int *retval;
30642441Smckusick {
30741298Smckusick 	register struct mount *mp;
30842441Smckusick 	register struct nameidata *ndp = &u.u_nd;
30941298Smckusick 	int error;
31041298Smckusick 
31141298Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
31241298Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
31341298Smckusick 	ndp->ni_dirp = uap->path;
31441298Smckusick 	if (error = namei(ndp))
31541298Smckusick 		RETURN (error);
31641298Smckusick 	mp = ndp->ni_vp->v_mount;
31741298Smckusick 	vrele(ndp->ni_vp);
31841298Smckusick 	RETURN (VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg));
31941298Smckusick }
32041298Smckusick 
32141298Smckusick /*
32237741Smckusick  * get filesystem statistics
32337741Smckusick  */
32442441Smckusick /* ARGSUSED */
32542441Smckusick statfs(p, uap, retval)
32642441Smckusick 	register struct proc *p;
32742441Smckusick 	register struct args {
32837741Smckusick 		char *path;
32937741Smckusick 		struct statfs *buf;
33042441Smckusick 	} *uap;
33142441Smckusick 	int *retval;
33242441Smckusick {
33339464Smckusick 	register struct mount *mp;
33442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
33540343Smckusick 	register struct statfs *sp;
33637741Smckusick 	int error;
33737741Smckusick 
33839544Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
33937741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
34037741Smckusick 	ndp->ni_dirp = uap->path;
34137741Smckusick 	if (error = namei(ndp))
34237741Smckusick 		RETURN (error);
34339544Smckusick 	mp = ndp->ni_vp->v_mount;
34441400Smckusick 	sp = &mp->mnt_stat;
34539544Smckusick 	vrele(ndp->ni_vp);
34640343Smckusick 	if (error = VFS_STATFS(mp, sp))
34739544Smckusick 		RETURN (error);
34841400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
34940343Smckusick 	RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
35037741Smckusick }
35137741Smckusick 
35242441Smckusick /*
35342441Smckusick  * get filesystem statistics
35442441Smckusick  */
35542441Smckusick /* ARGSUSED */
35642441Smckusick fstatfs(p, uap, retval)
35742441Smckusick 	register struct proc *p;
35842441Smckusick 	register struct args {
35937741Smckusick 		int fd;
36037741Smckusick 		struct statfs *buf;
36142441Smckusick 	} *uap;
36242441Smckusick 	int *retval;
36342441Smckusick {
36437741Smckusick 	struct file *fp;
36539464Smckusick 	struct mount *mp;
36640343Smckusick 	register struct statfs *sp;
36737741Smckusick 	int error;
36837741Smckusick 
36942441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
37037741Smckusick 		RETURN (error);
37139464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
37241400Smckusick 	sp = &mp->mnt_stat;
37340343Smckusick 	if (error = VFS_STATFS(mp, sp))
37437741Smckusick 		RETURN (error);
37541400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
37640343Smckusick 	RETURN (copyout((caddr_t)sp, (caddr_t)uap->buf, sizeof(*sp)));
37737741Smckusick }
37837741Smckusick 
37937741Smckusick /*
38038270Smckusick  * get statistics on all filesystems
38138270Smckusick  */
38242441Smckusick getfsstat(p, uap, retval)
38342441Smckusick 	register struct proc *p;
38442441Smckusick 	register struct args {
38538270Smckusick 		struct statfs *buf;
38638270Smckusick 		long bufsize;
38740343Smckusick 		int flags;
38842441Smckusick 	} *uap;
38942441Smckusick 	int *retval;
39042441Smckusick {
39138270Smckusick 	register struct mount *mp;
39240343Smckusick 	register struct statfs *sp;
39339606Smckusick 	caddr_t sfsp;
39438270Smckusick 	long count, maxcount, error;
39538270Smckusick 
39638270Smckusick 	maxcount = uap->bufsize / sizeof(struct statfs);
39739606Smckusick 	sfsp = (caddr_t)uap->buf;
39838270Smckusick 	mp = rootfs;
39938270Smckusick 	count = 0;
40038270Smckusick 	do {
40141400Smckusick 		if (sfsp && count < maxcount &&
40241400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
40341400Smckusick 			sp = &mp->mnt_stat;
40440343Smckusick 			/*
40540343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
40640343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
40740343Smckusick 			 */
40840343Smckusick 			if (((uap->flags & MNT_NOWAIT) == 0 ||
40940343Smckusick 			    (uap->flags & MNT_WAIT)) &&
41040343Smckusick 			    (error = VFS_STATFS(mp, sp))) {
41141400Smckusick 				mp = mp->mnt_prev;
41239607Smckusick 				continue;
41339607Smckusick 			}
41441400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
41540343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
41639606Smckusick 				RETURN (error);
41740343Smckusick 			sfsp += sizeof(*sp);
41838270Smckusick 		}
41939606Smckusick 		count++;
42041400Smckusick 		mp = mp->mnt_prev;
42138270Smckusick 	} while (mp != rootfs);
42238270Smckusick 	if (sfsp && count > maxcount)
42342441Smckusick 		*retval = maxcount;
42438270Smckusick 	else
42542441Smckusick 		*retval = count;
42638270Smckusick 	RETURN (0);
42738270Smckusick }
42838270Smckusick 
42938270Smckusick /*
43038259Smckusick  * Change current working directory to a given file descriptor.
43138259Smckusick  */
43242441Smckusick /* ARGSUSED */
43342441Smckusick fchdir(p, uap, retval)
43442441Smckusick 	register struct proc *p;
43542441Smckusick 	struct args {
43642441Smckusick 		int	fd;
43742441Smckusick 	} *uap;
43842441Smckusick 	int *retval;
43938259Smckusick {
44042441Smckusick 	register struct nameidata *ndp = &u.u_nd;
44138259Smckusick 	register struct vnode *vp;
44238259Smckusick 	struct file *fp;
44338259Smckusick 	int error;
44438259Smckusick 
44542441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
44638259Smckusick 		RETURN (error);
44738259Smckusick 	vp = (struct vnode *)fp->f_data;
44838259Smckusick 	VOP_LOCK(vp);
44938259Smckusick 	if (vp->v_type != VDIR)
45038259Smckusick 		error = ENOTDIR;
45138259Smckusick 	else
45242441Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
45338259Smckusick 	VOP_UNLOCK(vp);
45439860Smckusick 	if (error)
45539860Smckusick 		RETURN (error);
45639860Smckusick 	VREF(vp);
45742441Smckusick 	vrele(ndp->ni_cdir);
45842441Smckusick 	ndp->ni_cdir = vp;
45939860Smckusick 	RETURN (0);
46038259Smckusick }
46138259Smckusick 
46238259Smckusick /*
46337741Smckusick  * Change current working directory (``.'').
46437741Smckusick  */
46542441Smckusick /* ARGSUSED */
46642441Smckusick chdir(p, uap, retval)
46742441Smckusick 	register struct proc *p;
46842441Smckusick 	struct args {
46942441Smckusick 		char	*fname;
47042441Smckusick 	} *uap;
47142441Smckusick 	int *retval;
47237741Smckusick {
47342441Smckusick 	register struct nameidata *ndp = &u.u_nd;
47437741Smckusick 	int error;
4756254Sroot 
47637741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
47716694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
47816694Smckusick 	ndp->ni_dirp = uap->fname;
47937741Smckusick 	if (error = chdirec(ndp))
48037741Smckusick 		RETURN (error);
48142441Smckusick 	vrele(ndp->ni_cdir);
48242441Smckusick 	ndp->ni_cdir = ndp->ni_vp;
48337741Smckusick 	RETURN (0);
48437741Smckusick }
4856254Sroot 
48637741Smckusick /*
48737741Smckusick  * Change notion of root (``/'') directory.
48837741Smckusick  */
48942441Smckusick /* ARGSUSED */
49042441Smckusick chroot(p, uap, retval)
49142441Smckusick 	register struct proc *p;
49242441Smckusick 	struct args {
49342441Smckusick 		char	*fname;
49442441Smckusick 	} *uap;
49542441Smckusick 	int *retval;
49637741Smckusick {
49742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
49837741Smckusick 	int error;
49937741Smckusick 
50042441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
50137741Smckusick 		RETURN (error);
50237741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
50337741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
50437741Smckusick 	ndp->ni_dirp = uap->fname;
50537741Smckusick 	if (error = chdirec(ndp))
50637741Smckusick 		RETURN (error);
50742441Smckusick 	if (ndp->ni_rdir != NULL)
50842441Smckusick 		vrele(ndp->ni_rdir);
50942441Smckusick 	ndp->ni_rdir = ndp->ni_vp;
51037741Smckusick 	RETURN (0);
5116254Sroot }
5126254Sroot 
51337Sbill /*
51437741Smckusick  * Common routine for chroot and chdir.
51537741Smckusick  */
51637741Smckusick chdirec(ndp)
51737741Smckusick 	register struct nameidata *ndp;
51837741Smckusick {
51937741Smckusick 	struct vnode *vp;
52037741Smckusick 	int error;
52137741Smckusick 
52237741Smckusick 	if (error = namei(ndp))
52337741Smckusick 		return (error);
52437741Smckusick 	vp = ndp->ni_vp;
52537741Smckusick 	if (vp->v_type != VDIR)
52637741Smckusick 		error = ENOTDIR;
52737741Smckusick 	else
52838399Smckusick 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
52937741Smckusick 	VOP_UNLOCK(vp);
53037741Smckusick 	if (error)
53137741Smckusick 		vrele(vp);
53237741Smckusick 	return (error);
53337741Smckusick }
53437741Smckusick 
53537741Smckusick /*
5366254Sroot  * Open system call.
53742441Smckusick  * Check permissions, allocate an open file structure,
53842441Smckusick  * and call the device open routine if any.
5396254Sroot  */
54042441Smckusick open(p, uap, retval)
54142441Smckusick 	register struct proc *p;
54242441Smckusick 	register struct args {
5436254Sroot 		char	*fname;
5447701Ssam 		int	mode;
54512756Ssam 		int	crtmode;
54642441Smckusick 	} *uap;
54742441Smckusick 	int *retval;
5486254Sroot {
54942441Smckusick 	struct nameidata *ndp = &u.u_nd;
55042441Smckusick 	register struct file *fp;
55137741Smckusick 	int fmode, cmode;
55237741Smckusick 	struct file *nfp;
55337741Smckusick 	int indx, error;
55437741Smckusick 	extern struct fileops vnops;
5556254Sroot 
55637741Smckusick 	if (error = falloc(&nfp, &indx))
55742441Smckusick 		RETURN (error);
55837741Smckusick 	fp = nfp;
55942441Smckusick 	fmode = uap->mode - FOPEN;
56042441Smckusick 	cmode = ((uap->crtmode &~ u.u_cmask) & 07777) &~ S_ISVTX;
56142441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
56242441Smckusick 	ndp->ni_dirp = uap->fname;
563*43405Smckusick 	p->p_devtmp = -1;			/* XXX check for fdopen */
56442441Smckusick 	if (error = vn_open(ndp, fmode, cmode)) {
56537741Smckusick 		crfree(fp->f_cred);
56637741Smckusick 		fp->f_count--;
567*43405Smckusick 		if (error == ENODEV &&		/* XXX from fdopen */
568*43405Smckusick 		    p->p_devtmp >= 0 &&
569*43405Smckusick 		    (error = dupfdopen(indx, p->p_devtmp, fmode)) == 0) {
57042441Smckusick 			*retval = indx;
57142441Smckusick 			RETURN (0);
57242441Smckusick 		}
57340884Smckusick 		if (error == ERESTART)
57440884Smckusick 			error = EINTR;
57542441Smckusick 		u.u_ofile[indx] = NULL;
57642441Smckusick 		RETURN (error);
57712756Ssam 	}
57837741Smckusick 	fp->f_flag = fmode & FMASK;
57937741Smckusick 	fp->f_type = DTYPE_VNODE;
58037741Smckusick 	fp->f_ops = &vnops;
58137741Smckusick 	fp->f_data = (caddr_t)ndp->ni_vp;
58242441Smckusick 	*retval = indx;
58342441Smckusick 	RETURN (0);
5846254Sroot }
5856254Sroot 
58642955Smckusick #ifdef COMPAT_43
5876254Sroot /*
58842441Smckusick  * Creat system call.
5896254Sroot  */
59042955Smckusick ocreat(p, uap, retval)
59142441Smckusick 	struct proc *p;
59242441Smckusick 	register struct args {
59342441Smckusick 		char	*fname;
59442441Smckusick 		int	fmode;
59542441Smckusick 	} *uap;
59642441Smckusick 	int *retval;
5976254Sroot {
59842441Smckusick 	struct args {
5996254Sroot 		char	*fname;
60042441Smckusick 		int	mode;
60142441Smckusick 		int	crtmode;
60242441Smckusick 	} openuap;
60342441Smckusick 
60442441Smckusick 	openuap.fname = uap->fname;
60542441Smckusick 	openuap.crtmode = uap->fmode;
60642441Smckusick 	openuap.mode = O_WRONLY | O_CREAT | O_TRUNC;
60742441Smckusick 	RETURN (open(p, &openuap, retval));
60842441Smckusick }
60942955Smckusick #endif /* COMPAT_43 */
61042441Smckusick 
61142441Smckusick /*
61242441Smckusick  * Mknod system call
61342441Smckusick  */
61442441Smckusick /* ARGSUSED */
61542441Smckusick mknod(p, uap, retval)
61642441Smckusick 	register struct proc *p;
61742441Smckusick 	register struct args {
61842441Smckusick 		char	*fname;
6196254Sroot 		int	fmode;
6206254Sroot 		int	dev;
62142441Smckusick 	} *uap;
62242441Smckusick 	int *retval;
62342441Smckusick {
62442441Smckusick 	register struct nameidata *ndp = &u.u_nd;
62537741Smckusick 	register struct vnode *vp;
62637741Smckusick 	struct vattr vattr;
62737741Smckusick 	int error;
6286254Sroot 
62942441Smckusick 	if (error = suser(ndp->ni_cred, &u.u_acflag))
63037741Smckusick 		RETURN (error);
63137741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
63216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
63316694Smckusick 	ndp->ni_dirp = uap->fname;
63437741Smckusick 	if (error = namei(ndp))
63537741Smckusick 		RETURN (error);
63637741Smckusick 	vp = ndp->ni_vp;
63737741Smckusick 	if (vp != NULL) {
63837741Smckusick 		error = EEXIST;
63912756Ssam 		goto out;
6406254Sroot 	}
64141362Smckusick 	VATTR_NULL(&vattr);
64240635Smckusick 	switch (uap->fmode & S_IFMT) {
64312756Ssam 
64440635Smckusick 	case S_IFMT:	/* used by badsect to flag bad sectors */
64537741Smckusick 		vattr.va_type = VBAD;
64637741Smckusick 		break;
64740635Smckusick 	case S_IFCHR:
64837741Smckusick 		vattr.va_type = VCHR;
64937741Smckusick 		break;
65040635Smckusick 	case S_IFBLK:
65137741Smckusick 		vattr.va_type = VBLK;
65237741Smckusick 		break;
65337741Smckusick 	default:
65437741Smckusick 		error = EINVAL;
65537741Smckusick 		goto out;
6566254Sroot 	}
65742441Smckusick 	vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask;
65837741Smckusick 	vattr.va_rdev = uap->dev;
6596254Sroot out:
66042465Smckusick 	if (!error) {
66142465Smckusick 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
66242465Smckusick 	} else {
66337741Smckusick 		VOP_ABORTOP(ndp);
66443344Smckusick 		if (ndp->ni_dvp == vp)
66543344Smckusick 			vrele(ndp->ni_dvp);
66643344Smckusick 		else
66743344Smckusick 			vput(ndp->ni_dvp);
66842465Smckusick 		if (vp)
66942465Smckusick 			vrele(vp);
67042465Smckusick 	}
67137741Smckusick 	RETURN (error);
6726254Sroot }
6736254Sroot 
6746254Sroot /*
67540285Smckusick  * Mkfifo system call
67640285Smckusick  */
67742441Smckusick /* ARGSUSED */
67842441Smckusick mkfifo(p, uap, retval)
67942441Smckusick 	register struct proc *p;
68042441Smckusick 	register struct args {
68140285Smckusick 		char	*fname;
68240285Smckusick 		int	fmode;
68342441Smckusick 	} *uap;
68442441Smckusick 	int *retval;
68542441Smckusick {
68642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
68740285Smckusick 	struct vattr vattr;
68840285Smckusick 	int error;
68940285Smckusick 
69040285Smckusick #ifndef FIFO
69140285Smckusick 	RETURN (EOPNOTSUPP);
69240285Smckusick #else
69340285Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
69440285Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
69540285Smckusick 	ndp->ni_dirp = uap->fname;
69640285Smckusick 	if (error = namei(ndp))
69740285Smckusick 		RETURN (error);
69840285Smckusick 	if (ndp->ni_vp != NULL) {
69940285Smckusick 		VOP_ABORTOP(ndp);
70043344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
70143344Smckusick 			vrele(ndp->ni_dvp);
70243344Smckusick 		else
70343344Smckusick 			vput(ndp->ni_dvp);
70442465Smckusick 		vrele(ndp->ni_vp);
70540285Smckusick 		RETURN (EEXIST);
70640285Smckusick 	} else {
70741362Smckusick 		VATTR_NULL(&vattr);
70840285Smckusick 		vattr.va_type = VFIFO;
70942441Smckusick 		vattr.va_mode = (uap->fmode & 07777) &~ u.u_cmask;
71040285Smckusick 	}
71140285Smckusick 	RETURN (VOP_MKNOD(ndp, &vattr, ndp->ni_cred));
71240285Smckusick #endif /* FIFO */
71340285Smckusick }
71440285Smckusick 
71540285Smckusick /*
7166254Sroot  * link system call
7176254Sroot  */
71842441Smckusick /* ARGSUSED */
71942441Smckusick link(p, uap, retval)
72042441Smckusick 	register struct proc *p;
72142441Smckusick 	register struct args {
7226254Sroot 		char	*target;
7236254Sroot 		char	*linkname;
72442441Smckusick 	} *uap;
72542441Smckusick 	int *retval;
72642441Smckusick {
72742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
72837741Smckusick 	register struct vnode *vp, *xp;
72937741Smckusick 	int error;
7306254Sroot 
73116694Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
73216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
73316694Smckusick 	ndp->ni_dirp = uap->target;
73437741Smckusick 	if (error = namei(ndp))
73537741Smckusick 		RETURN (error);
73637741Smckusick 	vp = ndp->ni_vp;
73737741Smckusick 	if (vp->v_type == VDIR &&
73842441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
73937741Smckusick 		goto out1;
74037741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
74116694Smckusick 	ndp->ni_dirp = (caddr_t)uap->linkname;
74237741Smckusick 	if (error = namei(ndp))
74337741Smckusick 		goto out1;
74437741Smckusick 	xp = ndp->ni_vp;
7456254Sroot 	if (xp != NULL) {
74637741Smckusick 		error = EEXIST;
7476254Sroot 		goto out;
7486254Sroot 	}
74937741Smckusick 	xp = ndp->ni_dvp;
75037741Smckusick 	if (vp->v_mount != xp->v_mount)
75137741Smckusick 		error = EXDEV;
7526254Sroot out:
75342465Smckusick 	if (!error) {
75442465Smckusick 		error = VOP_LINK(vp, ndp);
75542465Smckusick 	} else {
75637741Smckusick 		VOP_ABORTOP(ndp);
75743344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
75843344Smckusick 			vrele(ndp->ni_dvp);
75943344Smckusick 		else
76043344Smckusick 			vput(ndp->ni_dvp);
76142465Smckusick 		if (ndp->ni_vp)
76242465Smckusick 			vrele(ndp->ni_vp);
76342465Smckusick 	}
76437741Smckusick out1:
76537741Smckusick 	vrele(vp);
76637741Smckusick 	RETURN (error);
7676254Sroot }
7686254Sroot 
7696254Sroot /*
7706254Sroot  * symlink -- make a symbolic link
7716254Sroot  */
77242441Smckusick /* ARGSUSED */
77342441Smckusick symlink(p, uap, retval)
77442441Smckusick 	register struct proc *p;
77542441Smckusick 	register struct args {
7766254Sroot 		char	*target;
7776254Sroot 		char	*linkname;
77842441Smckusick 	} *uap;
77942441Smckusick 	int *retval;
78042441Smckusick {
78142441Smckusick 	register struct nameidata *ndp = &u.u_nd;
78237741Smckusick 	struct vattr vattr;
78337741Smckusick 	char *target;
78437741Smckusick 	int error;
7856254Sroot 
78616694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
78716694Smckusick 	ndp->ni_dirp = uap->linkname;
78837741Smckusick 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
78937741Smckusick 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
79042465Smckusick 		goto out;
79137741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
79237741Smckusick 	if (error = namei(ndp))
79342465Smckusick 		goto out;
79442465Smckusick 	if (ndp->ni_vp) {
79542465Smckusick 		VOP_ABORTOP(ndp);
79643344Smckusick 		if (ndp->ni_dvp == ndp->ni_vp)
79743344Smckusick 			vrele(ndp->ni_dvp);
79843344Smckusick 		else
79943344Smckusick 			vput(ndp->ni_dvp);
80042465Smckusick 		vrele(ndp->ni_vp);
80137741Smckusick 		error = EEXIST;
80237741Smckusick 		goto out;
8036254Sroot 	}
80441362Smckusick 	VATTR_NULL(&vattr);
80542441Smckusick 	vattr.va_mode = 0777 &~ u.u_cmask;
80642465Smckusick 	error = VOP_SYMLINK(ndp, &vattr, target);
80737741Smckusick out:
80837741Smckusick 	FREE(target, M_NAMEI);
80937741Smckusick 	RETURN (error);
8106254Sroot }
8116254Sroot 
8126254Sroot /*
8136254Sroot  * Unlink system call.
8146254Sroot  * Hard to avoid races here, especially
8156254Sroot  * in unlinking directories.
8166254Sroot  */
81742441Smckusick /* ARGSUSED */
81842441Smckusick unlink(p, uap, retval)
81942441Smckusick 	register struct proc *p;
82042441Smckusick 	struct args {
82142441Smckusick 		char	*fname;
82242441Smckusick 	} *uap;
82342441Smckusick 	int *retval;
8246254Sroot {
82542441Smckusick 	register struct nameidata *ndp = &u.u_nd;
82637741Smckusick 	register struct vnode *vp;
82737741Smckusick 	int error;
8286254Sroot 
82937741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
83016694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
83116694Smckusick 	ndp->ni_dirp = uap->fname;
83237741Smckusick 	if (error = namei(ndp))
83337741Smckusick 		RETURN (error);
83437741Smckusick 	vp = ndp->ni_vp;
83537741Smckusick 	if (vp->v_type == VDIR &&
83642441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
8376254Sroot 		goto out;
8386254Sroot 	/*
8396254Sroot 	 * Don't unlink a mounted file.
8406254Sroot 	 */
84137741Smckusick 	if (vp->v_flag & VROOT) {
84237741Smckusick 		error = EBUSY;
8436254Sroot 		goto out;
8446254Sroot 	}
84537741Smckusick 	if (vp->v_flag & VTEXT)
84637741Smckusick 		xrele(vp);	/* try once to free text */
8476254Sroot out:
84842465Smckusick 	if (!error) {
84942465Smckusick 		error = VOP_REMOVE(ndp);
85042465Smckusick 	} else {
85137741Smckusick 		VOP_ABORTOP(ndp);
85243344Smckusick 		if (ndp->ni_dvp == vp)
85343344Smckusick 			vrele(ndp->ni_dvp);
85443344Smckusick 		else
85543344Smckusick 			vput(ndp->ni_dvp);
85642465Smckusick 		vput(vp);
85742465Smckusick 	}
85837741Smckusick 	RETURN (error);
8596254Sroot }
8606254Sroot 
8616254Sroot /*
8626254Sroot  * Seek system call
8636254Sroot  */
86442441Smckusick lseek(p, uap, retval)
86542441Smckusick 	register struct proc *p;
86642441Smckusick 	register struct args {
86737741Smckusick 		int	fdes;
8686254Sroot 		off_t	off;
8696254Sroot 		int	sbase;
87042441Smckusick 	} *uap;
87142441Smckusick 	off_t *retval;
87242441Smckusick {
87342441Smckusick 	struct ucred *cred = u.u_nd.ni_cred;
87442441Smckusick 	register struct file *fp;
87537741Smckusick 	struct vattr vattr;
87637741Smckusick 	int error;
8776254Sroot 
87837741Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
87942441Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
88037741Smckusick 		RETURN (EBADF);
88137741Smckusick 	if (fp->f_type != DTYPE_VNODE)
88237741Smckusick 		RETURN (ESPIPE);
88313878Ssam 	switch (uap->sbase) {
88413878Ssam 
88513878Ssam 	case L_INCR:
88613878Ssam 		fp->f_offset += uap->off;
88713878Ssam 		break;
88813878Ssam 
88913878Ssam 	case L_XTND:
89037741Smckusick 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
89142441Smckusick 		    &vattr, cred))
89237741Smckusick 			RETURN (error);
89337741Smckusick 		fp->f_offset = uap->off + vattr.va_size;
89413878Ssam 		break;
89513878Ssam 
89613878Ssam 	case L_SET:
89713878Ssam 		fp->f_offset = uap->off;
89813878Ssam 		break;
89913878Ssam 
90013878Ssam 	default:
90137741Smckusick 		RETURN (EINVAL);
90213878Ssam 	}
90342441Smckusick 	*retval = fp->f_offset;
90437741Smckusick 	RETURN (0);
9056254Sroot }
9066254Sroot 
9076254Sroot /*
9086254Sroot  * Access system call
9096254Sroot  */
91042441Smckusick /* ARGSUSED */
91142441Smckusick saccess(p, uap, retval)
91242441Smckusick 	register struct proc *p;
91342441Smckusick 	register struct args {
9146254Sroot 		char	*fname;
9156254Sroot 		int	fmode;
91642441Smckusick 	} *uap;
91742441Smckusick 	int *retval;
91842441Smckusick {
91942441Smckusick 	register struct nameidata *ndp = &u.u_nd;
92042441Smckusick 	register struct ucred *cred = ndp->ni_cred;
92137741Smckusick 	register struct vnode *vp;
92237741Smckusick 	int error, mode, svuid, svgid;
9236254Sroot 
92442441Smckusick 	svuid = cred->cr_uid;
92542441Smckusick 	svgid = cred->cr_groups[0];
92642441Smckusick 	cred->cr_uid = p->p_ruid;
92742441Smckusick 	cred->cr_groups[0] = p->p_rgid;
92837741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
92916694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
93016694Smckusick 	ndp->ni_dirp = uap->fname;
93137741Smckusick 	if (error = namei(ndp))
93237741Smckusick 		goto out1;
93337741Smckusick 	vp = ndp->ni_vp;
93437741Smckusick 	/*
93537741Smckusick 	 * fmode == 0 means only check for exist
93637741Smckusick 	 */
93737741Smckusick 	if (uap->fmode) {
93837741Smckusick 		mode = 0;
93937741Smckusick 		if (uap->fmode & R_OK)
94037741Smckusick 			mode |= VREAD;
94137741Smckusick 		if (uap->fmode & W_OK)
94237741Smckusick 			mode |= VWRITE;
94337741Smckusick 		if (uap->fmode & X_OK)
94437741Smckusick 			mode |= VEXEC;
94539543Smckusick 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
94638399Smckusick 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
9476254Sroot 	}
94837741Smckusick 	vput(vp);
94937741Smckusick out1:
95042441Smckusick 	cred->cr_uid = svuid;
95142441Smckusick 	cred->cr_groups[0] = svgid;
95237741Smckusick 	RETURN (error);
9536254Sroot }
9546254Sroot 
9556254Sroot /*
9566574Smckusic  * Stat system call.  This version follows links.
95737Sbill  */
95842441Smckusick /* ARGSUSED */
95942441Smckusick stat(p, uap, retval)
96042441Smckusick 	register struct proc *p;
96142441Smckusick 	register struct args {
96242441Smckusick 		char	*fname;
96342441Smckusick 		struct stat *ub;
96442441Smckusick 	} *uap;
96542441Smckusick 	int *retval;
96637Sbill {
96742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
96842441Smckusick 	struct stat sb;
96942441Smckusick 	int error;
97037Sbill 
97142441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
97242441Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
97342441Smckusick 	ndp->ni_dirp = uap->fname;
97442441Smckusick 	if (error = namei(ndp))
97542441Smckusick 		RETURN (error);
97642441Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
97742441Smckusick 	vput(ndp->ni_vp);
97842441Smckusick 	if (error)
97942441Smckusick 		RETURN (error);
98042441Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
98142441Smckusick 	RETURN (error);
98237Sbill }
98337Sbill 
98437Sbill /*
9856574Smckusic  * Lstat system call.  This version does not follow links.
9865992Swnj  */
98742441Smckusick /* ARGSUSED */
98842441Smckusick lstat(p, uap, retval)
98942441Smckusick 	register struct proc *p;
99042441Smckusick 	register struct args {
9915992Swnj 		char	*fname;
99212756Ssam 		struct stat *ub;
99342441Smckusick 	} *uap;
99442441Smckusick 	int *retval;
99542441Smckusick {
99642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
99712756Ssam 	struct stat sb;
99837741Smckusick 	int error;
9995992Swnj 
100042441Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | NOFOLLOW;
100116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
100216694Smckusick 	ndp->ni_dirp = uap->fname;
100337741Smckusick 	if (error = namei(ndp))
100437741Smckusick 		RETURN (error);
100537741Smckusick 	error = vn_stat(ndp->ni_vp, &sb);
100637741Smckusick 	vput(ndp->ni_vp);
100737741Smckusick 	if (error)
100837741Smckusick 		RETURN (error);
100937741Smckusick 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
101037741Smckusick 	RETURN (error);
10115992Swnj }
10125992Swnj 
10135992Swnj /*
10145992Swnj  * Return target name of a symbolic link
101537Sbill  */
101642441Smckusick /* ARGSUSED */
101742441Smckusick readlink(p, uap, retval)
101842441Smckusick 	register struct proc *p;
101942441Smckusick 	register struct args {
10205992Swnj 		char	*name;
10215992Swnj 		char	*buf;
10225992Swnj 		int	count;
102342441Smckusick 	} *uap;
102442441Smckusick 	int *retval;
102542441Smckusick {
102642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
102737741Smckusick 	register struct vnode *vp;
102837741Smckusick 	struct iovec aiov;
102937741Smckusick 	struct uio auio;
103037741Smckusick 	int error;
10315992Swnj 
103237741Smckusick 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
103316694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
103416694Smckusick 	ndp->ni_dirp = uap->name;
103537741Smckusick 	if (error = namei(ndp))
103637741Smckusick 		RETURN (error);
103737741Smckusick 	vp = ndp->ni_vp;
103837741Smckusick 	if (vp->v_type != VLNK) {
103937741Smckusick 		error = EINVAL;
10405992Swnj 		goto out;
10415992Swnj 	}
104237741Smckusick 	aiov.iov_base = uap->buf;
104337741Smckusick 	aiov.iov_len = uap->count;
104437741Smckusick 	auio.uio_iov = &aiov;
104537741Smckusick 	auio.uio_iovcnt = 1;
104637741Smckusick 	auio.uio_offset = 0;
104737741Smckusick 	auio.uio_rw = UIO_READ;
104837741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
104937741Smckusick 	auio.uio_resid = uap->count;
105037741Smckusick 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
10515992Swnj out:
105237741Smckusick 	vput(vp);
105342441Smckusick 	*retval = uap->count - auio.uio_resid;
105437741Smckusick 	RETURN (error);
10555992Swnj }
10565992Swnj 
10579167Ssam /*
105838259Smckusick  * Change flags of a file given path name.
105938259Smckusick  */
106042441Smckusick /* ARGSUSED */
106142441Smckusick chflags(p, uap, retval)
106242441Smckusick 	register struct proc *p;
106342441Smckusick 	register struct args {
106438259Smckusick 		char	*fname;
106538259Smckusick 		int	flags;
106642441Smckusick 	} *uap;
106742441Smckusick 	int *retval;
106842441Smckusick {
106942441Smckusick 	register struct nameidata *ndp = &u.u_nd;
107038259Smckusick 	register struct vnode *vp;
107138259Smckusick 	struct vattr vattr;
107238259Smckusick 	int error;
107338259Smckusick 
107438259Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
107538259Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
107638259Smckusick 	ndp->ni_dirp = uap->fname;
107741362Smckusick 	VATTR_NULL(&vattr);
107838259Smckusick 	vattr.va_flags = uap->flags;
107938259Smckusick 	if (error = namei(ndp))
108038259Smckusick 		RETURN (error);
108138259Smckusick 	vp = ndp->ni_vp;
108241400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
108338259Smckusick 		error = EROFS;
108438259Smckusick 		goto out;
108538259Smckusick 	}
108638259Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
108738259Smckusick out:
108838259Smckusick 	vput(vp);
108938259Smckusick 	RETURN (error);
109038259Smckusick }
109138259Smckusick 
109238259Smckusick /*
109338259Smckusick  * Change flags of a file given a file descriptor.
109438259Smckusick  */
109542441Smckusick /* ARGSUSED */
109642441Smckusick fchflags(p, uap, retval)
109742441Smckusick 	register struct proc *p;
109842441Smckusick 	register struct args {
109938259Smckusick 		int	fd;
110038259Smckusick 		int	flags;
110142441Smckusick 	} *uap;
110242441Smckusick 	int *retval;
110342441Smckusick {
110438259Smckusick 	struct vattr vattr;
110538259Smckusick 	struct vnode *vp;
110638259Smckusick 	struct file *fp;
110738259Smckusick 	int error;
110838259Smckusick 
110942441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
111038259Smckusick 		RETURN (error);
111141362Smckusick 	VATTR_NULL(&vattr);
111238259Smckusick 	vattr.va_flags = uap->flags;
111338259Smckusick 	vp = (struct vnode *)fp->f_data;
111438259Smckusick 	VOP_LOCK(vp);
111541400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
111638259Smckusick 		error = EROFS;
111738259Smckusick 		goto out;
111838259Smckusick 	}
111938259Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
112038259Smckusick out:
112138259Smckusick 	VOP_UNLOCK(vp);
112238259Smckusick 	RETURN (error);
112338259Smckusick }
112438259Smckusick 
112538259Smckusick /*
11269167Ssam  * Change mode of a file given path name.
11279167Ssam  */
112842441Smckusick /* ARGSUSED */
112942441Smckusick chmod(p, uap, retval)
113042441Smckusick 	register struct proc *p;
113142441Smckusick 	register struct args {
11326254Sroot 		char	*fname;
11336254Sroot 		int	fmode;
113442441Smckusick 	} *uap;
113542441Smckusick 	int *retval;
113642441Smckusick {
113742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
113837741Smckusick 	register struct vnode *vp;
113937741Smckusick 	struct vattr vattr;
114037741Smckusick 	int error;
11415992Swnj 
114237741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
114337741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
114437741Smckusick 	ndp->ni_dirp = uap->fname;
114541362Smckusick 	VATTR_NULL(&vattr);
114637741Smckusick 	vattr.va_mode = uap->fmode & 07777;
114737741Smckusick 	if (error = namei(ndp))
114837741Smckusick 		RETURN (error);
114937741Smckusick 	vp = ndp->ni_vp;
115041400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
115137741Smckusick 		error = EROFS;
115237741Smckusick 		goto out;
115337741Smckusick 	}
115437741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
115537741Smckusick out:
115637741Smckusick 	vput(vp);
115737741Smckusick 	RETURN (error);
11587701Ssam }
11597439Sroot 
11609167Ssam /*
11619167Ssam  * Change mode of a file given a file descriptor.
11629167Ssam  */
116342441Smckusick /* ARGSUSED */
116442441Smckusick fchmod(p, uap, retval)
116542441Smckusick 	register struct proc *p;
116642441Smckusick 	register struct args {
11677701Ssam 		int	fd;
11687701Ssam 		int	fmode;
116942441Smckusick 	} *uap;
117042441Smckusick 	int *retval;
117142441Smckusick {
117237741Smckusick 	struct vattr vattr;
117337741Smckusick 	struct vnode *vp;
117437741Smckusick 	struct file *fp;
117537741Smckusick 	int error;
11767701Ssam 
117742441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
117837741Smckusick 		RETURN (error);
117941362Smckusick 	VATTR_NULL(&vattr);
118037741Smckusick 	vattr.va_mode = uap->fmode & 07777;
118137741Smckusick 	vp = (struct vnode *)fp->f_data;
118237741Smckusick 	VOP_LOCK(vp);
118341400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
118437741Smckusick 		error = EROFS;
118537741Smckusick 		goto out;
11867439Sroot 	}
118737741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
118837741Smckusick out:
118937741Smckusick 	VOP_UNLOCK(vp);
119037741Smckusick 	RETURN (error);
11915992Swnj }
11925992Swnj 
11939167Ssam /*
11949167Ssam  * Set ownership given a path name.
11959167Ssam  */
119642441Smckusick /* ARGSUSED */
119742441Smckusick chown(p, uap, retval)
119842441Smckusick 	register struct proc *p;
119942441Smckusick 	register struct args {
12006254Sroot 		char	*fname;
12016254Sroot 		int	uid;
12026254Sroot 		int	gid;
120342441Smckusick 	} *uap;
120442441Smckusick 	int *retval;
120542441Smckusick {
120642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
120737741Smckusick 	register struct vnode *vp;
120837741Smckusick 	struct vattr vattr;
120937741Smckusick 	int error;
121037Sbill 
121137741Smckusick 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
121236614Sbostic 	ndp->ni_segflg = UIO_USERSPACE;
121336614Sbostic 	ndp->ni_dirp = uap->fname;
121441362Smckusick 	VATTR_NULL(&vattr);
121537741Smckusick 	vattr.va_uid = uap->uid;
121637741Smckusick 	vattr.va_gid = uap->gid;
121737741Smckusick 	if (error = namei(ndp))
121837741Smckusick 		RETURN (error);
121937741Smckusick 	vp = ndp->ni_vp;
122041400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
122137741Smckusick 		error = EROFS;
122237741Smckusick 		goto out;
122337741Smckusick 	}
122437741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
122537741Smckusick out:
122637741Smckusick 	vput(vp);
122737741Smckusick 	RETURN (error);
12287701Ssam }
12297439Sroot 
12309167Ssam /*
12319167Ssam  * Set ownership given a file descriptor.
12329167Ssam  */
123342441Smckusick /* ARGSUSED */
123442441Smckusick fchown(p, uap, retval)
123542441Smckusick 	register struct proc *p;
123642441Smckusick 	register struct args {
12377701Ssam 		int	fd;
12387701Ssam 		int	uid;
12397701Ssam 		int	gid;
124042441Smckusick 	} *uap;
124142441Smckusick 	int *retval;
124242441Smckusick {
124337741Smckusick 	struct vattr vattr;
124437741Smckusick 	struct vnode *vp;
124537741Smckusick 	struct file *fp;
124637741Smckusick 	int error;
12477701Ssam 
124842441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
124937741Smckusick 		RETURN (error);
125041362Smckusick 	VATTR_NULL(&vattr);
125137741Smckusick 	vattr.va_uid = uap->uid;
125237741Smckusick 	vattr.va_gid = uap->gid;
125337741Smckusick 	vp = (struct vnode *)fp->f_data;
125437741Smckusick 	VOP_LOCK(vp);
125541400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
125637741Smckusick 		error = EROFS;
125737741Smckusick 		goto out;
125837741Smckusick 	}
125937741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
126037741Smckusick out:
126137741Smckusick 	VOP_UNLOCK(vp);
126237741Smckusick 	RETURN (error);
12637701Ssam }
12647701Ssam 
126542441Smckusick /*
126642441Smckusick  * Set the access and modification times of a file.
126742441Smckusick  */
126842441Smckusick /* ARGSUSED */
126942441Smckusick utimes(p, uap, retval)
127042441Smckusick 	register struct proc *p;
127142441Smckusick 	register struct args {
127211811Ssam 		char	*fname;
127311811Ssam 		struct	timeval *tptr;
127442441Smckusick 	} *uap;
127542441Smckusick 	int *retval;
127642441Smckusick {
127742441Smckusick 	register struct nameidata *ndp = &u.u_nd;
127837741Smckusick 	register struct vnode *vp;
127911811Ssam 	struct timeval tv[2];
128037741Smckusick 	struct vattr vattr;
128137741Smckusick 	int error;
128211811Ssam 
128337741Smckusick 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
128437741Smckusick 		RETURN (error);
128537741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
128637741Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
128737741Smckusick 	ndp->ni_dirp = uap->fname;
128841362Smckusick 	VATTR_NULL(&vattr);
128937741Smckusick 	vattr.va_atime = tv[0];
129037741Smckusick 	vattr.va_mtime = tv[1];
129137741Smckusick 	if (error = namei(ndp))
129237741Smckusick 		RETURN (error);
129337741Smckusick 	vp = ndp->ni_vp;
129441400Smckusick 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
129537741Smckusick 		error = EROFS;
129637741Smckusick 		goto out;
129721015Smckusick 	}
129837741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
129937741Smckusick out:
130037741Smckusick 	vput(vp);
130137741Smckusick 	RETURN (error);
130211811Ssam }
130311811Ssam 
13049167Ssam /*
13059167Ssam  * Truncate a file given its path name.
13069167Ssam  */
130742441Smckusick /* ARGSUSED */
130842441Smckusick truncate(p, uap, retval)
130942441Smckusick 	register struct proc *p;
131042441Smckusick 	register struct args {
13117701Ssam 		char	*fname;
131226473Skarels 		off_t	length;
131342441Smckusick 	} *uap;
131442441Smckusick 	int *retval;
131542441Smckusick {
131642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
131737741Smckusick 	register struct vnode *vp;
131837741Smckusick 	struct vattr vattr;
131937741Smckusick 	int error;
13207701Ssam 
132137741Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
132216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
132316694Smckusick 	ndp->ni_dirp = uap->fname;
132441362Smckusick 	VATTR_NULL(&vattr);
132537741Smckusick 	vattr.va_size = uap->length;
132637741Smckusick 	if (error = namei(ndp))
132737741Smckusick 		RETURN (error);
132837741Smckusick 	vp = ndp->ni_vp;
132937741Smckusick 	if (vp->v_type == VDIR) {
133037741Smckusick 		error = EISDIR;
133137741Smckusick 		goto out;
13327701Ssam 	}
133338399Smckusick 	if ((error = vn_writechk(vp)) ||
133438399Smckusick 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
133537741Smckusick 		goto out;
133637741Smckusick 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
133737741Smckusick out:
133837741Smckusick 	vput(vp);
133937741Smckusick 	RETURN (error);
13407701Ssam }
13417701Ssam 
13429167Ssam /*
13439167Ssam  * Truncate a file given a file descriptor.
13449167Ssam  */
134542441Smckusick /* ARGSUSED */
134642441Smckusick ftruncate(p, uap, retval)
134742441Smckusick 	register struct proc *p;
134842441Smckusick 	register struct args {
13497701Ssam 		int	fd;
135026473Skarels 		off_t	length;
135142441Smckusick 	} *uap;
135242441Smckusick 	int *retval;
135342441Smckusick {
135437741Smckusick 	struct vattr vattr;
135537741Smckusick 	struct vnode *vp;
13567701Ssam 	struct file *fp;
135737741Smckusick 	int error;
13587701Ssam 
135942441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
136037741Smckusick 		RETURN (error);
136137741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
136237741Smckusick 		RETURN (EINVAL);
136341362Smckusick 	VATTR_NULL(&vattr);
136437741Smckusick 	vattr.va_size = uap->length;
136537741Smckusick 	vp = (struct vnode *)fp->f_data;
136637741Smckusick 	VOP_LOCK(vp);
136737741Smckusick 	if (vp->v_type == VDIR) {
136837741Smckusick 		error = EISDIR;
136937741Smckusick 		goto out;
13707701Ssam 	}
137138399Smckusick 	if (error = vn_writechk(vp))
137237741Smckusick 		goto out;
137337741Smckusick 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
137437741Smckusick out:
137537741Smckusick 	VOP_UNLOCK(vp);
137637741Smckusick 	RETURN (error);
13777701Ssam }
13787701Ssam 
13799167Ssam /*
13809167Ssam  * Synch an open file.
13819167Ssam  */
138242441Smckusick /* ARGSUSED */
138342441Smckusick fsync(p, uap, retval)
138442441Smckusick 	register struct proc *p;
138542441Smckusick 	struct args {
138642441Smckusick 		int	fd;
138742441Smckusick 	} *uap;
138842441Smckusick 	int *retval;
13899167Ssam {
139039592Smckusick 	register struct vnode *vp;
13919167Ssam 	struct file *fp;
139237741Smckusick 	int error;
13939167Ssam 
139442441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
139537741Smckusick 		RETURN (error);
139639592Smckusick 	vp = (struct vnode *)fp->f_data;
139739592Smckusick 	VOP_LOCK(vp);
139839592Smckusick 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT);
139939592Smckusick 	VOP_UNLOCK(vp);
140037741Smckusick 	RETURN (error);
14019167Ssam }
14029167Ssam 
14039167Ssam /*
14049167Ssam  * Rename system call.
14059167Ssam  *
14069167Ssam  * Source and destination must either both be directories, or both
14079167Ssam  * not be directories.  If target is a directory, it must be empty.
14089167Ssam  */
140942441Smckusick /* ARGSUSED */
141042441Smckusick rename(p, uap, retval)
141142441Smckusick 	register struct proc *p;
141242441Smckusick 	register struct args {
14137701Ssam 		char	*from;
14147701Ssam 		char	*to;
141542441Smckusick 	} *uap;
141642441Smckusick 	int *retval;
141742441Smckusick {
141837741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
141942441Smckusick 	register struct nameidata *ndp = &u.u_nd;
142037741Smckusick 	struct nameidata tond;
142137741Smckusick 	int error;
14227701Ssam 
142337741Smckusick 	ndp->ni_nameiop = DELETE | WANTPARENT;
142416694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
142516694Smckusick 	ndp->ni_dirp = uap->from;
142637741Smckusick 	if (error = namei(ndp))
142737741Smckusick 		RETURN (error);
142837741Smckusick 	fvp = ndp->ni_vp;
142938266Smckusick 	nddup(ndp, &tond);
143037741Smckusick 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
143137741Smckusick 	tond.ni_segflg = UIO_USERSPACE;
143237741Smckusick 	tond.ni_dirp = uap->to;
143342465Smckusick 	if (error = namei(&tond)) {
143442465Smckusick 		VOP_ABORTOP(ndp);
143542465Smckusick 		vrele(ndp->ni_dvp);
143642465Smckusick 		vrele(fvp);
143742465Smckusick 		goto out1;
143842465Smckusick 	}
143937741Smckusick 	tdvp = tond.ni_dvp;
144037741Smckusick 	tvp = tond.ni_vp;
144137741Smckusick 	if (tvp != NULL) {
144237741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
144339242Sbostic 			error = ENOTDIR;
144437741Smckusick 			goto out;
144537741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
144639242Sbostic 			error = EISDIR;
144737741Smckusick 			goto out;
14489167Ssam 		}
14499167Ssam 	}
145037741Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
145137741Smckusick 		error = EXDEV;
14529167Ssam 		goto out;
145310051Ssam 	}
145439286Smckusick 	if (fvp == tdvp)
145537741Smckusick 		error = EINVAL;
145639286Smckusick 	/*
145739286Smckusick 	 * If source is the same as the destination,
145839286Smckusick 	 * then there is nothing to do.
145939286Smckusick 	 */
146039286Smckusick 	if (fvp == tvp)
146139286Smckusick 		error = -1;
146237741Smckusick out:
146342465Smckusick 	if (!error) {
146442465Smckusick 		error = VOP_RENAME(ndp, &tond);
146542465Smckusick 	} else {
146637741Smckusick 		VOP_ABORTOP(&tond);
146743344Smckusick 		if (tdvp == tvp)
146843344Smckusick 			vrele(tdvp);
146943344Smckusick 		else
147043344Smckusick 			vput(tdvp);
147142465Smckusick 		if (tvp)
147242465Smckusick 			vput(tvp);
147337741Smckusick 		VOP_ABORTOP(ndp);
147442465Smckusick 		vrele(ndp->ni_dvp);
147542465Smckusick 		vrele(fvp);
14769167Ssam 	}
147737741Smckusick out1:
147838266Smckusick 	ndrele(&tond);
147939286Smckusick 	if (error == -1)
148039286Smckusick 		RETURN (0);
148137741Smckusick 	RETURN (error);
14827701Ssam }
14837701Ssam 
14847535Sroot /*
148512756Ssam  * Mkdir system call
148612756Ssam  */
148742441Smckusick /* ARGSUSED */
148842441Smckusick mkdir(p, uap, retval)
148942441Smckusick 	register struct proc *p;
149042441Smckusick 	register struct args {
149112756Ssam 		char	*name;
149212756Ssam 		int	dmode;
149342441Smckusick 	} *uap;
149442441Smckusick 	int *retval;
149542441Smckusick {
149642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
149737741Smckusick 	register struct vnode *vp;
149837741Smckusick 	struct vattr vattr;
149937741Smckusick 	int error;
150012756Ssam 
150137741Smckusick 	ndp->ni_nameiop = CREATE | LOCKPARENT;
150216694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
150316694Smckusick 	ndp->ni_dirp = uap->name;
150437741Smckusick 	if (error = namei(ndp))
150537741Smckusick 		RETURN (error);
150637741Smckusick 	vp = ndp->ni_vp;
150737741Smckusick 	if (vp != NULL) {
150837741Smckusick 		VOP_ABORTOP(ndp);
150943344Smckusick 		if (ndp->ni_dvp == vp)
151043344Smckusick 			vrele(ndp->ni_dvp);
151143344Smckusick 		else
151243344Smckusick 			vput(ndp->ni_dvp);
151342465Smckusick 		vrele(vp);
151437741Smckusick 		RETURN (EEXIST);
151512756Ssam 	}
151641362Smckusick 	VATTR_NULL(&vattr);
151737741Smckusick 	vattr.va_type = VDIR;
151842441Smckusick 	vattr.va_mode = (uap->dmode & 0777) &~ u.u_cmask;
151937741Smckusick 	error = VOP_MKDIR(ndp, &vattr);
152038145Smckusick 	if (!error)
152138145Smckusick 		vput(ndp->ni_vp);
152237741Smckusick 	RETURN (error);
152312756Ssam }
152412756Ssam 
152512756Ssam /*
152612756Ssam  * Rmdir system call.
152712756Ssam  */
152842441Smckusick /* ARGSUSED */
152942441Smckusick rmdir(p, uap, retval)
153042441Smckusick 	register struct proc *p;
153142441Smckusick 	struct args {
153242441Smckusick 		char	*name;
153342441Smckusick 	} *uap;
153442441Smckusick 	int *retval;
153512756Ssam {
153642441Smckusick 	register struct nameidata *ndp = &u.u_nd;
153737741Smckusick 	register struct vnode *vp;
153837741Smckusick 	int error;
153912756Ssam 
154037741Smckusick 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
154116694Smckusick 	ndp->ni_segflg = UIO_USERSPACE;
154216694Smckusick 	ndp->ni_dirp = uap->name;
154337741Smckusick 	if (error = namei(ndp))
154437741Smckusick 		RETURN (error);
154537741Smckusick 	vp = ndp->ni_vp;
154637741Smckusick 	if (vp->v_type != VDIR) {
154737741Smckusick 		error = ENOTDIR;
154812756Ssam 		goto out;
154912756Ssam 	}
155012756Ssam 	/*
155137741Smckusick 	 * No rmdir "." please.
155212756Ssam 	 */
155337741Smckusick 	if (ndp->ni_dvp == vp) {
155437741Smckusick 		error = EINVAL;
155512756Ssam 		goto out;
155612756Ssam 	}
155712756Ssam 	/*
155837741Smckusick 	 * Don't unlink a mounted file.
155912756Ssam 	 */
156037741Smckusick 	if (vp->v_flag & VROOT)
156137741Smckusick 		error = EBUSY;
156212756Ssam out:
156342465Smckusick 	if (!error) {
156442465Smckusick 		error = VOP_RMDIR(ndp);
156542465Smckusick 	} else {
156637741Smckusick 		VOP_ABORTOP(ndp);
156743344Smckusick 		if (ndp->ni_dvp == vp)
156843344Smckusick 			vrele(ndp->ni_dvp);
156943344Smckusick 		else
157043344Smckusick 			vput(ndp->ni_dvp);
157142465Smckusick 		vput(vp);
157242465Smckusick 	}
157337741Smckusick 	RETURN (error);
157412756Ssam }
157512756Ssam 
157637741Smckusick /*
157737741Smckusick  * Read a block of directory entries in a file system independent format
157837741Smckusick  */
157942441Smckusick getdirentries(p, uap, retval)
158042441Smckusick 	register struct proc *p;
158142441Smckusick 	register struct args {
158237741Smckusick 		int	fd;
158337741Smckusick 		char	*buf;
158437741Smckusick 		unsigned count;
158537741Smckusick 		long	*basep;
158642441Smckusick 	} *uap;
158742441Smckusick 	int *retval;
158842441Smckusick {
158939592Smckusick 	register struct vnode *vp;
159016540Ssam 	struct file *fp;
159137741Smckusick 	struct uio auio;
159237741Smckusick 	struct iovec aiov;
159338129Smckusick 	off_t off;
159440321Smckusick 	int error, eofflag;
159512756Ssam 
159642441Smckusick 	if (error = getvnode(u.u_ofile, uap->fd, &fp))
159737741Smckusick 		RETURN (error);
159837741Smckusick 	if ((fp->f_flag & FREAD) == 0)
159937741Smckusick 		RETURN (EBADF);
160039592Smckusick 	vp = (struct vnode *)fp->f_data;
160139592Smckusick 	if (vp->v_type != VDIR)
160239592Smckusick 		RETURN (EINVAL);
160337741Smckusick 	aiov.iov_base = uap->buf;
160437741Smckusick 	aiov.iov_len = uap->count;
160537741Smckusick 	auio.uio_iov = &aiov;
160637741Smckusick 	auio.uio_iovcnt = 1;
160737741Smckusick 	auio.uio_rw = UIO_READ;
160837741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
160937741Smckusick 	auio.uio_resid = uap->count;
161039592Smckusick 	VOP_LOCK(vp);
161139592Smckusick 	auio.uio_offset = off = fp->f_offset;
161240321Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag);
161339592Smckusick 	fp->f_offset = auio.uio_offset;
161439592Smckusick 	VOP_UNLOCK(vp);
161539592Smckusick 	if (error)
161637741Smckusick 		RETURN (error);
161739592Smckusick 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
161842441Smckusick 	*retval = uap->count - auio.uio_resid;
161937741Smckusick 	RETURN (error);
162012756Ssam }
162112756Ssam 
162212756Ssam /*
162312756Ssam  * mode mask for creation of files
162412756Ssam  */
162542441Smckusick mode_t
162642441Smckusick umask(p, uap, retval)
162742441Smckusick 	register struct proc *p;
162842441Smckusick 	struct args {
162942441Smckusick 		int	mask;
163042441Smckusick 	} *uap;
163142441Smckusick 	int *retval;
163212756Ssam {
163312756Ssam 
163442441Smckusick 	*retval = u.u_cmask;
163542441Smckusick 	u.u_cmask = uap->mask & 07777;
163637741Smckusick 	RETURN (0);
163712756Ssam }
163837741Smckusick 
163939566Smarc /*
164039566Smarc  * Void all references to file by ripping underlying filesystem
164139566Smarc  * away from vnode.
164239566Smarc  */
164342441Smckusick /* ARGSUSED */
164442441Smckusick revoke(p, uap, retval)
164542441Smckusick 	register struct proc *p;
164642441Smckusick 	register struct args {
164739566Smarc 		char	*fname;
164842441Smckusick 	} *uap;
164942441Smckusick 	int *retval;
165042441Smckusick {
165142441Smckusick 	register struct nameidata *ndp = &u.u_nd;
165239566Smarc 	register struct vnode *vp;
165339566Smarc 	struct vattr vattr;
165439566Smarc 	int error;
165539566Smarc 
165639566Smarc 	ndp->ni_nameiop = LOOKUP | FOLLOW;
165739566Smarc 	ndp->ni_segflg = UIO_USERSPACE;
165839566Smarc 	ndp->ni_dirp = uap->fname;
165939566Smarc 	if (error = namei(ndp))
166039566Smarc 		RETURN (error);
166139566Smarc 	vp = ndp->ni_vp;
166239566Smarc 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
166339566Smarc 		error = EINVAL;
166439566Smarc 		goto out;
166539566Smarc 	}
166642441Smckusick 	if (error = VOP_GETATTR(vp, &vattr, ndp->ni_cred))
166739566Smarc 		goto out;
166842955Smckusick 	if (ndp->ni_cred->cr_uid != vattr.va_uid &&
166942441Smckusick 	    (error = suser(ndp->ni_cred, &u.u_acflag)))
167039566Smarc 		goto out;
167139805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
167239632Smckusick 		vgoneall(vp);
167339566Smarc out:
167439566Smarc 	vrele(vp);
167539566Smarc 	RETURN (error);
167639566Smarc }
167739566Smarc 
167838408Smckusick getvnode(ofile, fdes, fpp)
167938408Smckusick 	struct file *ofile[];
168037741Smckusick 	struct file **fpp;
168137741Smckusick 	int fdes;
168237741Smckusick {
168337741Smckusick 	struct file *fp;
168437741Smckusick 
168538408Smckusick 	if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
168637741Smckusick 		return (EBADF);
168737741Smckusick 	if (fp->f_type != DTYPE_VNODE)
168837741Smckusick 		return (EINVAL);
168937741Smckusick 	*fpp = fp;
169037741Smckusick 	return (0);
169137741Smckusick }
1692