xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 69325)
123405Smckusick /*
263428Sbostic  * Copyright (c) 1989, 1993
363428Sbostic  *	The Regents of the University of California.  All rights reserved.
465771Sbostic  * (c) UNIX System Laboratories, Inc.
565771Sbostic  * All or some portions of this file are derived from material licensed
665771Sbostic  * to the University of California by American Telephone and Telegraph
765771Sbostic  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
865771Sbostic  * the permission of UNIX System Laboratories, Inc.
923405Smckusick  *
1044459Sbostic  * %sccs.include.redist.c%
1137741Smckusick  *
12*69325Smckusick  *	@(#)vfs_syscalls.c	8.34 (Berkeley) 05/09/95
1323405Smckusick  */
1437Sbill 
1556517Sbostic #include <sys/param.h>
1656517Sbostic #include <sys/systm.h>
1756517Sbostic #include <sys/namei.h>
1856517Sbostic #include <sys/filedesc.h>
1956517Sbostic #include <sys/kernel.h>
2056517Sbostic #include <sys/file.h>
2156517Sbostic #include <sys/stat.h>
2256517Sbostic #include <sys/vnode.h>
2356517Sbostic #include <sys/mount.h>
2456517Sbostic #include <sys/proc.h>
2556517Sbostic #include <sys/uio.h>
2656517Sbostic #include <sys/malloc.h>
2756517Sbostic #include <sys/dirent.h>
2856517Sbostic 
2968318Scgd #include <sys/syscallargs.h>
3068318Scgd 
3153468Smckusick #include <vm/vm.h>
3259875Smckusick #include <sys/sysctl.h>
3337Sbill 
3464410Sbostic static int change_dir __P((struct nameidata *ndp, struct proc *p));
3568318Scgd static void checkdirs __P((struct vnode *olddp));
3664410Sbostic 
3737741Smckusick /*
3837741Smckusick  * Virtual File System System Calls
3937741Smckusick  */
4012756Ssam 
419167Ssam /*
4264410Sbostic  * Mount a file system.
439167Ssam  */
4442441Smckusick /* ARGSUSED */
4568318Scgd int
4642441Smckusick mount(p, uap, retval)
4745914Smckusick 	struct proc *p;
4868318Scgd 	register struct mount_args /* {
4968663Smckusick 		syscallarg(char *) type;
5068318Scgd 		syscallarg(char *) path;
5168318Scgd 		syscallarg(int) flags;
5268318Scgd 		syscallarg(caddr_t) data;
5368318Scgd 	} */ *uap;
5468318Scgd 	register_t *retval;
5542441Smckusick {
5668663Smckusick 	struct vnode *vp;
5768663Smckusick 	struct mount *mp;
5868663Smckusick 	struct vfsconf *vfsp;
5940111Smckusick 	int error, flag;
6067532Smckusick 	struct vattr va;
6168663Smckusick 	u_long fstypenum;
6247540Skarels 	struct nameidata nd;
6368663Smckusick 	char fstypename[MFSNAMELEN];
646254Sroot 
6537741Smckusick 	/*
6637741Smckusick 	 * Get vnode to be covered
6737741Smckusick 	 */
6868318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
6968318Scgd 	    SCARG(uap, path), p);
7052322Smckusick 	if (error = namei(&nd))
7147540Skarels 		return (error);
7252322Smckusick 	vp = nd.ni_vp;
7368318Scgd 	if (SCARG(uap, flags) & MNT_UPDATE) {
7439335Smckusick 		if ((vp->v_flag & VROOT) == 0) {
7539335Smckusick 			vput(vp);
7647540Skarels 			return (EINVAL);
7739335Smckusick 		}
7839335Smckusick 		mp = vp->v_mount;
7957047Smckusick 		flag = mp->mnt_flag;
8039335Smckusick 		/*
8157047Smckusick 		 * We only allow the filesystem to be reloaded if it
8257047Smckusick 		 * is currently mounted read-only.
8339335Smckusick 		 */
8468318Scgd 		if ((SCARG(uap, flags) & MNT_RELOAD) &&
8557047Smckusick 		    ((mp->mnt_flag & MNT_RDONLY) == 0)) {
8639335Smckusick 			vput(vp);
8747540Skarels 			return (EOPNOTSUPP);	/* Needs translation */
8839335Smckusick 		}
8957047Smckusick 		mp->mnt_flag |=
9068318Scgd 		    SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
9167532Smckusick 		/*
9267532Smckusick 		 * Only root, or the user that did the original mount is
9367532Smckusick 		 * permitted to update it.
9467532Smckusick 		 */
9567532Smckusick 		if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid &&
9667532Smckusick 		    (error = suser(p->p_ucred, &p->p_acflag))) {
9767532Smckusick 			vput(vp);
9867532Smckusick 			return (error);
9967532Smckusick 		}
10067532Smckusick 		/*
10167532Smckusick 		 * Do not allow NFS export by non-root users. Silently
10267532Smckusick 		 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
10367532Smckusick 		 */
10467532Smckusick 		if (p->p_ucred->cr_uid != 0) {
10568318Scgd 			if (SCARG(uap, flags) & MNT_EXPORTED) {
10667532Smckusick 				vput(vp);
10767532Smckusick 				return (EPERM);
10867532Smckusick 			}
10968318Scgd 			SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
11067532Smckusick 		}
11139335Smckusick 		VOP_UNLOCK(vp);
11239335Smckusick 		goto update;
11339335Smckusick 	}
11467532Smckusick 	/*
11567532Smckusick 	 * If the user is not root, ensure that they own the directory
11667532Smckusick 	 * onto which we are attempting to mount.
11767532Smckusick 	 */
11867532Smckusick 	if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) ||
11967532Smckusick 	    (va.va_uid != p->p_ucred->cr_uid &&
12067532Smckusick 	     (error = suser(p->p_ucred, &p->p_acflag)))) {
12167532Smckusick 		vput(vp);
12267532Smckusick 		return (error);
12367532Smckusick 	}
12467532Smckusick 	/*
12567532Smckusick 	 * Do not allow NFS export by non-root users. Silently
12667532Smckusick 	 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
12767532Smckusick 	 */
12867532Smckusick 	if (p->p_ucred->cr_uid != 0) {
12968318Scgd 		if (SCARG(uap, flags) & MNT_EXPORTED) {
13067532Smckusick 			vput(vp);
13167532Smckusick 			return (EPERM);
13267532Smckusick 		}
13368318Scgd 		SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
13467532Smckusick 	}
13557793Smckusick 	if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0))
13654441Smckusick 		return (error);
13737741Smckusick 	if (vp->v_type != VDIR) {
13837741Smckusick 		vput(vp);
13947540Skarels 		return (ENOTDIR);
14037741Smckusick 	}
14168663Smckusick #ifdef COMPAT_43
14268663Smckusick 	/*
14368663Smckusick 	 * Historically filesystem types were identified by number. If we
14468663Smckusick 	 * get an integer for the filesystem type instead of a string, we
14568663Smckusick 	 * check to see if it matches one of the historic filesystem types.
14668663Smckusick 	 */
14768663Smckusick 	fstypenum = (u_long)SCARG(uap, type);
14868663Smckusick 	if (fstypenum < maxvfsconf) {
14968663Smckusick 		for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
15068663Smckusick 			if (vfsp->vfc_typenum == fstypenum)
15168663Smckusick 				break;
15268663Smckusick 		if (vfsp == NULL) {
15368663Smckusick 			vput(vp);
15468663Smckusick 			return (ENODEV);
15568663Smckusick 		}
15668663Smckusick 		strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN);
15768663Smckusick 	} else
15868663Smckusick #endif /* COMPAT_43 */
15968663Smckusick 	if (error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL)) {
16037741Smckusick 		vput(vp);
16168663Smckusick 		return (error);
16268663Smckusick 	}
16368663Smckusick 	for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
16468663Smckusick 		if (!strcmp(vfsp->vfc_name, fstypename))
16568663Smckusick 			break;
16668663Smckusick 	if (vfsp == NULL) {
16768663Smckusick 		vput(vp);
16847540Skarels 		return (ENODEV);
16937741Smckusick 	}
17067969Spendry 	if (vp->v_mountedhere != NULL) {
17167961Smckusick 		vput(vp);
17267961Smckusick 		return (EBUSY);
17367961Smckusick 	}
17437741Smckusick 
17537741Smckusick 	/*
17668663Smckusick 	 * Allocate and initialize the filesystem.
17737741Smckusick 	 */
17837741Smckusick 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
17937741Smckusick 		M_MOUNT, M_WAITOK);
18054172Smckusick 	bzero((char *)mp, (u_long)sizeof(struct mount));
18168663Smckusick 	mp->mnt_op = vfsp->vfc_vfsops;
18239335Smckusick 	if (error = vfs_lock(mp)) {
18339335Smckusick 		free((caddr_t)mp, M_MOUNT);
18439335Smckusick 		vput(vp);
18547540Skarels 		return (error);
18639335Smckusick 	}
18768663Smckusick 	mp->mnt_vfc = vfsp;
18868663Smckusick 	vfsp->vfc_refcount++;
18968663Smckusick 	mp->mnt_stat.f_type = vfsp->vfc_typenum;
19068663Smckusick 	mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
19168663Smckusick 	strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
19239335Smckusick 	vp->v_mountedhere = mp;
19341400Smckusick 	mp->mnt_vnodecovered = vp;
19467532Smckusick 	mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
19539335Smckusick update:
19639335Smckusick 	/*
19739335Smckusick 	 * Set the mount level flags.
19839335Smckusick 	 */
19968318Scgd 	if (SCARG(uap, flags) & MNT_RDONLY)
20041400Smckusick 		mp->mnt_flag |= MNT_RDONLY;
20157047Smckusick 	else if (mp->mnt_flag & MNT_RDONLY)
20257047Smckusick 		mp->mnt_flag |= MNT_WANTRDWR;
20365613Smckusick 	mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
20465613Smckusick 	    MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);
20568318Scgd 	mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC |
20668318Scgd 	    MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC);
20739335Smckusick 	/*
20839335Smckusick 	 * Mount the filesystem.
20939335Smckusick 	 */
21068318Scgd 	error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p);
21141400Smckusick 	if (mp->mnt_flag & MNT_UPDATE) {
21239335Smckusick 		vrele(vp);
21357047Smckusick 		if (mp->mnt_flag & MNT_WANTRDWR)
21457047Smckusick 			mp->mnt_flag &= ~MNT_RDONLY;
21557047Smckusick 		mp->mnt_flag &=~
21657047Smckusick 		    (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
21740111Smckusick 		if (error)
21841400Smckusick 			mp->mnt_flag = flag;
21947540Skarels 		return (error);
22039335Smckusick 	}
22140110Smckusick 	/*
22240110Smckusick 	 * Put the new filesystem on the mount list after root.
22340110Smckusick 	 */
22437741Smckusick 	cache_purge(vp);
22537741Smckusick 	if (!error) {
226*69325Smckusick 		CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
22767974Smckusick 		checkdirs(vp);
22839335Smckusick 		VOP_UNLOCK(vp);
22937741Smckusick 		vfs_unlock(mp);
23048026Smckusick 		error = VFS_START(mp, 0, p);
23137741Smckusick 	} else {
23265259Smckusick 		mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
23368663Smckusick 		mp->mnt_vfc->vfc_refcount--;
23465259Smckusick 		vfs_unlock(mp);
23537741Smckusick 		free((caddr_t)mp, M_MOUNT);
23639335Smckusick 		vput(vp);
23737741Smckusick 	}
23847540Skarels 	return (error);
2396254Sroot }
2406254Sroot 
2419167Ssam /*
24267974Smckusick  * Scan all active processes to see if any of them have a current
24367974Smckusick  * or root directory onto which the new filesystem has just been
24467974Smckusick  * mounted. If so, replace them with the new mount point.
24567974Smckusick  */
24668318Scgd static void
24767974Smckusick checkdirs(olddp)
24867974Smckusick 	struct vnode *olddp;
24967974Smckusick {
25067974Smckusick 	struct filedesc *fdp;
25167974Smckusick 	struct vnode *newdp;
25267974Smckusick 	struct proc *p;
25367974Smckusick 
25467974Smckusick 	if (olddp->v_usecount == 1)
25567974Smckusick 		return;
25667974Smckusick 	if (VFS_ROOT(olddp->v_mountedhere, &newdp))
25767974Smckusick 		panic("mount: lost mount");
25867974Smckusick 	for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
25967974Smckusick 		fdp = p->p_fd;
26067974Smckusick 		if (fdp->fd_cdir == olddp) {
26167974Smckusick 			vrele(fdp->fd_cdir);
26267974Smckusick 			VREF(newdp);
26367974Smckusick 			fdp->fd_cdir = newdp;
26467974Smckusick 		}
26567974Smckusick 		if (fdp->fd_rdir == olddp) {
26667974Smckusick 			vrele(fdp->fd_rdir);
26767974Smckusick 			VREF(newdp);
26867974Smckusick 			fdp->fd_rdir = newdp;
26967974Smckusick 		}
27067974Smckusick 	}
27167974Smckusick 	if (rootvnode == olddp) {
27267974Smckusick 		vrele(rootvnode);
27367974Smckusick 		VREF(newdp);
27467974Smckusick 		rootvnode = newdp;
27567974Smckusick 	}
27667974Smckusick 	vput(newdp);
27767974Smckusick }
27867974Smckusick 
27967974Smckusick /*
28064410Sbostic  * Unmount a file system.
28137741Smckusick  *
28237741Smckusick  * Note: unmount takes a path to the vnode mounted on as argument,
28337741Smckusick  * not special file (as before).
2849167Ssam  */
28542441Smckusick /* ARGSUSED */
28668318Scgd int
28742441Smckusick unmount(p, uap, retval)
28845914Smckusick 	struct proc *p;
28968318Scgd 	register struct unmount_args /* {
29068318Scgd 		syscallarg(char *) path;
29168318Scgd 		syscallarg(int) flags;
29268318Scgd 	} */ *uap;
29368318Scgd 	register_t *retval;
29442441Smckusick {
29537741Smckusick 	register struct vnode *vp;
29639356Smckusick 	struct mount *mp;
29737741Smckusick 	int error;
29847540Skarels 	struct nameidata nd;
2996254Sroot 
30068318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
30168318Scgd 	    SCARG(uap, path), p);
30252322Smckusick 	if (error = namei(&nd))
30347540Skarels 		return (error);
30452322Smckusick 	vp = nd.ni_vp;
30567532Smckusick 	mp = vp->v_mount;
30666172Spendry 
30737741Smckusick 	/*
30867532Smckusick 	 * Only root, or the user that did the original mount is
30967532Smckusick 	 * permitted to unmount this filesystem.
31066172Spendry 	 */
31167532Smckusick 	if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) &&
31266172Spendry 	    (error = suser(p->p_ucred, &p->p_acflag))) {
31366172Spendry 		vput(vp);
31466172Spendry 		return (error);
31566172Spendry 	}
31666172Spendry 
31766172Spendry 	/*
31837741Smckusick 	 * Must be the root of the filesystem
31937741Smckusick 	 */
32037741Smckusick 	if ((vp->v_flag & VROOT) == 0) {
32137741Smckusick 		vput(vp);
32247540Skarels 		return (EINVAL);
32337741Smckusick 	}
32437741Smckusick 	vput(vp);
32568318Scgd 	return (dounmount(mp, SCARG(uap, flags), p));
32639356Smckusick }
32739356Smckusick 
32839356Smckusick /*
32964410Sbostic  * Do the actual file system unmount.
33039356Smckusick  */
33168318Scgd int
33248026Smckusick dounmount(mp, flags, p)
33339356Smckusick 	register struct mount *mp;
33439356Smckusick 	int flags;
33548026Smckusick 	struct proc *p;
33639356Smckusick {
33739356Smckusick 	struct vnode *coveredvp;
33839356Smckusick 	int error;
33939356Smckusick 
34041400Smckusick 	coveredvp = mp->mnt_vnodecovered;
34141298Smckusick 	if (vfs_busy(mp))
34241298Smckusick 		return (EBUSY);
34341400Smckusick 	mp->mnt_flag |= MNT_UNMOUNT;
34437741Smckusick 	if (error = vfs_lock(mp))
34539356Smckusick 		return (error);
34637741Smckusick 
34765859Smckusick 	mp->mnt_flag &=~ MNT_ASYNC;
34845738Smckusick 	vnode_pager_umount(mp);	/* release cached vnodes */
34937741Smckusick 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
35054441Smckusick 	if ((error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0 ||
35154441Smckusick 	    (flags & MNT_FORCE))
35248026Smckusick 		error = VFS_UNMOUNT(mp, flags, p);
35341400Smckusick 	mp->mnt_flag &= ~MNT_UNMOUNT;
35441298Smckusick 	vfs_unbusy(mp);
35537741Smckusick 	if (error) {
35637741Smckusick 		vfs_unlock(mp);
35737741Smckusick 	} else {
358*69325Smckusick 		CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);
359*69325Smckusick 		if (coveredvp != NULLVP) {
360*69325Smckusick 			vrele(coveredvp);
361*69325Smckusick 			mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
362*69325Smckusick 		}
36368663Smckusick 		mp->mnt_vfc->vfc_refcount--;
36465259Smckusick 		vfs_unlock(mp);
36565259Smckusick 		if (mp->mnt_vnodelist.lh_first != NULL)
36652287Smckusick 			panic("unmount: dangling vnode");
36737741Smckusick 		free((caddr_t)mp, M_MOUNT);
36837741Smckusick 	}
36939356Smckusick 	return (error);
3706254Sroot }
3716254Sroot 
3729167Ssam /*
37337741Smckusick  * Sync each mounted filesystem.
3749167Ssam  */
37567403Smckusick #ifdef DEBUG
37656352Smckusick int syncprt = 0;
37759875Smckusick struct ctldebug debug0 = { "syncprt", &syncprt };
37856352Smckusick #endif
37956352Smckusick 
38039491Smckusick /* ARGSUSED */
38168318Scgd int
38242441Smckusick sync(p, uap, retval)
38345914Smckusick 	struct proc *p;
38468318Scgd 	void *uap;
38568318Scgd 	register_t *retval;
3866254Sroot {
38765259Smckusick 	register struct mount *mp, *nmp;
38865859Smckusick 	int asyncflag;
38937741Smckusick 
390*69325Smckusick 	for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
39167678Smckusick 		/*
39267678Smckusick 		 * Get the next pointer in case we hang on vfs_busy
39367678Smckusick 		 * while we are being unmounted.
39467678Smckusick 		 */
395*69325Smckusick 		nmp = mp->mnt_list.cqe_next;
39640343Smckusick 		/*
39740343Smckusick 		 * The lock check below is to avoid races with mount
39840343Smckusick 		 * and unmount.
39940343Smckusick 		 */
40041400Smckusick 		if ((mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
40141298Smckusick 		    !vfs_busy(mp)) {
40265859Smckusick 			asyncflag = mp->mnt_flag & MNT_ASYNC;
40365859Smckusick 			mp->mnt_flag &= ~MNT_ASYNC;
40454441Smckusick 			VFS_SYNC(mp, MNT_NOWAIT, p->p_ucred, p);
40565859Smckusick 			if (asyncflag)
40665859Smckusick 				mp->mnt_flag |= MNT_ASYNC;
40767678Smckusick 			/*
40867678Smckusick 			 * Get the next pointer again, as the next filesystem
40967678Smckusick 			 * might have been unmounted while we were sync'ing.
41067678Smckusick 			 */
411*69325Smckusick 			nmp = mp->mnt_list.cqe_next;
41265259Smckusick 			vfs_unbusy(mp);
41365259Smckusick 		}
41465259Smckusick 	}
41556352Smckusick #ifdef DIAGNOSTIC
41656352Smckusick 	if (syncprt)
41756352Smckusick 		vfs_bufstats();
41856352Smckusick #endif /* DIAGNOSTIC */
41947688Skarels 	return (0);
42037741Smckusick }
42137741Smckusick 
42237741Smckusick /*
42364410Sbostic  * Change filesystem quotas.
42441298Smckusick  */
42542441Smckusick /* ARGSUSED */
42668318Scgd int
42742441Smckusick quotactl(p, uap, retval)
42845914Smckusick 	struct proc *p;
42968318Scgd 	register struct quotactl_args /* {
43068318Scgd 		syscallarg(char *) path;
43168318Scgd 		syscallarg(int) cmd;
43268318Scgd 		syscallarg(int) uid;
43368318Scgd 		syscallarg(caddr_t) arg;
43468318Scgd 	} */ *uap;
43568318Scgd 	register_t *retval;
43642441Smckusick {
43741298Smckusick 	register struct mount *mp;
43841298Smckusick 	int error;
43947540Skarels 	struct nameidata nd;
44041298Smckusick 
44168318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
44252322Smckusick 	if (error = namei(&nd))
44347540Skarels 		return (error);
44452322Smckusick 	mp = nd.ni_vp->v_mount;
44552322Smckusick 	vrele(nd.ni_vp);
44668318Scgd 	return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
44768318Scgd 	    SCARG(uap, arg), p));
44841298Smckusick }
44941298Smckusick 
45041298Smckusick /*
45149365Smckusick  * Get filesystem statistics.
45237741Smckusick  */
45342441Smckusick /* ARGSUSED */
45468318Scgd int
45542441Smckusick statfs(p, uap, retval)
45645914Smckusick 	struct proc *p;
45768318Scgd 	register struct statfs_args /* {
45868318Scgd 		syscallarg(char *) path;
45968318Scgd 		syscallarg(struct statfs *) buf;
46068318Scgd 	} */ *uap;
46168318Scgd 	register_t *retval;
46242441Smckusick {
46339464Smckusick 	register struct mount *mp;
46440343Smckusick 	register struct statfs *sp;
46537741Smckusick 	int error;
46647540Skarels 	struct nameidata nd;
46737741Smckusick 
46868318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
46952322Smckusick 	if (error = namei(&nd))
47047540Skarels 		return (error);
47152322Smckusick 	mp = nd.ni_vp->v_mount;
47241400Smckusick 	sp = &mp->mnt_stat;
47352322Smckusick 	vrele(nd.ni_vp);
47448026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
47547540Skarels 		return (error);
47641400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
47768318Scgd 	return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
47837741Smckusick }
47937741Smckusick 
48042441Smckusick /*
48149365Smckusick  * Get filesystem statistics.
48242441Smckusick  */
48342441Smckusick /* ARGSUSED */
48468318Scgd int
48542441Smckusick fstatfs(p, uap, retval)
48645914Smckusick 	struct proc *p;
48768318Scgd 	register struct fstatfs_args /* {
48868318Scgd 		syscallarg(int) fd;
48968318Scgd 		syscallarg(struct statfs *) buf;
49068318Scgd 	} */ *uap;
49168318Scgd 	register_t *retval;
49242441Smckusick {
49337741Smckusick 	struct file *fp;
49439464Smckusick 	struct mount *mp;
49540343Smckusick 	register struct statfs *sp;
49637741Smckusick 	int error;
49737741Smckusick 
49868318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
49947540Skarels 		return (error);
50039464Smckusick 	mp = ((struct vnode *)fp->f_data)->v_mount;
50141400Smckusick 	sp = &mp->mnt_stat;
50248026Smckusick 	if (error = VFS_STATFS(mp, sp, p))
50347540Skarels 		return (error);
50441400Smckusick 	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
50568318Scgd 	return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
50637741Smckusick }
50737741Smckusick 
50837741Smckusick /*
50949365Smckusick  * Get statistics on all filesystems.
51038270Smckusick  */
51168318Scgd int
51242441Smckusick getfsstat(p, uap, retval)
51345914Smckusick 	struct proc *p;
51468318Scgd 	register struct getfsstat_args /* {
51568318Scgd 		syscallarg(struct statfs *) buf;
51668318Scgd 		syscallarg(long) bufsize;
51768318Scgd 		syscallarg(int) flags;
51868318Scgd 	} */ *uap;
51968318Scgd 	register_t *retval;
52042441Smckusick {
52165259Smckusick 	register struct mount *mp, *nmp;
52240343Smckusick 	register struct statfs *sp;
52339606Smckusick 	caddr_t sfsp;
52438270Smckusick 	long count, maxcount, error;
52538270Smckusick 
52668318Scgd 	maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
52768318Scgd 	sfsp = (caddr_t)SCARG(uap, buf);
528*69325Smckusick 	count = 0;
529*69325Smckusick 	for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
530*69325Smckusick 		nmp = mp->mnt_list.cqe_next;
53141400Smckusick 		if (sfsp && count < maxcount &&
53241400Smckusick 		    ((mp->mnt_flag & MNT_MLOCK) == 0)) {
53341400Smckusick 			sp = &mp->mnt_stat;
53440343Smckusick 			/*
53540343Smckusick 			 * If MNT_NOWAIT is specified, do not refresh the
53640343Smckusick 			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
53740343Smckusick 			 */
53868318Scgd 			if (((SCARG(uap, flags) & MNT_NOWAIT) == 0 ||
53968318Scgd 			    (SCARG(uap, flags) & MNT_WAIT)) &&
54065259Smckusick 			    (error = VFS_STATFS(mp, sp, p)))
54139607Smckusick 				continue;
54241400Smckusick 			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
54340343Smckusick 			if (error = copyout((caddr_t)sp, sfsp, sizeof(*sp)))
54447540Skarels 				return (error);
54540343Smckusick 			sfsp += sizeof(*sp);
54638270Smckusick 		}
54739606Smckusick 		count++;
54865259Smckusick 	}
54938270Smckusick 	if (sfsp && count > maxcount)
55042441Smckusick 		*retval = maxcount;
55138270Smckusick 	else
55242441Smckusick 		*retval = count;
55347540Skarels 	return (0);
55438270Smckusick }
55538270Smckusick 
55638270Smckusick /*
55738259Smckusick  * Change current working directory to a given file descriptor.
55838259Smckusick  */
55942441Smckusick /* ARGSUSED */
56068318Scgd int
56142441Smckusick fchdir(p, uap, retval)
56245914Smckusick 	struct proc *p;
56368318Scgd 	struct fchdir_args /* {
56468318Scgd 		syscallarg(int) fd;
56568318Scgd 	} */ *uap;
56668318Scgd 	register_t *retval;
56738259Smckusick {
56845914Smckusick 	register struct filedesc *fdp = p->p_fd;
56967974Smckusick 	struct vnode *vp, *tdp;
57067974Smckusick 	struct mount *mp;
57138259Smckusick 	struct file *fp;
57238259Smckusick 	int error;
57338259Smckusick 
57468318Scgd 	if (error = getvnode(fdp, SCARG(uap, fd), &fp))
57547540Skarels 		return (error);
57638259Smckusick 	vp = (struct vnode *)fp->f_data;
57767974Smckusick 	VREF(vp);
57838259Smckusick 	VOP_LOCK(vp);
57938259Smckusick 	if (vp->v_type != VDIR)
58038259Smckusick 		error = ENOTDIR;
58138259Smckusick 	else
58248026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
58367974Smckusick 	while (!error && (mp = vp->v_mountedhere) != NULL) {
58467974Smckusick 		if (mp->mnt_flag & MNT_MLOCK) {
58567974Smckusick 			mp->mnt_flag |= MNT_MWAIT;
58667974Smckusick 			sleep((caddr_t)mp, PVFS);
58767974Smckusick 			continue;
58867974Smckusick 		}
58967974Smckusick 		if (error = VFS_ROOT(mp, &tdp))
59067974Smckusick 			break;
59167974Smckusick 		vput(vp);
59267974Smckusick 		vp = tdp;
59367974Smckusick 	}
59438259Smckusick 	VOP_UNLOCK(vp);
59567974Smckusick 	if (error) {
59667974Smckusick 		vrele(vp);
59747540Skarels 		return (error);
59867974Smckusick 	}
59945914Smckusick 	vrele(fdp->fd_cdir);
60045914Smckusick 	fdp->fd_cdir = vp;
60147540Skarels 	return (0);
60238259Smckusick }
60338259Smckusick 
60438259Smckusick /*
60537741Smckusick  * Change current working directory (``.'').
60637741Smckusick  */
60742441Smckusick /* ARGSUSED */
60868318Scgd int
60942441Smckusick chdir(p, uap, retval)
61045914Smckusick 	struct proc *p;
61168318Scgd 	struct chdir_args /* {
61268318Scgd 		syscallarg(char *) path;
61368318Scgd 	} */ *uap;
61468318Scgd 	register_t *retval;
61537741Smckusick {
61645914Smckusick 	register struct filedesc *fdp = p->p_fd;
61737741Smckusick 	int error;
61847540Skarels 	struct nameidata nd;
6196254Sroot 
62068318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
62168318Scgd 	    SCARG(uap, path), p);
62264410Sbostic 	if (error = change_dir(&nd, p))
62347540Skarels 		return (error);
62445914Smckusick 	vrele(fdp->fd_cdir);
62552322Smckusick 	fdp->fd_cdir = nd.ni_vp;
62647540Skarels 	return (0);
62737741Smckusick }
6286254Sroot 
62937741Smckusick /*
63037741Smckusick  * Change notion of root (``/'') directory.
63137741Smckusick  */
63242441Smckusick /* ARGSUSED */
63368318Scgd int
63442441Smckusick chroot(p, uap, retval)
63545914Smckusick 	struct proc *p;
63668318Scgd 	struct chroot_args /* {
63768318Scgd 		syscallarg(char *) path;
63868318Scgd 	} */ *uap;
63968318Scgd 	register_t *retval;
64037741Smckusick {
64145914Smckusick 	register struct filedesc *fdp = p->p_fd;
64237741Smckusick 	int error;
64347540Skarels 	struct nameidata nd;
64437741Smckusick 
64547540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
64647540Skarels 		return (error);
64768318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
64868318Scgd 	    SCARG(uap, path), p);
64964410Sbostic 	if (error = change_dir(&nd, p))
65047540Skarels 		return (error);
65145914Smckusick 	if (fdp->fd_rdir != NULL)
65245914Smckusick 		vrele(fdp->fd_rdir);
65352322Smckusick 	fdp->fd_rdir = nd.ni_vp;
65447540Skarels 	return (0);
6556254Sroot }
6566254Sroot 
65737Sbill /*
65837741Smckusick  * Common routine for chroot and chdir.
65937741Smckusick  */
66064410Sbostic static int
66164410Sbostic change_dir(ndp, p)
66252322Smckusick 	register struct nameidata *ndp;
66347540Skarels 	struct proc *p;
66437741Smckusick {
66537741Smckusick 	struct vnode *vp;
66637741Smckusick 	int error;
66737741Smckusick 
66852322Smckusick 	if (error = namei(ndp))
66937741Smckusick 		return (error);
67037741Smckusick 	vp = ndp->ni_vp;
67137741Smckusick 	if (vp->v_type != VDIR)
67237741Smckusick 		error = ENOTDIR;
67337741Smckusick 	else
67448026Smckusick 		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
67537741Smckusick 	VOP_UNLOCK(vp);
67637741Smckusick 	if (error)
67737741Smckusick 		vrele(vp);
67837741Smckusick 	return (error);
67937741Smckusick }
68037741Smckusick 
68137741Smckusick /*
68242441Smckusick  * Check permissions, allocate an open file structure,
68342441Smckusick  * and call the device open routine if any.
6846254Sroot  */
68568318Scgd int
68642441Smckusick open(p, uap, retval)
68745914Smckusick 	struct proc *p;
68868318Scgd 	register struct open_args /* {
68968318Scgd 		syscallarg(char *) path;
69068318Scgd 		syscallarg(int) flags;
69168318Scgd 		syscallarg(int) mode;
69268318Scgd 	} */ *uap;
69368318Scgd 	register_t *retval;
6946254Sroot {
69545914Smckusick 	register struct filedesc *fdp = p->p_fd;
69642441Smckusick 	register struct file *fp;
69750111Smckusick 	register struct vnode *vp;
69864410Sbostic 	int flags, cmode;
69937741Smckusick 	struct file *nfp;
70049945Smckusick 	int type, indx, error;
70149945Smckusick 	struct flock lf;
70247540Skarels 	struct nameidata nd;
70337741Smckusick 	extern struct fileops vnops;
7046254Sroot 
70545914Smckusick 	if (error = falloc(p, &nfp, &indx))
70647540Skarels 		return (error);
70737741Smckusick 	fp = nfp;
70868318Scgd 	flags = FFLAGS(SCARG(uap, flags));
70968318Scgd 	cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
71068318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
71145202Smckusick 	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
71264410Sbostic 	if (error = vn_open(&nd, flags, cmode)) {
71349980Smckusick 		ffree(fp);
71454723Smckusick 		if ((error == ENODEV || error == ENXIO) &&
71568318Scgd 		    p->p_dupfd >= 0 &&			/* XXX from fdopen */
71664410Sbostic 		    (error =
71768318Scgd 			dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
71842441Smckusick 			*retval = indx;
71947540Skarels 			return (0);
72042441Smckusick 		}
72140884Smckusick 		if (error == ERESTART)
72240884Smckusick 			error = EINTR;
72347688Skarels 		fdp->fd_ofiles[indx] = NULL;
72447540Skarels 		return (error);
72512756Ssam 	}
72653828Spendry 	p->p_dupfd = 0;
72752322Smckusick 	vp = nd.ni_vp;
72864410Sbostic 	fp->f_flag = flags & FMASK;
72954348Smckusick 	fp->f_type = DTYPE_VNODE;
73054348Smckusick 	fp->f_ops = &vnops;
73154348Smckusick 	fp->f_data = (caddr_t)vp;
73264410Sbostic 	if (flags & (O_EXLOCK | O_SHLOCK)) {
73349945Smckusick 		lf.l_whence = SEEK_SET;
73449945Smckusick 		lf.l_start = 0;
73549945Smckusick 		lf.l_len = 0;
73664410Sbostic 		if (flags & O_EXLOCK)
73749945Smckusick 			lf.l_type = F_WRLCK;
73849945Smckusick 		else
73949945Smckusick 			lf.l_type = F_RDLCK;
74049945Smckusick 		type = F_FLOCK;
74164410Sbostic 		if ((flags & FNONBLOCK) == 0)
74249945Smckusick 			type |= F_WAIT;
74365757Smckusick 		VOP_UNLOCK(vp);
74450111Smckusick 		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
74550111Smckusick 			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
74649980Smckusick 			ffree(fp);
74749945Smckusick 			fdp->fd_ofiles[indx] = NULL;
74849945Smckusick 			return (error);
74949945Smckusick 		}
75065757Smckusick 		VOP_LOCK(vp);
75149949Smckusick 		fp->f_flag |= FHASLOCK;
75249945Smckusick 	}
75350111Smckusick 	VOP_UNLOCK(vp);
75442441Smckusick 	*retval = indx;
75547540Skarels 	return (0);
7566254Sroot }
7576254Sroot 
75842955Smckusick #ifdef COMPAT_43
7596254Sroot /*
76064410Sbostic  * Create a file.
7616254Sroot  */
76268318Scgd int
76368318Scgd compat_43_creat(p, uap, retval)
76442441Smckusick 	struct proc *p;
76568318Scgd 	register struct compat_43_creat_args /* {
76668318Scgd 		syscallarg(char *) path;
76768318Scgd 		syscallarg(int) mode;
76868318Scgd 	} */ *uap;
76968318Scgd 	register_t *retval;
7706254Sroot {
77168318Scgd 	struct open_args /* {
77268318Scgd 		syscallarg(char *) path;
77368318Scgd 		syscallarg(int) flags;
77468318Scgd 		syscallarg(int) mode;
77568318Scgd 	} */ nuap;
77642441Smckusick 
77768318Scgd 	SCARG(&nuap, path) = SCARG(uap, path);
77868318Scgd 	SCARG(&nuap, mode) = SCARG(uap, mode);
77968318Scgd 	SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
78068318Scgd 	return (open(p, &nuap, retval));
78142441Smckusick }
78242955Smckusick #endif /* COMPAT_43 */
78342441Smckusick 
78442441Smckusick /*
78564410Sbostic  * Create a special file.
78642441Smckusick  */
78742441Smckusick /* ARGSUSED */
78868318Scgd int
78942441Smckusick mknod(p, uap, retval)
79045914Smckusick 	struct proc *p;
79168318Scgd 	register struct mknod_args /* {
79268318Scgd 		syscallarg(char *) path;
79368318Scgd 		syscallarg(int) mode;
79468318Scgd 		syscallarg(int) dev;
79568318Scgd 	} */ *uap;
79668318Scgd 	register_t *retval;
79742441Smckusick {
79837741Smckusick 	register struct vnode *vp;
79937741Smckusick 	struct vattr vattr;
80037741Smckusick 	int error;
80167575Spendry 	int whiteout;
80247540Skarels 	struct nameidata nd;
8036254Sroot 
80447540Skarels 	if (error = suser(p->p_ucred, &p->p_acflag))
80547540Skarels 		return (error);
80668318Scgd 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
80752322Smckusick 	if (error = namei(&nd))
80847540Skarels 		return (error);
80952322Smckusick 	vp = nd.ni_vp;
81064585Sbostic 	if (vp != NULL)
81137741Smckusick 		error = EEXIST;
81264585Sbostic 	else {
81364585Sbostic 		VATTR_NULL(&vattr);
81468318Scgd 		vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
81568318Scgd 		vattr.va_rdev = SCARG(uap, dev);
81667575Spendry 		whiteout = 0;
81764585Sbostic 
81868318Scgd 		switch (SCARG(uap, mode) & S_IFMT) {
81964585Sbostic 		case S_IFMT:	/* used by badsect to flag bad sectors */
82064585Sbostic 			vattr.va_type = VBAD;
82164585Sbostic 			break;
82264585Sbostic 		case S_IFCHR:
82364585Sbostic 			vattr.va_type = VCHR;
82464585Sbostic 			break;
82564585Sbostic 		case S_IFBLK:
82664585Sbostic 			vattr.va_type = VBLK;
82764585Sbostic 			break;
82867575Spendry 		case S_IFWHT:
82967575Spendry 			whiteout = 1;
83067575Spendry 			break;
83164585Sbostic 		default:
83264585Sbostic 			error = EINVAL;
83364585Sbostic 			break;
83464585Sbostic 		}
8356254Sroot 	}
83667747Spendry 	if (!error) {
83767654Smckusick 		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
83867747Spendry 		if (whiteout) {
83967747Spendry 			error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
84067747Spendry 			if (error)
84167747Spendry 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
84267747Spendry 			vput(nd.ni_dvp);
84367747Spendry 		} else {
84467747Spendry 			error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
84567747Spendry 						&nd.ni_cnd, &vattr);
84667747Spendry 		}
84742465Smckusick 	} else {
84852322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
84952322Smckusick 		if (nd.ni_dvp == vp)
85052322Smckusick 			vrele(nd.ni_dvp);
85143344Smckusick 		else
85252322Smckusick 			vput(nd.ni_dvp);
85342465Smckusick 		if (vp)
85442465Smckusick 			vrele(vp);
85542465Smckusick 	}
85647540Skarels 	return (error);
8576254Sroot }
8586254Sroot 
8596254Sroot /*
86068318Scgd  * Create a named pipe.
86140285Smckusick  */
86242441Smckusick /* ARGSUSED */
86368318Scgd int
86442441Smckusick mkfifo(p, uap, retval)
86545914Smckusick 	struct proc *p;
86668318Scgd 	register struct mkfifo_args /* {
86768318Scgd 		syscallarg(char *) path;
86868318Scgd 		syscallarg(int) mode;
86968318Scgd 	} */ *uap;
87068318Scgd 	register_t *retval;
87142441Smckusick {
87240285Smckusick 	struct vattr vattr;
87340285Smckusick 	int error;
87447540Skarels 	struct nameidata nd;
87540285Smckusick 
87640285Smckusick #ifndef FIFO
87747540Skarels 	return (EOPNOTSUPP);
87840285Smckusick #else
87968318Scgd 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
88052322Smckusick 	if (error = namei(&nd))
88147540Skarels 		return (error);
88252322Smckusick 	if (nd.ni_vp != NULL) {
88352322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
88452322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
88552322Smckusick 			vrele(nd.ni_dvp);
88643344Smckusick 		else
88752322Smckusick 			vput(nd.ni_dvp);
88852322Smckusick 		vrele(nd.ni_vp);
88947540Skarels 		return (EEXIST);
89040285Smckusick 	}
89145785Sbostic 	VATTR_NULL(&vattr);
89245785Sbostic 	vattr.va_type = VFIFO;
89368318Scgd 	vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
89467654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
89552322Smckusick 	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
89640285Smckusick #endif /* FIFO */
89740285Smckusick }
89840285Smckusick 
89940285Smckusick /*
90064410Sbostic  * Make a hard file link.
9016254Sroot  */
90242441Smckusick /* ARGSUSED */
90368318Scgd int
90442441Smckusick link(p, uap, retval)
90545914Smckusick 	struct proc *p;
90668318Scgd 	register struct link_args /* {
90768318Scgd 		syscallarg(char *) path;
90868318Scgd 		syscallarg(char *) link;
90968318Scgd 	} */ *uap;
91068318Scgd 	register_t *retval;
91142441Smckusick {
91264410Sbostic 	register struct vnode *vp;
91364410Sbostic 	struct nameidata nd;
91437741Smckusick 	int error;
9156254Sroot 
91668318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
91752322Smckusick 	if (error = namei(&nd))
91847540Skarels 		return (error);
91952322Smckusick 	vp = nd.ni_vp;
92064585Sbostic 	if (vp->v_type != VDIR ||
92164585Sbostic 	    (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
92264585Sbostic 		nd.ni_cnd.cn_nameiop = CREATE;
92364585Sbostic 		nd.ni_cnd.cn_flags = LOCKPARENT;
92468318Scgd 		nd.ni_dirp = SCARG(uap, link);
92564585Sbostic 		if ((error = namei(&nd)) == 0) {
92664585Sbostic 			if (nd.ni_vp != NULL)
92764585Sbostic 				error = EEXIST;
92864585Sbostic 			if (!error) {
92967654Smckusick 				VOP_LEASE(nd.ni_dvp, p, p->p_ucred,
93067654Smckusick 				    LEASE_WRITE);
93167654Smckusick 				VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
93268538Smckusick 				error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd);
93364585Sbostic 			} else {
93464585Sbostic 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
93564585Sbostic 				if (nd.ni_dvp == nd.ni_vp)
93664585Sbostic 					vrele(nd.ni_dvp);
93764585Sbostic 				else
93864585Sbostic 					vput(nd.ni_dvp);
93964585Sbostic 				if (nd.ni_vp)
94064585Sbostic 					vrele(nd.ni_vp);
94164585Sbostic 			}
94264585Sbostic 		}
94342465Smckusick 	}
94464585Sbostic 	vrele(vp);
94547540Skarels 	return (error);
9466254Sroot }
9476254Sroot 
9486254Sroot /*
94949365Smckusick  * Make a symbolic link.
9506254Sroot  */
95142441Smckusick /* ARGSUSED */
95268318Scgd int
95342441Smckusick symlink(p, uap, retval)
95445914Smckusick 	struct proc *p;
95568318Scgd 	register struct symlink_args /* {
95668318Scgd 		syscallarg(char *) path;
95768318Scgd 		syscallarg(char *) link;
95868318Scgd 	} */ *uap;
95968318Scgd 	register_t *retval;
96042441Smckusick {
96137741Smckusick 	struct vattr vattr;
96264410Sbostic 	char *path;
96337741Smckusick 	int error;
96447540Skarels 	struct nameidata nd;
9656254Sroot 
96664410Sbostic 	MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
96768318Scgd 	if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL))
96842465Smckusick 		goto out;
96968318Scgd 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
97052322Smckusick 	if (error = namei(&nd))
97142465Smckusick 		goto out;
97252322Smckusick 	if (nd.ni_vp) {
97352322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
97452322Smckusick 		if (nd.ni_dvp == nd.ni_vp)
97552322Smckusick 			vrele(nd.ni_dvp);
97643344Smckusick 		else
97752322Smckusick 			vput(nd.ni_dvp);
97852322Smckusick 		vrele(nd.ni_vp);
97937741Smckusick 		error = EEXIST;
98037741Smckusick 		goto out;
9816254Sroot 	}
98241362Smckusick 	VATTR_NULL(&vattr);
98364410Sbostic 	vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
98467654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
98564410Sbostic 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
98637741Smckusick out:
98764410Sbostic 	FREE(path, M_NAMEI);
98847540Skarels 	return (error);
9896254Sroot }
9906254Sroot 
9916254Sroot /*
99267518Spendry  * Delete a whiteout from the filesystem.
99367518Spendry  */
99467518Spendry /* ARGSUSED */
99568318Scgd int
99667845Smckusick undelete(p, uap, retval)
99767518Spendry 	struct proc *p;
99868318Scgd 	register struct undelete_args /* {
99968318Scgd 		syscallarg(char *) path;
100068318Scgd 	} */ *uap;
100168318Scgd 	register_t *retval;
100267518Spendry {
100367518Spendry 	int error;
100467518Spendry 	struct nameidata nd;
100567518Spendry 
100668318Scgd 	NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
100768318Scgd 	    SCARG(uap, path), p);
100867575Spendry 	error = namei(&nd);
100967575Spendry 	if (error)
101067518Spendry 		return (error);
101167575Spendry 
101267575Spendry 	if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
101367518Spendry 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
101467518Spendry 		if (nd.ni_dvp == nd.ni_vp)
101567518Spendry 			vrele(nd.ni_dvp);
101667518Spendry 		else
101767518Spendry 			vput(nd.ni_dvp);
101867518Spendry 		if (nd.ni_vp)
101967518Spendry 			vrele(nd.ni_vp);
102067518Spendry 		return (EEXIST);
102167518Spendry 	}
102267575Spendry 
102367654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
102467747Spendry 	if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE))
102567575Spendry 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
102667518Spendry 	vput(nd.ni_dvp);
102767518Spendry 	return (error);
102867518Spendry }
102967518Spendry 
103067518Spendry /*
103149365Smckusick  * Delete a name from the filesystem.
10326254Sroot  */
103342441Smckusick /* ARGSUSED */
103468318Scgd int
103542441Smckusick unlink(p, uap, retval)
103645914Smckusick 	struct proc *p;
103768318Scgd 	struct unlink_args /* {
103868318Scgd 		syscallarg(char *) path;
103968318Scgd 	} */ *uap;
104068318Scgd 	register_t *retval;
10416254Sroot {
104237741Smckusick 	register struct vnode *vp;
104337741Smckusick 	int error;
104447540Skarels 	struct nameidata nd;
10456254Sroot 
104668318Scgd 	NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
104752322Smckusick 	if (error = namei(&nd))
104847540Skarels 		return (error);
104952322Smckusick 	vp = nd.ni_vp;
105067654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
105159382Smckusick 	VOP_LOCK(vp);
105264410Sbostic 
105364585Sbostic 	if (vp->v_type != VDIR ||
105464585Sbostic 	    (error = suser(p->p_ucred, &p->p_acflag)) == 0) {
105564585Sbostic 		/*
105664585Sbostic 		 * The root of a mounted filesystem cannot be deleted.
105764585Sbostic 		 */
105864585Sbostic 		if (vp->v_flag & VROOT)
105964585Sbostic 			error = EBUSY;
106064585Sbostic 		else
106164585Sbostic 			(void)vnode_pager_uncache(vp);
106264585Sbostic 	}
106364585Sbostic 
106464585Sbostic 	if (!error) {
106567654Smckusick 		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
106652322Smckusick 		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
106742465Smckusick 	} else {
106852322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
106952322Smckusick 		if (nd.ni_dvp == vp)
107052322Smckusick 			vrele(nd.ni_dvp);
107143344Smckusick 		else
107252322Smckusick 			vput(nd.ni_dvp);
107367575Spendry 		if (vp != NULLVP)
107467575Spendry 			vput(vp);
107542465Smckusick 	}
107647540Skarels 	return (error);
10776254Sroot }
10786254Sroot 
107964410Sbostic /*
108064410Sbostic  * Reposition read/write file offset.
108164410Sbostic  */
108268318Scgd int
108360414Smckusick lseek(p, uap, retval)
108453468Smckusick 	struct proc *p;
108568318Scgd 	register struct lseek_args /* {
108668318Scgd 		syscallarg(int) fd;
108768318Scgd 		syscallarg(int) pad;
108868318Scgd 		syscallarg(off_t) offset;
108968318Scgd 		syscallarg(int) whence;
109068318Scgd 	} */ *uap;
109168318Scgd 	register_t *retval;
109242441Smckusick {
109347540Skarels 	struct ucred *cred = p->p_ucred;
109445914Smckusick 	register struct filedesc *fdp = p->p_fd;
109542441Smckusick 	register struct file *fp;
109637741Smckusick 	struct vattr vattr;
109737741Smckusick 	int error;
10986254Sroot 
109968318Scgd 	if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
110068318Scgd 	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
110147540Skarels 		return (EBADF);
110237741Smckusick 	if (fp->f_type != DTYPE_VNODE)
110347540Skarels 		return (ESPIPE);
110468318Scgd 	switch (SCARG(uap, whence)) {
110513878Ssam 	case L_INCR:
110668318Scgd 		fp->f_offset += SCARG(uap, offset);
110713878Ssam 		break;
110813878Ssam 	case L_XTND:
110964410Sbostic 		if (error =
111064410Sbostic 		    VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p))
111147540Skarels 			return (error);
111268318Scgd 		fp->f_offset = SCARG(uap, offset) + vattr.va_size;
111313878Ssam 		break;
111413878Ssam 	case L_SET:
111568318Scgd 		fp->f_offset = SCARG(uap, offset);
111613878Ssam 		break;
111713878Ssam 	default:
111847540Skarels 		return (EINVAL);
111913878Ssam 	}
112054916Storek 	*(off_t *)retval = fp->f_offset;
112147540Skarels 	return (0);
11226254Sroot }
11236254Sroot 
112460414Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
11256254Sroot /*
112664410Sbostic  * Reposition read/write file offset.
112760036Smckusick  */
112868318Scgd int
112968318Scgd compat_43_lseek(p, uap, retval)
113060036Smckusick 	struct proc *p;
113168318Scgd 	register struct compat_43_lseek_args /* {
113268318Scgd 		syscallarg(int) fd;
113368318Scgd 		syscallarg(long) offset;
113468318Scgd 		syscallarg(int) whence;
113568318Scgd 	} */ *uap;
113668318Scgd 	register_t *retval;
113760036Smckusick {
113868318Scgd 	struct lseek_args /* {
113968318Scgd 		syscallarg(int) fd;
114068318Scgd 		syscallarg(int) pad;
114168318Scgd 		syscallarg(off_t) offset;
114268318Scgd 		syscallarg(int) whence;
114368318Scgd 	} */ nuap;
114460036Smckusick 	off_t qret;
114560036Smckusick 	int error;
114660036Smckusick 
114768318Scgd 	SCARG(&nuap, fd) = SCARG(uap, fd);
114868318Scgd 	SCARG(&nuap, offset) = SCARG(uap, offset);
114968318Scgd 	SCARG(&nuap, whence) = SCARG(uap, whence);
115060428Smckusick 	error = lseek(p, &nuap, &qret);
115160036Smckusick 	*(long *)retval = qret;
115260036Smckusick 	return (error);
115360036Smckusick }
115460414Smckusick #endif /* COMPAT_43 */
115560036Smckusick 
115660036Smckusick /*
115749365Smckusick  * Check access permissions.
11586254Sroot  */
115968318Scgd int
116063427Sbostic access(p, uap, retval)
116145914Smckusick 	struct proc *p;
116268318Scgd 	register struct access_args /* {
116368318Scgd 		syscallarg(char *) path;
116468318Scgd 		syscallarg(int) flags;
116568318Scgd 	} */ *uap;
116668318Scgd 	register_t *retval;
116742441Smckusick {
116847540Skarels 	register struct ucred *cred = p->p_ucred;
116937741Smckusick 	register struct vnode *vp;
117064585Sbostic 	int error, flags, t_gid, t_uid;
117147540Skarels 	struct nameidata nd;
11726254Sroot 
117364585Sbostic 	t_uid = cred->cr_uid;
117464585Sbostic 	t_gid = cred->cr_groups[0];
117547540Skarels 	cred->cr_uid = p->p_cred->p_ruid;
117647540Skarels 	cred->cr_groups[0] = p->p_cred->p_rgid;
117768318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
117868318Scgd 	    SCARG(uap, path), p);
117952322Smckusick 	if (error = namei(&nd))
118037741Smckusick 		goto out1;
118152322Smckusick 	vp = nd.ni_vp;
118264410Sbostic 
118364410Sbostic 	/* Flags == 0 means only check for existence. */
118468318Scgd 	if (SCARG(uap, flags)) {
118564410Sbostic 		flags = 0;
118668318Scgd 		if (SCARG(uap, flags) & R_OK)
118764410Sbostic 			flags |= VREAD;
118868318Scgd 		if (SCARG(uap, flags) & W_OK)
118964410Sbostic 			flags |= VWRITE;
119068318Scgd 		if (SCARG(uap, flags) & X_OK)
119164410Sbostic 			flags |= VEXEC;
119264410Sbostic 		if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
119364410Sbostic 			error = VOP_ACCESS(vp, flags, cred, p);
11946254Sroot 	}
119537741Smckusick 	vput(vp);
119637741Smckusick out1:
119764585Sbostic 	cred->cr_uid = t_uid;
119864585Sbostic 	cred->cr_groups[0] = t_gid;
119947540Skarels 	return (error);
12006254Sroot }
12016254Sroot 
120254348Smckusick #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
12036254Sroot /*
120464410Sbostic  * Get file status; this version follows links.
120537Sbill  */
120642441Smckusick /* ARGSUSED */
120768318Scgd int
120868318Scgd compat_43_stat(p, uap, retval)
120945914Smckusick 	struct proc *p;
121068318Scgd 	register struct compat_43_stat_args /* {
121168318Scgd 		syscallarg(char *) path;
121268318Scgd 		syscallarg(struct ostat *) ub;
121368318Scgd 	} */ *uap;
121468318Scgd 	register_t *retval;
121553468Smckusick {
121653468Smckusick 	struct stat sb;
121753468Smckusick 	struct ostat osb;
121853468Smckusick 	int error;
121953468Smckusick 	struct nameidata nd;
122053468Smckusick 
122168318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
122268318Scgd 	    SCARG(uap, path), p);
122353468Smckusick 	if (error = namei(&nd))
122453468Smckusick 		return (error);
122553468Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
122653468Smckusick 	vput(nd.ni_vp);
122753468Smckusick 	if (error)
122853468Smckusick 		return (error);
122953468Smckusick 	cvtstat(&sb, &osb);
123068318Scgd 	error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
123153468Smckusick 	return (error);
123253468Smckusick }
123353468Smckusick 
123453468Smckusick /*
123564410Sbostic  * Get file status; this version does not follow links.
123653468Smckusick  */
123753468Smckusick /* ARGSUSED */
123868318Scgd int
123968318Scgd compat_43_lstat(p, uap, retval)
124053468Smckusick 	struct proc *p;
124168318Scgd 	register struct compat_43_lstat_args /* {
124268318Scgd 		syscallarg(char *) path;
124368318Scgd 		syscallarg(struct ostat *) ub;
124468318Scgd 	} */ *uap;
124568318Scgd 	register_t *retval;
124653468Smckusick {
124767748Smckusick 	struct vnode *vp, *dvp;
124867748Smckusick 	struct stat sb, sb1;
124953468Smckusick 	struct ostat osb;
125053468Smckusick 	int error;
125153468Smckusick 	struct nameidata nd;
125253468Smckusick 
125367748Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
125468318Scgd 	    SCARG(uap, path), p);
125553468Smckusick 	if (error = namei(&nd))
125653468Smckusick 		return (error);
125767748Smckusick 	/*
125867748Smckusick 	 * For symbolic links, always return the attributes of its
125967748Smckusick 	 * containing directory, except for mode, size, and links.
126067748Smckusick 	 */
126167748Smckusick 	vp = nd.ni_vp;
126267748Smckusick 	dvp = nd.ni_dvp;
126367748Smckusick 	if (vp->v_type != VLNK) {
126467748Smckusick 		if (dvp == vp)
126567748Smckusick 			vrele(dvp);
126667748Smckusick 		else
126767748Smckusick 			vput(dvp);
126867748Smckusick 		error = vn_stat(vp, &sb, p);
126967748Smckusick 		vput(vp);
127067748Smckusick 		if (error)
127167748Smckusick 			return (error);
127267748Smckusick 	} else {
127367748Smckusick 		error = vn_stat(dvp, &sb, p);
127467748Smckusick 		vput(dvp);
127567748Smckusick 		if (error) {
127667748Smckusick 			vput(vp);
127767748Smckusick 			return (error);
127867748Smckusick 		}
127967748Smckusick 		error = vn_stat(vp, &sb1, p);
128067748Smckusick 		vput(vp);
128167748Smckusick 		if (error)
128267748Smckusick 			return (error);
128367748Smckusick 		sb.st_mode &= ~S_IFDIR;
128467748Smckusick 		sb.st_mode |= S_IFLNK;
128567748Smckusick 		sb.st_nlink = sb1.st_nlink;
128667748Smckusick 		sb.st_size = sb1.st_size;
128767748Smckusick 		sb.st_blocks = sb1.st_blocks;
128867748Smckusick 	}
128953468Smckusick 	cvtstat(&sb, &osb);
129068318Scgd 	error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
129153468Smckusick 	return (error);
129253468Smckusick }
129353468Smckusick 
129453468Smckusick /*
129564410Sbostic  * Convert from an old to a new stat structure.
129653468Smckusick  */
129768318Scgd void
129853468Smckusick cvtstat(st, ost)
129953468Smckusick 	struct stat *st;
130053468Smckusick 	struct ostat *ost;
130153468Smckusick {
130253468Smckusick 
130353468Smckusick 	ost->st_dev = st->st_dev;
130453468Smckusick 	ost->st_ino = st->st_ino;
130553468Smckusick 	ost->st_mode = st->st_mode;
130653468Smckusick 	ost->st_nlink = st->st_nlink;
130753468Smckusick 	ost->st_uid = st->st_uid;
130853468Smckusick 	ost->st_gid = st->st_gid;
130953468Smckusick 	ost->st_rdev = st->st_rdev;
131053468Smckusick 	if (st->st_size < (quad_t)1 << 32)
131153468Smckusick 		ost->st_size = st->st_size;
131253468Smckusick 	else
131353468Smckusick 		ost->st_size = -2;
131453468Smckusick 	ost->st_atime = st->st_atime;
131553468Smckusick 	ost->st_mtime = st->st_mtime;
131653468Smckusick 	ost->st_ctime = st->st_ctime;
131753468Smckusick 	ost->st_blksize = st->st_blksize;
131853468Smckusick 	ost->st_blocks = st->st_blocks;
131953468Smckusick 	ost->st_flags = st->st_flags;
132053468Smckusick 	ost->st_gen = st->st_gen;
132153468Smckusick }
132254348Smckusick #endif /* COMPAT_43 || COMPAT_SUNOS */
132353468Smckusick 
132453468Smckusick /*
132564410Sbostic  * Get file status; this version follows links.
132653468Smckusick  */
132753468Smckusick /* ARGSUSED */
132868318Scgd int
132953759Smckusick stat(p, uap, retval)
133053468Smckusick 	struct proc *p;
133168318Scgd 	register struct stat_args /* {
133268318Scgd 		syscallarg(char *) path;
133368318Scgd 		syscallarg(struct stat *) ub;
133468318Scgd 	} */ *uap;
133568318Scgd 	register_t *retval;
133637Sbill {
133742441Smckusick 	struct stat sb;
133842441Smckusick 	int error;
133947540Skarels 	struct nameidata nd;
134037Sbill 
134168318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
134268318Scgd 	    SCARG(uap, path), p);
134352322Smckusick 	if (error = namei(&nd))
134447540Skarels 		return (error);
134552322Smckusick 	error = vn_stat(nd.ni_vp, &sb, p);
134652322Smckusick 	vput(nd.ni_vp);
134742441Smckusick 	if (error)
134847540Skarels 		return (error);
134968318Scgd 	error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
135047540Skarels 	return (error);
135137Sbill }
135237Sbill 
135337Sbill /*
135464410Sbostic  * Get file status; this version does not follow links.
13555992Swnj  */
135642441Smckusick /* ARGSUSED */
135768318Scgd int
135853759Smckusick lstat(p, uap, retval)
135945914Smckusick 	struct proc *p;
136068318Scgd 	register struct lstat_args /* {
136168318Scgd 		syscallarg(char *) path;
136268318Scgd 		syscallarg(struct stat *) ub;
136368318Scgd 	} */ *uap;
136468318Scgd 	register_t *retval;
136542441Smckusick {
136637741Smckusick 	int error;
136759373Smckusick 	struct vnode *vp, *dvp;
136859373Smckusick 	struct stat sb, sb1;
136947540Skarels 	struct nameidata nd;
13705992Swnj 
137159373Smckusick 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKPARENT, UIO_USERSPACE,
137268318Scgd 	    SCARG(uap, path), p);
137352322Smckusick 	if (error = namei(&nd))
137447540Skarels 		return (error);
137559373Smckusick 	/*
137668579Smckusick 	 * For symbolic links, always return the attributes of its containing
137768579Smckusick 	 * directory, except for mode, size, inode number, and links.
137859373Smckusick 	 */
137959373Smckusick 	vp = nd.ni_vp;
138059373Smckusick 	dvp = nd.ni_dvp;
138159373Smckusick 	if (vp->v_type != VLNK) {
138259373Smckusick 		if (dvp == vp)
138359373Smckusick 			vrele(dvp);
138459373Smckusick 		else
138559373Smckusick 			vput(dvp);
138659373Smckusick 		error = vn_stat(vp, &sb, p);
138759373Smckusick 		vput(vp);
138859373Smckusick 		if (error)
138959373Smckusick 			return (error);
139059373Smckusick 	} else {
139159373Smckusick 		error = vn_stat(dvp, &sb, p);
139259373Smckusick 		vput(dvp);
139359373Smckusick 		if (error) {
139459373Smckusick 			vput(vp);
139559373Smckusick 			return (error);
139659373Smckusick 		}
139759373Smckusick 		error = vn_stat(vp, &sb1, p);
139859373Smckusick 		vput(vp);
139959373Smckusick 		if (error)
140059373Smckusick 			return (error);
140159373Smckusick 		sb.st_mode &= ~S_IFDIR;
140259373Smckusick 		sb.st_mode |= S_IFLNK;
140359373Smckusick 		sb.st_nlink = sb1.st_nlink;
140459373Smckusick 		sb.st_size = sb1.st_size;
140559373Smckusick 		sb.st_blocks = sb1.st_blocks;
140668579Smckusick 		sb.st_ino = sb1.st_ino;
140759373Smckusick 	}
140868318Scgd 	error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
140947540Skarels 	return (error);
14105992Swnj }
14115992Swnj 
14125992Swnj /*
141364410Sbostic  * Get configurable pathname variables.
141460414Smckusick  */
141560414Smckusick /* ARGSUSED */
141668318Scgd int
141760414Smckusick pathconf(p, uap, retval)
141860414Smckusick 	struct proc *p;
141968318Scgd 	register struct pathconf_args /* {
142068318Scgd 		syscallarg(char *) path;
142168318Scgd 		syscallarg(int) name;
142268318Scgd 	} */ *uap;
142368318Scgd 	register_t *retval;
142460414Smckusick {
142560414Smckusick 	int error;
142660414Smckusick 	struct nameidata nd;
142760414Smckusick 
142868318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
142968318Scgd 	    SCARG(uap, path), p);
143060414Smckusick 	if (error = namei(&nd))
143160414Smckusick 		return (error);
143268318Scgd 	error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
143360414Smckusick 	vput(nd.ni_vp);
143460414Smckusick 	return (error);
143560414Smckusick }
143660414Smckusick 
143760414Smckusick /*
143849365Smckusick  * Return target name of a symbolic link.
143937Sbill  */
144042441Smckusick /* ARGSUSED */
144168318Scgd int
144242441Smckusick readlink(p, uap, retval)
144345914Smckusick 	struct proc *p;
144468318Scgd 	register struct readlink_args /* {
144568318Scgd 		syscallarg(char *) path;
144668318Scgd 		syscallarg(char *) buf;
144768318Scgd 		syscallarg(int) count;
144868318Scgd 	} */ *uap;
144968318Scgd 	register_t *retval;
145042441Smckusick {
145137741Smckusick 	register struct vnode *vp;
145237741Smckusick 	struct iovec aiov;
145337741Smckusick 	struct uio auio;
145437741Smckusick 	int error;
145547540Skarels 	struct nameidata nd;
14565992Swnj 
145768318Scgd 	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
145868318Scgd 	    SCARG(uap, path), p);
145952322Smckusick 	if (error = namei(&nd))
146047540Skarels 		return (error);
146152322Smckusick 	vp = nd.ni_vp;
146264410Sbostic 	if (vp->v_type != VLNK)
146337741Smckusick 		error = EINVAL;
146464410Sbostic 	else {
146568318Scgd 		aiov.iov_base = SCARG(uap, buf);
146668318Scgd 		aiov.iov_len = SCARG(uap, count);
146764410Sbostic 		auio.uio_iov = &aiov;
146864410Sbostic 		auio.uio_iovcnt = 1;
146964410Sbostic 		auio.uio_offset = 0;
147064410Sbostic 		auio.uio_rw = UIO_READ;
147164410Sbostic 		auio.uio_segflg = UIO_USERSPACE;
147264410Sbostic 		auio.uio_procp = p;
147368318Scgd 		auio.uio_resid = SCARG(uap, count);
147464410Sbostic 		error = VOP_READLINK(vp, &auio, p->p_ucred);
14755992Swnj 	}
147637741Smckusick 	vput(vp);
147768318Scgd 	*retval = SCARG(uap, count) - auio.uio_resid;
147847540Skarels 	return (error);
14795992Swnj }
14805992Swnj 
14819167Ssam /*
148264410Sbostic  * Change flags of a file given a path name.
148338259Smckusick  */
148442441Smckusick /* ARGSUSED */
148568318Scgd int
148642441Smckusick chflags(p, uap, retval)
148745914Smckusick 	struct proc *p;
148868318Scgd 	register struct chflags_args /* {
148968318Scgd 		syscallarg(char *) path;
149068318Scgd 		syscallarg(int) flags;
149168318Scgd 	} */ *uap;
149268318Scgd 	register_t *retval;
149342441Smckusick {
149438259Smckusick 	register struct vnode *vp;
149538259Smckusick 	struct vattr vattr;
149638259Smckusick 	int error;
149747540Skarels 	struct nameidata nd;
149838259Smckusick 
149968318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
150052322Smckusick 	if (error = namei(&nd))
150147540Skarels 		return (error);
150252322Smckusick 	vp = nd.ni_vp;
150367654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
150459382Smckusick 	VOP_LOCK(vp);
150564410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
150638259Smckusick 		error = EROFS;
150764410Sbostic 	else {
150864410Sbostic 		VATTR_NULL(&vattr);
150968318Scgd 		vattr.va_flags = SCARG(uap, flags);
151064410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
151138259Smckusick 	}
151238259Smckusick 	vput(vp);
151347540Skarels 	return (error);
151438259Smckusick }
151538259Smckusick 
151638259Smckusick /*
151738259Smckusick  * Change flags of a file given a file descriptor.
151838259Smckusick  */
151942441Smckusick /* ARGSUSED */
152068318Scgd int
152142441Smckusick fchflags(p, uap, retval)
152245914Smckusick 	struct proc *p;
152368318Scgd 	register struct fchflags_args /* {
152468318Scgd 		syscallarg(int) fd;
152568318Scgd 		syscallarg(int) flags;
152668318Scgd 	} */ *uap;
152768318Scgd 	register_t *retval;
152842441Smckusick {
152938259Smckusick 	struct vattr vattr;
153038259Smckusick 	struct vnode *vp;
153138259Smckusick 	struct file *fp;
153238259Smckusick 	int error;
153338259Smckusick 
153468318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
153547540Skarels 		return (error);
153638259Smckusick 	vp = (struct vnode *)fp->f_data;
153767654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
153838259Smckusick 	VOP_LOCK(vp);
153964410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
154038259Smckusick 		error = EROFS;
154164410Sbostic 	else {
154264410Sbostic 		VATTR_NULL(&vattr);
154368318Scgd 		vattr.va_flags = SCARG(uap, flags);
154464410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
154538259Smckusick 	}
154638259Smckusick 	VOP_UNLOCK(vp);
154747540Skarels 	return (error);
154838259Smckusick }
154938259Smckusick 
155038259Smckusick /*
15519167Ssam  * Change mode of a file given path name.
15529167Ssam  */
155342441Smckusick /* ARGSUSED */
155468318Scgd int
155542441Smckusick chmod(p, uap, retval)
155645914Smckusick 	struct proc *p;
155768318Scgd 	register struct chmod_args /* {
155868318Scgd 		syscallarg(char *) path;
155968318Scgd 		syscallarg(int) mode;
156068318Scgd 	} */ *uap;
156168318Scgd 	register_t *retval;
156242441Smckusick {
156337741Smckusick 	register struct vnode *vp;
156437741Smckusick 	struct vattr vattr;
156537741Smckusick 	int error;
156647540Skarels 	struct nameidata nd;
15675992Swnj 
156868318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
156952322Smckusick 	if (error = namei(&nd))
157047540Skarels 		return (error);
157152322Smckusick 	vp = nd.ni_vp;
157267654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
157359382Smckusick 	VOP_LOCK(vp);
157464410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
157537741Smckusick 		error = EROFS;
157664410Sbostic 	else {
157764410Sbostic 		VATTR_NULL(&vattr);
157868318Scgd 		vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
157964410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
158037741Smckusick 	}
158137741Smckusick 	vput(vp);
158247540Skarels 	return (error);
15837701Ssam }
15847439Sroot 
15859167Ssam /*
15869167Ssam  * Change mode of a file given a file descriptor.
15879167Ssam  */
158842441Smckusick /* ARGSUSED */
158968318Scgd int
159042441Smckusick fchmod(p, uap, retval)
159145914Smckusick 	struct proc *p;
159268318Scgd 	register struct fchmod_args /* {
159368318Scgd 		syscallarg(int) fd;
159468318Scgd 		syscallarg(int) mode;
159568318Scgd 	} */ *uap;
159668318Scgd 	register_t *retval;
159742441Smckusick {
159837741Smckusick 	struct vattr vattr;
159937741Smckusick 	struct vnode *vp;
160037741Smckusick 	struct file *fp;
160137741Smckusick 	int error;
16027701Ssam 
160368318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
160447540Skarels 		return (error);
160537741Smckusick 	vp = (struct vnode *)fp->f_data;
160667654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
160737741Smckusick 	VOP_LOCK(vp);
160864410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
160937741Smckusick 		error = EROFS;
161064410Sbostic 	else {
161164410Sbostic 		VATTR_NULL(&vattr);
161268318Scgd 		vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
161364410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
16147439Sroot 	}
161537741Smckusick 	VOP_UNLOCK(vp);
161647540Skarels 	return (error);
16175992Swnj }
16185992Swnj 
16199167Ssam /*
16209167Ssam  * Set ownership given a path name.
16219167Ssam  */
162242441Smckusick /* ARGSUSED */
162368318Scgd int
162442441Smckusick chown(p, uap, retval)
162545914Smckusick 	struct proc *p;
162668318Scgd 	register struct chown_args /* {
162768318Scgd 		syscallarg(char *) path;
162868318Scgd 		syscallarg(int) uid;
162968318Scgd 		syscallarg(int) gid;
163068318Scgd 	} */ *uap;
163168318Scgd 	register_t *retval;
163242441Smckusick {
163337741Smckusick 	register struct vnode *vp;
163437741Smckusick 	struct vattr vattr;
163537741Smckusick 	int error;
163647540Skarels 	struct nameidata nd;
163737Sbill 
163868318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
163952322Smckusick 	if (error = namei(&nd))
164047540Skarels 		return (error);
164152322Smckusick 	vp = nd.ni_vp;
164267654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
164359382Smckusick 	VOP_LOCK(vp);
164464410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
164537741Smckusick 		error = EROFS;
164664410Sbostic 	else {
164764410Sbostic 		VATTR_NULL(&vattr);
164868318Scgd 		vattr.va_uid = SCARG(uap, uid);
164968318Scgd 		vattr.va_gid = SCARG(uap, gid);
165064410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
165137741Smckusick 	}
165237741Smckusick 	vput(vp);
165347540Skarels 	return (error);
16547701Ssam }
16557439Sroot 
16569167Ssam /*
16579167Ssam  * Set ownership given a file descriptor.
16589167Ssam  */
165942441Smckusick /* ARGSUSED */
166068318Scgd int
166142441Smckusick fchown(p, uap, retval)
166245914Smckusick 	struct proc *p;
166368318Scgd 	register struct fchown_args /* {
166468318Scgd 		syscallarg(int) fd;
166568318Scgd 		syscallarg(int) uid;
166668318Scgd 		syscallarg(int) gid;
166768318Scgd 	} */ *uap;
166868318Scgd 	register_t *retval;
166942441Smckusick {
167037741Smckusick 	struct vattr vattr;
167137741Smckusick 	struct vnode *vp;
167237741Smckusick 	struct file *fp;
167337741Smckusick 	int error;
16747701Ssam 
167568318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
167647540Skarels 		return (error);
167737741Smckusick 	vp = (struct vnode *)fp->f_data;
167867654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
167937741Smckusick 	VOP_LOCK(vp);
168064410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
168137741Smckusick 		error = EROFS;
168264410Sbostic 	else {
168364410Sbostic 		VATTR_NULL(&vattr);
168468318Scgd 		vattr.va_uid = SCARG(uap, uid);
168568318Scgd 		vattr.va_gid = SCARG(uap, gid);
168664410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
168737741Smckusick 	}
168837741Smckusick 	VOP_UNLOCK(vp);
168947540Skarels 	return (error);
16907701Ssam }
16917701Ssam 
169242441Smckusick /*
169342441Smckusick  * Set the access and modification times of a file.
169442441Smckusick  */
169542441Smckusick /* ARGSUSED */
169668318Scgd int
169742441Smckusick utimes(p, uap, retval)
169845914Smckusick 	struct proc *p;
169968318Scgd 	register struct utimes_args /* {
170068318Scgd 		syscallarg(char *) path;
170168318Scgd 		syscallarg(struct timeval *) tptr;
170268318Scgd 	} */ *uap;
170368318Scgd 	register_t *retval;
170442441Smckusick {
170537741Smckusick 	register struct vnode *vp;
170611811Ssam 	struct timeval tv[2];
170737741Smckusick 	struct vattr vattr;
170858840Storek 	int error;
170947540Skarels 	struct nameidata nd;
171011811Ssam 
171158505Sbostic 	VATTR_NULL(&vattr);
171268318Scgd 	if (SCARG(uap, tptr) == NULL) {
171358505Sbostic 		microtime(&tv[0]);
171458505Sbostic 		tv[1] = tv[0];
171558548Sbostic 		vattr.va_vaflags |= VA_UTIMES_NULL;
171668318Scgd 	} else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv,
171768318Scgd 	    sizeof (tv)))
171858505Sbostic   		return (error);
171968318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
172052322Smckusick 	if (error = namei(&nd))
172147540Skarels 		return (error);
172252322Smckusick 	vp = nd.ni_vp;
172367654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
172459382Smckusick 	VOP_LOCK(vp);
172564410Sbostic 	if (vp->v_mount->mnt_flag & MNT_RDONLY)
172637741Smckusick 		error = EROFS;
172764410Sbostic 	else {
172864410Sbostic 		vattr.va_atime.ts_sec = tv[0].tv_sec;
172964410Sbostic 		vattr.va_atime.ts_nsec = tv[0].tv_usec * 1000;
173064410Sbostic 		vattr.va_mtime.ts_sec = tv[1].tv_sec;
173164410Sbostic 		vattr.va_mtime.ts_nsec = tv[1].tv_usec * 1000;
173264410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
173321015Smckusick 	}
173437741Smckusick 	vput(vp);
173547540Skarels 	return (error);
173611811Ssam }
173711811Ssam 
173864410Sbostic /*
173964410Sbostic  * Truncate a file given its path name.
174064410Sbostic  */
174153468Smckusick /* ARGSUSED */
174268318Scgd int
174360414Smckusick truncate(p, uap, retval)
174453468Smckusick 	struct proc *p;
174568318Scgd 	register struct truncate_args /* {
174668318Scgd 		syscallarg(char *) path;
174768318Scgd 		syscallarg(int) pad;
174868318Scgd 		syscallarg(off_t) length;
174968318Scgd 	} */ *uap;
175068318Scgd 	register_t *retval;
175153468Smckusick {
175237741Smckusick 	register struct vnode *vp;
175337741Smckusick 	struct vattr vattr;
175437741Smckusick 	int error;
175547540Skarels 	struct nameidata nd;
17567701Ssam 
175768318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
175852322Smckusick 	if (error = namei(&nd))
175947540Skarels 		return (error);
176052322Smckusick 	vp = nd.ni_vp;
176167654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
176259382Smckusick 	VOP_LOCK(vp);
176364410Sbostic 	if (vp->v_type == VDIR)
176437741Smckusick 		error = EISDIR;
176564410Sbostic 	else if ((error = vn_writechk(vp)) == 0 &&
176664410Sbostic 	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
176764410Sbostic 		VATTR_NULL(&vattr);
176868318Scgd 		vattr.va_size = SCARG(uap, length);
176964410Sbostic 		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
17707701Ssam 	}
177137741Smckusick 	vput(vp);
177247540Skarels 	return (error);
17737701Ssam }
17747701Ssam 
177564410Sbostic /*
177664410Sbostic  * Truncate a file given a file descriptor.
177764410Sbostic  */
177842441Smckusick /* ARGSUSED */
177968318Scgd int
178060414Smckusick ftruncate(p, uap, retval)
178145914Smckusick 	struct proc *p;
178268318Scgd 	register struct ftruncate_args /* {
178368318Scgd 		syscallarg(int) fd;
178468318Scgd 		syscallarg(int) pad;
178568318Scgd 		syscallarg(off_t) length;
178668318Scgd 	} */ *uap;
178768318Scgd 	register_t *retval;
178842441Smckusick {
178937741Smckusick 	struct vattr vattr;
179037741Smckusick 	struct vnode *vp;
17917701Ssam 	struct file *fp;
179237741Smckusick 	int error;
17937701Ssam 
179468318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
179547540Skarels 		return (error);
179637741Smckusick 	if ((fp->f_flag & FWRITE) == 0)
179747540Skarels 		return (EINVAL);
179837741Smckusick 	vp = (struct vnode *)fp->f_data;
179967654Smckusick 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
180037741Smckusick 	VOP_LOCK(vp);
180164410Sbostic 	if (vp->v_type == VDIR)
180237741Smckusick 		error = EISDIR;
180364410Sbostic 	else if ((error = vn_writechk(vp)) == 0) {
180464410Sbostic 		VATTR_NULL(&vattr);
180568318Scgd 		vattr.va_size = SCARG(uap, length);
180664410Sbostic 		error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
18077701Ssam 	}
180837741Smckusick 	VOP_UNLOCK(vp);
180947540Skarels 	return (error);
18107701Ssam }
18117701Ssam 
181254863Storek #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
18139167Ssam /*
181454863Storek  * Truncate a file given its path name.
181554863Storek  */
181654863Storek /* ARGSUSED */
181768318Scgd int
181868318Scgd compat_43_truncate(p, uap, retval)
181954863Storek 	struct proc *p;
182068318Scgd 	register struct compat_43_truncate_args /* {
182168318Scgd 		syscallarg(char *) path;
182268318Scgd 		syscallarg(long) length;
182368318Scgd 	} */ *uap;
182468318Scgd 	register_t *retval;
182554863Storek {
182668318Scgd 	struct truncate_args /* {
182768318Scgd 		syscallarg(char *) path;
182868318Scgd 		syscallarg(int) pad;
182968318Scgd 		syscallarg(off_t) length;
183068318Scgd 	} */ nuap;
183154863Storek 
183268318Scgd 	SCARG(&nuap, path) = SCARG(uap, path);
183368318Scgd 	SCARG(&nuap, length) = SCARG(uap, length);
183460428Smckusick 	return (truncate(p, &nuap, retval));
183554863Storek }
183654863Storek 
183754863Storek /*
183854863Storek  * Truncate a file given a file descriptor.
183954863Storek  */
184054863Storek /* ARGSUSED */
184168318Scgd int
184268318Scgd compat_43_ftruncate(p, uap, retval)
184354863Storek 	struct proc *p;
184468318Scgd 	register struct compat_43_ftruncate_args /* {
184568318Scgd 		syscallarg(int) fd;
184668318Scgd 		syscallarg(long) length;
184768318Scgd 	} */ *uap;
184868318Scgd 	register_t *retval;
184954863Storek {
185068318Scgd 	struct ftruncate_args /* {
185168318Scgd 		syscallarg(int) fd;
185268318Scgd 		syscallarg(int) pad;
185368318Scgd 		syscallarg(off_t) length;
185468318Scgd 	} */ nuap;
185554863Storek 
185668318Scgd 	SCARG(&nuap, fd) = SCARG(uap, fd);
185768318Scgd 	SCARG(&nuap, length) = SCARG(uap, length);
185860428Smckusick 	return (ftruncate(p, &nuap, retval));
185954863Storek }
186054863Storek #endif /* COMPAT_43 || COMPAT_SUNOS */
186154863Storek 
186254863Storek /*
186364410Sbostic  * Sync an open file.
18649167Ssam  */
186542441Smckusick /* ARGSUSED */
186668318Scgd int
186742441Smckusick fsync(p, uap, retval)
186845914Smckusick 	struct proc *p;
186968318Scgd 	struct fsync_args /* {
187068318Scgd 		syscallarg(int) fd;
187168318Scgd 	} */ *uap;
187268318Scgd 	register_t *retval;
18739167Ssam {
187439592Smckusick 	register struct vnode *vp;
18759167Ssam 	struct file *fp;
187637741Smckusick 	int error;
18779167Ssam 
187868318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
187947540Skarels 		return (error);
188039592Smckusick 	vp = (struct vnode *)fp->f_data;
188139592Smckusick 	VOP_LOCK(vp);
188254441Smckusick 	error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, p);
188339592Smckusick 	VOP_UNLOCK(vp);
188447540Skarels 	return (error);
18859167Ssam }
18869167Ssam 
18879167Ssam /*
188864410Sbostic  * Rename files.  Source and destination must either both be directories,
188964410Sbostic  * or both not be directories.  If target is a directory, it must be empty.
18909167Ssam  */
189142441Smckusick /* ARGSUSED */
189268318Scgd int
189342441Smckusick rename(p, uap, retval)
189445914Smckusick 	struct proc *p;
189568318Scgd 	register struct rename_args /* {
189668318Scgd 		syscallarg(char *) from;
189768318Scgd 		syscallarg(char *) to;
189868318Scgd 	} */ *uap;
189968318Scgd 	register_t *retval;
190042441Smckusick {
190137741Smckusick 	register struct vnode *tvp, *fvp, *tdvp;
190249735Smckusick 	struct nameidata fromnd, tond;
190337741Smckusick 	int error;
19047701Ssam 
190552322Smckusick 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
190668318Scgd 	    SCARG(uap, from), p);
190752322Smckusick 	if (error = namei(&fromnd))
190847540Skarels 		return (error);
190949735Smckusick 	fvp = fromnd.ni_vp;
191052322Smckusick 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
191168318Scgd 	    UIO_USERSPACE, SCARG(uap, to), p);
191252322Smckusick 	if (error = namei(&tond)) {
191352230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
191449735Smckusick 		vrele(fromnd.ni_dvp);
191542465Smckusick 		vrele(fvp);
191642465Smckusick 		goto out1;
191742465Smckusick 	}
191837741Smckusick 	tdvp = tond.ni_dvp;
191937741Smckusick 	tvp = tond.ni_vp;
192037741Smckusick 	if (tvp != NULL) {
192137741Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
192239242Sbostic 			error = ENOTDIR;
192337741Smckusick 			goto out;
192437741Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
192539242Sbostic 			error = EISDIR;
192637741Smckusick 			goto out;
19279167Ssam 		}
19289167Ssam 	}
192939286Smckusick 	if (fvp == tdvp)
193037741Smckusick 		error = EINVAL;
193139286Smckusick 	/*
193249735Smckusick 	 * If source is the same as the destination (that is the
193349735Smckusick 	 * same inode number with the same name in the same directory),
193439286Smckusick 	 * then there is nothing to do.
193539286Smckusick 	 */
193649735Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
193752322Smckusick 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
193852322Smckusick 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
193952322Smckusick 	      fromnd.ni_cnd.cn_namelen))
194039286Smckusick 		error = -1;
194137741Smckusick out:
194242465Smckusick 	if (!error) {
194367654Smckusick 		VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE);
194452192Smckusick 		if (fromnd.ni_dvp != tdvp)
194567654Smckusick 			VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
194652192Smckusick 		if (tvp)
194767654Smckusick 			VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE);
194852230Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
194952230Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
195042465Smckusick 	} else {
195152230Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
195243344Smckusick 		if (tdvp == tvp)
195343344Smckusick 			vrele(tdvp);
195443344Smckusick 		else
195543344Smckusick 			vput(tdvp);
195642465Smckusick 		if (tvp)
195742465Smckusick 			vput(tvp);
195852230Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
195949735Smckusick 		vrele(fromnd.ni_dvp);
196042465Smckusick 		vrele(fvp);
19619167Ssam 	}
196249735Smckusick 	vrele(tond.ni_startdir);
196352322Smckusick 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
196437741Smckusick out1:
196566801Smckusick 	if (fromnd.ni_startdir)
196666801Smckusick 		vrele(fromnd.ni_startdir);
196752322Smckusick 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
196839286Smckusick 	if (error == -1)
196947540Skarels 		return (0);
197047540Skarels 	return (error);
19717701Ssam }
19727701Ssam 
19737535Sroot /*
197464410Sbostic  * Make a directory file.
197512756Ssam  */
197642441Smckusick /* ARGSUSED */
197768318Scgd int
197842441Smckusick mkdir(p, uap, retval)
197945914Smckusick 	struct proc *p;
198068318Scgd 	register struct mkdir_args /* {
198168318Scgd 		syscallarg(char *) path;
198268318Scgd 		syscallarg(int) mode;
198368318Scgd 	} */ *uap;
198468318Scgd 	register_t *retval;
198542441Smckusick {
198637741Smckusick 	register struct vnode *vp;
198737741Smckusick 	struct vattr vattr;
198837741Smckusick 	int error;
198947540Skarels 	struct nameidata nd;
199012756Ssam 
199168318Scgd 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
199252322Smckusick 	if (error = namei(&nd))
199347540Skarels 		return (error);
199452322Smckusick 	vp = nd.ni_vp;
199537741Smckusick 	if (vp != NULL) {
199652322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
199752322Smckusick 		if (nd.ni_dvp == vp)
199852322Smckusick 			vrele(nd.ni_dvp);
199943344Smckusick 		else
200052322Smckusick 			vput(nd.ni_dvp);
200142465Smckusick 		vrele(vp);
200247540Skarels 		return (EEXIST);
200312756Ssam 	}
200441362Smckusick 	VATTR_NULL(&vattr);
200537741Smckusick 	vattr.va_type = VDIR;
200668318Scgd 	vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask;
200767654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
200852322Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
200938145Smckusick 	if (!error)
201052322Smckusick 		vput(nd.ni_vp);
201147540Skarels 	return (error);
201212756Ssam }
201312756Ssam 
201412756Ssam /*
201564410Sbostic  * Remove a directory file.
201612756Ssam  */
201742441Smckusick /* ARGSUSED */
201868318Scgd int
201942441Smckusick rmdir(p, uap, retval)
202045914Smckusick 	struct proc *p;
202168318Scgd 	struct rmdir_args /* {
202268318Scgd 		syscallarg(char *) path;
202368318Scgd 	} */ *uap;
202468318Scgd 	register_t *retval;
202512756Ssam {
202637741Smckusick 	register struct vnode *vp;
202737741Smckusick 	int error;
202847540Skarels 	struct nameidata nd;
202912756Ssam 
203068318Scgd 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
203168318Scgd 	    SCARG(uap, path), p);
203252322Smckusick 	if (error = namei(&nd))
203347540Skarels 		return (error);
203452322Smckusick 	vp = nd.ni_vp;
203537741Smckusick 	if (vp->v_type != VDIR) {
203637741Smckusick 		error = ENOTDIR;
203712756Ssam 		goto out;
203812756Ssam 	}
203912756Ssam 	/*
204037741Smckusick 	 * No rmdir "." please.
204112756Ssam 	 */
204252322Smckusick 	if (nd.ni_dvp == vp) {
204337741Smckusick 		error = EINVAL;
204412756Ssam 		goto out;
204512756Ssam 	}
204612756Ssam 	/*
204749365Smckusick 	 * The root of a mounted filesystem cannot be deleted.
204812756Ssam 	 */
204937741Smckusick 	if (vp->v_flag & VROOT)
205037741Smckusick 		error = EBUSY;
205112756Ssam out:
205242465Smckusick 	if (!error) {
205367654Smckusick 		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
205467654Smckusick 		VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
205552322Smckusick 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
205642465Smckusick 	} else {
205752322Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
205852322Smckusick 		if (nd.ni_dvp == vp)
205952322Smckusick 			vrele(nd.ni_dvp);
206043344Smckusick 		else
206152322Smckusick 			vput(nd.ni_dvp);
206242465Smckusick 		vput(vp);
206342465Smckusick 	}
206447540Skarels 	return (error);
206512756Ssam }
206612756Ssam 
206754620Smckusick #ifdef COMPAT_43
206837741Smckusick /*
206949365Smckusick  * Read a block of directory entries in a file system independent format.
207037741Smckusick  */
207168318Scgd int
207268318Scgd compat_43_getdirentries(p, uap, retval)
207354620Smckusick 	struct proc *p;
207468318Scgd 	register struct compat_43_getdirentries_args /* {
207568318Scgd 		syscallarg(int) fd;
207668318Scgd 		syscallarg(char *) buf;
207768318Scgd 		syscallarg(u_int) count;
207868318Scgd 		syscallarg(long *) basep;
207968318Scgd 	} */ *uap;
208068318Scgd 	register_t *retval;
208154620Smckusick {
208254620Smckusick 	register struct vnode *vp;
208354620Smckusick 	struct file *fp;
208454620Smckusick 	struct uio auio, kuio;
208554620Smckusick 	struct iovec aiov, kiov;
208654620Smckusick 	struct dirent *dp, *edp;
208754620Smckusick 	caddr_t dirbuf;
208867362Smckusick 	int error, eofflag, readcnt;
208954969Smckusick 	long loff;
209054620Smckusick 
209168318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
209254620Smckusick 		return (error);
209354620Smckusick 	if ((fp->f_flag & FREAD) == 0)
209454620Smckusick 		return (EBADF);
209554620Smckusick 	vp = (struct vnode *)fp->f_data;
209667362Smckusick unionread:
209754620Smckusick 	if (vp->v_type != VDIR)
209854620Smckusick 		return (EINVAL);
209968318Scgd 	aiov.iov_base = SCARG(uap, buf);
210068318Scgd 	aiov.iov_len = SCARG(uap, count);
210154620Smckusick 	auio.uio_iov = &aiov;
210254620Smckusick 	auio.uio_iovcnt = 1;
210354620Smckusick 	auio.uio_rw = UIO_READ;
210454620Smckusick 	auio.uio_segflg = UIO_USERSPACE;
210554620Smckusick 	auio.uio_procp = p;
210668318Scgd 	auio.uio_resid = SCARG(uap, count);
210754620Smckusick 	VOP_LOCK(vp);
210854969Smckusick 	loff = auio.uio_offset = fp->f_offset;
210954620Smckusick #	if (BYTE_ORDER != LITTLE_ENDIAN)
211056339Smckusick 		if (vp->v_mount->mnt_maxsymlinklen <= 0) {
211167362Smckusick 			error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
211268663Smckusick 			    (int *)0, (u_long *)0);
211356339Smckusick 			fp->f_offset = auio.uio_offset;
211456339Smckusick 		} else
211554620Smckusick #	endif
211654620Smckusick 	{
211754620Smckusick 		kuio = auio;
211854620Smckusick 		kuio.uio_iov = &kiov;
211954620Smckusick 		kuio.uio_segflg = UIO_SYSSPACE;
212068318Scgd 		kiov.iov_len = SCARG(uap, count);
212168318Scgd 		MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK);
212254620Smckusick 		kiov.iov_base = dirbuf;
212367362Smckusick 		error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
212468663Smckusick 			    (int *)0, (u_long *)0);
212556339Smckusick 		fp->f_offset = kuio.uio_offset;
212654620Smckusick 		if (error == 0) {
212768318Scgd 			readcnt = SCARG(uap, count) - kuio.uio_resid;
212854620Smckusick 			edp = (struct dirent *)&dirbuf[readcnt];
212954620Smckusick 			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
213054620Smckusick #				if (BYTE_ORDER == LITTLE_ENDIAN)
213154969Smckusick 					/*
213255009Smckusick 					 * The expected low byte of
213355009Smckusick 					 * dp->d_namlen is our dp->d_type.
213455009Smckusick 					 * The high MBZ byte of dp->d_namlen
213555009Smckusick 					 * is our dp->d_namlen.
213654969Smckusick 					 */
213755009Smckusick 					dp->d_type = dp->d_namlen;
213855009Smckusick 					dp->d_namlen = 0;
213955009Smckusick #				else
214055009Smckusick 					/*
214155009Smckusick 					 * The dp->d_type is the high byte
214255009Smckusick 					 * of the expected dp->d_namlen,
214355009Smckusick 					 * so must be zero'ed.
214455009Smckusick 					 */
214555009Smckusick 					dp->d_type = 0;
214654620Smckusick #				endif
214754620Smckusick 				if (dp->d_reclen > 0) {
214854620Smckusick 					dp = (struct dirent *)
214954620Smckusick 					    ((char *)dp + dp->d_reclen);
215054620Smckusick 				} else {
215154620Smckusick 					error = EIO;
215254620Smckusick 					break;
215354620Smckusick 				}
215454620Smckusick 			}
215554620Smckusick 			if (dp >= edp)
215654620Smckusick 				error = uiomove(dirbuf, readcnt, &auio);
215754620Smckusick 		}
215854620Smckusick 		FREE(dirbuf, M_TEMP);
215954620Smckusick 	}
216054620Smckusick 	VOP_UNLOCK(vp);
216154620Smckusick 	if (error)
216254620Smckusick 		return (error);
216367362Smckusick 
216467362Smckusick #ifdef UNION
216567362Smckusick {
216667362Smckusick 	extern int (**union_vnodeop_p)();
216768079Spendry 	extern struct vnode *union_dircache __P((struct vnode *));
216867362Smckusick 
216968318Scgd 	if ((SCARG(uap, count) == auio.uio_resid) &&
217067362Smckusick 	    (vp->v_op == union_vnodeop_p)) {
217167362Smckusick 		struct vnode *lvp;
217267362Smckusick 
217368079Spendry 		lvp = union_dircache(vp);
217467362Smckusick 		if (lvp != NULLVP) {
217567575Spendry 			struct vattr va;
217667575Spendry 
217767575Spendry 			/*
217867575Spendry 			 * If the directory is opaque,
217967575Spendry 			 * then don't show lower entries
218067575Spendry 			 */
218167575Spendry 			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
218267575Spendry 			if (va.va_flags & OPAQUE) {
218368079Spendry 				vput(lvp);
218467575Spendry 				lvp = NULL;
218567575Spendry 			}
218667575Spendry 		}
218767575Spendry 
218867575Spendry 		if (lvp != NULLVP) {
218967362Smckusick 			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
219067362Smckusick 			VOP_UNLOCK(lvp);
219167362Smckusick 
219267362Smckusick 			if (error) {
219367362Smckusick 				vrele(lvp);
219467362Smckusick 				return (error);
219567362Smckusick 			}
219667362Smckusick 			fp->f_data = (caddr_t) lvp;
219767362Smckusick 			fp->f_offset = 0;
219867362Smckusick 			error = vn_close(vp, FREAD, fp->f_cred, p);
219967362Smckusick 			if (error)
220067362Smckusick 				return (error);
220167362Smckusick 			vp = lvp;
220267362Smckusick 			goto unionread;
220367362Smckusick 		}
220467362Smckusick 	}
220567362Smckusick }
220667362Smckusick #endif /* UNION */
220767362Smckusick 
220868318Scgd 	if ((SCARG(uap, count) == auio.uio_resid) &&
220967362Smckusick 	    (vp->v_flag & VROOT) &&
221067362Smckusick 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
221167362Smckusick 		struct vnode *tvp = vp;
221267362Smckusick 		vp = vp->v_mount->mnt_vnodecovered;
221367362Smckusick 		VREF(vp);
221467362Smckusick 		fp->f_data = (caddr_t) vp;
221567362Smckusick 		fp->f_offset = 0;
221667362Smckusick 		vrele(tvp);
221767362Smckusick 		goto unionread;
221867362Smckusick 	}
221968318Scgd 	error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
222068318Scgd 	    sizeof(long));
222168318Scgd 	*retval = SCARG(uap, count) - auio.uio_resid;
222254620Smckusick 	return (error);
222354620Smckusick }
222467362Smckusick #endif /* COMPAT_43 */
222554620Smckusick 
222654620Smckusick /*
222754620Smckusick  * Read a block of directory entries in a file system independent format.
222854620Smckusick  */
222968318Scgd int
223042441Smckusick getdirentries(p, uap, retval)
223145914Smckusick 	struct proc *p;
223268318Scgd 	register struct getdirentries_args /* {
223368318Scgd 		syscallarg(int) fd;
223468318Scgd 		syscallarg(char *) buf;
223568318Scgd 		syscallarg(u_int) count;
223668318Scgd 		syscallarg(long *) basep;
223768318Scgd 	} */ *uap;
223868318Scgd 	register_t *retval;
223942441Smckusick {
224039592Smckusick 	register struct vnode *vp;
224116540Ssam 	struct file *fp;
224237741Smckusick 	struct uio auio;
224337741Smckusick 	struct iovec aiov;
224454969Smckusick 	long loff;
224567362Smckusick 	int error, eofflag;
224612756Ssam 
224768318Scgd 	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
224847540Skarels 		return (error);
224937741Smckusick 	if ((fp->f_flag & FREAD) == 0)
225047540Skarels 		return (EBADF);
225139592Smckusick 	vp = (struct vnode *)fp->f_data;
225255451Spendry unionread:
225339592Smckusick 	if (vp->v_type != VDIR)
225447540Skarels 		return (EINVAL);
225568318Scgd 	aiov.iov_base = SCARG(uap, buf);
225668318Scgd 	aiov.iov_len = SCARG(uap, count);
225737741Smckusick 	auio.uio_iov = &aiov;
225837741Smckusick 	auio.uio_iovcnt = 1;
225937741Smckusick 	auio.uio_rw = UIO_READ;
226037741Smckusick 	auio.uio_segflg = UIO_USERSPACE;
226148026Smckusick 	auio.uio_procp = p;
226268318Scgd 	auio.uio_resid = SCARG(uap, count);
226339592Smckusick 	VOP_LOCK(vp);
226454969Smckusick 	loff = auio.uio_offset = fp->f_offset;
226568663Smckusick 	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
226668663Smckusick 			    (int *)0, (u_long *)0);
226739592Smckusick 	fp->f_offset = auio.uio_offset;
226839592Smckusick 	VOP_UNLOCK(vp);
226939592Smckusick 	if (error)
227047540Skarels 		return (error);
227166095Spendry 
227266095Spendry #ifdef UNION
227366095Spendry {
227466095Spendry 	extern int (**union_vnodeop_p)();
227568079Spendry 	extern struct vnode *union_dircache __P((struct vnode *));
227666095Spendry 
227768318Scgd 	if ((SCARG(uap, count) == auio.uio_resid) &&
227866095Spendry 	    (vp->v_op == union_vnodeop_p)) {
227967122Spendry 		struct vnode *lvp;
228066095Spendry 
228168079Spendry 		lvp = union_dircache(vp);
228267122Spendry 		if (lvp != NULLVP) {
228367575Spendry 			struct vattr va;
228467575Spendry 
228567575Spendry 			/*
228667575Spendry 			 * If the directory is opaque,
228767575Spendry 			 * then don't show lower entries
228867575Spendry 			 */
228967575Spendry 			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
229067575Spendry 			if (va.va_flags & OPAQUE) {
229168079Spendry 				vput(lvp);
229267575Spendry 				lvp = NULL;
229367575Spendry 			}
229467575Spendry 		}
229567575Spendry 
229667575Spendry 		if (lvp != NULLVP) {
229767362Smckusick 			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
229867122Spendry 			VOP_UNLOCK(lvp);
229966095Spendry 
230066095Spendry 			if (error) {
230167122Spendry 				vrele(lvp);
230266095Spendry 				return (error);
230366095Spendry 			}
230467122Spendry 			fp->f_data = (caddr_t) lvp;
230566095Spendry 			fp->f_offset = 0;
230667122Spendry 			error = vn_close(vp, FREAD, fp->f_cred, p);
230766095Spendry 			if (error)
230866095Spendry 				return (error);
230967122Spendry 			vp = lvp;
231066095Spendry 			goto unionread;
231166095Spendry 		}
231266095Spendry 	}
231366095Spendry }
231468318Scgd #endif /* UNION */
231566095Spendry 
231668318Scgd 	if ((SCARG(uap, count) == auio.uio_resid) &&
231755451Spendry 	    (vp->v_flag & VROOT) &&
231855451Spendry 	    (vp->v_mount->mnt_flag & MNT_UNION)) {
231955451Spendry 		struct vnode *tvp = vp;
232055451Spendry 		vp = vp->v_mount->mnt_vnodecovered;
232155451Spendry 		VREF(vp);
232255451Spendry 		fp->f_data = (caddr_t) vp;
232355451Spendry 		fp->f_offset = 0;
232455451Spendry 		vrele(tvp);
232555451Spendry 		goto unionread;
232655451Spendry 	}
232768318Scgd 	error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
232868318Scgd 	    sizeof(long));
232968318Scgd 	*retval = SCARG(uap, count) - auio.uio_resid;
233047540Skarels 	return (error);
233112756Ssam }
233212756Ssam 
233312756Ssam /*
233449365Smckusick  * Set the mode mask for creation of filesystem nodes.
233512756Ssam  */
233668318Scgd int
233742441Smckusick umask(p, uap, retval)
233845914Smckusick 	struct proc *p;
233968318Scgd 	struct umask_args /* {
234068318Scgd 		syscallarg(int) newmask;
234168318Scgd 	} */ *uap;
234268318Scgd 	register_t *retval;
234312756Ssam {
234464410Sbostic 	register struct filedesc *fdp;
234512756Ssam 
234664410Sbostic 	fdp = p->p_fd;
234745914Smckusick 	*retval = fdp->fd_cmask;
234868318Scgd 	fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS;
234947540Skarels 	return (0);
235012756Ssam }
235137741Smckusick 
235239566Smarc /*
235339566Smarc  * Void all references to file by ripping underlying filesystem
235439566Smarc  * away from vnode.
235539566Smarc  */
235642441Smckusick /* ARGSUSED */
235768318Scgd int
235842441Smckusick revoke(p, uap, retval)
235945914Smckusick 	struct proc *p;
236068318Scgd 	register struct revoke_args /* {
236168318Scgd 		syscallarg(char *) path;
236268318Scgd 	} */ *uap;
236368318Scgd 	register_t *retval;
236442441Smckusick {
236539566Smarc 	register struct vnode *vp;
236639566Smarc 	struct vattr vattr;
236739566Smarc 	int error;
236847540Skarels 	struct nameidata nd;
236939566Smarc 
237068318Scgd 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
237152322Smckusick 	if (error = namei(&nd))
237247540Skarels 		return (error);
237352322Smckusick 	vp = nd.ni_vp;
237448026Smckusick 	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
237539566Smarc 		goto out;
237647540Skarels 	if (p->p_ucred->cr_uid != vattr.va_uid &&
237747540Skarels 	    (error = suser(p->p_ucred, &p->p_acflag)))
237839566Smarc 		goto out;
237939805Smckusick 	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
238068423Smckusick 		VOP_REVOKE(vp, REVOKEALL);
238139566Smarc out:
238239566Smarc 	vrele(vp);
238347540Skarels 	return (error);
238439566Smarc }
238539566Smarc 
238649365Smckusick /*
238749365Smckusick  * Convert a user file descriptor to a kernel file entry.
238849365Smckusick  */
238968318Scgd int
239064410Sbostic getvnode(fdp, fd, fpp)
239145914Smckusick 	struct filedesc *fdp;
239237741Smckusick 	struct file **fpp;
239364410Sbostic 	int fd;
239437741Smckusick {
239537741Smckusick 	struct file *fp;
239637741Smckusick 
239764410Sbostic 	if ((u_int)fd >= fdp->fd_nfiles ||
239864410Sbostic 	    (fp = fdp->fd_ofiles[fd]) == NULL)
239937741Smckusick 		return (EBADF);
240037741Smckusick 	if (fp->f_type != DTYPE_VNODE)
240137741Smckusick 		return (EINVAL);
240237741Smckusick 	*fpp = fp;
240337741Smckusick 	return (0);
240437741Smckusick }
2405