vfs_syscalls.c revision 35275
1167514Skmacy/*
2167514Skmacy * Copyright (c) 1989, 1993
3167514Skmacy *	The Regents of the University of California.  All rights reserved.
4167514Skmacy * (c) UNIX System Laboratories, Inc.
5167514Skmacy * All or some portions of this file are derived from material licensed
6167514Skmacy * to the University of California by American Telephone and Telegraph
7167514Skmacy * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8167514Skmacy * the permission of UNIX System Laboratories, Inc.
9167514Skmacy *
10167514Skmacy * Redistribution and use in source and binary forms, with or without
11167514Skmacy * modification, are permitted provided that the following conditions
12169978Skmacy * are met:
13167514Skmacy * 1. Redistributions of source code must retain the above copyright
14167514Skmacy *    notice, this list of conditions and the following disclaimer.
15167514Skmacy * 2. Redistributions in binary form must reproduce the above copyright
16167514Skmacy *    notice, this list of conditions and the following disclaimer in the
17167514Skmacy *    documentation and/or other materials provided with the distribution.
18167514Skmacy * 3. All advertising materials mentioning features or use of this software
19167514Skmacy *    must display the following acknowledgement:
20167514Skmacy *	This product includes software developed by the University of
21167514Skmacy *	California, Berkeley and its contributors.
22167514Skmacy * 4. Neither the name of the University nor the names of its contributors
23167514Skmacy *    may be used to endorse or promote products derived from this software
24167514Skmacy *    without specific prior written permission.
25167514Skmacy *
26167514Skmacy * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27167514Skmacy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28167514Skmacy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29167514Skmacy * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30167514Skmacy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31167514Skmacy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32167514Skmacy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33167514Skmacy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34167514Skmacy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35167514Skmacy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36167514Skmacy * SUCH DAMAGE.
37167514Skmacy *
38167514Skmacy *	@(#)vfs_syscalls.c	8.13 (Berkeley) 4/15/94
39174708Skmacy * $Id: vfs_syscalls.c,v 1.97 1998/04/08 18:31:57 wosch Exp $
40174708Skmacy */
41174708Skmacy
42167514Skmacy/* For 4.3 integer FS ID compatibility */
43167514Skmacy#include "opt_compat.h"
44171471Skmacy
45171471Skmacy/*
46171471Skmacy * XXX - The following is required because of some magic done
47171471Skmacy * in getdirentries() below which is only done if the translucent
48167514Skmacy * filesystem `UNION' is compiled into the kernel.  This is broken,
49167526Skmacy * but I don't have time to study the code deeply enough to understand
50171471Skmacy * what's going on and determine an appropriate fix.  -GAW
51167514Skmacy */
52167514Skmacy#include "opt_union.h"
53167514Skmacy
54167514Skmacy#include <sys/param.h>
55167514Skmacy#include <sys/systm.h>
56167514Skmacy#include <sys/sysent.h>
57167514Skmacy#include <sys/sysproto.h>
58180583Skmacy#include <sys/namei.h>
59180583Skmacy#include <sys/filedesc.h>
60180583Skmacy#include <sys/kernel.h>
61180583Skmacy#include <sys/fcntl.h>
62180583Skmacy#include <sys/file.h>
63180583Skmacy#include <sys/stat.h>
64174708Skmacy#include <sys/unistd.h>
65172101Skmacy#include <sys/vnode.h>
66172101Skmacy#include <sys/malloc.h>
67172101Skmacy#include <sys/mount.h>
68172101Skmacy#include <sys/proc.h>
69172101Skmacy#include <sys/dirent.h>
70178800Skmacy
71169978Skmacy#ifdef UNION
72169978Skmacy#include <miscfs/union/union.h>
73174626Skmacy#endif
74169978Skmacy
75178800Skmacy#include <vm/vm.h>
76169978Skmacy#include <vm/vm_object.h>
77169978Skmacy#include <vm/vm_extern.h>
78170038Skmacy#include <vm/vm_zone.h>
79174638Skmacy#include <sys/sysctl.h>
80174638Skmacy
81174638Skmacystatic int change_dir __P((struct nameidata *ndp, struct proc *p));
82174638Skmacystatic void checkdirs __P((struct vnode *olddp));
83169978Skmacy
84174638Skmacystatic int	usermount = 0;	/* if 1, non-root can mount fs. */
85174638Skmacy
86174638SkmacySYSCTL_INT(_vfs, OID_AUTO, usermount, CTLFLAG_RW, &usermount, 0, "");
87174638Skmacy
88174638Skmacy/*
89174638Skmacy * Virtual File System System Calls
90174638Skmacy */
91174638Skmacy
92174638Skmacy/*
93174638Skmacy * Mount a file system.
94176472Skmacy */
95176472Skmacy#ifndef _SYS_SYSPROTO_H_
96176472Skmacystruct mount_args {
97174638Skmacy	char	*type;
98174638Skmacy	char	*path;
99167514Skmacy	int	flags;
100167514Skmacy	caddr_t	data;
101167514Skmacy};
102167514Skmacy#endif
103167514Skmacy/* ARGSUSED */
104167514Skmacyint
105167514Skmacymount(p, uap)
106167514Skmacy	struct proc *p;
107167514Skmacy	register struct mount_args /* {
108167514Skmacy		syscallarg(char *) type;
109167514Skmacy		syscallarg(char *) path;
110167514Skmacy		syscallarg(int) flags;
111167514Skmacy		syscallarg(caddr_t) data;
112167514Skmacy	} */ *uap;
113172109Skmacy{
114172109Skmacy	struct vnode *vp;
115172109Skmacy	struct mount *mp;
116167514Skmacy	struct vfsconf *vfsp;
117167514Skmacy	int error, flag = 0, flag2 = 0;
118169978Skmacy	struct vattr va;
119169978Skmacy	u_long fstypenum;
120167514Skmacy	struct nameidata nd;
121167514Skmacy	char fstypename[MFSNAMELEN];
122167514Skmacy
123167514Skmacy	if (usermount == 0 && (error = suser(p->p_ucred, &p->p_acflag)))
124167514Skmacy		return (error);
125167514Skmacy
126167514Skmacy	/*
127169978Skmacy	 * Get vnode to be covered
128167514Skmacy	 */
129174708Skmacy	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
130167514Skmacy	    SCARG(uap, path), p);
131167514Skmacy	if (error = namei(&nd))
132167514Skmacy		return (error);
133167514Skmacy	vp = nd.ni_vp;
134167514Skmacy	if (SCARG(uap, flags) & MNT_UPDATE) {
135167514Skmacy		if ((vp->v_flag & VROOT) == 0) {
136167514Skmacy			vput(vp);
137167514Skmacy			return (EINVAL);
138174708Skmacy		}
139167514Skmacy		mp = vp->v_mount;
140171471Skmacy		flag = mp->mnt_flag;
141174708Skmacy		flag2 = mp->mnt_kern_flag;
142171471Skmacy		/*
143171469Skmacy		 * We only allow the filesystem to be reloaded if it
144167514Skmacy		 * is currently mounted read-only.
145171471Skmacy		 */
146170038Skmacy		if ((SCARG(uap, flags) & MNT_RELOAD) &&
147167514Skmacy		    ((mp->mnt_flag & MNT_RDONLY) == 0)) {
148174708Skmacy			vput(vp);
149174708Skmacy			return (EOPNOTSUPP);	/* Needs translation */
150174708Skmacy		}
151174708Skmacy		mp->mnt_flag |=
152174708Skmacy		    SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
153174708Skmacy		/*
154167514Skmacy		 * Only root, or the user that did the original mount is
155167514Skmacy		 * permitted to update it.
156167514Skmacy		 */
157167514Skmacy		if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid &&
158167514Skmacy		    (error = suser(p->p_ucred, &p->p_acflag))) {
159167514Skmacy			vput(vp);
160167514Skmacy			return (error);
161167526Skmacy		}
162174708Skmacy		/*
163167526Skmacy		 * Do not allow NFS export by non-root users. Silently
164167526Skmacy		 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
165167526Skmacy		 */
166167526Skmacy		if (p->p_ucred->cr_uid != 0) {
167167526Skmacy			if (SCARG(uap, flags) & MNT_EXPORTED) {
168167560Skmacy				vput(vp);
169169978Skmacy				return (EPERM);
170169978Skmacy			}
171169978Skmacy			SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
172183063Skmacy		}
173169978Skmacy		if (vfs_busy(mp, LK_NOWAIT, 0, p)) {
174169978Skmacy			vput(vp);
175169978Skmacy			return (EBUSY);
176169978Skmacy		}
177169978Skmacy		VOP_UNLOCK(vp, 0, p);
178169978Skmacy		goto update;
179167528Skmacy	}
180167528Skmacy	/*
181167528Skmacy	 * If the user is not root, ensure that they own the directory
182167528Skmacy	 * onto which we are attempting to mount.
183167528Skmacy	 */
184167560Skmacy	if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) ||
185167561Skmacy	    (va.va_uid != p->p_ucred->cr_uid &&
186167526Skmacy	     (error = suser(p->p_ucred, &p->p_acflag)))) {
187174708Skmacy		vput(vp);
188174708Skmacy		return (error);
189174708Skmacy	}
190174708Skmacy	/*
191174708Skmacy	 * Do not allow NFS export by non-root users. Silently
192174708Skmacy	 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
193174708Skmacy	 */
194174708Skmacy	if (p->p_ucred->cr_uid != 0) {
195174708Skmacy		if (SCARG(uap, flags) & MNT_EXPORTED) {
196174708Skmacy			vput(vp);
197174708Skmacy			return (EPERM);
198174708Skmacy		}
199174708Skmacy		SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
200174708Skmacy	}
201174708Skmacy	if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0))
202174708Skmacy		return (error);
203175311Skmacy	if (vp->v_type != VDIR) {
204174708Skmacy		vput(vp);
205174708Skmacy		return (ENOTDIR);
206174708Skmacy	}
207174708Skmacy#ifdef COMPAT_43
208174708Skmacy	/*
209174708Skmacy	 * Historically filesystem types were identified by number. If we
210174708Skmacy	 * get an integer for the filesystem type instead of a string, we
211174708Skmacy	 * check to see if it matches one of the historic filesystem types.
212174708Skmacy	 */
213174708Skmacy	fstypenum = (u_long)SCARG(uap, type);
214175304Skmacy	if (fstypenum < maxvfsconf) {
215175304Skmacy		for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
216175304Skmacy			if (vfsp->vfc_typenum == fstypenum)
217175311Skmacy				break;
218175311Skmacy		if (vfsp == NULL) {
219175311Skmacy			vput(vp);
220175311Skmacy			return (ENODEV);
221175304Skmacy		}
222175304Skmacy		strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN);
223174708Skmacy	} else
224174708Skmacy#endif /* COMPAT_43 */
225174708Skmacy	if (error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL)) {
226174708Skmacy		vput(vp);
227174708Skmacy		return (error);
228174708Skmacy	}
229174708Skmacy	for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
230174708Skmacy		if (!strcmp(vfsp->vfc_name, fstypename))
231175311Skmacy			break;
232174708Skmacy	if (vfsp == NULL) {
233174708Skmacy		vput(vp);
234174708Skmacy		return (ENODEV);
235174708Skmacy	}
236174708Skmacy	if (vp->v_mountedhere != NULL) {
237175304Skmacy		vput(vp);
238174708Skmacy		return (EBUSY);
239174708Skmacy	}
240174708Skmacy
241174708Skmacy	/*
242175311Skmacy	 * Allocate and initialize the filesystem.
243174708Skmacy	 */
244174708Skmacy	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
245174708Skmacy		M_MOUNT, M_WAITOK);
246174708Skmacy	bzero((char *)mp, (u_long)sizeof(struct mount));
247174708Skmacy	lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, LK_NOPAUSE);
248174708Skmacy	(void)vfs_busy(mp, LK_NOWAIT, 0, p);
249175311Skmacy	mp->mnt_op = vfsp->vfc_vfsops;
250175311Skmacy	mp->mnt_vfc = vfsp;
251175311Skmacy	vfsp->vfc_refcount++;
252175311Skmacy	mp->mnt_stat.f_type = vfsp->vfc_typenum;
253175311Skmacy	mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
254174708Skmacy	strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
255175311Skmacy	vp->v_mountedhere = mp;
256175311Skmacy	mp->mnt_vnodecovered = vp;
257175311Skmacy	mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
258175311Skmacyupdate:
259175311Skmacy	/*
260175311Skmacy	 * Set the mount level flags.
261175311Skmacy	 */
262175311Skmacy	if (SCARG(uap, flags) & MNT_RDONLY)
263175311Skmacy		mp->mnt_flag |= MNT_RDONLY;
264175311Skmacy	else if (mp->mnt_flag & MNT_RDONLY)
265175311Skmacy		mp->mnt_kern_flag |= MNTK_WANTRDWR;
266175311Skmacy	mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
267175311Skmacy	    MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOATIME |
268175311Skmacy	    MNT_NOSYMFOLLOW |
269175311Skmacy	    MNT_NOCLUSTERR | MNT_NOCLUSTERW | MNT_SUIDDIR);
270175311Skmacy	mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC |
271175311Skmacy	    MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_FORCE |
272175311Skmacy	    MNT_NOSYMFOLLOW |
273175311Skmacy	    MNT_NOATIME | MNT_NOCLUSTERR | MNT_NOCLUSTERW | MNT_SUIDDIR);
274175311Skmacy	/*
275175311Skmacy	 * Mount the filesystem.
276175311Skmacy	 */
277175311Skmacy	error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p);
278175311Skmacy	if (mp->mnt_flag & MNT_UPDATE) {
279175311Skmacy		vrele(vp);
280175311Skmacy		if (mp->mnt_kern_flag & MNTK_WANTRDWR)
281174708Skmacy			mp->mnt_flag &= ~MNT_RDONLY;
282175311Skmacy		mp->mnt_flag &=~ (MNT_UPDATE | MNT_RELOAD | MNT_FORCE);
283174708Skmacy		mp->mnt_kern_flag &=~ MNTK_WANTRDWR;
284174708Skmacy		if (error) {
285175311Skmacy			mp->mnt_flag = flag;
286175311Skmacy			mp->mnt_kern_flag = flag2;
287174708Skmacy		}
288175304Skmacy		if ((mp->mnt_flag & MNT_RDONLY) == 0) {
289175304Skmacy			if (mp->mnt_syncer == NULL)
290175304Skmacy				error = vfs_allocate_syncvnode(mp);
291174708Skmacy		} else {
292175311Skmacy			if (mp->mnt_syncer != NULL)
293174708Skmacy				vrele(mp->mnt_syncer);
294175311Skmacy			mp->mnt_syncer = NULL;
295174708Skmacy		}
296174708Skmacy		vfs_unbusy(mp, p);
297174708Skmacy		return (error);
298174708Skmacy	}
299174708Skmacy	/*
300174708Skmacy	 * Put the new filesystem on the mount list after root.
301174708Skmacy	 */
302174708Skmacy	cache_purge(vp);
303174708Skmacy	if (!error) {
304174708Skmacy		simple_lock(&mountlist_slock);
305174708Skmacy		CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
306175311Skmacy		simple_unlock(&mountlist_slock);
307174708Skmacy		checkdirs(vp);
308174708Skmacy		VOP_UNLOCK(vp, 0, p);
309174708Skmacy		if ((mp->mnt_flag & MNT_RDONLY) == 0)
310174708Skmacy			error = vfs_allocate_syncvnode(mp);
311175311Skmacy		vfs_unbusy(mp, p);
312174708Skmacy		if (error = VFS_START(mp, 0, p))
313174708Skmacy			vrele(vp);
314174708Skmacy	} else {
315174708Skmacy		mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
316174708Skmacy		mp->mnt_vfc->vfc_refcount--;
317175311Skmacy		vfs_unbusy(mp, p);
318175311Skmacy		free((caddr_t)mp, M_MOUNT);
319175311Skmacy		vput(vp);
320174708Skmacy	}
321174708Skmacy	return (error);
322174708Skmacy}
323174708Skmacy
324174708Skmacy/*
325174708Skmacy * Scan all active processes to see if any of them have a current
326174708Skmacy * or root directory onto which the new filesystem has just been
327174708Skmacy * mounted. If so, replace them with the new mount point.
328174708Skmacy */
329174708Skmacystatic void
330174708Skmacycheckdirs(olddp)
331174708Skmacy	struct vnode *olddp;
332174708Skmacy{
333174708Skmacy	struct filedesc *fdp;
334174708Skmacy	struct vnode *newdp;
335174708Skmacy	struct proc *p;
336174708Skmacy
337167514Skmacy	if (olddp->v_usecount == 1)
338167514Skmacy		return;
339167514Skmacy	if (VFS_ROOT(olddp->v_mountedhere, &newdp))
340167514Skmacy		panic("mount: lost mount");
341167514Skmacy	for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
342167514Skmacy		fdp = p->p_fd;
343167514Skmacy		if (fdp->fd_cdir == olddp) {
344167514Skmacy			vrele(fdp->fd_cdir);
345167514Skmacy			VREF(newdp);
346167514Skmacy			fdp->fd_cdir = newdp;
347167514Skmacy		}
348167514Skmacy		if (fdp->fd_rdir == olddp) {
349176472Skmacy			vrele(fdp->fd_rdir);
350176472Skmacy			VREF(newdp);
351167514Skmacy			fdp->fd_rdir = newdp;
352167514Skmacy		}
353167514Skmacy	}
354176472Skmacy	if (rootvnode == olddp) {
355176472Skmacy		vrele(rootvnode);
356176472Skmacy		VREF(newdp);
357167514Skmacy		rootvnode = newdp;
358167514Skmacy	}
359167514Skmacy	vput(newdp);
360174708Skmacy}
361169978Skmacy
362167746Skmacy/*
363169978Skmacy * Unmount a file system.
364171471Skmacy *
365167746Skmacy * Note: unmount takes a path to the vnode mounted on as argument,
366167514Skmacy * not special file (as before).
367167514Skmacy */
368167514Skmacy#ifndef _SYS_SYSPROTO_H_
369167514Skmacystruct unmount_args {
370167514Skmacy	char	*path;
371167514Skmacy	int	flags;
372167514Skmacy};
373167514Skmacy#endif
374167514Skmacy/* ARGSUSED */
375167514Skmacyint
376167514Skmacyunmount(p, uap)
377167514Skmacy	struct proc *p;
378167514Skmacy	register struct unmount_args /* {
379167514Skmacy		syscallarg(char *) path;
380167514Skmacy		syscallarg(int) flags;
381167514Skmacy	} */ *uap;
382176472Skmacy{
383176472Skmacy	register struct vnode *vp;
384167514Skmacy	struct mount *mp;
385167514Skmacy	int error;
386167514Skmacy	struct nameidata nd;
387167514Skmacy
388167514Skmacy	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
389167514Skmacy	    SCARG(uap, path), p);
390167514Skmacy	if (error = namei(&nd))
391176472Skmacy		return (error);
392176472Skmacy	vp = nd.ni_vp;
393176472Skmacy	mp = vp->v_mount;
394176472Skmacy
395176472Skmacy	/*
396176472Skmacy	 * Only root, or the user that did the original mount is
397180583Skmacy	 * permitted to unmount this filesystem.
398180583Skmacy	 */
399176472Skmacy	if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) &&
400180583Skmacy	    (error = suser(p->p_ucred, &p->p_acflag))) {
401167514Skmacy		vput(vp);
402167514Skmacy		return (error);
403167514Skmacy	}
404167514Skmacy
405167514Skmacy	/*
406167514Skmacy	 * Don't allow unmounting the root file system.
407167514Skmacy	 */
408167514Skmacy	if (mp->mnt_flag & MNT_ROOTFS) {
409167514Skmacy		vput(vp);
410167514Skmacy		return (EINVAL);
411167514Skmacy	}
412167514Skmacy
413167514Skmacy	/*
414167514Skmacy	 * Must be the root of the filesystem
415167514Skmacy	 */
416167514Skmacy	if ((vp->v_flag & VROOT) == 0) {
417167514Skmacy		vput(vp);
418167514Skmacy		return (EINVAL);
419167514Skmacy	}
420167514Skmacy	vput(vp);
421167514Skmacy	return (dounmount(mp, SCARG(uap, flags), p));
422176472Skmacy}
423167514Skmacy
424167514Skmacy/*
425167514Skmacy * Do the actual file system unmount.
426167514Skmacy */
427174708Skmacyint
428176472Skmacydounmount(mp, flags, p)
429176472Skmacy	register struct mount *mp;
430176472Skmacy	int flags;
431176472Skmacy	struct proc *p;
432176472Skmacy{
433174708Skmacy	struct vnode *coveredvp;
434176472Skmacy	int error;
435176472Skmacy
436176472Skmacy	simple_lock(&mountlist_slock);
437176472Skmacy	mp->mnt_kern_flag |= MNTK_UNMOUNT;
438176472Skmacy	lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock, p);
439176472Skmacy
440176472Skmacy	if (mp->mnt_flag & MNT_EXPUBLIC)
441176472Skmacy		vfs_setpublicfs(NULL, NULL, NULL);
442167514Skmacy
443174708Skmacy	vfs_msync(mp, MNT_WAIT);
444167514Skmacy	mp->mnt_flag &=~ MNT_ASYNC;
445167514Skmacy	cache_purgevfs(mp);	/* remove cache entries for this file sys */
446167514Skmacy	if (mp->mnt_syncer != NULL)
447167514Skmacy		vrele(mp->mnt_syncer);
448167514Skmacy	if (((mp->mnt_flag & MNT_RDONLY) ||
449167514Skmacy	     (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) ||
450167514Skmacy	    (flags & MNT_FORCE))
451167514Skmacy		error = VFS_UNMOUNT(mp, flags, p);
452167514Skmacy	simple_lock(&mountlist_slock);
453167514Skmacy	if (error) {
454167514Skmacy		if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL)
455167514Skmacy			(void) vfs_allocate_syncvnode(mp);
456167514Skmacy		mp->mnt_kern_flag &= ~MNTK_UNMOUNT;
457167514Skmacy		lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE,
458167514Skmacy		    &mountlist_slock, p);
459167514Skmacy		return (error);
460167514Skmacy	}
461167514Skmacy	CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);
462167514Skmacy	if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {
463167514Skmacy		coveredvp->v_mountedhere = (struct mount *)0;
464167514Skmacy		vrele(coveredvp);
465167514Skmacy	}
466167514Skmacy	mp->mnt_vfc->vfc_refcount--;
467167514Skmacy	if (mp->mnt_vnodelist.lh_first != NULL)
468167514Skmacy		panic("unmount: dangling vnode");
469167514Skmacy	lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock, p);
470167514Skmacy	if (mp->mnt_kern_flag & MNTK_MWAIT)
471167514Skmacy		wakeup((caddr_t)mp);
472167514Skmacy	free((caddr_t)mp, M_MOUNT);
473167514Skmacy	return (0);
474167514Skmacy}
475167514Skmacy
476167514Skmacy/*
477167514Skmacy * Sync each mounted filesystem.
478167514Skmacy */
479167514Skmacy#ifndef _SYS_SYSPROTO_H_
480167514Skmacystruct sync_args {
481167514Skmacy        int     dummy;
482167514Skmacy};
483167514Skmacy#endif
484167514Skmacy
485167514Skmacy#ifdef DEBUG
486167514Skmacystatic int syncprt = 0;
487167514SkmacySYSCTL_INT(_debug, OID_AUTO, syncprt, CTLFLAG_RW, &syncprt, 0, "");
488167514Skmacy#endif
489167514Skmacy
490167514Skmacy/* ARGSUSED */
491167514Skmacyint
492167514Skmacysync(p, uap)
493167514Skmacy	struct proc *p;
494167514Skmacy	struct sync_args *uap;
495167514Skmacy{
496167514Skmacy	register struct mount *mp, *nmp;
497167514Skmacy	int asyncflag;
498167514Skmacy
499167514Skmacy	simple_lock(&mountlist_slock);
500	for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
501		if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
502			nmp = mp->mnt_list.cqe_next;
503			continue;
504		}
505		if ((mp->mnt_flag & MNT_RDONLY) == 0) {
506			asyncflag = mp->mnt_flag & MNT_ASYNC;
507			mp->mnt_flag &= ~MNT_ASYNC;
508			vfs_msync(mp, MNT_NOWAIT);
509			VFS_SYNC(mp, MNT_NOWAIT,
510				((p != NULL) ? p->p_ucred : NOCRED), p);
511			mp->mnt_flag |= asyncflag;
512		}
513		simple_lock(&mountlist_slock);
514		nmp = mp->mnt_list.cqe_next;
515		vfs_unbusy(mp, p);
516	}
517	simple_unlock(&mountlist_slock);
518#if 0
519/*
520 * XXX don't call vfs_bufstats() yet because that routine
521 * was not imported in the Lite2 merge.
522 */
523#ifdef DIAGNOSTIC
524	if (syncprt)
525		vfs_bufstats();
526#endif /* DIAGNOSTIC */
527#endif
528	return (0);
529}
530
531/*
532 * Change filesystem quotas.
533 */
534#ifndef _SYS_SYSPROTO_H_
535struct quotactl_args {
536	char *path;
537	int cmd;
538	int uid;
539	caddr_t arg;
540};
541#endif
542/* ARGSUSED */
543int
544quotactl(p, uap)
545	struct proc *p;
546	register struct quotactl_args /* {
547		syscallarg(char *) path;
548		syscallarg(int) cmd;
549		syscallarg(int) uid;
550		syscallarg(caddr_t) arg;
551	} */ *uap;
552{
553	register struct mount *mp;
554	int error;
555	struct nameidata nd;
556
557	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
558	if (error = namei(&nd))
559		return (error);
560	mp = nd.ni_vp->v_mount;
561	vrele(nd.ni_vp);
562	return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
563	    SCARG(uap, arg), p));
564}
565
566/*
567 * Get filesystem statistics.
568 */
569#ifndef _SYS_SYSPROTO_H_
570struct statfs_args {
571	char *path;
572	struct statfs *buf;
573};
574#endif
575/* ARGSUSED */
576int
577statfs(p, uap)
578	struct proc *p;
579	register struct statfs_args /* {
580		syscallarg(char *) path;
581		syscallarg(struct statfs *) buf;
582	} */ *uap;
583{
584	register struct mount *mp;
585	register struct statfs *sp;
586	int error;
587	struct nameidata nd;
588	struct statfs sb;
589
590	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
591	if (error = namei(&nd))
592		return (error);
593	mp = nd.ni_vp->v_mount;
594	sp = &mp->mnt_stat;
595	vrele(nd.ni_vp);
596	error = VFS_STATFS(mp, sp, p);
597	if (error)
598		return (error);
599	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
600	if (p->p_ucred->cr_uid != 0) {
601		bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
602		sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
603		sp = &sb;
604	}
605	return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
606}
607
608/*
609 * Get filesystem statistics.
610 */
611#ifndef _SYS_SYSPROTO_H_
612struct fstatfs_args {
613	int fd;
614	struct statfs *buf;
615};
616#endif
617/* ARGSUSED */
618int
619fstatfs(p, uap)
620	struct proc *p;
621	register struct fstatfs_args /* {
622		syscallarg(int) fd;
623		syscallarg(struct statfs *) buf;
624	} */ *uap;
625{
626	struct file *fp;
627	struct mount *mp;
628	register struct statfs *sp;
629	int error;
630	struct statfs sb;
631
632	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
633		return (error);
634	mp = ((struct vnode *)fp->f_data)->v_mount;
635	sp = &mp->mnt_stat;
636	error = VFS_STATFS(mp, sp, p);
637	if (error)
638		return (error);
639	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
640	if (p->p_ucred->cr_uid != 0) {
641		bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
642		sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
643		sp = &sb;
644	}
645	return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
646}
647
648/*
649 * Get statistics on all filesystems.
650 */
651#ifndef _SYS_SYSPROTO_H_
652struct getfsstat_args {
653	struct statfs *buf;
654	long bufsize;
655	int flags;
656};
657#endif
658int
659getfsstat(p, uap)
660	struct proc *p;
661	register struct getfsstat_args /* {
662		syscallarg(struct statfs *) buf;
663		syscallarg(long) bufsize;
664		syscallarg(int) flags;
665	} */ *uap;
666{
667	register struct mount *mp, *nmp;
668	register struct statfs *sp;
669	caddr_t sfsp;
670	long count, maxcount, error;
671
672	maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
673	sfsp = (caddr_t)SCARG(uap, buf);
674	count = 0;
675	simple_lock(&mountlist_slock);
676	for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
677		if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
678			nmp = mp->mnt_list.cqe_next;
679			continue;
680		}
681		if (sfsp && count < maxcount) {
682			sp = &mp->mnt_stat;
683			/*
684			 * If MNT_NOWAIT or MNT_LAZY is specified, do not
685			 * refresh the fsstat cache. MNT_NOWAIT or MNT_LAZY
686			 * overrides MNT_WAIT.
687			 */
688			if (((SCARG(uap, flags) & (MNT_LAZY|MNT_NOWAIT)) == 0 ||
689			    (SCARG(uap, flags) & MNT_WAIT)) &&
690			    (error = VFS_STATFS(mp, sp, p))) {
691				simple_lock(&mountlist_slock);
692				nmp = mp->mnt_list.cqe_next;
693				vfs_unbusy(mp, p);
694				continue;
695			}
696			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
697			error = copyout((caddr_t)sp, sfsp, sizeof(*sp));
698			if (error) {
699				vfs_unbusy(mp, p);
700				return (error);
701			}
702			sfsp += sizeof(*sp);
703		}
704		count++;
705		simple_lock(&mountlist_slock);
706		nmp = mp->mnt_list.cqe_next;
707		vfs_unbusy(mp, p);
708	}
709	simple_unlock(&mountlist_slock);
710	if (sfsp && count > maxcount)
711		p->p_retval[0] = maxcount;
712	else
713		p->p_retval[0] = count;
714	return (0);
715}
716
717/*
718 * Change current working directory to a given file descriptor.
719 */
720#ifndef _SYS_SYSPROTO_H_
721struct fchdir_args {
722	int	fd;
723};
724#endif
725/* ARGSUSED */
726int
727fchdir(p, uap)
728	struct proc *p;
729	struct fchdir_args /* {
730		syscallarg(int) fd;
731	} */ *uap;
732{
733	register struct filedesc *fdp = p->p_fd;
734	struct vnode *vp, *tdp;
735	struct mount *mp;
736	struct file *fp;
737	int error;
738
739	if (error = getvnode(fdp, SCARG(uap, fd), &fp))
740		return (error);
741	vp = (struct vnode *)fp->f_data;
742	VREF(vp);
743	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
744	if (vp->v_type != VDIR)
745		error = ENOTDIR;
746	else
747		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
748	while (!error && (mp = vp->v_mountedhere) != NULL) {
749		if (vfs_busy(mp, 0, 0, p))
750			continue;
751		error = VFS_ROOT(mp, &tdp);
752		vfs_unbusy(mp, p);
753		if (error)
754			break;
755		vput(vp);
756		vp = tdp;
757	}
758	if (error) {
759		vput(vp);
760		return (error);
761	}
762	VOP_UNLOCK(vp, 0, p);
763	vrele(fdp->fd_cdir);
764	fdp->fd_cdir = vp;
765	return (0);
766}
767
768/*
769 * Change current working directory (``.'').
770 */
771#ifndef _SYS_SYSPROTO_H_
772struct chdir_args {
773	char	*path;
774};
775#endif
776/* ARGSUSED */
777int
778chdir(p, uap)
779	struct proc *p;
780	struct chdir_args /* {
781		syscallarg(char *) path;
782	} */ *uap;
783{
784	register struct filedesc *fdp = p->p_fd;
785	int error;
786	struct nameidata nd;
787
788	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
789	    SCARG(uap, path), p);
790	if (error = change_dir(&nd, p))
791		return (error);
792	vrele(fdp->fd_cdir);
793	fdp->fd_cdir = nd.ni_vp;
794	return (0);
795}
796
797/*
798 * Change notion of root (``/'') directory.
799 */
800#ifndef _SYS_SYSPROTO_H_
801struct chroot_args {
802	char	*path;
803};
804#endif
805/* ARGSUSED */
806int
807chroot(p, uap)
808	struct proc *p;
809	struct chroot_args /* {
810		syscallarg(char *) path;
811	} */ *uap;
812{
813	register struct filedesc *fdp = p->p_fd;
814	int error;
815	struct nameidata nd;
816
817	error = suser(p->p_ucred, &p->p_acflag);
818	if (error)
819		return (error);
820	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
821	    SCARG(uap, path), p);
822	if (error = change_dir(&nd, p))
823		return (error);
824	vrele(fdp->fd_rdir);
825	fdp->fd_rdir = nd.ni_vp;
826	return (0);
827}
828
829/*
830 * Common routine for chroot and chdir.
831 */
832static int
833change_dir(ndp, p)
834	register struct nameidata *ndp;
835	struct proc *p;
836{
837	struct vnode *vp;
838	int error;
839
840	error = namei(ndp);
841	if (error)
842		return (error);
843	vp = ndp->ni_vp;
844	if (vp->v_type != VDIR)
845		error = ENOTDIR;
846	else
847		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
848	if (error)
849		vput(vp);
850	else
851		VOP_UNLOCK(vp, 0, p);
852	return (error);
853}
854
855/*
856 * Check permissions, allocate an open file structure,
857 * and call the device open routine if any.
858 */
859#ifndef _SYS_SYSPROTO_H_
860struct open_args {
861	char	*path;
862	int	flags;
863	int	mode;
864};
865#endif
866int
867open(p, uap)
868	struct proc *p;
869	register struct open_args /* {
870		syscallarg(char *) path;
871		syscallarg(int) flags;
872		syscallarg(int) mode;
873	} */ *uap;
874{
875	register struct filedesc *fdp = p->p_fd;
876	register struct file *fp;
877	register struct vnode *vp;
878	int cmode, flags, oflags;
879	struct file *nfp;
880	int type, indx, error;
881	struct flock lf;
882	struct nameidata nd;
883
884	oflags = SCARG(uap, flags);
885	if ((oflags & O_ACCMODE) == O_ACCMODE)
886		return (EINVAL);
887	flags = FFLAGS(oflags);
888	error = falloc(p, &nfp, &indx);
889	if (error)
890		return (error);
891	fp = nfp;
892	cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
893	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
894	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
895	error = vn_open(&nd, flags, cmode);
896	if (error) {
897		ffree(fp);
898		if ((error == ENODEV || error == ENXIO) &&
899		    p->p_dupfd >= 0 &&			/* XXX from fdopen */
900		    (error =
901			dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
902			p->p_retval[0] = indx;
903			return (0);
904		}
905		if (error == ERESTART)
906			error = EINTR;
907		fdp->fd_ofiles[indx] = NULL;
908		return (error);
909	}
910	p->p_dupfd = 0;
911	vp = nd.ni_vp;
912
913	fp->f_flag = flags & FMASK;
914	fp->f_type = (vp->v_type == VFIFO ? DTYPE_FIFO : DTYPE_VNODE);
915	fp->f_ops = &vnops;
916	fp->f_data = (caddr_t)vp;
917	if (flags & (O_EXLOCK | O_SHLOCK)) {
918		lf.l_whence = SEEK_SET;
919		lf.l_start = 0;
920		lf.l_len = 0;
921		if (flags & O_EXLOCK)
922			lf.l_type = F_WRLCK;
923		else
924			lf.l_type = F_RDLCK;
925		type = F_FLOCK;
926		if ((flags & FNONBLOCK) == 0)
927			type |= F_WAIT;
928		VOP_UNLOCK(vp, 0, p);
929		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
930			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
931			ffree(fp);
932			fdp->fd_ofiles[indx] = NULL;
933			return (error);
934		}
935		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
936		fp->f_flag |= FHASLOCK;
937	}
938	if ((vp->v_type == VREG) && (vp->v_object == NULL))
939		vfs_object_create(vp, p, p->p_ucred, TRUE);
940	VOP_UNLOCK(vp, 0, p);
941	p->p_retval[0] = indx;
942	return (0);
943}
944
945#ifdef COMPAT_43
946/*
947 * Create a file.
948 */
949#ifndef _SYS_SYSPROTO_H_
950struct ocreat_args {
951	char	*path;
952	int	mode;
953};
954#endif
955int
956ocreat(p, uap)
957	struct proc *p;
958	register struct ocreat_args /* {
959		syscallarg(char *) path;
960		syscallarg(int) mode;
961	} */ *uap;
962{
963	struct open_args /* {
964		syscallarg(char *) path;
965		syscallarg(int) flags;
966		syscallarg(int) mode;
967	} */ nuap;
968
969	SCARG(&nuap, path) = SCARG(uap, path);
970	SCARG(&nuap, mode) = SCARG(uap, mode);
971	SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
972	return (open(p, &nuap));
973}
974#endif /* COMPAT_43 */
975
976/*
977 * Create a special file.
978 */
979#ifndef _SYS_SYSPROTO_H_
980struct mknod_args {
981	char	*path;
982	int	mode;
983	int	dev;
984};
985#endif
986/* ARGSUSED */
987int
988mknod(p, uap)
989	struct proc *p;
990	register struct mknod_args /* {
991		syscallarg(char *) path;
992		syscallarg(int) mode;
993		syscallarg(int) dev;
994	} */ *uap;
995{
996	register struct vnode *vp;
997	struct vattr vattr;
998	int error;
999	int whiteout;
1000	struct nameidata nd;
1001
1002	error = suser(p->p_ucred, &p->p_acflag);
1003	if (error)
1004		return (error);
1005	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
1006	if (error = namei(&nd))
1007		return (error);
1008	vp = nd.ni_vp;
1009	if (vp != NULL)
1010		error = EEXIST;
1011	else {
1012		VATTR_NULL(&vattr);
1013		vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
1014		vattr.va_rdev = SCARG(uap, dev);
1015		whiteout = 0;
1016
1017		switch (SCARG(uap, mode) & S_IFMT) {
1018		case S_IFMT:	/* used by badsect to flag bad sectors */
1019			vattr.va_type = VBAD;
1020			break;
1021		case S_IFCHR:
1022			vattr.va_type = VCHR;
1023			break;
1024		case S_IFBLK:
1025			vattr.va_type = VBLK;
1026			break;
1027		case S_IFWHT:
1028			whiteout = 1;
1029			break;
1030		default:
1031			error = EINVAL;
1032			break;
1033		}
1034	}
1035	if (!error) {
1036		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1037		if (whiteout) {
1038			error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
1039			if (error)
1040				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1041			vput(nd.ni_dvp);
1042		} else {
1043			error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
1044						&nd.ni_cnd, &vattr);
1045		}
1046	} else {
1047		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1048		if (nd.ni_dvp == vp)
1049			vrele(nd.ni_dvp);
1050		else
1051			vput(nd.ni_dvp);
1052		if (vp)
1053			vrele(vp);
1054	}
1055	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mknod");
1056	ASSERT_VOP_UNLOCKED(nd.ni_vp, "mknod");
1057	return (error);
1058}
1059
1060/*
1061 * Create a named pipe.
1062 */
1063#ifndef _SYS_SYSPROTO_H_
1064struct mkfifo_args {
1065	char	*path;
1066	int	mode;
1067};
1068#endif
1069/* ARGSUSED */
1070int
1071mkfifo(p, uap)
1072	struct proc *p;
1073	register struct mkfifo_args /* {
1074		syscallarg(char *) path;
1075		syscallarg(int) mode;
1076	} */ *uap;
1077{
1078	struct vattr vattr;
1079	int error;
1080	struct nameidata nd;
1081
1082	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
1083	if (error = namei(&nd))
1084		return (error);
1085	if (nd.ni_vp != NULL) {
1086		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1087		if (nd.ni_dvp == nd.ni_vp)
1088			vrele(nd.ni_dvp);
1089		else
1090			vput(nd.ni_dvp);
1091		vrele(nd.ni_vp);
1092		return (EEXIST);
1093	}
1094	VATTR_NULL(&vattr);
1095	vattr.va_type = VFIFO;
1096	vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
1097	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1098	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
1099}
1100
1101/*
1102 * Make a hard file link.
1103 */
1104#ifndef _SYS_SYSPROTO_H_
1105struct link_args {
1106	char	*path;
1107	char	*link;
1108};
1109#endif
1110/* ARGSUSED */
1111int
1112link(p, uap)
1113	struct proc *p;
1114	register struct link_args /* {
1115		syscallarg(char *) path;
1116		syscallarg(char *) link;
1117	} */ *uap;
1118{
1119	register struct vnode *vp;
1120	struct nameidata nd;
1121	int error;
1122
1123	NDINIT(&nd, LOOKUP, FOLLOW|NOOBJ, UIO_USERSPACE, SCARG(uap, path), p);
1124	if (error = namei(&nd))
1125		return (error);
1126	vp = nd.ni_vp;
1127	if (vp->v_type == VDIR)
1128		error = EPERM;		/* POSIX */
1129	else {
1130		NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), p);
1131		error = namei(&nd);
1132		if (!error) {
1133			if (nd.ni_vp != NULL) {
1134				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1135				if (nd.ni_dvp == nd.ni_vp)
1136					vrele(nd.ni_dvp);
1137				else
1138					vput(nd.ni_dvp);
1139				if (nd.ni_vp)
1140					vrele(nd.ni_vp);
1141				error = EEXIST;
1142			} else {
1143				VOP_LEASE(nd.ni_dvp, p, p->p_ucred,
1144				    LEASE_WRITE);
1145				VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1146				error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
1147			}
1148		}
1149	}
1150	vrele(vp);
1151	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "link");
1152	ASSERT_VOP_UNLOCKED(nd.ni_vp, "link");
1153	return (error);
1154}
1155
1156/*
1157 * Make a symbolic link.
1158 */
1159#ifndef _SYS_SYSPROTO_H_
1160struct symlink_args {
1161	char	*path;
1162	char	*link;
1163};
1164#endif
1165/* ARGSUSED */
1166int
1167symlink(p, uap)
1168	struct proc *p;
1169	register struct symlink_args /* {
1170		syscallarg(char *) path;
1171		syscallarg(char *) link;
1172	} */ *uap;
1173{
1174	struct vattr vattr;
1175	char *path;
1176	int error;
1177	struct nameidata nd;
1178
1179	path = zalloc(namei_zone);
1180	if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL))
1181		goto out;
1182	NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), p);
1183	if (error = namei(&nd))
1184		goto out;
1185	if (nd.ni_vp) {
1186		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1187		if (nd.ni_dvp == nd.ni_vp)
1188			vrele(nd.ni_dvp);
1189		else
1190			vput(nd.ni_dvp);
1191		vrele(nd.ni_vp);
1192		error = EEXIST;
1193		goto out;
1194	}
1195	VATTR_NULL(&vattr);
1196	vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
1197	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1198	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1199	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "symlink");
1200	ASSERT_VOP_UNLOCKED(nd.ni_vp, "symlink");
1201out:
1202	zfree(namei_zone, path);
1203	return (error);
1204}
1205
1206/*
1207 * Delete a whiteout from the filesystem.
1208 */
1209/* ARGSUSED */
1210int
1211undelete(p, uap)
1212	struct proc *p;
1213	register struct undelete_args /* {
1214		syscallarg(char *) path;
1215	} */ *uap;
1216{
1217	int error;
1218	struct nameidata nd;
1219
1220	NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
1221	    SCARG(uap, path), p);
1222	error = namei(&nd);
1223	if (error)
1224		return (error);
1225
1226	if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
1227		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1228		if (nd.ni_dvp == nd.ni_vp)
1229			vrele(nd.ni_dvp);
1230		else
1231			vput(nd.ni_dvp);
1232		if (nd.ni_vp)
1233			vrele(nd.ni_vp);
1234		return (EEXIST);
1235	}
1236
1237	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1238	if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE))
1239		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1240	vput(nd.ni_dvp);
1241	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "undelete");
1242	ASSERT_VOP_UNLOCKED(nd.ni_vp, "undelete");
1243	return (error);
1244}
1245
1246/*
1247 * Delete a name from the filesystem.
1248 */
1249#ifndef _SYS_SYSPROTO_H_
1250struct unlink_args {
1251	char	*path;
1252};
1253#endif
1254/* ARGSUSED */
1255int
1256unlink(p, uap)
1257	struct proc *p;
1258	struct unlink_args /* {
1259		syscallarg(char *) path;
1260	} */ *uap;
1261{
1262	register struct vnode *vp;
1263	int error;
1264	struct nameidata nd;
1265
1266	NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
1267	if (error = namei(&nd))
1268		return (error);
1269	vp = nd.ni_vp;
1270	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1271	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1272
1273	if (vp->v_type == VDIR)
1274		error = EPERM;		/* POSIX */
1275	else {
1276		/*
1277		 * The root of a mounted filesystem cannot be deleted.
1278		 *
1279		 * XXX: can this only be a VDIR case?
1280		 */
1281		if (vp->v_flag & VROOT)
1282			error = EBUSY;
1283	}
1284
1285	if (!error) {
1286		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1287		error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd);
1288	} else {
1289		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1290		if (nd.ni_dvp == vp)
1291			vrele(nd.ni_dvp);
1292		else
1293			vput(nd.ni_dvp);
1294		if (vp != NULLVP)
1295			vput(vp);
1296	}
1297	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "unlink");
1298	ASSERT_VOP_UNLOCKED(nd.ni_vp, "unlink");
1299	return (error);
1300}
1301
1302/*
1303 * Reposition read/write file offset.
1304 */
1305#ifndef _SYS_SYSPROTO_H_
1306struct lseek_args {
1307	int	fd;
1308	int	pad;
1309	off_t	offset;
1310	int	whence;
1311};
1312#endif
1313int
1314lseek(p, uap)
1315	struct proc *p;
1316	register struct lseek_args /* {
1317		syscallarg(int) fd;
1318		syscallarg(int) pad;
1319		syscallarg(off_t) offset;
1320		syscallarg(int) whence;
1321	} */ *uap;
1322{
1323	struct ucred *cred = p->p_ucred;
1324	register struct filedesc *fdp = p->p_fd;
1325	register struct file *fp;
1326	struct vattr vattr;
1327	off_t ofs;
1328	int error;
1329
1330	if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
1331	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
1332		return (EBADF);
1333	if (fp->f_type != DTYPE_VNODE)
1334		return (ESPIPE);
1335	switch (SCARG(uap, whence)) {
1336	case L_INCR:
1337		ofs = fp->f_offset + SCARG(uap, offset);
1338		break;
1339	case L_XTND:
1340		error=VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p);
1341		if (error)
1342			return (error);
1343		ofs = SCARG(uap, offset) + vattr.va_size;
1344		break;
1345	case L_SET:
1346		ofs = SCARG(uap, offset);
1347		break;
1348	default:
1349		return (EINVAL);
1350	}
1351	if (ofs < 0) return (EINVAL);
1352	*(off_t *)(p->p_retval) = fp->f_offset = ofs;
1353	return (0);
1354}
1355
1356#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1357/*
1358 * Reposition read/write file offset.
1359 */
1360#ifndef _SYS_SYSPROTO_H_
1361struct olseek_args {
1362	int	fd;
1363	long	offset;
1364	int	whence;
1365};
1366#endif
1367int
1368olseek(p, uap)
1369	struct proc *p;
1370	register struct olseek_args /* {
1371		syscallarg(int) fd;
1372		syscallarg(long) offset;
1373		syscallarg(int) whence;
1374	} */ *uap;
1375{
1376	struct lseek_args /* {
1377		syscallarg(int) fd;
1378		syscallarg(int) pad;
1379		syscallarg(off_t) offset;
1380		syscallarg(int) whence;
1381	} */ nuap;
1382	int error;
1383
1384	SCARG(&nuap, fd) = SCARG(uap, fd);
1385	SCARG(&nuap, offset) = SCARG(uap, offset);
1386	SCARG(&nuap, whence) = SCARG(uap, whence);
1387	error = lseek(p, &nuap);
1388	return (error);
1389}
1390#endif /* COMPAT_43 */
1391
1392/*
1393 * Check access permissions.
1394 */
1395#ifndef _SYS_SYSPROTO_H_
1396struct access_args {
1397	char	*path;
1398	int	flags;
1399};
1400#endif
1401int
1402access(p, uap)
1403	struct proc *p;
1404	register struct access_args /* {
1405		syscallarg(char *) path;
1406		syscallarg(int) flags;
1407	} */ *uap;
1408{
1409	register struct ucred *cred = p->p_ucred;
1410	register struct vnode *vp;
1411	int error, flags, t_gid, t_uid;
1412	struct nameidata nd;
1413
1414	t_uid = cred->cr_uid;
1415	t_gid = cred->cr_groups[0];
1416	cred->cr_uid = p->p_cred->p_ruid;
1417	cred->cr_groups[0] = p->p_cred->p_rgid;
1418	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1419	    SCARG(uap, path), p);
1420	if (error = namei(&nd))
1421		goto out1;
1422	vp = nd.ni_vp;
1423
1424	/* Flags == 0 means only check for existence. */
1425	if (SCARG(uap, flags)) {
1426		flags = 0;
1427		if (SCARG(uap, flags) & R_OK)
1428			flags |= VREAD;
1429		if (SCARG(uap, flags) & W_OK)
1430			flags |= VWRITE;
1431		if (SCARG(uap, flags) & X_OK)
1432			flags |= VEXEC;
1433		if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
1434			error = VOP_ACCESS(vp, flags, cred, p);
1435	}
1436	vput(vp);
1437out1:
1438	cred->cr_uid = t_uid;
1439	cred->cr_groups[0] = t_gid;
1440	return (error);
1441}
1442
1443#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1444/*
1445 * Get file status; this version follows links.
1446 */
1447#ifndef _SYS_SYSPROTO_H_
1448struct ostat_args {
1449	char	*path;
1450	struct ostat *ub;
1451};
1452#endif
1453/* ARGSUSED */
1454int
1455ostat(p, uap)
1456	struct proc *p;
1457	register struct ostat_args /* {
1458		syscallarg(char *) path;
1459		syscallarg(struct ostat *) ub;
1460	} */ *uap;
1461{
1462	struct stat sb;
1463	struct ostat osb;
1464	int error;
1465	struct nameidata nd;
1466
1467	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1468	    SCARG(uap, path), p);
1469	if (error = namei(&nd))
1470		return (error);
1471	error = vn_stat(nd.ni_vp, &sb, p);
1472	vput(nd.ni_vp);
1473	if (error)
1474		return (error);
1475	cvtstat(&sb, &osb);
1476	error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
1477	return (error);
1478}
1479
1480/*
1481 * Get file status; this version does not follow links.
1482 */
1483#ifndef _SYS_SYSPROTO_H_
1484struct olstat_args {
1485	char	*path;
1486	struct ostat *ub;
1487};
1488#endif
1489/* ARGSUSED */
1490int
1491olstat(p, uap)
1492	struct proc *p;
1493	register struct olstat_args /* {
1494		syscallarg(char *) path;
1495		syscallarg(struct ostat *) ub;
1496	} */ *uap;
1497{
1498	struct vnode *vp;
1499	struct stat sb;
1500	struct ostat osb;
1501	int error;
1502	struct nameidata nd;
1503
1504	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1505	    SCARG(uap, path), p);
1506	if (error = namei(&nd))
1507		return (error);
1508	vp = nd.ni_vp;
1509	error = vn_stat(vp, &sb, p);
1510	vput(vp);
1511	if (error)
1512		return (error);
1513	cvtstat(&sb, &osb);
1514	error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
1515	return (error);
1516}
1517
1518/*
1519 * Convert from an old to a new stat structure.
1520 */
1521void
1522cvtstat(st, ost)
1523	struct stat *st;
1524	struct ostat *ost;
1525{
1526
1527	ost->st_dev = st->st_dev;
1528	ost->st_ino = st->st_ino;
1529	ost->st_mode = st->st_mode;
1530	ost->st_nlink = st->st_nlink;
1531	ost->st_uid = st->st_uid;
1532	ost->st_gid = st->st_gid;
1533	ost->st_rdev = st->st_rdev;
1534	if (st->st_size < (quad_t)1 << 32)
1535		ost->st_size = st->st_size;
1536	else
1537		ost->st_size = -2;
1538	ost->st_atime = st->st_atime;
1539	ost->st_mtime = st->st_mtime;
1540	ost->st_ctime = st->st_ctime;
1541	ost->st_blksize = st->st_blksize;
1542	ost->st_blocks = st->st_blocks;
1543	ost->st_flags = st->st_flags;
1544	ost->st_gen = st->st_gen;
1545}
1546#endif /* COMPAT_43 || COMPAT_SUNOS */
1547
1548/*
1549 * Get file status; this version follows links.
1550 */
1551#ifndef _SYS_SYSPROTO_H_
1552struct stat_args {
1553	char	*path;
1554	struct stat *ub;
1555};
1556#endif
1557/* ARGSUSED */
1558int
1559stat(p, uap)
1560	struct proc *p;
1561	register struct stat_args /* {
1562		syscallarg(char *) path;
1563		syscallarg(struct stat *) ub;
1564	} */ *uap;
1565{
1566	struct stat sb;
1567	int error;
1568	struct nameidata nd;
1569
1570	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1571	    SCARG(uap, path), p);
1572	if (error = namei(&nd))
1573		return (error);
1574	error = vn_stat(nd.ni_vp, &sb, p);
1575	vput(nd.ni_vp);
1576	if (error)
1577		return (error);
1578	error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
1579	return (error);
1580}
1581
1582/*
1583 * Get file status; this version does not follow links.
1584 */
1585#ifndef _SYS_SYSPROTO_H_
1586struct lstat_args {
1587	char	*path;
1588	struct stat *ub;
1589};
1590#endif
1591/* ARGSUSED */
1592int
1593lstat(p, uap)
1594	struct proc *p;
1595	register struct lstat_args /* {
1596		syscallarg(char *) path;
1597		syscallarg(struct stat *) ub;
1598	} */ *uap;
1599{
1600	int error;
1601	struct vnode *vp;
1602	struct stat sb;
1603	struct nameidata nd;
1604
1605	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1606	    SCARG(uap, path), p);
1607	if (error = namei(&nd))
1608		return (error);
1609	vp = nd.ni_vp;
1610	error = vn_stat(vp, &sb, p);
1611	vput(vp);
1612	if (error)
1613		return (error);
1614	error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
1615	return (error);
1616}
1617
1618/*
1619 * Get configurable pathname variables.
1620 */
1621#ifndef _SYS_SYSPROTO_H_
1622struct pathconf_args {
1623	char	*path;
1624	int	name;
1625};
1626#endif
1627/* ARGSUSED */
1628int
1629pathconf(p, uap)
1630	struct proc *p;
1631	register struct pathconf_args /* {
1632		syscallarg(char *) path;
1633		syscallarg(int) name;
1634	} */ *uap;
1635{
1636	int error;
1637	struct nameidata nd;
1638
1639	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1640	    SCARG(uap, path), p);
1641	if (error = namei(&nd))
1642		return (error);
1643	error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), p->p_retval);
1644	vput(nd.ni_vp);
1645	return (error);
1646}
1647
1648/*
1649 * Return target name of a symbolic link.
1650 */
1651#ifndef _SYS_SYSPROTO_H_
1652struct readlink_args {
1653	char	*path;
1654	char	*buf;
1655	int	count;
1656};
1657#endif
1658/* ARGSUSED */
1659int
1660readlink(p, uap)
1661	struct proc *p;
1662	register struct readlink_args /* {
1663		syscallarg(char *) path;
1664		syscallarg(char *) buf;
1665		syscallarg(int) count;
1666	} */ *uap;
1667{
1668	register struct vnode *vp;
1669	struct iovec aiov;
1670	struct uio auio;
1671	int error;
1672	struct nameidata nd;
1673
1674	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1675	    SCARG(uap, path), p);
1676	if (error = namei(&nd))
1677		return (error);
1678	vp = nd.ni_vp;
1679	if (vp->v_type != VLNK)
1680		error = EINVAL;
1681	else {
1682		aiov.iov_base = SCARG(uap, buf);
1683		aiov.iov_len = SCARG(uap, count);
1684		auio.uio_iov = &aiov;
1685		auio.uio_iovcnt = 1;
1686		auio.uio_offset = 0;
1687		auio.uio_rw = UIO_READ;
1688		auio.uio_segflg = UIO_USERSPACE;
1689		auio.uio_procp = p;
1690		auio.uio_resid = SCARG(uap, count);
1691		error = VOP_READLINK(vp, &auio, p->p_ucred);
1692	}
1693	vput(vp);
1694	p->p_retval[0] = SCARG(uap, count) - auio.uio_resid;
1695	return (error);
1696}
1697
1698/*
1699 * Change flags of a file given a path name.
1700 */
1701#ifndef _SYS_SYSPROTO_H_
1702struct chflags_args {
1703	char	*path;
1704	int	flags;
1705};
1706#endif
1707/* ARGSUSED */
1708int
1709chflags(p, uap)
1710	struct proc *p;
1711	register struct chflags_args /* {
1712		syscallarg(char *) path;
1713		syscallarg(int) flags;
1714	} */ *uap;
1715{
1716	register struct vnode *vp;
1717	struct vattr vattr;
1718	int error;
1719	struct nameidata nd;
1720
1721	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1722	if (error = namei(&nd))
1723		return (error);
1724	vp = nd.ni_vp;
1725	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1726	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1727	VATTR_NULL(&vattr);
1728	vattr.va_flags = SCARG(uap, flags);
1729	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1730	vput(vp);
1731	return (error);
1732}
1733
1734/*
1735 * Change flags of a file given a file descriptor.
1736 */
1737#ifndef _SYS_SYSPROTO_H_
1738struct fchflags_args {
1739	int	fd;
1740	int	flags;
1741};
1742#endif
1743/* ARGSUSED */
1744int
1745fchflags(p, uap)
1746	struct proc *p;
1747	register struct fchflags_args /* {
1748		syscallarg(int) fd;
1749		syscallarg(int) flags;
1750	} */ *uap;
1751{
1752	struct vattr vattr;
1753	struct vnode *vp;
1754	struct file *fp;
1755	int error;
1756
1757	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
1758		return (error);
1759	vp = (struct vnode *)fp->f_data;
1760	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1761	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1762	VATTR_NULL(&vattr);
1763	vattr.va_flags = SCARG(uap, flags);
1764	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1765	VOP_UNLOCK(vp, 0, p);
1766	return (error);
1767}
1768
1769/*
1770 * Change mode of a file given path name.
1771 */
1772#ifndef _SYS_SYSPROTO_H_
1773struct chmod_args {
1774	char	*path;
1775	int	mode;
1776};
1777#endif
1778/* ARGSUSED */
1779int
1780chmod(p, uap)
1781	struct proc *p;
1782	register struct chmod_args /* {
1783		syscallarg(char *) path;
1784		syscallarg(int) mode;
1785	} */ *uap;
1786{
1787	register struct vnode *vp;
1788	struct vattr vattr;
1789	int error;
1790	struct nameidata nd;
1791
1792	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1793	if (error = namei(&nd))
1794		return (error);
1795	vp = nd.ni_vp;
1796	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1797	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1798	VATTR_NULL(&vattr);
1799	vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
1800	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1801	vput(vp);
1802	return (error);
1803}
1804
1805/*
1806 * Change mode of a file given a file descriptor.
1807 */
1808#ifndef _SYS_SYSPROTO_H_
1809struct fchmod_args {
1810	int	fd;
1811	int	mode;
1812};
1813#endif
1814/* ARGSUSED */
1815int
1816fchmod(p, uap)
1817	struct proc *p;
1818	register struct fchmod_args /* {
1819		syscallarg(int) fd;
1820		syscallarg(int) mode;
1821	} */ *uap;
1822{
1823	struct vattr vattr;
1824	struct vnode *vp;
1825	struct file *fp;
1826	int error;
1827
1828	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
1829		return (error);
1830	vp = (struct vnode *)fp->f_data;
1831	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1832	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1833	VATTR_NULL(&vattr);
1834	vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
1835	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1836	VOP_UNLOCK(vp, 0, p);
1837	return (error);
1838}
1839
1840/*
1841 * Set ownership given a path name.
1842 */
1843#ifndef _SYS_SYSPROTO_H_
1844struct chown_args {
1845	char	*path;
1846	int	uid;
1847	int	gid;
1848};
1849#endif
1850/* ARGSUSED */
1851int
1852chown(p, uap)
1853	struct proc *p;
1854	register struct chown_args /* {
1855		syscallarg(char *) path;
1856		syscallarg(int) uid;
1857		syscallarg(int) gid;
1858	} */ *uap;
1859{
1860	register struct vnode *vp;
1861	struct vattr vattr;
1862	int error;
1863	struct nameidata nd;
1864
1865	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1866	if (error = namei(&nd))
1867		return (error);
1868	vp = nd.ni_vp;
1869	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1870	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1871	VATTR_NULL(&vattr);
1872	vattr.va_uid = SCARG(uap, uid);
1873	vattr.va_gid = SCARG(uap, gid);
1874	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1875	vput(vp);
1876	return (error);
1877}
1878
1879/*
1880 * Set ownership given a path name, do not cross symlinks.
1881 */
1882#ifndef _SYS_SYSPROTO_H_
1883struct lchown_args {
1884	char	*path;
1885	int	uid;
1886	int	gid;
1887};
1888#endif
1889/* ARGSUSED */
1890int
1891lchown(p, uap)
1892	struct proc *p;
1893	register struct lchown_args /* {
1894		syscallarg(char *) path;
1895		syscallarg(int) uid;
1896		syscallarg(int) gid;
1897	} */ *uap;
1898{
1899	register struct vnode *vp;
1900	struct vattr vattr;
1901	int error;
1902	struct nameidata nd;
1903
1904	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1905	if (error = namei(&nd))
1906		return (error);
1907	vp = nd.ni_vp;
1908	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1909	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1910	VATTR_NULL(&vattr);
1911	vattr.va_uid = SCARG(uap, uid);
1912	vattr.va_gid = SCARG(uap, gid);
1913	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1914	vput(vp);
1915	return (error);
1916}
1917
1918/*
1919 * Set ownership given a file descriptor.
1920 */
1921#ifndef _SYS_SYSPROTO_H_
1922struct fchown_args {
1923	int	fd;
1924	int	uid;
1925	int	gid;
1926};
1927#endif
1928/* ARGSUSED */
1929int
1930fchown(p, uap)
1931	struct proc *p;
1932	register struct fchown_args /* {
1933		syscallarg(int) fd;
1934		syscallarg(int) uid;
1935		syscallarg(int) gid;
1936	} */ *uap;
1937{
1938	struct vattr vattr;
1939	struct vnode *vp;
1940	struct file *fp;
1941	int error;
1942
1943	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
1944		return (error);
1945	vp = (struct vnode *)fp->f_data;
1946	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1947	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1948	VATTR_NULL(&vattr);
1949	vattr.va_uid = SCARG(uap, uid);
1950	vattr.va_gid = SCARG(uap, gid);
1951	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1952	VOP_UNLOCK(vp, 0, p);
1953	return (error);
1954}
1955
1956/*
1957 * Set the access and modification times of a file.
1958 */
1959#ifndef _SYS_SYSPROTO_H_
1960struct utimes_args {
1961	char	*path;
1962	struct	timeval *tptr;
1963};
1964#endif
1965/* ARGSUSED */
1966int
1967utimes(p, uap)
1968	struct proc *p;
1969	register struct utimes_args /* {
1970		syscallarg(char *) path;
1971		syscallarg(struct timeval *) tptr;
1972	} */ *uap;
1973{
1974	register struct vnode *vp;
1975	struct timeval tv[2];
1976	struct vattr vattr;
1977	int error;
1978	struct nameidata nd;
1979
1980	VATTR_NULL(&vattr);
1981	if (SCARG(uap, tptr) == NULL) {
1982		microtime(&tv[0]);
1983		tv[1] = tv[0];
1984		vattr.va_vaflags |= VA_UTIMES_NULL;
1985	} else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv,
1986	    sizeof (tv)))
1987  		return (error);
1988	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1989	if (error = namei(&nd))
1990		return (error);
1991	vp = nd.ni_vp;
1992	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1993	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1994	vattr.va_atime.tv_sec = tv[0].tv_sec;
1995	vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000;
1996	vattr.va_mtime.tv_sec = tv[1].tv_sec;
1997	vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000;
1998	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1999	vput(vp);
2000	return (error);
2001}
2002
2003/*
2004 * Truncate a file given its path name.
2005 */
2006#ifndef _SYS_SYSPROTO_H_
2007struct truncate_args {
2008	char	*path;
2009	int	pad;
2010	off_t	length;
2011};
2012#endif
2013/* ARGSUSED */
2014int
2015truncate(p, uap)
2016	struct proc *p;
2017	register struct truncate_args /* {
2018		syscallarg(char *) path;
2019		syscallarg(int) pad;
2020		syscallarg(off_t) length;
2021	} */ *uap;
2022{
2023	register struct vnode *vp;
2024	struct vattr vattr;
2025	int error;
2026	struct nameidata nd;
2027
2028	if (uap->length < 0)
2029		return(EINVAL);
2030	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2031	if (error = namei(&nd))
2032		return (error);
2033	vp = nd.ni_vp;
2034	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2035	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2036	if (vp->v_type == VDIR)
2037		error = EISDIR;
2038	else if ((error = vn_writechk(vp)) == 0 &&
2039	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
2040		VATTR_NULL(&vattr);
2041		vattr.va_size = SCARG(uap, length);
2042		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2043	}
2044	vput(vp);
2045	return (error);
2046}
2047
2048/*
2049 * Truncate a file given a file descriptor.
2050 */
2051#ifndef _SYS_SYSPROTO_H_
2052struct ftruncate_args {
2053	int	fd;
2054	int	pad;
2055	off_t	length;
2056};
2057#endif
2058/* ARGSUSED */
2059int
2060ftruncate(p, uap)
2061	struct proc *p;
2062	register struct ftruncate_args /* {
2063		syscallarg(int) fd;
2064		syscallarg(int) pad;
2065		syscallarg(off_t) length;
2066	} */ *uap;
2067{
2068	struct vattr vattr;
2069	struct vnode *vp;
2070	struct file *fp;
2071	int error;
2072
2073	if (uap->length < 0)
2074		return(EINVAL);
2075	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
2076		return (error);
2077	if ((fp->f_flag & FWRITE) == 0)
2078		return (EINVAL);
2079	vp = (struct vnode *)fp->f_data;
2080	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2081	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2082	if (vp->v_type == VDIR)
2083		error = EISDIR;
2084	else if ((error = vn_writechk(vp)) == 0) {
2085		VATTR_NULL(&vattr);
2086		vattr.va_size = SCARG(uap, length);
2087		error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
2088	}
2089	VOP_UNLOCK(vp, 0, p);
2090	return (error);
2091}
2092
2093#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
2094/*
2095 * Truncate a file given its path name.
2096 */
2097#ifndef _SYS_SYSPROTO_H_
2098struct otruncate_args {
2099	char	*path;
2100	long	length;
2101};
2102#endif
2103/* ARGSUSED */
2104int
2105otruncate(p, uap)
2106	struct proc *p;
2107	register struct otruncate_args /* {
2108		syscallarg(char *) path;
2109		syscallarg(long) length;
2110	} */ *uap;
2111{
2112	struct truncate_args /* {
2113		syscallarg(char *) path;
2114		syscallarg(int) pad;
2115		syscallarg(off_t) length;
2116	} */ nuap;
2117
2118	SCARG(&nuap, path) = SCARG(uap, path);
2119	SCARG(&nuap, length) = SCARG(uap, length);
2120	return (truncate(p, &nuap));
2121}
2122
2123/*
2124 * Truncate a file given a file descriptor.
2125 */
2126#ifndef _SYS_SYSPROTO_H_
2127struct oftruncate_args {
2128	int	fd;
2129	long	length;
2130};
2131#endif
2132/* ARGSUSED */
2133int
2134oftruncate(p, uap)
2135	struct proc *p;
2136	register struct oftruncate_args /* {
2137		syscallarg(int) fd;
2138		syscallarg(long) length;
2139	} */ *uap;
2140{
2141	struct ftruncate_args /* {
2142		syscallarg(int) fd;
2143		syscallarg(int) pad;
2144		syscallarg(off_t) length;
2145	} */ nuap;
2146
2147	SCARG(&nuap, fd) = SCARG(uap, fd);
2148	SCARG(&nuap, length) = SCARG(uap, length);
2149	return (ftruncate(p, &nuap));
2150}
2151#endif /* COMPAT_43 || COMPAT_SUNOS */
2152
2153/*
2154 * Sync an open file.
2155 */
2156#ifndef _SYS_SYSPROTO_H_
2157struct fsync_args {
2158	int	fd;
2159};
2160#endif
2161/* ARGSUSED */
2162int
2163fsync(p, uap)
2164	struct proc *p;
2165	struct fsync_args /* {
2166		syscallarg(int) fd;
2167	} */ *uap;
2168{
2169	register struct vnode *vp;
2170	struct file *fp;
2171	int error;
2172
2173	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
2174		return (error);
2175	vp = (struct vnode *)fp->f_data;
2176	if ((error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p)) == NULL) {
2177		if (vp->v_object) {
2178			vm_object_page_clean(vp->v_object, 0, 0, FALSE);
2179		}
2180		if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP)) {
2181			error = VOP_FSYNC(vp, fp->f_cred, MNT_LAZY, p);
2182		} else {
2183			error = VOP_FSYNC(vp, fp->f_cred,
2184				(vp->v_mount && (vp->v_mount->mnt_flag & MNT_ASYNC)) ?
2185				MNT_NOWAIT : MNT_WAIT, p);
2186		}
2187		VOP_UNLOCK(vp, 0, p);
2188
2189		if ((vp->v_mount->mnt_flag & MNT_SOFTDEP) && bioops.io_sync)
2190			(*bioops.io_sync)(NULL);
2191	}
2192	return (error);
2193}
2194
2195/*
2196 * Rename files.  Source and destination must either both be directories,
2197 * or both not be directories.  If target is a directory, it must be empty.
2198 */
2199#ifndef _SYS_SYSPROTO_H_
2200struct rename_args {
2201	char	*from;
2202	char	*to;
2203};
2204#endif
2205/* ARGSUSED */
2206int
2207rename(p, uap)
2208	struct proc *p;
2209	register struct rename_args /* {
2210		syscallarg(char *) from;
2211		syscallarg(char *) to;
2212	} */ *uap;
2213{
2214	register struct vnode *tvp, *fvp, *tdvp;
2215	struct nameidata fromnd, tond;
2216	int error;
2217
2218	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
2219	    SCARG(uap, from), p);
2220	if (error = namei(&fromnd))
2221		return (error);
2222	fvp = fromnd.ni_vp;
2223	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | NOOBJ,
2224	    UIO_USERSPACE, SCARG(uap, to), p);
2225	if (fromnd.ni_vp->v_type == VDIR)
2226		tond.ni_cnd.cn_flags |= WILLBEDIR;
2227	if (error = namei(&tond)) {
2228		/* Translate error code for rename("dir1", "dir2/."). */
2229		if (error == EISDIR && fvp->v_type == VDIR)
2230			error = EINVAL;
2231		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2232		vrele(fromnd.ni_dvp);
2233		vrele(fvp);
2234		goto out1;
2235	}
2236	tdvp = tond.ni_dvp;
2237	tvp = tond.ni_vp;
2238	if (tvp != NULL) {
2239		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
2240			error = ENOTDIR;
2241			goto out;
2242		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
2243			error = EISDIR;
2244			goto out;
2245		}
2246	}
2247	if (fvp == tdvp)
2248		error = EINVAL;
2249	/*
2250	 * If source is the same as the destination (that is the
2251	 * same inode number with the same name in the same directory),
2252	 * then there is nothing to do.
2253	 */
2254	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
2255	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
2256	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
2257	      fromnd.ni_cnd.cn_namelen))
2258		error = -1;
2259out:
2260	if (!error) {
2261		VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE);
2262		if (fromnd.ni_dvp != tdvp) {
2263			VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2264		}
2265		if (tvp) {
2266			VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE);
2267		}
2268		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
2269				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
2270	} else {
2271		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
2272		if (tdvp == tvp)
2273			vrele(tdvp);
2274		else
2275			vput(tdvp);
2276		if (tvp)
2277			vput(tvp);
2278		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2279		vrele(fromnd.ni_dvp);
2280		vrele(fvp);
2281	}
2282	vrele(tond.ni_startdir);
2283	ASSERT_VOP_UNLOCKED(fromnd.ni_dvp, "rename");
2284	ASSERT_VOP_UNLOCKED(fromnd.ni_vp, "rename");
2285	ASSERT_VOP_UNLOCKED(tond.ni_dvp, "rename");
2286	ASSERT_VOP_UNLOCKED(tond.ni_vp, "rename");
2287	zfree(namei_zone, tond.ni_cnd.cn_pnbuf);
2288out1:
2289	if (fromnd.ni_startdir)
2290		vrele(fromnd.ni_startdir);
2291	zfree(namei_zone, fromnd.ni_cnd.cn_pnbuf);
2292	if (error == -1)
2293		return (0);
2294	return (error);
2295}
2296
2297/*
2298 * Make a directory file.
2299 */
2300#ifndef _SYS_SYSPROTO_H_
2301struct mkdir_args {
2302	char	*path;
2303	int	mode;
2304};
2305#endif
2306/* ARGSUSED */
2307int
2308mkdir(p, uap)
2309	struct proc *p;
2310	register struct mkdir_args /* {
2311		syscallarg(char *) path;
2312		syscallarg(int) mode;
2313	} */ *uap;
2314{
2315	register struct vnode *vp;
2316	struct vattr vattr;
2317	int error;
2318	struct nameidata nd;
2319
2320	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
2321	nd.ni_cnd.cn_flags |= WILLBEDIR;
2322	if (error = namei(&nd))
2323		return (error);
2324	vp = nd.ni_vp;
2325	if (vp != NULL) {
2326		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2327		if (nd.ni_dvp == vp)
2328			vrele(nd.ni_dvp);
2329		else
2330			vput(nd.ni_dvp);
2331		vrele(vp);
2332		return (EEXIST);
2333	}
2334	VATTR_NULL(&vattr);
2335	vattr.va_type = VDIR;
2336	vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask;
2337	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2338	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
2339	if (!error)
2340		vput(nd.ni_vp);
2341	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mkdir");
2342	ASSERT_VOP_UNLOCKED(nd.ni_vp, "mkdir");
2343	return (error);
2344}
2345
2346/*
2347 * Remove a directory file.
2348 */
2349#ifndef _SYS_SYSPROTO_H_
2350struct rmdir_args {
2351	char	*path;
2352};
2353#endif
2354/* ARGSUSED */
2355int
2356rmdir(p, uap)
2357	struct proc *p;
2358	struct rmdir_args /* {
2359		syscallarg(char *) path;
2360	} */ *uap;
2361{
2362	register struct vnode *vp;
2363	int error;
2364	struct nameidata nd;
2365
2366	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
2367	    SCARG(uap, path), p);
2368	if (error = namei(&nd))
2369		return (error);
2370	vp = nd.ni_vp;
2371	if (vp->v_type != VDIR) {
2372		error = ENOTDIR;
2373		goto out;
2374	}
2375	/*
2376	 * No rmdir "." please.
2377	 */
2378	if (nd.ni_dvp == vp) {
2379		error = EINVAL;
2380		goto out;
2381	}
2382	/*
2383	 * The root of a mounted filesystem cannot be deleted.
2384	 */
2385	if (vp->v_flag & VROOT)
2386		error = EBUSY;
2387out:
2388	if (!error) {
2389		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2390		VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2391		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2392	} else {
2393		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2394		if (nd.ni_dvp == vp)
2395			vrele(nd.ni_dvp);
2396		else
2397			vput(nd.ni_dvp);
2398		vput(vp);
2399	}
2400	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "rmdir");
2401	ASSERT_VOP_UNLOCKED(nd.ni_vp, "rmdir");
2402	return (error);
2403}
2404
2405#ifdef COMPAT_43
2406/*
2407 * Read a block of directory entries in a file system independent format.
2408 */
2409#ifndef _SYS_SYSPROTO_H_
2410struct ogetdirentries_args {
2411	int	fd;
2412	char	*buf;
2413	u_int	count;
2414	long	*basep;
2415};
2416#endif
2417int
2418ogetdirentries(p, uap)
2419	struct proc *p;
2420	register struct ogetdirentries_args /* {
2421		syscallarg(int) fd;
2422		syscallarg(char *) buf;
2423		syscallarg(u_int) count;
2424		syscallarg(long *) basep;
2425	} */ *uap;
2426{
2427	register struct vnode *vp;
2428	struct file *fp;
2429	struct uio auio, kuio;
2430	struct iovec aiov, kiov;
2431	struct dirent *dp, *edp;
2432	caddr_t dirbuf;
2433	int error, eofflag, readcnt;
2434	long loff;
2435
2436	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
2437		return (error);
2438	if ((fp->f_flag & FREAD) == 0)
2439		return (EBADF);
2440	vp = (struct vnode *)fp->f_data;
2441unionread:
2442	if (vp->v_type != VDIR)
2443		return (EINVAL);
2444	aiov.iov_base = SCARG(uap, buf);
2445	aiov.iov_len = SCARG(uap, count);
2446	auio.uio_iov = &aiov;
2447	auio.uio_iovcnt = 1;
2448	auio.uio_rw = UIO_READ;
2449	auio.uio_segflg = UIO_USERSPACE;
2450	auio.uio_procp = p;
2451	auio.uio_resid = SCARG(uap, count);
2452	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2453	loff = auio.uio_offset = fp->f_offset;
2454#	if (BYTE_ORDER != LITTLE_ENDIAN)
2455		if (vp->v_mount->mnt_maxsymlinklen <= 0) {
2456			error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
2457			    NULL, NULL);
2458			fp->f_offset = auio.uio_offset;
2459		} else
2460#	endif
2461	{
2462		kuio = auio;
2463		kuio.uio_iov = &kiov;
2464		kuio.uio_segflg = UIO_SYSSPACE;
2465		kiov.iov_len = SCARG(uap, count);
2466		MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK);
2467		kiov.iov_base = dirbuf;
2468		error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
2469			    NULL, NULL);
2470		fp->f_offset = kuio.uio_offset;
2471		if (error == 0) {
2472			readcnt = SCARG(uap, count) - kuio.uio_resid;
2473			edp = (struct dirent *)&dirbuf[readcnt];
2474			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
2475#				if (BYTE_ORDER == LITTLE_ENDIAN)
2476					/*
2477					 * The expected low byte of
2478					 * dp->d_namlen is our dp->d_type.
2479					 * The high MBZ byte of dp->d_namlen
2480					 * is our dp->d_namlen.
2481					 */
2482					dp->d_type = dp->d_namlen;
2483					dp->d_namlen = 0;
2484#				else
2485					/*
2486					 * The dp->d_type is the high byte
2487					 * of the expected dp->d_namlen,
2488					 * so must be zero'ed.
2489					 */
2490					dp->d_type = 0;
2491#				endif
2492				if (dp->d_reclen > 0) {
2493					dp = (struct dirent *)
2494					    ((char *)dp + dp->d_reclen);
2495				} else {
2496					error = EIO;
2497					break;
2498				}
2499			}
2500			if (dp >= edp)
2501				error = uiomove(dirbuf, readcnt, &auio);
2502		}
2503		FREE(dirbuf, M_TEMP);
2504	}
2505	VOP_UNLOCK(vp, 0, p);
2506	if (error)
2507		return (error);
2508
2509#ifdef UNION
2510{
2511	if ((SCARG(uap, count) == auio.uio_resid) &&
2512	    (vp->v_op == union_vnodeop_p)) {
2513		struct vnode *lvp;
2514
2515		lvp = union_dircache(vp, p);
2516		if (lvp != NULLVP) {
2517			struct vattr va;
2518
2519			/*
2520			 * If the directory is opaque,
2521			 * then don't show lower entries
2522			 */
2523			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
2524			if (va.va_flags & OPAQUE) {
2525				vput(lvp);
2526				lvp = NULL;
2527			}
2528		}
2529
2530		if (lvp != NULLVP) {
2531			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
2532			if (error) {
2533				vput(lvp);
2534				return (error);
2535			}
2536			VOP_UNLOCK(lvp, 0, p);
2537			fp->f_data = (caddr_t) lvp;
2538			fp->f_offset = 0;
2539			error = vn_close(vp, FREAD, fp->f_cred, p);
2540			if (error)
2541				return (error);
2542			vp = lvp;
2543			goto unionread;
2544		}
2545	}
2546}
2547#endif /* UNION */
2548
2549	if ((SCARG(uap, count) == auio.uio_resid) &&
2550	    (vp->v_flag & VROOT) &&
2551	    (vp->v_mount->mnt_flag & MNT_UNION)) {
2552		struct vnode *tvp = vp;
2553		vp = vp->v_mount->mnt_vnodecovered;
2554		VREF(vp);
2555		fp->f_data = (caddr_t) vp;
2556		fp->f_offset = 0;
2557		vrele(tvp);
2558		goto unionread;
2559	}
2560	error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
2561	    sizeof(long));
2562	p->p_retval[0] = SCARG(uap, count) - auio.uio_resid;
2563	return (error);
2564}
2565#endif /* COMPAT_43 */
2566
2567/*
2568 * Read a block of directory entries in a file system independent format.
2569 */
2570#ifndef _SYS_SYSPROTO_H_
2571struct getdirentries_args {
2572	int	fd;
2573	char	*buf;
2574	u_int	count;
2575	long	*basep;
2576};
2577#endif
2578int
2579getdirentries(p, uap)
2580	struct proc *p;
2581	register struct getdirentries_args /* {
2582		syscallarg(int) fd;
2583		syscallarg(char *) buf;
2584		syscallarg(u_int) count;
2585		syscallarg(long *) basep;
2586	} */ *uap;
2587{
2588	register struct vnode *vp;
2589	struct file *fp;
2590	struct uio auio;
2591	struct iovec aiov;
2592	long loff;
2593	int error, eofflag;
2594
2595	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
2596		return (error);
2597	if ((fp->f_flag & FREAD) == 0)
2598		return (EBADF);
2599	vp = (struct vnode *)fp->f_data;
2600unionread:
2601	if (vp->v_type != VDIR)
2602		return (EINVAL);
2603	aiov.iov_base = SCARG(uap, buf);
2604	aiov.iov_len = SCARG(uap, count);
2605	auio.uio_iov = &aiov;
2606	auio.uio_iovcnt = 1;
2607	auio.uio_rw = UIO_READ;
2608	auio.uio_segflg = UIO_USERSPACE;
2609	auio.uio_procp = p;
2610	auio.uio_resid = SCARG(uap, count);
2611	/* vn_lock(vp, LK_SHARED | LK_RETRY, p); */
2612	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2613	loff = auio.uio_offset = fp->f_offset;
2614	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, NULL);
2615	fp->f_offset = auio.uio_offset;
2616	VOP_UNLOCK(vp, 0, p);
2617	if (error)
2618		return (error);
2619
2620#ifdef UNION
2621{
2622	if ((SCARG(uap, count) == auio.uio_resid) &&
2623	    (vp->v_op == union_vnodeop_p)) {
2624		struct vnode *lvp;
2625
2626		lvp = union_dircache(vp, p);
2627		if (lvp != NULLVP) {
2628			struct vattr va;
2629
2630			/*
2631			 * If the directory is opaque,
2632			 * then don't show lower entries
2633			 */
2634			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
2635			if (va.va_flags & OPAQUE) {
2636				vput(lvp);
2637				lvp = NULL;
2638			}
2639		}
2640
2641		if (lvp != NULLVP) {
2642			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
2643			if (error) {
2644				vput(lvp);
2645				return (error);
2646			}
2647			VOP_UNLOCK(lvp, 0, p);
2648			fp->f_data = (caddr_t) lvp;
2649			fp->f_offset = 0;
2650			error = vn_close(vp, FREAD, fp->f_cred, p);
2651			if (error)
2652				return (error);
2653			vp = lvp;
2654			goto unionread;
2655		}
2656	}
2657}
2658#endif /* UNION */
2659
2660	if ((SCARG(uap, count) == auio.uio_resid) &&
2661	    (vp->v_flag & VROOT) &&
2662	    (vp->v_mount->mnt_flag & MNT_UNION)) {
2663		struct vnode *tvp = vp;
2664		vp = vp->v_mount->mnt_vnodecovered;
2665		VREF(vp);
2666		fp->f_data = (caddr_t) vp;
2667		fp->f_offset = 0;
2668		vrele(tvp);
2669		goto unionread;
2670	}
2671	error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
2672	    sizeof(long));
2673	p->p_retval[0] = SCARG(uap, count) - auio.uio_resid;
2674	return (error);
2675}
2676
2677/*
2678 * Set the mode mask for creation of filesystem nodes.
2679 */
2680#ifndef _SYS_SYSPROTO_H_
2681struct umask_args {
2682	int	newmask;
2683};
2684#endif
2685int
2686umask(p, uap)
2687	struct proc *p;
2688	struct umask_args /* {
2689		syscallarg(int) newmask;
2690	} */ *uap;
2691{
2692	register struct filedesc *fdp;
2693
2694	fdp = p->p_fd;
2695	p->p_retval[0] = fdp->fd_cmask;
2696	fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS;
2697	return (0);
2698}
2699
2700/*
2701 * Void all references to file by ripping underlying filesystem
2702 * away from vnode.
2703 */
2704#ifndef _SYS_SYSPROTO_H_
2705struct revoke_args {
2706	char	*path;
2707};
2708#endif
2709/* ARGSUSED */
2710int
2711revoke(p, uap)
2712	struct proc *p;
2713	register struct revoke_args /* {
2714		syscallarg(char *) path;
2715	} */ *uap;
2716{
2717	register struct vnode *vp;
2718	struct vattr vattr;
2719	int error;
2720	struct nameidata nd;
2721
2722	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2723	if (error = namei(&nd))
2724		return (error);
2725	vp = nd.ni_vp;
2726	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
2727		goto out;
2728	if (p->p_ucred->cr_uid != vattr.va_uid &&
2729	    (error = suser(p->p_ucred, &p->p_acflag)))
2730		goto out;
2731	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
2732		VOP_REVOKE(vp, REVOKEALL);
2733out:
2734	vrele(vp);
2735	return (error);
2736}
2737
2738/*
2739 * Convert a user file descriptor to a kernel file entry.
2740 */
2741int
2742getvnode(fdp, fd, fpp)
2743	struct filedesc *fdp;
2744	int fd;
2745	struct file **fpp;
2746{
2747	struct file *fp;
2748
2749	if ((u_int)fd >= fdp->fd_nfiles ||
2750	    (fp = fdp->fd_ofiles[fd]) == NULL)
2751		return (EBADF);
2752	if (fp->f_type != DTYPE_VNODE && fp->f_type != DTYPE_FIFO)
2753		return (EINVAL);
2754	*fpp = fp;
2755	return (0);
2756}
2757#ifndef _SYS_SYSPROTO_H_
2758struct  __getcwd_args {
2759	u_char	*buf;
2760	u_int	buflen;
2761};
2762#endif
2763#define STATNODE(mode, name, var) \
2764	SYSCTL_INT(_vfs_cache, OID_AUTO, name, mode, var, 0, "");
2765
2766static int disablecwd;
2767SYSCTL_INT(_debug, OID_AUTO, disablecwd, CTLFLAG_RW, &disablecwd, 0, "");
2768
2769static u_long numcwdcalls; STATNODE(CTLFLAG_RD, numcwdcalls, &numcwdcalls);
2770static u_long numcwdfail1; STATNODE(CTLFLAG_RD, numcwdfail1, &numcwdfail1);
2771static u_long numcwdfail2; STATNODE(CTLFLAG_RD, numcwdfail2, &numcwdfail2);
2772static u_long numcwdfail3; STATNODE(CTLFLAG_RD, numcwdfail3, &numcwdfail3);
2773static u_long numcwdfail4; STATNODE(CTLFLAG_RD, numcwdfail4, &numcwdfail4);
2774static u_long numcwdfound; STATNODE(CTLFLAG_RD, numcwdfound, &numcwdfound);
2775int
2776__getcwd(p, uap)
2777	struct proc *p;
2778	struct __getcwd_args *uap;
2779{
2780	char *bp, *buf;
2781	int error, i, slash_prefixed;
2782	struct filedesc *fdp;
2783	struct namecache *ncp;
2784	struct vnode *vp;
2785
2786	numcwdcalls++;
2787	if (disablecwd)
2788		return (ENODEV);
2789	if (uap->buflen < 2)
2790		return (EINVAL);
2791	if (uap->buflen > MAXPATHLEN)
2792		uap->buflen = MAXPATHLEN;
2793	buf = bp = malloc(uap->buflen, M_TEMP, M_WAITOK);
2794	bp += uap->buflen - 1;
2795	*bp = '\0';
2796	fdp = p->p_fd;
2797	slash_prefixed = 0;
2798	for (vp = fdp->fd_cdir; vp != fdp->fd_rdir && vp != rootvnode;) {
2799		if (vp->v_flag & VROOT) {
2800			vp = vp->v_mount->mnt_vnodecovered;
2801			continue;
2802		}
2803		if (vp->v_dd->v_id != vp->v_ddid) {
2804			numcwdfail1++;
2805			free(buf, M_TEMP);
2806			return (ENOTDIR);
2807		}
2808		ncp = TAILQ_FIRST(&vp->v_cache_dst);
2809		if (!ncp) {
2810			numcwdfail2++;
2811			free(buf, M_TEMP);
2812			return (ENOENT);
2813		}
2814		if (ncp->nc_dvp != vp->v_dd) {
2815			numcwdfail3++;
2816			free(buf, M_TEMP);
2817			return (EBADF);
2818		}
2819		for (i = ncp->nc_nlen - 1; i >= 0; i--) {
2820			if (bp == buf) {
2821				numcwdfail4++;
2822				free(buf, M_TEMP);
2823				return (ENOMEM);
2824			}
2825			*--bp = ncp->nc_name[i];
2826		}
2827		if (bp == buf) {
2828			numcwdfail4++;
2829			free(buf, M_TEMP);
2830			return (ENOMEM);
2831		}
2832		*--bp = '/';
2833		slash_prefixed = 1;
2834		vp = vp->v_dd;
2835	}
2836	if (!slash_prefixed) {
2837		if (bp == buf) {
2838			numcwdfail4++;
2839			free(buf, M_TEMP);
2840			return (ENOMEM);
2841		}
2842		*--bp = '/';
2843	}
2844	numcwdfound++;
2845	error = copyout(bp, uap->buf, strlen(bp) + 1);
2846	free(buf, M_TEMP);
2847	return (error);
2848}
2849