vfs_syscalls.c revision 24438
1183724Ssos/*
2183724Ssos * Copyright (c) 1989, 1993
3183724Ssos *	The Regents of the University of California.  All rights reserved.
4183724Ssos * (c) UNIX System Laboratories, Inc.
5183724Ssos * All or some portions of this file are derived from material licensed
6183724Ssos * to the University of California by American Telephone and Telegraph
7183724Ssos * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8183724Ssos * the permission of UNIX System Laboratories, Inc.
9183724Ssos *
10183724Ssos * Redistribution and use in source and binary forms, with or without
11183724Ssos * modification, are permitted provided that the following conditions
12183724Ssos * are met:
13183724Ssos * 1. Redistributions of source code must retain the above copyright
14183724Ssos *    notice, this list of conditions and the following disclaimer.
15183724Ssos * 2. Redistributions in binary form must reproduce the above copyright
16183724Ssos *    notice, this list of conditions and the following disclaimer in the
17183724Ssos *    documentation and/or other materials provided with the distribution.
18183724Ssos * 3. All advertising materials mentioning features or use of this software
19183724Ssos *    must display the following acknowledgement:
20183724Ssos *	This product includes software developed by the University of
21183724Ssos *	California, Berkeley and its contributors.
22183724Ssos * 4. Neither the name of the University nor the names of its contributors
23183724Ssos *    may be used to endorse or promote products derived from this software
24183724Ssos *    without specific prior written permission.
25183724Ssos *
26183724Ssos * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27183724Ssos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28183724Ssos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29183724Ssos * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30183724Ssos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31183724Ssos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32183724Ssos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33183724Ssos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34183724Ssos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35183724Ssos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36183724Ssos * SUCH DAMAGE.
37183724Ssos *
38183724Ssos *	@(#)vfs_syscalls.c	8.13 (Berkeley) 4/15/94
39183724Ssos * $Id: vfs_syscalls.c,v 1.61 1997/03/23 20:08:11 guido Exp $
40183724Ssos */
41183724Ssos
42183724Ssos/*
43183724Ssos * XXX - The following is required because of some magic done
44183724Ssos * in getdirentries() below which is only done if the translucent
45183724Ssos * filesystem `UNION' is compiled into the kernel.  This is broken,
46183724Ssos * but I don't have time to study the code deeply enough to understand
47183724Ssos * what's going on and determine an appropriate fix.  -GAW
48183724Ssos */
49183724Ssos#include "opt_union.h"
50183724Ssos
51183724Ssos#include <sys/param.h>
52183724Ssos#include <sys/systm.h>
53183724Ssos#include <sys/sysent.h>
54183724Ssos#include <sys/sysproto.h>
55188765Smav#include <sys/namei.h>
56183724Ssos#include <sys/filedesc.h>
57183724Ssos#include <sys/kernel.h>
58188765Smav#include <sys/fcntl.h>
59183724Ssos#include <sys/file.h>
60183724Ssos#include <sys/stat.h>
61183724Ssos#include <sys/unistd.h>
62188765Smav#include <sys/vnode.h>
63183724Ssos#include <sys/mount.h>
64183724Ssos#include <sys/proc.h>
65183724Ssos#include <sys/uio.h>
66183724Ssos#include <sys/malloc.h>
67183724Ssos#include <sys/dirent.h>
68183724Ssos
69183724Ssos#ifdef UNION
70183724Ssos#include <miscfs/union/union.h>
71183724Ssos#endif
72183724Ssos
73183724Ssos#include <vm/vm.h>
74183724Ssos#include <vm/vm_param.h>
75183724Ssos#include <vm/vm_object.h>
76183724Ssos#include <vm/vm_extern.h>
77183724Ssos#include <sys/sysctl.h>
78183724Ssos
79183724Ssosstatic int change_dir __P((struct nameidata *ndp, struct proc *p));
80183724Ssosstatic void checkdirs __P((struct vnode *olddp));
81183724Ssos
82183724Ssos/*
83183724Ssos * Virtual File System System Calls
84183724Ssos */
85183724Ssos
86183724Ssos/*
87183724Ssos * Mount a file system.
88183724Ssos */
89183724Ssos#ifndef _SYS_SYSPROTO_H_
90183724Ssosstruct mount_args {
91183724Ssos	char	*type;
92183724Ssos	char	*path;
93183724Ssos	int	flags;
94183724Ssos	caddr_t	data;
95183724Ssos};
96183724Ssos#endif
97183724Ssos/* ARGSUSED */
98183724Ssosint
99183724Ssosmount(p, uap, retval)
100183724Ssos	struct proc *p;
101183724Ssos	register struct mount_args /* {
102183724Ssos		syscallarg(char *) type;
103183724Ssos		syscallarg(char *) path;
104183724Ssos		syscallarg(int) flags;
105183724Ssos		syscallarg(caddr_t) data;
106183724Ssos	} */ *uap;
107183724Ssos	register_t *retval;
108183724Ssos{
109183724Ssos	struct vnode *vp;
110183724Ssos	struct mount *mp;
111183724Ssos	struct vfsconf *vfsp;
112183724Ssos	int error, flag = 0;
113183724Ssos	struct vattr va;
114183724Ssos	u_long fstypenum;
115183724Ssos	struct nameidata nd;
116183724Ssos	char fstypename[MFSNAMELEN];
117183724Ssos
118183724Ssos	/*
119183724Ssos	 * Get vnode to be covered
120183724Ssos	 */
121183724Ssos	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
122183724Ssos	    SCARG(uap, path), p);
123183724Ssos	if (error = namei(&nd))
124183724Ssos		return (error);
125183724Ssos	vp = nd.ni_vp;
126183724Ssos	if (SCARG(uap, flags) & MNT_UPDATE) {
127183724Ssos		if ((vp->v_flag & VROOT) == 0) {
128183724Ssos			vput(vp);
129183724Ssos			return (EINVAL);
130183724Ssos		}
131183724Ssos		mp = vp->v_mount;
132183724Ssos		flag = mp->mnt_flag;
133183724Ssos		/*
134183724Ssos		 * We only allow the filesystem to be reloaded if it
135183724Ssos		 * is currently mounted read-only.
136183724Ssos		 */
137183724Ssos		if ((SCARG(uap, flags) & MNT_RELOAD) &&
138183724Ssos		    ((mp->mnt_flag & MNT_RDONLY) == 0)) {
139183724Ssos			vput(vp);
140183724Ssos			return (EOPNOTSUPP);	/* Needs translation */
141188765Smav		}
142183724Ssos		mp->mnt_flag |=
143183724Ssos		    SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
144183724Ssos		/*
145183724Ssos		 * Only root, or the user that did the original mount is
146183724Ssos		 * permitted to update it.
147183724Ssos		 */
148183724Ssos		if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid &&
149183724Ssos		    (error = suser(p->p_ucred, &p->p_acflag))) {
150183724Ssos			vput(vp);
151183724Ssos			return (error);
152183724Ssos		}
153183724Ssos		/*
154183724Ssos		 * Do not allow NFS export by non-root users. Silently
155183724Ssos		 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
156183724Ssos		 */
157183724Ssos		if (p->p_ucred->cr_uid != 0) {
158183724Ssos			if (SCARG(uap, flags) & MNT_EXPORTED) {
159183724Ssos				vput(vp);
160183724Ssos				return (EPERM);
161183724Ssos			}
162183724Ssos			SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
163183724Ssos		}
164183724Ssos		if (vfs_busy(mp, LK_NOWAIT, 0, p)) {
165183724Ssos			vput(vp);
166183724Ssos			return (EBUSY);
167183724Ssos		}
168183724Ssos		VOP_UNLOCK(vp, 0, p);
169183724Ssos		goto update;
170183724Ssos	}
171183724Ssos	/*
172183724Ssos	 * If the user is not root, ensure that they own the directory
173183724Ssos	 * onto which we are attempting to mount.
174183724Ssos	 */
175183724Ssos	if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) ||
176183724Ssos	    (va.va_uid != p->p_ucred->cr_uid &&
177183724Ssos	     (error = suser(p->p_ucred, &p->p_acflag)))) {
178183724Ssos		vput(vp);
179183724Ssos		return (error);
180183724Ssos	}
181183724Ssos	/*
182183724Ssos	 * Do not allow NFS export by non-root users. Silently
183183724Ssos	 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
184183724Ssos	 */
185183724Ssos	if (p->p_ucred->cr_uid != 0) {
186183724Ssos		if (SCARG(uap, flags) & MNT_EXPORTED) {
187183724Ssos			vput(vp);
188183724Ssos			return (EPERM);
189188765Smav		}
190183724Ssos		SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
191183724Ssos	}
192183724Ssos	if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0))
193183724Ssos		return (error);
194183724Ssos	if (vp->v_type != VDIR) {
195183724Ssos		vput(vp);
196183724Ssos		return (ENOTDIR);
197183724Ssos	}
198183724Ssos#ifdef COMPAT_43
199183724Ssos	/*
200183724Ssos	 * Historically filesystem types were identified by number. If we
201183724Ssos	 * get an integer for the filesystem type instead of a string, we
202183724Ssos	 * check to see if it matches one of the historic filesystem types.
203183724Ssos	 */
204183724Ssos	fstypenum = (u_long)SCARG(uap, type);
205183724Ssos	if (fstypenum < maxvfsconf) {
206183724Ssos		for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
207183724Ssos			if (vfsp->vfc_typenum == fstypenum)
208188765Smav				break;
209183724Ssos		if (vfsp == NULL) {
210183724Ssos			vput(vp);
211183724Ssos			return (ENODEV);
212183724Ssos		}
213183724Ssos		strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN);
214183724Ssos	} else
215183724Ssos#endif /* COMPAT_43 */
216188765Smav	if (error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL)) {
217183724Ssos		vput(vp);
218183724Ssos		return (error);
219183724Ssos	}
220183724Ssos	for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
221183724Ssos		if (!strcmp(vfsp->vfc_name, fstypename))
222188765Smav			break;
223183724Ssos	if (vfsp == NULL) {
224183724Ssos		vput(vp);
225183724Ssos		return (ENODEV);
226183724Ssos	}
227183724Ssos	if (vp->v_mountedhere != NULL) {
228183724Ssos		vput(vp);
229183724Ssos		return (EBUSY);
230183724Ssos	}
231183724Ssos
232183724Ssos	/*
233183724Ssos	 * Allocate and initialize the filesystem.
234183724Ssos	 */
235183724Ssos	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
236183724Ssos		M_MOUNT, M_WAITOK);
237183724Ssos	bzero((char *)mp, (u_long)sizeof(struct mount));
238183724Ssos	lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0);
239183724Ssos	(void)vfs_busy(mp, LK_NOWAIT, 0, p);
240183724Ssos	mp->mnt_op = vfsp->vfc_vfsops;
241183724Ssos	mp->mnt_vfc = vfsp;
242183724Ssos	vfsp->vfc_refcount++;
243183724Ssos	mp->mnt_stat.f_type = vfsp->vfc_typenum;
244183724Ssos	mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
245183724Ssos	strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
246183724Ssos	vp->v_mountedhere = mp;
247183724Ssos	mp->mnt_vnodecovered = vp;
248183724Ssos	mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
249183724Ssosupdate:
250183724Ssos	/*
251183724Ssos	 * Set the mount level flags.
252183724Ssos	 */
253183724Ssos	if (SCARG(uap, flags) & MNT_RDONLY)
254183724Ssos		mp->mnt_flag |= MNT_RDONLY;
255183724Ssos	else if (mp->mnt_flag & MNT_RDONLY)
256183724Ssos		mp->mnt_flag |= MNT_WANTRDWR;
257183724Ssos	mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
258183724Ssos	    MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOATIME);
259183724Ssos	mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC |
260183724Ssos	    MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_FORCE |
261183724Ssos	    MNT_NOATIME);
262183724Ssos	/*
263183724Ssos	 * Mount the filesystem.
264183724Ssos	 */
265183724Ssos	error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p);
266183724Ssos	if (mp->mnt_flag & MNT_UPDATE) {
267183724Ssos		vrele(vp);
268183724Ssos		if (mp->mnt_flag & MNT_WANTRDWR)
269183724Ssos			mp->mnt_flag &= ~MNT_RDONLY;
270183724Ssos		mp->mnt_flag &=~
271183724Ssos		    (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
272183724Ssos		if (error)
273183724Ssos			mp->mnt_flag = flag;
274183724Ssos		vfs_unbusy(mp, p);
275183724Ssos		return (error);
276183724Ssos	}
277183724Ssos	/*
278183724Ssos	 * Put the new filesystem on the mount list after root.
279183724Ssos	 */
280183724Ssos	cache_purge(vp);
281183724Ssos	if (!error) {
282183724Ssos		simple_lock(&mountlist_slock);
283183724Ssos		CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
284183724Ssos		simple_unlock(&mountlist_slock);
285183724Ssos		checkdirs(vp);
286183724Ssos		VOP_UNLOCK(vp, 0, p);
287183724Ssos		vfs_unbusy(mp, p);
288183724Ssos		if (error = VFS_START(mp, 0, p))
289183724Ssos			vrele(vp);
290183724Ssos	} else {
291183724Ssos		mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
292183724Ssos		mp->mnt_vfc->vfc_refcount--;
293183724Ssos		vfs_unbusy(mp, p);
294183724Ssos		free((caddr_t)mp, M_MOUNT);
295183724Ssos		vput(vp);
296183724Ssos	}
297183724Ssos	return (error);
298183724Ssos}
299183724Ssos
300183724Ssos/*
301183724Ssos * Scan all active processes to see if any of them have a current
302188765Smav * or root directory onto which the new filesystem has just been
303183724Ssos * mounted. If so, replace them with the new mount point.
304183724Ssos */
305183724Ssosstatic void
306183724Ssoscheckdirs(olddp)
307183724Ssos	struct vnode *olddp;
308183724Ssos{
309183724Ssos	struct filedesc *fdp;
310183724Ssos	struct vnode *newdp;
311183724Ssos	struct proc *p;
312183724Ssos
313183724Ssos	if (olddp->v_usecount == 1)
314183724Ssos		return;
315183724Ssos	if (VFS_ROOT(olddp->v_mountedhere, &newdp))
316183724Ssos		panic("mount: lost mount");
317183724Ssos	for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
318183724Ssos		fdp = p->p_fd;
319183724Ssos		if (fdp->fd_cdir == olddp) {
320183724Ssos			vrele(fdp->fd_cdir);
321183724Ssos			VREF(newdp);
322183724Ssos			fdp->fd_cdir = newdp;
323183724Ssos		}
324183724Ssos		if (fdp->fd_rdir == olddp) {
325183724Ssos			vrele(fdp->fd_rdir);
326183724Ssos			VREF(newdp);
327183724Ssos			fdp->fd_rdir = newdp;
328183724Ssos		}
329183724Ssos	}
330183724Ssos	if (rootvnode == olddp) {
331183724Ssos		vrele(rootvnode);
332183724Ssos		VREF(newdp);
333183724Ssos		rootvnode = newdp;
334183724Ssos	}
335183724Ssos	vput(newdp);
336183724Ssos}
337183724Ssos
338183724Ssos/*
339183724Ssos * Unmount a file system.
340183724Ssos *
341183724Ssos * Note: unmount takes a path to the vnode mounted on as argument,
342183724Ssos * not special file (as before).
343183724Ssos */
344183724Ssos#ifndef _SYS_SYSPROTO_H_
345183724Ssosstruct unmount_args {
346183724Ssos	char	*path;
347183724Ssos	int	flags;
348183724Ssos};
349183724Ssos#endif
350183724Ssos/* ARGSUSED */
351183724Ssosint
352183724Ssosunmount(p, uap, retval)
353183724Ssos	struct proc *p;
354183724Ssos	register struct unmount_args /* {
355183724Ssos		syscallarg(char *) path;
356183724Ssos		syscallarg(int) flags;
357183724Ssos	} */ *uap;
358183724Ssos	register_t *retval;
359183724Ssos{
360183724Ssos	register struct vnode *vp;
361183724Ssos	struct mount *mp;
362183724Ssos	int error;
363183724Ssos	struct nameidata nd;
364183724Ssos
365183724Ssos	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
366183724Ssos	    SCARG(uap, path), p);
367183724Ssos	if (error = namei(&nd))
368183724Ssos		return (error);
369183724Ssos	vp = nd.ni_vp;
370183724Ssos	mp = vp->v_mount;
371183724Ssos
372183724Ssos	/*
373183724Ssos	 * Only root, or the user that did the original mount is
374183724Ssos	 * permitted to unmount this filesystem.
375183724Ssos	 */
376183724Ssos	if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) &&
377183724Ssos	    (error = suser(p->p_ucred, &p->p_acflag))) {
378183724Ssos		vput(vp);
379183724Ssos		return (error);
380183724Ssos	}
381183724Ssos
382183724Ssos	/*
383183724Ssos	 * Don't allow unmounting the root file system.
384183724Ssos	 */
385183724Ssos	if (mp->mnt_flag & MNT_ROOTFS) {
386183724Ssos		vput(vp);
387183724Ssos		return (EINVAL);
388183724Ssos	}
389183724Ssos
390183724Ssos	/*
391183724Ssos	 * Must be the root of the filesystem
392183724Ssos	 */
393183724Ssos	if ((vp->v_flag & VROOT) == 0) {
394183724Ssos		vput(vp);
395183724Ssos		return (EINVAL);
396183724Ssos	}
397183724Ssos	vput(vp);
398183724Ssos	return (dounmount(mp, SCARG(uap, flags), p));
399183724Ssos}
400183724Ssos
401183724Ssos/*
402183724Ssos * Do the actual file system unmount.
403183724Ssos */
404183724Ssosint
405183724Ssosdounmount(mp, flags, p)
406183724Ssos	register struct mount *mp;
407183724Ssos	int flags;
408183724Ssos	struct proc *p;
409183724Ssos{
410183724Ssos	struct vnode *coveredvp;
411183724Ssos	int error;
412183724Ssos
413183724Ssos	simple_lock(&mountlist_slock);
414183724Ssos	mp->mnt_flag |= MNT_UNMOUNT;
415183724Ssos	lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock, p);
416183724Ssos	mp->mnt_flag &=~ MNT_ASYNC;
417183724Ssos	vfs_msync(mp, MNT_NOWAIT);
418183724Ssos	vnode_pager_umount(mp);	/* release cached vnodes */
419183724Ssos	cache_purgevfs(mp);	/* remove cache entries for this file sys */
420183724Ssos	if (((mp->mnt_flag & MNT_RDONLY) ||
421183724Ssos	     (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) ||
422183724Ssos	    (flags & MNT_FORCE))
423183724Ssos		error = VFS_UNMOUNT(mp, flags, p);
424183724Ssos	simple_lock(&mountlist_slock);
425183724Ssos	if (error) {
426183724Ssos		mp->mnt_flag &= ~MNT_UNMOUNT;
427183724Ssos		lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE,
428183724Ssos		    &mountlist_slock, p);
429183724Ssos		return (error);
430183724Ssos	}
431183724Ssos	CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);
432183724Ssos	if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {
433183724Ssos		coveredvp->v_mountedhere = (struct mount *)0;
434183724Ssos		vrele(coveredvp);
435183724Ssos	}
436183724Ssos	mp->mnt_vfc->vfc_refcount--;
437183724Ssos	if (mp->mnt_vnodelist.lh_first != NULL)
438183724Ssos		panic("unmount: dangling vnode");
439183724Ssos	lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock, p);
440183724Ssos	if (mp->mnt_flag & MNT_MWAIT)
441183724Ssos		wakeup((caddr_t)mp);
442183724Ssos	free((caddr_t)mp, M_MOUNT);
443183724Ssos	return (0);
444183724Ssos}
445183724Ssos
446183724Ssos/*
447183724Ssos * Sync each mounted filesystem.
448183724Ssos */
449183724Ssos#ifndef _SYS_SYSPROTO_H_
450183724Ssosstruct sync_args {
451183724Ssos        int     dummy;
452183724Ssos};
453183724Ssos#endif
454183724Ssos
455183724Ssos#ifdef DEBUG
456183724Ssosint syncprt = 0;
457183724SsosSYSCTL_INT(_debug, 0, syncprt, CTLFLAG_RW, &syncprt, 0, "");
458183724Ssos#endif
459183724Ssos
460183724Ssos/* ARGSUSED */
461183724Ssosint
462183724Ssossync(p, uap, retval)
463183724Ssos	struct proc *p;
464183724Ssos	struct sync_args *uap;
465183724Ssos	register_t *retval;
466183724Ssos{
467183724Ssos	register struct mount *mp, *nmp;
468183724Ssos	int asyncflag;
469188765Smav
470183724Ssos	simple_lock(&mountlist_slock);
471183724Ssos	for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
472183724Ssos		if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
473183724Ssos			nmp = mp->mnt_list.cqe_next;
474183724Ssos			continue;
475188765Smav		}
476188765Smav		if ((mp->mnt_flag & MNT_RDONLY) == 0) {
477183724Ssos			asyncflag = mp->mnt_flag & MNT_ASYNC;
478183724Ssos			mp->mnt_flag &= ~MNT_ASYNC;
479183724Ssos			vfs_msync(mp, MNT_NOWAIT);
480183724Ssos			VFS_SYNC(mp, MNT_NOWAIT, p != NULL ? p->p_ucred : NOCRED, p);
481183724Ssos			if (asyncflag)
482183724Ssos				mp->mnt_flag |= MNT_ASYNC;
483183724Ssos		}
484183724Ssos		simple_lock(&mountlist_slock);
485183724Ssos		nmp = mp->mnt_list.cqe_next;
486183724Ssos		vfs_unbusy(mp, p);
487183724Ssos	}
488183724Ssos	simple_unlock(&mountlist_slock);
489183724Ssos#if 0
490183724Ssos/*
491183724Ssos * XXX don't call vfs_bufstats() yet because that routine
492183724Ssos * was not imported in the Lite2 merge.
493183724Ssos */
494183724Ssos#ifdef DIAGNOSTIC
495183724Ssos	if (syncprt)
496183724Ssos		vfs_bufstats();
497183724Ssos#endif /* DIAGNOSTIC */
498183724Ssos#endif
499183724Ssos	return (0);
500183724Ssos}
501183724Ssos
502183724Ssos/*
503183724Ssos * Change filesystem quotas.
504183724Ssos */
505183724Ssos#ifndef _SYS_SYSPROTO_H_
506183724Ssosstruct quotactl_args {
507183724Ssos	char *path;
508183724Ssos	int cmd;
509183724Ssos	int uid;
510183724Ssos	caddr_t arg;
511183724Ssos};
512183724Ssos#endif
513183724Ssos/* ARGSUSED */
514183724Ssosint
515183724Ssosquotactl(p, uap, retval)
516183724Ssos	struct proc *p;
517183724Ssos	register struct quotactl_args /* {
518183724Ssos		syscallarg(char *) path;
519183724Ssos		syscallarg(int) cmd;
520183724Ssos		syscallarg(int) uid;
521183724Ssos		syscallarg(caddr_t) arg;
522183724Ssos	} */ *uap;
523183724Ssos	register_t *retval;
524183724Ssos{
525183724Ssos	register struct mount *mp;
526183724Ssos	int error;
527183724Ssos	struct nameidata nd;
528183724Ssos
529183724Ssos	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
530183724Ssos	if (error = namei(&nd))
531183724Ssos		return (error);
532183724Ssos	mp = nd.ni_vp->v_mount;
533183724Ssos	vrele(nd.ni_vp);
534183724Ssos	return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
535183724Ssos	    SCARG(uap, arg), p));
536183724Ssos}
537183724Ssos
538183724Ssos/*
539183724Ssos * Get filesystem statistics.
540183724Ssos */
541183724Ssos#ifndef _SYS_SYSPROTO_H_
542183724Ssosstruct statfs_args {
543183724Ssos	char *path;
544183724Ssos	struct statfs *buf;
545183724Ssos};
546183724Ssos#endif
547183724Ssos/* ARGSUSED */
548183724Ssosint
549183724Ssosstatfs(p, uap, retval)
550183724Ssos	struct proc *p;
551183724Ssos	register struct statfs_args /* {
552183724Ssos		syscallarg(char *) path;
553183724Ssos		syscallarg(struct statfs *) buf;
554183724Ssos	} */ *uap;
555183724Ssos	register_t *retval;
556183724Ssos{
557183724Ssos	register struct mount *mp;
558183724Ssos	register struct statfs *sp;
559183724Ssos	int error;
560183724Ssos	struct nameidata nd;
561183724Ssos	struct statfs sb;
562183724Ssos
563183724Ssos	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
564183724Ssos	if (error = namei(&nd))
565183724Ssos		return (error);
566183724Ssos	mp = nd.ni_vp->v_mount;
567183724Ssos	sp = &mp->mnt_stat;
568183724Ssos	vrele(nd.ni_vp);
569183724Ssos	error = VFS_STATFS(mp, sp, p);
570183724Ssos	if (error)
571183724Ssos		return (error);
572183724Ssos	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
573183724Ssos	if (p->p_ucred->cr_uid != 0) {
574183724Ssos		bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
575183724Ssos		sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
576183724Ssos		sp = &sb;
577183724Ssos	}
578183724Ssos	return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
579183724Ssos}
580183724Ssos
581183724Ssos/*
582183724Ssos * Get filesystem statistics.
583183724Ssos */
584183724Ssos#ifndef _SYS_SYSPROTO_H_
585183724Ssosstruct fstatfs_args {
586183724Ssos	int fd;
587183724Ssos	struct statfs *buf;
588183724Ssos};
589183724Ssos#endif
590183724Ssos/* ARGSUSED */
591183724Ssosint
592183724Ssosfstatfs(p, uap, retval)
593183724Ssos	struct proc *p;
594183724Ssos	register struct fstatfs_args /* {
595183724Ssos		syscallarg(int) fd;
596183724Ssos		syscallarg(struct statfs *) buf;
597183724Ssos	} */ *uap;
598183724Ssos	register_t *retval;
599183724Ssos{
600183724Ssos	struct file *fp;
601183724Ssos	struct mount *mp;
602183724Ssos	register struct statfs *sp;
603183724Ssos	int error;
604183724Ssos	struct statfs sb;
605183724Ssos
606183724Ssos	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
607183724Ssos		return (error);
608183724Ssos	mp = ((struct vnode *)fp->f_data)->v_mount;
609183724Ssos	sp = &mp->mnt_stat;
610183724Ssos	error = VFS_STATFS(mp, sp, p);
611183724Ssos	if (error)
612183724Ssos		return (error);
613183724Ssos	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
614183724Ssos	if (p->p_ucred->cr_uid != 0) {
615183724Ssos		bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
616183724Ssos		sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
617183724Ssos		sp = &sb;
618183724Ssos	}
619183724Ssos	return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
620183724Ssos}
621183724Ssos
622183724Ssos/*
623183724Ssos * Get statistics on all filesystems.
624183724Ssos */
625183724Ssos#ifndef _SYS_SYSPROTO_H_
626183724Ssosstruct getfsstat_args {
627183724Ssos	struct statfs *buf;
628183724Ssos	long bufsize;
629183724Ssos	int flags;
630183724Ssos};
631183724Ssos#endif
632183724Ssosint
633183724Ssosgetfsstat(p, uap, retval)
634183724Ssos	struct proc *p;
635183724Ssos	register struct getfsstat_args /* {
636183724Ssos		syscallarg(struct statfs *) buf;
637183724Ssos		syscallarg(long) bufsize;
638183724Ssos		syscallarg(int) flags;
639183724Ssos	} */ *uap;
640183724Ssos	register_t *retval;
641183724Ssos{
642183724Ssos	register struct mount *mp, *nmp;
643183724Ssos	register struct statfs *sp;
644183724Ssos	caddr_t sfsp;
645183724Ssos	long count, maxcount, error;
646183724Ssos
647183724Ssos	maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
648183724Ssos	sfsp = (caddr_t)SCARG(uap, buf);
649183724Ssos	count = 0;
650183724Ssos	simple_lock(&mountlist_slock);
651183724Ssos	for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
652183724Ssos		if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
653183724Ssos			nmp = mp->mnt_list.cqe_next;
654183724Ssos			continue;
655183724Ssos		}
656183724Ssos		if (sfsp && count < maxcount) {
657183724Ssos			sp = &mp->mnt_stat;
658183724Ssos			/*
659183724Ssos			 * If MNT_NOWAIT is specified, do not refresh the
660183724Ssos			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
661183724Ssos			 */
662183724Ssos			if (((SCARG(uap, flags) & MNT_NOWAIT) == 0 ||
663183724Ssos			    (SCARG(uap, flags) & MNT_WAIT)) &&
664183724Ssos			    (error = VFS_STATFS(mp, sp, p))) {
665183724Ssos				simple_lock(&mountlist_slock);
666183724Ssos				nmp = mp->mnt_list.cqe_next;
667183724Ssos				vfs_unbusy(mp, p);
668183724Ssos				continue;
669183724Ssos			}
670183724Ssos			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
671183724Ssos			error = copyout((caddr_t)sp, sfsp, sizeof(*sp));
672183724Ssos			if (error) {
673183724Ssos				vfs_unbusy(mp, p);
674183724Ssos				return (error);
675183724Ssos			}
676183724Ssos			sfsp += sizeof(*sp);
677183724Ssos		}
678183724Ssos		count++;
679183724Ssos		simple_lock(&mountlist_slock);
680183724Ssos		nmp = mp->mnt_list.cqe_next;
681183724Ssos		vfs_unbusy(mp, p);
682183724Ssos	}
683183724Ssos	simple_unlock(&mountlist_slock);
684183724Ssos	if (sfsp && count > maxcount)
685183724Ssos		*retval = maxcount;
686183724Ssos	else
687183724Ssos		*retval = count;
688183724Ssos	return (0);
689183724Ssos}
690183724Ssos
691183724Ssos/*
692183724Ssos * Change current working directory to a given file descriptor.
693183724Ssos */
694183724Ssos#ifndef _SYS_SYSPROTO_H_
695183724Ssosstruct fchdir_args {
696183724Ssos	int	fd;
697183724Ssos};
698183724Ssos#endif
699183724Ssos/* ARGSUSED */
700183724Ssosint
701183724Ssosfchdir(p, uap, retval)
702183724Ssos	struct proc *p;
703183724Ssos	struct fchdir_args /* {
704183724Ssos		syscallarg(int) fd;
705183724Ssos	} */ *uap;
706183724Ssos	register_t *retval;
707183724Ssos{
708183724Ssos	register struct filedesc *fdp = p->p_fd;
709183724Ssos	struct vnode *vp, *tdp;
710183724Ssos	struct mount *mp;
711183724Ssos	struct file *fp;
712183724Ssos	int error;
713183724Ssos
714183724Ssos	if (error = getvnode(fdp, SCARG(uap, fd), &fp))
715183724Ssos		return (error);
716183724Ssos	vp = (struct vnode *)fp->f_data;
717183724Ssos	VREF(vp);
718183724Ssos	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
719183724Ssos	if (vp->v_type != VDIR)
720183724Ssos		error = ENOTDIR;
721183724Ssos	else
722183724Ssos		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
723183724Ssos	while (!error && (mp = vp->v_mountedhere) != NULL) {
724183724Ssos		if (vfs_busy(mp, 0, 0, p))
725183724Ssos			continue;
726183724Ssos		error = VFS_ROOT(mp, &tdp);
727183724Ssos		vfs_unbusy(mp, p);
728183724Ssos		if (error)
729183724Ssos			break;
730183724Ssos		vput(vp);
731183724Ssos		vp = tdp;
732183724Ssos	}
733183724Ssos	if (error) {
734183724Ssos		vput(vp);
735183724Ssos		return (error);
736183724Ssos	}
737183724Ssos	VOP_UNLOCK(vp, 0, p);
738183724Ssos	vrele(fdp->fd_cdir);
739183724Ssos	fdp->fd_cdir = vp;
740183724Ssos	return (0);
741183724Ssos}
742183724Ssos
743183724Ssos/*
744183724Ssos * Change current working directory (``.'').
745183724Ssos */
746183724Ssos#ifndef _SYS_SYSPROTO_H_
747183724Ssosstruct chdir_args {
748183724Ssos	char	*path;
749183724Ssos};
750183724Ssos#endif
751183724Ssos/* ARGSUSED */
752183724Ssosint
753183724Ssoschdir(p, uap, retval)
754183724Ssos	struct proc *p;
755183724Ssos	struct chdir_args /* {
756183724Ssos		syscallarg(char *) path;
757183724Ssos	} */ *uap;
758183724Ssos	register_t *retval;
759183724Ssos{
760183724Ssos	register struct filedesc *fdp = p->p_fd;
761183724Ssos	int error;
762183724Ssos	struct nameidata nd;
763183724Ssos
764183724Ssos	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
765183724Ssos	    SCARG(uap, path), p);
766183724Ssos	if (error = change_dir(&nd, p))
767183724Ssos		return (error);
768183724Ssos	vrele(fdp->fd_cdir);
769183724Ssos	fdp->fd_cdir = nd.ni_vp;
770183724Ssos	return (0);
771183724Ssos}
772183724Ssos
773183724Ssos/*
774183724Ssos * Change notion of root (``/'') directory.
775183724Ssos */
776183724Ssos#ifndef _SYS_SYSPROTO_H_
777183724Ssosstruct chroot_args {
778183724Ssos	char	*path;
779183724Ssos};
780183724Ssos#endif
781183724Ssos/* ARGSUSED */
782183724Ssosint
783183724Ssoschroot(p, uap, retval)
784183724Ssos	struct proc *p;
785183724Ssos	struct chroot_args /* {
786183724Ssos		syscallarg(char *) path;
787183724Ssos	} */ *uap;
788183724Ssos	register_t *retval;
789183724Ssos{
790183724Ssos	register struct filedesc *fdp = p->p_fd;
791183724Ssos	int error;
792183724Ssos	struct nameidata nd;
793183724Ssos
794183724Ssos	error = suser(p->p_ucred, &p->p_acflag);
795183724Ssos	if (error)
796183724Ssos		return (error);
797183724Ssos	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
798183724Ssos	    SCARG(uap, path), p);
799183724Ssos	if (error = change_dir(&nd, p))
800183724Ssos		return (error);
801183724Ssos	if (fdp->fd_rdir != NULL)
802183724Ssos		vrele(fdp->fd_rdir);
803183724Ssos	fdp->fd_rdir = nd.ni_vp;
804183724Ssos	return (0);
805183724Ssos}
806183724Ssos
807183724Ssos/*
808183724Ssos * Common routine for chroot and chdir.
809183724Ssos */
810183724Ssosstatic int
811183724Ssoschange_dir(ndp, p)
812183724Ssos	register struct nameidata *ndp;
813183724Ssos	struct proc *p;
814183724Ssos{
815183724Ssos	struct vnode *vp;
816183724Ssos	int error;
817183724Ssos
818183724Ssos	error = namei(ndp);
819183724Ssos	if (error)
820183724Ssos		return (error);
821183724Ssos	vp = ndp->ni_vp;
822183724Ssos	if (vp->v_type != VDIR)
823183724Ssos		error = ENOTDIR;
824183724Ssos	else
825183724Ssos		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
826183724Ssos	if (error)
827183724Ssos		vput(vp);
828183724Ssos	else
829183724Ssos		VOP_UNLOCK(vp, 0, p);
830183724Ssos	return (error);
831183724Ssos}
832183724Ssos
833183724Ssos/*
834183724Ssos * Check permissions, allocate an open file structure,
835183724Ssos * and call the device open routine if any.
836183724Ssos */
837183724Ssos#ifndef _SYS_SYSPROTO_H_
838183724Ssosstruct open_args {
839183724Ssos	char	*path;
840183724Ssos	int	flags;
841183724Ssos	int	mode;
842183724Ssos};
843183724Ssos#endif
844183724Ssosint
845183724Ssosopen(p, uap, retval)
846183724Ssos	struct proc *p;
847183724Ssos	register struct open_args /* {
848183724Ssos		syscallarg(char *) path;
849183724Ssos		syscallarg(int) flags;
850183724Ssos		syscallarg(int) mode;
851183724Ssos	} */ *uap;
852183724Ssos	register_t *retval;
853183724Ssos{
854183724Ssos	register struct filedesc *fdp = p->p_fd;
855183724Ssos	register struct file *fp;
856183724Ssos	register struct vnode *vp;
857183724Ssos	int flags, cmode;
858183724Ssos	struct file *nfp;
859183724Ssos	int type, indx, error;
860183724Ssos	struct flock lf;
861183724Ssos	struct nameidata nd;
862183724Ssos
863183724Ssos	error = falloc(p, &nfp, &indx);
864183724Ssos	if (error)
865183724Ssos		return (error);
866183724Ssos	fp = nfp;
867183724Ssos	flags = FFLAGS(SCARG(uap, flags));
868183724Ssos	cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
869183724Ssos	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
870183724Ssos	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
871183724Ssos	error = vn_open(&nd, flags, cmode);
872183724Ssos	if (error) {
873183724Ssos		ffree(fp);
874183724Ssos		if ((error == ENODEV || error == ENXIO) &&
875183724Ssos		    p->p_dupfd >= 0 &&			/* XXX from fdopen */
876183724Ssos		    (error =
877183724Ssos			dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
878183724Ssos			*retval = indx;
879183724Ssos			return (0);
880183724Ssos		}
881183724Ssos		if (error == ERESTART)
882183724Ssos			error = EINTR;
883183724Ssos		fdp->fd_ofiles[indx] = NULL;
884183724Ssos		return (error);
885183724Ssos	}
886183724Ssos	p->p_dupfd = 0;
887183724Ssos	vp = nd.ni_vp;
888183724Ssos
889183724Ssos	fp->f_flag = flags & FMASK;
890183724Ssos	fp->f_type = (vp->v_type == VFIFO ? DTYPE_FIFO : DTYPE_VNODE);
891183724Ssos	fp->f_ops = &vnops;
892	fp->f_data = (caddr_t)vp;
893	if (flags & (O_EXLOCK | O_SHLOCK)) {
894		lf.l_whence = SEEK_SET;
895		lf.l_start = 0;
896		lf.l_len = 0;
897		if (flags & O_EXLOCK)
898			lf.l_type = F_WRLCK;
899		else
900			lf.l_type = F_RDLCK;
901		type = F_FLOCK;
902		if ((flags & FNONBLOCK) == 0)
903			type |= F_WAIT;
904		VOP_UNLOCK(vp, 0, p);
905		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
906			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
907			ffree(fp);
908			fdp->fd_ofiles[indx] = NULL;
909			return (error);
910		}
911		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
912		fp->f_flag |= FHASLOCK;
913	}
914	VOP_UNLOCK(vp, 0, p);
915	*retval = indx;
916	return (0);
917}
918
919#ifdef COMPAT_43
920/*
921 * Create a file.
922 */
923#ifndef _SYS_SYSPROTO_H_
924struct ocreat_args {
925	char	*path;
926	int	mode;
927};
928#endif
929int
930ocreat(p, uap, retval)
931	struct proc *p;
932	register struct ocreat_args /* {
933		syscallarg(char *) path;
934		syscallarg(int) mode;
935	} */ *uap;
936	register_t *retval;
937{
938	struct open_args /* {
939		syscallarg(char *) path;
940		syscallarg(int) flags;
941		syscallarg(int) mode;
942	} */ nuap;
943
944	SCARG(&nuap, path) = SCARG(uap, path);
945	SCARG(&nuap, mode) = SCARG(uap, mode);
946	SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
947	return (open(p, &nuap, retval));
948}
949#endif /* COMPAT_43 */
950
951/*
952 * Create a special file.
953 */
954#ifndef _SYS_SYSPROTO_H_
955struct mknod_args {
956	char	*path;
957	int	mode;
958	int	dev;
959};
960#endif
961/* ARGSUSED */
962int
963mknod(p, uap, retval)
964	struct proc *p;
965	register struct mknod_args /* {
966		syscallarg(char *) path;
967		syscallarg(int) mode;
968		syscallarg(int) dev;
969	} */ *uap;
970	register_t *retval;
971{
972	register struct vnode *vp;
973	struct vattr vattr;
974	int error;
975	int whiteout;
976	struct nameidata nd;
977
978	error = suser(p->p_ucred, &p->p_acflag);
979	if (error)
980		return (error);
981	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
982	if (error = namei(&nd))
983		return (error);
984	vp = nd.ni_vp;
985	if (vp != NULL)
986		error = EEXIST;
987	else {
988		VATTR_NULL(&vattr);
989		vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
990		vattr.va_rdev = SCARG(uap, dev);
991		whiteout = 0;
992
993		switch (SCARG(uap, mode) & S_IFMT) {
994		case S_IFMT:	/* used by badsect to flag bad sectors */
995			vattr.va_type = VBAD;
996			break;
997		case S_IFCHR:
998			vattr.va_type = VCHR;
999			break;
1000		case S_IFBLK:
1001			vattr.va_type = VBLK;
1002			break;
1003		case S_IFWHT:
1004			whiteout = 1;
1005			break;
1006		default:
1007			error = EINVAL;
1008			break;
1009		}
1010	}
1011	if (!error) {
1012		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1013		if (whiteout) {
1014			error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
1015			if (error)
1016				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1017			vput(nd.ni_dvp);
1018		} else {
1019			error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
1020						&nd.ni_cnd, &vattr);
1021		}
1022	} else {
1023		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1024		if (nd.ni_dvp == vp)
1025			vrele(nd.ni_dvp);
1026		else
1027			vput(nd.ni_dvp);
1028		if (vp)
1029			vrele(vp);
1030	}
1031	return (error);
1032}
1033
1034/*
1035 * Create a named pipe.
1036 */
1037#ifndef _SYS_SYSPROTO_H_
1038struct mkfifo_args {
1039	char	*path;
1040	int	mode;
1041};
1042#endif
1043/* ARGSUSED */
1044int
1045mkfifo(p, uap, retval)
1046	struct proc *p;
1047	register struct mkfifo_args /* {
1048		syscallarg(char *) path;
1049		syscallarg(int) mode;
1050	} */ *uap;
1051	register_t *retval;
1052{
1053	struct vattr vattr;
1054	int error;
1055	struct nameidata nd;
1056
1057	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
1058	if (error = namei(&nd))
1059		return (error);
1060	if (nd.ni_vp != NULL) {
1061		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1062		if (nd.ni_dvp == nd.ni_vp)
1063			vrele(nd.ni_dvp);
1064		else
1065			vput(nd.ni_dvp);
1066		vrele(nd.ni_vp);
1067		return (EEXIST);
1068	}
1069	VATTR_NULL(&vattr);
1070	vattr.va_type = VFIFO;
1071	vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
1072	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1073	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
1074}
1075
1076/*
1077 * Make a hard file link.
1078 */
1079#ifndef _SYS_SYSPROTO_H_
1080struct link_args {
1081	char	*path;
1082	char	*link;
1083};
1084#endif
1085/* ARGSUSED */
1086int
1087link(p, uap, retval)
1088	struct proc *p;
1089	register struct link_args /* {
1090		syscallarg(char *) path;
1091		syscallarg(char *) link;
1092	} */ *uap;
1093	register_t *retval;
1094{
1095	register struct vnode *vp;
1096	struct nameidata nd;
1097	int error;
1098
1099	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1100	if (error = namei(&nd))
1101		return (error);
1102	vp = nd.ni_vp;
1103	if (vp->v_type == VDIR)
1104		error = EPERM;		/* POSIX */
1105	else {
1106		NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
1107		error = namei(&nd);
1108		if (!error) {
1109			if (nd.ni_vp != NULL) {
1110				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1111				if (nd.ni_dvp == nd.ni_vp)
1112					vrele(nd.ni_dvp);
1113				else
1114					vput(nd.ni_dvp);
1115				if (nd.ni_vp)
1116					vrele(nd.ni_vp);
1117				error = EEXIST;
1118			} else {
1119				VOP_LEASE(nd.ni_dvp, p, p->p_ucred,
1120				    LEASE_WRITE);
1121				VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1122				error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
1123			}
1124		}
1125	}
1126	vrele(vp);
1127	return (error);
1128}
1129
1130/*
1131 * Make a symbolic link.
1132 */
1133#ifndef _SYS_SYSPROTO_H_
1134struct symlink_args {
1135	char	*path;
1136	char	*link;
1137};
1138#endif
1139/* ARGSUSED */
1140int
1141symlink(p, uap, retval)
1142	struct proc *p;
1143	register struct symlink_args /* {
1144		syscallarg(char *) path;
1145		syscallarg(char *) link;
1146	} */ *uap;
1147	register_t *retval;
1148{
1149	struct vattr vattr;
1150	char *path;
1151	int error;
1152	struct nameidata nd;
1153
1154	MALLOC(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
1155	if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL))
1156		goto out;
1157	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
1158	if (error = namei(&nd))
1159		goto out;
1160	if (nd.ni_vp) {
1161		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1162		if (nd.ni_dvp == nd.ni_vp)
1163			vrele(nd.ni_dvp);
1164		else
1165			vput(nd.ni_dvp);
1166		vrele(nd.ni_vp);
1167		error = EEXIST;
1168		goto out;
1169	}
1170	VATTR_NULL(&vattr);
1171	vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
1172	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1173	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1174out:
1175	FREE(path, M_NAMEI);
1176	return (error);
1177}
1178
1179/*
1180 * Delete a whiteout from the filesystem.
1181 */
1182/* ARGSUSED */
1183int
1184undelete(p, uap, retval)
1185	struct proc *p;
1186	register struct undelete_args /* {
1187		syscallarg(char *) path;
1188	} */ *uap;
1189	register_t *retval;
1190{
1191	int error;
1192	struct nameidata nd;
1193
1194	NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
1195	    SCARG(uap, path), p);
1196	error = namei(&nd);
1197	if (error)
1198		return (error);
1199
1200	if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
1201		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1202		if (nd.ni_dvp == nd.ni_vp)
1203			vrele(nd.ni_dvp);
1204		else
1205			vput(nd.ni_dvp);
1206		if (nd.ni_vp)
1207			vrele(nd.ni_vp);
1208		return (EEXIST);
1209	}
1210
1211	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1212	if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE))
1213		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1214	vput(nd.ni_dvp);
1215	return (error);
1216}
1217
1218/*
1219 * Delete a name from the filesystem.
1220 */
1221#ifndef _SYS_SYSPROTO_H_
1222struct unlink_args {
1223	char	*path;
1224};
1225#endif
1226/* ARGSUSED */
1227int
1228unlink(p, uap, retval)
1229	struct proc *p;
1230	struct unlink_args /* {
1231		syscallarg(char *) path;
1232	} */ *uap;
1233	register_t *retval;
1234{
1235	register struct vnode *vp;
1236	int error;
1237	struct nameidata nd;
1238
1239	NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
1240	if (error = namei(&nd))
1241		return (error);
1242	vp = nd.ni_vp;
1243	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1244	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1245
1246	if (vp->v_type == VDIR)
1247		error = EPERM;		/* POSIX */
1248	else {
1249		/*
1250		 * The root of a mounted filesystem cannot be deleted.
1251		 *
1252		 * XXX: can this only be a VDIR case?
1253		 */
1254		if (vp->v_flag & VROOT)
1255			error = EBUSY;
1256		else
1257			(void) vnode_pager_uncache(vp, p);
1258	}
1259
1260	if (!error) {
1261		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1262		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1263	} else {
1264		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1265		if (nd.ni_dvp == vp)
1266			vrele(nd.ni_dvp);
1267		else
1268			vput(nd.ni_dvp);
1269		if (vp != NULLVP)
1270			vput(vp);
1271	}
1272	return (error);
1273}
1274
1275/*
1276 * Reposition read/write file offset.
1277 */
1278#ifndef _SYS_SYSPROTO_H_
1279struct lseek_args {
1280	int	fd;
1281	int	pad;
1282	off_t	offset;
1283	int	whence;
1284};
1285#endif
1286int
1287lseek(p, uap, retval)
1288	struct proc *p;
1289	register struct lseek_args /* {
1290		syscallarg(int) fd;
1291		syscallarg(int) pad;
1292		syscallarg(off_t) offset;
1293		syscallarg(int) whence;
1294	} */ *uap;
1295	register_t *retval;	/* XXX */
1296{
1297	struct ucred *cred = p->p_ucred;
1298	register struct filedesc *fdp = p->p_fd;
1299	register struct file *fp;
1300	struct vattr vattr;
1301	int error;
1302
1303	if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
1304	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
1305		return (EBADF);
1306	if (fp->f_type != DTYPE_VNODE)
1307		return (ESPIPE);
1308	switch (SCARG(uap, whence)) {
1309	case L_INCR:
1310		fp->f_offset += SCARG(uap, offset);
1311		break;
1312	case L_XTND:
1313		error=VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p);
1314		if (error)
1315			return (error);
1316		fp->f_offset = SCARG(uap, offset) + vattr.va_size;
1317		break;
1318	case L_SET:
1319		fp->f_offset = SCARG(uap, offset);
1320		break;
1321	default:
1322		return (EINVAL);
1323	}
1324	*(off_t *)retval = fp->f_offset;
1325	return (0);
1326}
1327
1328#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1329/*
1330 * Reposition read/write file offset.
1331 */
1332#ifndef _SYS_SYSPROTO_H_
1333struct olseek_args {
1334	int	fd;
1335	long	offset;
1336	int	whence;
1337};
1338#endif
1339int
1340olseek(p, uap, retval)
1341	struct proc *p;
1342	register struct olseek_args /* {
1343		syscallarg(int) fd;
1344		syscallarg(long) offset;
1345		syscallarg(int) whence;
1346	} */ *uap;
1347	register_t *retval;
1348{
1349	struct lseek_args /* {
1350		syscallarg(int) fd;
1351		syscallarg(int) pad;
1352		syscallarg(off_t) offset;
1353		syscallarg(int) whence;
1354	} */ nuap;
1355	off_t qret;
1356	int error;
1357
1358	SCARG(&nuap, fd) = SCARG(uap, fd);
1359	SCARG(&nuap, offset) = SCARG(uap, offset);
1360	SCARG(&nuap, whence) = SCARG(uap, whence);
1361	error = lseek(p, &nuap, (register_t *) &qret);
1362	*(long *)retval = qret;
1363	return (error);
1364}
1365#endif /* COMPAT_43 */
1366
1367/*
1368 * Check access permissions.
1369 */
1370#ifndef _SYS_SYSPROTO_H_
1371struct access_args {
1372	char	*path;
1373	int	flags;
1374};
1375#endif
1376int
1377access(p, uap, retval)
1378	struct proc *p;
1379	register struct access_args /* {
1380		syscallarg(char *) path;
1381		syscallarg(int) flags;
1382	} */ *uap;
1383	register_t *retval;
1384{
1385	register struct ucred *cred = p->p_ucred;
1386	register struct vnode *vp;
1387	int error, flags, t_gid, t_uid;
1388	struct nameidata nd;
1389
1390	t_uid = cred->cr_uid;
1391	t_gid = cred->cr_groups[0];
1392	cred->cr_uid = p->p_cred->p_ruid;
1393	cred->cr_groups[0] = p->p_cred->p_rgid;
1394	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1395	    SCARG(uap, path), p);
1396	if (error = namei(&nd))
1397		goto out1;
1398	vp = nd.ni_vp;
1399
1400	/* Flags == 0 means only check for existence. */
1401	if (SCARG(uap, flags)) {
1402		flags = 0;
1403		if (SCARG(uap, flags) & R_OK)
1404			flags |= VREAD;
1405		if (SCARG(uap, flags) & W_OK)
1406			flags |= VWRITE;
1407		if (SCARG(uap, flags) & X_OK)
1408			flags |= VEXEC;
1409		if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
1410			error = VOP_ACCESS(vp, flags, cred, p);
1411	}
1412	vput(vp);
1413out1:
1414	cred->cr_uid = t_uid;
1415	cred->cr_groups[0] = t_gid;
1416	return (error);
1417}
1418
1419#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1420/*
1421 * Get file status; this version follows links.
1422 */
1423#ifndef _SYS_SYSPROTO_H_
1424struct ostat_args {
1425	char	*path;
1426	struct ostat *ub;
1427};
1428#endif
1429/* ARGSUSED */
1430int
1431ostat(p, uap, retval)
1432	struct proc *p;
1433	register struct ostat_args /* {
1434		syscallarg(char *) path;
1435		syscallarg(struct ostat *) ub;
1436	} */ *uap;
1437	register_t *retval;
1438{
1439	struct stat sb;
1440	struct ostat osb;
1441	int error;
1442	struct nameidata nd;
1443
1444	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1445	    SCARG(uap, path), p);
1446	if (error = namei(&nd))
1447		return (error);
1448	error = vn_stat(nd.ni_vp, &sb, p);
1449	vput(nd.ni_vp);
1450	if (error)
1451		return (error);
1452	cvtstat(&sb, &osb);
1453	error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
1454	return (error);
1455}
1456
1457/*
1458 * Get file status; this version does not follow links.
1459 */
1460#ifndef _SYS_SYSPROTO_H_
1461struct olstat_args {
1462	char	*path;
1463	struct ostat *ub;
1464};
1465#endif
1466/* ARGSUSED */
1467int
1468olstat(p, uap, retval)
1469	struct proc *p;
1470	register struct olstat_args /* {
1471		syscallarg(char *) path;
1472		syscallarg(struct ostat *) ub;
1473	} */ *uap;
1474	register_t *retval;
1475{
1476	struct vnode *vp;
1477	struct stat sb;
1478	struct ostat osb;
1479	int error;
1480	struct nameidata nd;
1481
1482	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
1483	    SCARG(uap, path), p);
1484	if (error = namei(&nd))
1485		return (error);
1486	vp = nd.ni_vp;
1487	error = vn_stat(vp, &sb, p);
1488	if (vp->v_type == VLNK)
1489		sb.st_mode |= S_IFLNK | ACCESSPERMS;	/* 0777 */
1490	vput(vp);
1491	if (error)
1492		return (error);
1493	cvtstat(&sb, &osb);
1494	error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
1495	return (error);
1496}
1497
1498/*
1499 * Convert from an old to a new stat structure.
1500 */
1501void
1502cvtstat(st, ost)
1503	struct stat *st;
1504	struct ostat *ost;
1505{
1506
1507	ost->st_dev = st->st_dev;
1508	ost->st_ino = st->st_ino;
1509	ost->st_mode = st->st_mode;
1510	ost->st_nlink = st->st_nlink;
1511	ost->st_uid = st->st_uid;
1512	ost->st_gid = st->st_gid;
1513	ost->st_rdev = st->st_rdev;
1514	if (st->st_size < (quad_t)1 << 32)
1515		ost->st_size = st->st_size;
1516	else
1517		ost->st_size = -2;
1518	ost->st_atime = st->st_atime;
1519	ost->st_mtime = st->st_mtime;
1520	ost->st_ctime = st->st_ctime;
1521	ost->st_blksize = st->st_blksize;
1522	ost->st_blocks = st->st_blocks;
1523	ost->st_flags = st->st_flags;
1524	ost->st_gen = st->st_gen;
1525}
1526#endif /* COMPAT_43 || COMPAT_SUNOS */
1527
1528/*
1529 * Get file status; this version follows links.
1530 */
1531#ifndef _SYS_SYSPROTO_H_
1532struct stat_args {
1533	char	*path;
1534	struct stat *ub;
1535};
1536#endif
1537/* ARGSUSED */
1538int
1539stat(p, uap, retval)
1540	struct proc *p;
1541	register struct stat_args /* {
1542		syscallarg(char *) path;
1543		syscallarg(struct stat *) ub;
1544	} */ *uap;
1545	register_t *retval;
1546{
1547	struct stat sb;
1548	int error;
1549	struct nameidata nd;
1550
1551	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1552	    SCARG(uap, path), p);
1553	if (error = namei(&nd))
1554		return (error);
1555	error = vn_stat(nd.ni_vp, &sb, p);
1556	vput(nd.ni_vp);
1557	if (error)
1558		return (error);
1559	error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
1560	return (error);
1561}
1562
1563/*
1564 * Get file status; this version does not follow links.
1565 */
1566#ifndef _SYS_SYSPROTO_H_
1567struct lstat_args {
1568	char	*path;
1569	struct stat *ub;
1570};
1571#endif
1572/* ARGSUSED */
1573int
1574lstat(p, uap, retval)
1575	struct proc *p;
1576	register struct lstat_args /* {
1577		syscallarg(char *) path;
1578		syscallarg(struct stat *) ub;
1579	} */ *uap;
1580	register_t *retval;
1581{
1582	int error;
1583	struct vnode *vp;
1584	struct stat sb;
1585	struct nameidata nd;
1586
1587	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
1588	    SCARG(uap, path), p);
1589	if (error = namei(&nd))
1590		return (error);
1591	vp = nd.ni_vp;
1592	error = vn_stat(vp, &sb, p);
1593	if (vp->v_type == VLNK)
1594		sb.st_mode |= S_IFLNK | ACCESSPERMS;	/* 0777 */
1595	vput(vp);
1596	if (error)
1597		return (error);
1598	error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
1599	return (error);
1600}
1601
1602/*
1603 * Get configurable pathname variables.
1604 */
1605#ifndef _SYS_SYSPROTO_H_
1606struct pathconf_args {
1607	char	*path;
1608	int	name;
1609};
1610#endif
1611/* ARGSUSED */
1612int
1613pathconf(p, uap, retval)
1614	struct proc *p;
1615	register struct pathconf_args /* {
1616		syscallarg(char *) path;
1617		syscallarg(int) name;
1618	} */ *uap;
1619	register_t *retval;
1620{
1621	int error;
1622	struct nameidata nd;
1623
1624	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1625	    SCARG(uap, path), p);
1626	if (error = namei(&nd))
1627		return (error);
1628	error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), retval);
1629	vput(nd.ni_vp);
1630	return (error);
1631}
1632
1633/*
1634 * Return target name of a symbolic link.
1635 */
1636#ifndef _SYS_SYSPROTO_H_
1637struct readlink_args {
1638	char	*path;
1639	char	*buf;
1640	int	count;
1641};
1642#endif
1643/* ARGSUSED */
1644int
1645readlink(p, uap, retval)
1646	struct proc *p;
1647	register struct readlink_args /* {
1648		syscallarg(char *) path;
1649		syscallarg(char *) buf;
1650		syscallarg(int) count;
1651	} */ *uap;
1652	register_t *retval;
1653{
1654	register struct vnode *vp;
1655	struct iovec aiov;
1656	struct uio auio;
1657	int error;
1658	struct nameidata nd;
1659
1660	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
1661	    SCARG(uap, path), p);
1662	if (error = namei(&nd))
1663		return (error);
1664	vp = nd.ni_vp;
1665	if (vp->v_type != VLNK)
1666		error = EINVAL;
1667	else {
1668		aiov.iov_base = SCARG(uap, buf);
1669		aiov.iov_len = SCARG(uap, count);
1670		auio.uio_iov = &aiov;
1671		auio.uio_iovcnt = 1;
1672		auio.uio_offset = 0;
1673		auio.uio_rw = UIO_READ;
1674		auio.uio_segflg = UIO_USERSPACE;
1675		auio.uio_procp = p;
1676		auio.uio_resid = SCARG(uap, count);
1677		error = VOP_READLINK(vp, &auio, p->p_ucred);
1678	}
1679	vput(vp);
1680	*retval = SCARG(uap, count) - auio.uio_resid;
1681	return (error);
1682}
1683
1684/*
1685 * Change flags of a file given a path name.
1686 */
1687#ifndef _SYS_SYSPROTO_H_
1688struct chflags_args {
1689	char	*path;
1690	int	flags;
1691};
1692#endif
1693/* ARGSUSED */
1694int
1695chflags(p, uap, retval)
1696	struct proc *p;
1697	register struct chflags_args /* {
1698		syscallarg(char *) path;
1699		syscallarg(int) flags;
1700	} */ *uap;
1701	register_t *retval;
1702{
1703	register struct vnode *vp;
1704	struct vattr vattr;
1705	int error;
1706	struct nameidata nd;
1707
1708	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1709	if (error = namei(&nd))
1710		return (error);
1711	vp = nd.ni_vp;
1712	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1713	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1714	VATTR_NULL(&vattr);
1715	vattr.va_flags = SCARG(uap, flags);
1716	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1717	vput(vp);
1718	return (error);
1719}
1720
1721/*
1722 * Change flags of a file given a file descriptor.
1723 */
1724#ifndef _SYS_SYSPROTO_H_
1725struct fchflags_args {
1726	int	fd;
1727	int	flags;
1728};
1729#endif
1730/* ARGSUSED */
1731int
1732fchflags(p, uap, retval)
1733	struct proc *p;
1734	register struct fchflags_args /* {
1735		syscallarg(int) fd;
1736		syscallarg(int) flags;
1737	} */ *uap;
1738	register_t *retval;
1739{
1740	struct vattr vattr;
1741	struct vnode *vp;
1742	struct file *fp;
1743	int error;
1744
1745	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
1746		return (error);
1747	vp = (struct vnode *)fp->f_data;
1748	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1749	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1750	VATTR_NULL(&vattr);
1751	vattr.va_flags = SCARG(uap, flags);
1752	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1753	VOP_UNLOCK(vp, 0, p);
1754	return (error);
1755}
1756
1757/*
1758 * Change mode of a file given path name.
1759 */
1760#ifndef _SYS_SYSPROTO_H_
1761struct chmod_args {
1762	char	*path;
1763	int	mode;
1764};
1765#endif
1766/* ARGSUSED */
1767int
1768chmod(p, uap, retval)
1769	struct proc *p;
1770	register struct chmod_args /* {
1771		syscallarg(char *) path;
1772		syscallarg(int) mode;
1773	} */ *uap;
1774	register_t *retval;
1775{
1776	register struct vnode *vp;
1777	struct vattr vattr;
1778	int error;
1779	struct nameidata nd;
1780
1781	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1782	if (error = namei(&nd))
1783		return (error);
1784	vp = nd.ni_vp;
1785	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1786	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1787	VATTR_NULL(&vattr);
1788	vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
1789	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1790	vput(vp);
1791	return (error);
1792}
1793
1794/*
1795 * Change mode of a file given a file descriptor.
1796 */
1797#ifndef _SYS_SYSPROTO_H_
1798struct fchmod_args {
1799	int	fd;
1800	int	mode;
1801};
1802#endif
1803/* ARGSUSED */
1804int
1805fchmod(p, uap, retval)
1806	struct proc *p;
1807	register struct fchmod_args /* {
1808		syscallarg(int) fd;
1809		syscallarg(int) mode;
1810	} */ *uap;
1811	register_t *retval;
1812{
1813	struct vattr vattr;
1814	struct vnode *vp;
1815	struct file *fp;
1816	int error;
1817
1818	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
1819		return (error);
1820	vp = (struct vnode *)fp->f_data;
1821	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1822	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1823	VATTR_NULL(&vattr);
1824	vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
1825	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1826	VOP_UNLOCK(vp, 0, p);
1827	return (error);
1828}
1829
1830/*
1831 * Set ownership given a path name.
1832 */
1833#ifndef _SYS_SYSPROTO_H_
1834struct chown_args {
1835	char	*path;
1836	int	uid;
1837	int	gid;
1838};
1839#endif
1840/* ARGSUSED */
1841int
1842chown(p, uap, retval)
1843	struct proc *p;
1844	register struct chown_args /* {
1845		syscallarg(char *) path;
1846		syscallarg(int) uid;
1847		syscallarg(int) gid;
1848	} */ *uap;
1849	register_t *retval;
1850{
1851	register struct vnode *vp;
1852	struct vattr vattr;
1853	int error;
1854	struct nameidata nd;
1855
1856	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1857	if (error = namei(&nd))
1858		return (error);
1859	vp = nd.ni_vp;
1860	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1861	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1862	VATTR_NULL(&vattr);
1863	vattr.va_uid = SCARG(uap, uid);
1864	vattr.va_gid = SCARG(uap, gid);
1865	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1866	vput(vp);
1867	return (error);
1868}
1869
1870/*
1871 * Set ownership given a file descriptor.
1872 */
1873#ifndef _SYS_SYSPROTO_H_
1874struct fchown_args {
1875	int	fd;
1876	int	uid;
1877	int	gid;
1878};
1879#endif
1880/* ARGSUSED */
1881int
1882fchown(p, uap, retval)
1883	struct proc *p;
1884	register struct fchown_args /* {
1885		syscallarg(int) fd;
1886		syscallarg(int) uid;
1887		syscallarg(int) gid;
1888	} */ *uap;
1889	register_t *retval;
1890{
1891	struct vattr vattr;
1892	struct vnode *vp;
1893	struct file *fp;
1894	int error;
1895
1896	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
1897		return (error);
1898	vp = (struct vnode *)fp->f_data;
1899	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1900	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1901	VATTR_NULL(&vattr);
1902	vattr.va_uid = SCARG(uap, uid);
1903	vattr.va_gid = SCARG(uap, gid);
1904	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1905	VOP_UNLOCK(vp, 0, p);
1906	return (error);
1907}
1908
1909/*
1910 * Set the access and modification times of a file.
1911 */
1912#ifndef _SYS_SYSPROTO_H_
1913struct utimes_args {
1914	char	*path;
1915	struct	timeval *tptr;
1916};
1917#endif
1918/* ARGSUSED */
1919int
1920utimes(p, uap, retval)
1921	struct proc *p;
1922	register struct utimes_args /* {
1923		syscallarg(char *) path;
1924		syscallarg(struct timeval *) tptr;
1925	} */ *uap;
1926	register_t *retval;
1927{
1928	register struct vnode *vp;
1929	struct timeval tv[2];
1930	struct vattr vattr;
1931	int error;
1932	struct nameidata nd;
1933
1934	VATTR_NULL(&vattr);
1935	if (SCARG(uap, tptr) == NULL) {
1936		microtime(&tv[0]);
1937		tv[1] = tv[0];
1938		vattr.va_vaflags |= VA_UTIMES_NULL;
1939	} else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv,
1940	    sizeof (tv)))
1941  		return (error);
1942	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1943	if (error = namei(&nd))
1944		return (error);
1945	vp = nd.ni_vp;
1946	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1947	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1948	vattr.va_atime.tv_sec = tv[0].tv_sec;
1949	vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000;
1950	vattr.va_mtime.tv_sec = tv[1].tv_sec;
1951	vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000;
1952	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1953	vput(vp);
1954	return (error);
1955}
1956
1957/*
1958 * Truncate a file given its path name.
1959 */
1960#ifndef _SYS_SYSPROTO_H_
1961struct truncate_args {
1962	char	*path;
1963	int	pad;
1964	off_t	length;
1965};
1966#endif
1967/* ARGSUSED */
1968int
1969truncate(p, uap, retval)
1970	struct proc *p;
1971	register struct truncate_args /* {
1972		syscallarg(char *) path;
1973		syscallarg(int) pad;
1974		syscallarg(off_t) length;
1975	} */ *uap;
1976	register_t *retval;
1977{
1978	register struct vnode *vp;
1979	struct vattr vattr;
1980	int error;
1981	struct nameidata nd;
1982
1983	if (uap->length < 0)
1984		return(EINVAL);
1985	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1986	if (error = namei(&nd))
1987		return (error);
1988	vp = nd.ni_vp;
1989	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1990	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1991	if (vp->v_type == VDIR)
1992		error = EISDIR;
1993	else if ((error = vn_writechk(vp)) == 0 &&
1994	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
1995		VATTR_NULL(&vattr);
1996		vattr.va_size = SCARG(uap, length);
1997		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1998	}
1999	vput(vp);
2000	return (error);
2001}
2002
2003/*
2004 * Truncate a file given a file descriptor.
2005 */
2006#ifndef _SYS_SYSPROTO_H_
2007struct ftruncate_args {
2008	int	fd;
2009	int	pad;
2010	off_t	length;
2011};
2012#endif
2013/* ARGSUSED */
2014int
2015ftruncate(p, uap, retval)
2016	struct proc *p;
2017	register struct ftruncate_args /* {
2018		syscallarg(int) fd;
2019		syscallarg(int) pad;
2020		syscallarg(off_t) length;
2021	} */ *uap;
2022	register_t *retval;
2023{
2024	struct vattr vattr;
2025	struct vnode *vp;
2026	struct file *fp;
2027	int error;
2028
2029	if (uap->length < 0)
2030		return(EINVAL);
2031	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
2032		return (error);
2033	if ((fp->f_flag & FWRITE) == 0)
2034		return (EINVAL);
2035	vp = (struct vnode *)fp->f_data;
2036	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2037	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2038	if (vp->v_type == VDIR)
2039		error = EISDIR;
2040	else if ((error = vn_writechk(vp)) == 0) {
2041		VATTR_NULL(&vattr);
2042		vattr.va_size = SCARG(uap, length);
2043		error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
2044	}
2045	VOP_UNLOCK(vp, 0, p);
2046	return (error);
2047}
2048
2049#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
2050/*
2051 * Truncate a file given its path name.
2052 */
2053#ifndef _SYS_SYSPROTO_H_
2054struct otruncate_args {
2055	char	*path;
2056	long	length;
2057};
2058#endif
2059/* ARGSUSED */
2060int
2061otruncate(p, uap, retval)
2062	struct proc *p;
2063	register struct otruncate_args /* {
2064		syscallarg(char *) path;
2065		syscallarg(long) length;
2066	} */ *uap;
2067	register_t *retval;
2068{
2069	struct truncate_args /* {
2070		syscallarg(char *) path;
2071		syscallarg(int) pad;
2072		syscallarg(off_t) length;
2073	} */ nuap;
2074
2075	SCARG(&nuap, path) = SCARG(uap, path);
2076	SCARG(&nuap, length) = SCARG(uap, length);
2077	return (truncate(p, &nuap, retval));
2078}
2079
2080/*
2081 * Truncate a file given a file descriptor.
2082 */
2083#ifndef _SYS_SYSPROTO_H_
2084struct oftruncate_args {
2085	int	fd;
2086	long	length;
2087};
2088#endif
2089/* ARGSUSED */
2090int
2091oftruncate(p, uap, retval)
2092	struct proc *p;
2093	register struct oftruncate_args /* {
2094		syscallarg(int) fd;
2095		syscallarg(long) length;
2096	} */ *uap;
2097	register_t *retval;
2098{
2099	struct ftruncate_args /* {
2100		syscallarg(int) fd;
2101		syscallarg(int) pad;
2102		syscallarg(off_t) length;
2103	} */ nuap;
2104
2105	SCARG(&nuap, fd) = SCARG(uap, fd);
2106	SCARG(&nuap, length) = SCARG(uap, length);
2107	return (ftruncate(p, &nuap, retval));
2108}
2109#endif /* COMPAT_43 || COMPAT_SUNOS */
2110
2111/*
2112 * Sync an open file.
2113 */
2114#ifndef _SYS_SYSPROTO_H_
2115struct fsync_args {
2116	int	fd;
2117};
2118#endif
2119/* ARGSUSED */
2120int
2121fsync(p, uap, retval)
2122	struct proc *p;
2123	struct fsync_args /* {
2124		syscallarg(int) fd;
2125	} */ *uap;
2126	register_t *retval;
2127{
2128	register struct vnode *vp;
2129	struct file *fp;
2130	int error;
2131
2132	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
2133		return (error);
2134	vp = (struct vnode *)fp->f_data;
2135	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2136	if (vp->v_object) {
2137		vm_object_page_clean(vp->v_object, 0, 0 ,0, FALSE);
2138	}
2139	error = VOP_FSYNC(vp, fp->f_cred,
2140		(vp->v_mount && (vp->v_mount->mnt_flag & MNT_ASYNC)) ?
2141		MNT_NOWAIT : MNT_WAIT, p);
2142	VOP_UNLOCK(vp, 0, p);
2143	return (error);
2144}
2145
2146/*
2147 * Rename files.  Source and destination must either both be directories,
2148 * or both not be directories.  If target is a directory, it must be empty.
2149 */
2150#ifndef _SYS_SYSPROTO_H_
2151struct rename_args {
2152	char	*from;
2153	char	*to;
2154};
2155#endif
2156/* ARGSUSED */
2157int
2158rename(p, uap, retval)
2159	struct proc *p;
2160	register struct rename_args /* {
2161		syscallarg(char *) from;
2162		syscallarg(char *) to;
2163	} */ *uap;
2164	register_t *retval;
2165{
2166	register struct vnode *tvp, *fvp, *tdvp;
2167	struct nameidata fromnd, tond;
2168	int error;
2169
2170	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
2171	    SCARG(uap, from), p);
2172	if (error = namei(&fromnd))
2173		return (error);
2174	fvp = fromnd.ni_vp;
2175	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
2176	    UIO_USERSPACE, SCARG(uap, to), p);
2177	if (fromnd.ni_vp->v_type == VDIR)
2178		tond.ni_cnd.cn_flags |= WILLBEDIR;
2179	if (error = namei(&tond)) {
2180		/* Translate error code for rename("dir1", "dir2/."). */
2181		if (error == EISDIR && fvp->v_type == VDIR)
2182			error = EINVAL;
2183		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2184		vrele(fromnd.ni_dvp);
2185		vrele(fvp);
2186		goto out1;
2187	}
2188	tdvp = tond.ni_dvp;
2189	tvp = tond.ni_vp;
2190	if (tvp != NULL) {
2191		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
2192			error = ENOTDIR;
2193			goto out;
2194		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
2195			error = EISDIR;
2196			goto out;
2197		}
2198	}
2199	if (fvp == tdvp)
2200		error = EINVAL;
2201	/*
2202	 * If source is the same as the destination (that is the
2203	 * same inode number with the same name in the same directory),
2204	 * then there is nothing to do.
2205	 */
2206	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
2207	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
2208	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
2209	      fromnd.ni_cnd.cn_namelen))
2210		error = -1;
2211out:
2212	if (!error) {
2213		VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE);
2214		if (fromnd.ni_dvp != tdvp)
2215			VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2216		if (tvp) {
2217			VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE);
2218			(void) vnode_pager_uncache(tvp, p);
2219		}
2220		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
2221				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
2222	} else {
2223		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
2224		if (tdvp == tvp)
2225			vrele(tdvp);
2226		else
2227			vput(tdvp);
2228		if (tvp)
2229			vput(tvp);
2230		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2231		vrele(fromnd.ni_dvp);
2232		vrele(fvp);
2233	}
2234	vrele(tond.ni_startdir);
2235	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
2236out1:
2237	if (fromnd.ni_startdir)
2238		vrele(fromnd.ni_startdir);
2239	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
2240	if (error == -1)
2241		return (0);
2242	return (error);
2243}
2244
2245/*
2246 * Make a directory file.
2247 */
2248#ifndef _SYS_SYSPROTO_H_
2249struct mkdir_args {
2250	char	*path;
2251	int	mode;
2252};
2253#endif
2254/* ARGSUSED */
2255int
2256mkdir(p, uap, retval)
2257	struct proc *p;
2258	register struct mkdir_args /* {
2259		syscallarg(char *) path;
2260		syscallarg(int) mode;
2261	} */ *uap;
2262	register_t *retval;
2263{
2264	register struct vnode *vp;
2265	struct vattr vattr;
2266	int error;
2267	struct nameidata nd;
2268
2269	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
2270	nd.ni_cnd.cn_flags |= WILLBEDIR;
2271	if (error = namei(&nd))
2272		return (error);
2273	vp = nd.ni_vp;
2274	if (vp != NULL) {
2275		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2276		if (nd.ni_dvp == vp)
2277			vrele(nd.ni_dvp);
2278		else
2279			vput(nd.ni_dvp);
2280		vrele(vp);
2281		return (EEXIST);
2282	}
2283	VATTR_NULL(&vattr);
2284	vattr.va_type = VDIR;
2285	vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask;
2286	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2287	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
2288	if (!error)
2289		vput(nd.ni_vp);
2290	return (error);
2291}
2292
2293/*
2294 * Remove a directory file.
2295 */
2296#ifndef _SYS_SYSPROTO_H_
2297struct rmdir_args {
2298	char	*path;
2299};
2300#endif
2301/* ARGSUSED */
2302int
2303rmdir(p, uap, retval)
2304	struct proc *p;
2305	struct rmdir_args /* {
2306		syscallarg(char *) path;
2307	} */ *uap;
2308	register_t *retval;
2309{
2310	register struct vnode *vp;
2311	int error;
2312	struct nameidata nd;
2313
2314	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
2315	    SCARG(uap, path), p);
2316	if (error = namei(&nd))
2317		return (error);
2318	vp = nd.ni_vp;
2319	if (vp->v_type != VDIR) {
2320		error = ENOTDIR;
2321		goto out;
2322	}
2323	/*
2324	 * No rmdir "." please.
2325	 */
2326	if (nd.ni_dvp == vp) {
2327		error = EINVAL;
2328		goto out;
2329	}
2330	/*
2331	 * The root of a mounted filesystem cannot be deleted.
2332	 */
2333	if (vp->v_flag & VROOT)
2334		error = EBUSY;
2335out:
2336	if (!error) {
2337		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2338		VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2339		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2340	} else {
2341		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2342		if (nd.ni_dvp == vp)
2343			vrele(nd.ni_dvp);
2344		else
2345			vput(nd.ni_dvp);
2346		vput(vp);
2347	}
2348	return (error);
2349}
2350
2351#ifdef COMPAT_43
2352/*
2353 * Read a block of directory entries in a file system independent format.
2354 */
2355#ifndef _SYS_SYSPROTO_H_
2356struct ogetdirentries_args {
2357	int	fd;
2358	char	*buf;
2359	u_int	count;
2360	long	*basep;
2361};
2362#endif
2363int
2364ogetdirentries(p, uap, retval)
2365	struct proc *p;
2366	register struct ogetdirentries_args /* {
2367		syscallarg(int) fd;
2368		syscallarg(char *) buf;
2369		syscallarg(u_int) count;
2370		syscallarg(long *) basep;
2371	} */ *uap;
2372	register_t *retval;
2373{
2374	register struct vnode *vp;
2375	struct file *fp;
2376	struct uio auio, kuio;
2377	struct iovec aiov, kiov;
2378	struct dirent *dp, *edp;
2379	caddr_t dirbuf;
2380	int error, eofflag, readcnt;
2381	long loff;
2382
2383	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
2384		return (error);
2385	if ((fp->f_flag & FREAD) == 0)
2386		return (EBADF);
2387	vp = (struct vnode *)fp->f_data;
2388unionread:
2389	if (vp->v_type != VDIR)
2390		return (EINVAL);
2391	aiov.iov_base = SCARG(uap, buf);
2392	aiov.iov_len = SCARG(uap, count);
2393	auio.uio_iov = &aiov;
2394	auio.uio_iovcnt = 1;
2395	auio.uio_rw = UIO_READ;
2396	auio.uio_segflg = UIO_USERSPACE;
2397	auio.uio_procp = p;
2398	auio.uio_resid = SCARG(uap, count);
2399	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2400	loff = auio.uio_offset = fp->f_offset;
2401#	if (BYTE_ORDER != LITTLE_ENDIAN)
2402		if (vp->v_mount->mnt_maxsymlinklen <= 0) {
2403			error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
2404			    NULL, NULL);
2405			fp->f_offset = auio.uio_offset;
2406		} else
2407#	endif
2408	{
2409		kuio = auio;
2410		kuio.uio_iov = &kiov;
2411		kuio.uio_segflg = UIO_SYSSPACE;
2412		kiov.iov_len = SCARG(uap, count);
2413		MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK);
2414		kiov.iov_base = dirbuf;
2415		error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
2416			    NULL, NULL);
2417		fp->f_offset = kuio.uio_offset;
2418		if (error == 0) {
2419			readcnt = SCARG(uap, count) - kuio.uio_resid;
2420			edp = (struct dirent *)&dirbuf[readcnt];
2421			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
2422#				if (BYTE_ORDER == LITTLE_ENDIAN)
2423					/*
2424					 * The expected low byte of
2425					 * dp->d_namlen is our dp->d_type.
2426					 * The high MBZ byte of dp->d_namlen
2427					 * is our dp->d_namlen.
2428					 */
2429					dp->d_type = dp->d_namlen;
2430					dp->d_namlen = 0;
2431#				else
2432					/*
2433					 * The dp->d_type is the high byte
2434					 * of the expected dp->d_namlen,
2435					 * so must be zero'ed.
2436					 */
2437					dp->d_type = 0;
2438#				endif
2439				if (dp->d_reclen > 0) {
2440					dp = (struct dirent *)
2441					    ((char *)dp + dp->d_reclen);
2442				} else {
2443					error = EIO;
2444					break;
2445				}
2446			}
2447			if (dp >= edp)
2448				error = uiomove(dirbuf, readcnt, &auio);
2449		}
2450		FREE(dirbuf, M_TEMP);
2451	}
2452	VOP_UNLOCK(vp, 0, p);
2453	if (error)
2454		return (error);
2455
2456#ifdef UNION
2457{
2458	if ((SCARG(uap, count) == auio.uio_resid) &&
2459	    (vp->v_op == union_vnodeop_p)) {
2460		struct vnode *lvp;
2461
2462		lvp = union_dircache(vp, p);
2463		if (lvp != NULLVP) {
2464			struct vattr va;
2465
2466			/*
2467			 * If the directory is opaque,
2468			 * then don't show lower entries
2469			 */
2470			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
2471			if (va.va_flags & OPAQUE) {
2472				vput(lvp);
2473				lvp = NULL;
2474			}
2475		}
2476
2477		if (lvp != NULLVP) {
2478			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
2479			if (error) {
2480				vput(lvp);
2481				return (error);
2482			}
2483			VOP_UNLOCK(lvp, 0, p);
2484			fp->f_data = (caddr_t) lvp;
2485			fp->f_offset = 0;
2486			error = vn_close(vp, FREAD, fp->f_cred, p);
2487			if (error)
2488				return (error);
2489			vp = lvp;
2490			goto unionread;
2491		}
2492	}
2493}
2494#endif /* UNION */
2495
2496	if ((SCARG(uap, count) == auio.uio_resid) &&
2497	    (vp->v_flag & VROOT) &&
2498	    (vp->v_mount->mnt_flag & MNT_UNION)) {
2499		struct vnode *tvp = vp;
2500		vp = vp->v_mount->mnt_vnodecovered;
2501		VREF(vp);
2502		fp->f_data = (caddr_t) vp;
2503		fp->f_offset = 0;
2504		vrele(tvp);
2505		goto unionread;
2506	}
2507	error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
2508	    sizeof(long));
2509	*retval = SCARG(uap, count) - auio.uio_resid;
2510	return (error);
2511}
2512#endif /* COMPAT_43 */
2513
2514/*
2515 * Read a block of directory entries in a file system independent format.
2516 */
2517#ifndef _SYS_SYSPROTO_H_
2518struct getdirentries_args {
2519	int	fd;
2520	char	*buf;
2521	u_int	count;
2522	long	*basep;
2523};
2524#endif
2525int
2526getdirentries(p, uap, retval)
2527	struct proc *p;
2528	register struct getdirentries_args /* {
2529		syscallarg(int) fd;
2530		syscallarg(char *) buf;
2531		syscallarg(u_int) count;
2532		syscallarg(long *) basep;
2533	} */ *uap;
2534	register_t *retval;
2535{
2536	register struct vnode *vp;
2537	struct file *fp;
2538	struct uio auio;
2539	struct iovec aiov;
2540	long loff;
2541	int error, eofflag;
2542
2543	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
2544		return (error);
2545	if ((fp->f_flag & FREAD) == 0)
2546		return (EBADF);
2547	vp = (struct vnode *)fp->f_data;
2548unionread:
2549	if (vp->v_type != VDIR)
2550		return (EINVAL);
2551	aiov.iov_base = SCARG(uap, buf);
2552	aiov.iov_len = SCARG(uap, count);
2553	auio.uio_iov = &aiov;
2554	auio.uio_iovcnt = 1;
2555	auio.uio_rw = UIO_READ;
2556	auio.uio_segflg = UIO_USERSPACE;
2557	auio.uio_procp = p;
2558	auio.uio_resid = SCARG(uap, count);
2559	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2560	loff = auio.uio_offset = fp->f_offset;
2561	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, NULL);
2562	fp->f_offset = auio.uio_offset;
2563	VOP_UNLOCK(vp, 0, p);
2564	if (error)
2565		return (error);
2566
2567#ifdef UNION
2568{
2569	if ((SCARG(uap, count) == auio.uio_resid) &&
2570	    (vp->v_op == union_vnodeop_p)) {
2571		struct vnode *lvp;
2572
2573		lvp = union_dircache(vp, p);
2574		if (lvp != NULLVP) {
2575			struct vattr va;
2576
2577			/*
2578			 * If the directory is opaque,
2579			 * then don't show lower entries
2580			 */
2581			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
2582			if (va.va_flags & OPAQUE) {
2583				vput(lvp);
2584				lvp = NULL;
2585			}
2586		}
2587
2588		if (lvp != NULLVP) {
2589			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
2590			if (error) {
2591				vput(lvp);
2592				return (error);
2593			}
2594			VOP_UNLOCK(lvp, 0, p);
2595			fp->f_data = (caddr_t) lvp;
2596			fp->f_offset = 0;
2597			error = vn_close(vp, FREAD, fp->f_cred, p);
2598			if (error)
2599				return (error);
2600			vp = lvp;
2601			goto unionread;
2602		}
2603	}
2604}
2605#endif /* UNION */
2606
2607	if ((SCARG(uap, count) == auio.uio_resid) &&
2608	    (vp->v_flag & VROOT) &&
2609	    (vp->v_mount->mnt_flag & MNT_UNION)) {
2610		struct vnode *tvp = vp;
2611		vp = vp->v_mount->mnt_vnodecovered;
2612		VREF(vp);
2613		fp->f_data = (caddr_t) vp;
2614		fp->f_offset = 0;
2615		vrele(tvp);
2616		goto unionread;
2617	}
2618	error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
2619	    sizeof(long));
2620	*retval = SCARG(uap, count) - auio.uio_resid;
2621	return (error);
2622}
2623
2624/*
2625 * Set the mode mask for creation of filesystem nodes.
2626 */
2627#ifndef _SYS_SYSPROTO_H_
2628struct umask_args {
2629	int	newmask;
2630};
2631#endif
2632int
2633umask(p, uap, retval)
2634	struct proc *p;
2635	struct umask_args /* {
2636		syscallarg(int) newmask;
2637	} */ *uap;
2638	int *retval;	/* XXX */
2639{
2640	register struct filedesc *fdp;
2641
2642	fdp = p->p_fd;
2643	*retval = fdp->fd_cmask;
2644	fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS;
2645	return (0);
2646}
2647
2648/*
2649 * Void all references to file by ripping underlying filesystem
2650 * away from vnode.
2651 */
2652#ifndef _SYS_SYSPROTO_H_
2653struct revoke_args {
2654	char	*path;
2655};
2656#endif
2657/* ARGSUSED */
2658int
2659revoke(p, uap, retval)
2660	struct proc *p;
2661	register struct revoke_args /* {
2662		syscallarg(char *) path;
2663	} */ *uap;
2664	register_t *retval;
2665{
2666	register struct vnode *vp;
2667	struct vattr vattr;
2668	int error;
2669	struct nameidata nd;
2670
2671	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2672	if (error = namei(&nd))
2673		return (error);
2674	vp = nd.ni_vp;
2675	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
2676		goto out;
2677	if (p->p_ucred->cr_uid != vattr.va_uid &&
2678	    (error = suser(p->p_ucred, &p->p_acflag)))
2679		goto out;
2680	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
2681		VOP_REVOKE(vp, REVOKEALL);
2682out:
2683	vrele(vp);
2684	return (error);
2685}
2686
2687/*
2688 * Convert a user file descriptor to a kernel file entry.
2689 */
2690int
2691getvnode(fdp, fd, fpp)
2692	struct filedesc *fdp;
2693	int fd;
2694	struct file **fpp;
2695{
2696	struct file *fp;
2697
2698	if ((u_int)fd >= fdp->fd_nfiles ||
2699	    (fp = fdp->fd_ofiles[fd]) == NULL)
2700		return (EBADF);
2701	if (fp->f_type != DTYPE_VNODE && fp->f_type != DTYPE_FIFO)
2702		return (EINVAL);
2703	*fpp = fp;
2704	return (0);
2705}
2706