vfs_syscalls.c revision 30994
1/*
2 * Copyright (c) 1989, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *	This product includes software developed by the University of
21 *	California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 *    may be used to endorse or promote products derived from this software
24 *    without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 *	@(#)vfs_syscalls.c	8.13 (Berkeley) 4/15/94
39 * $Id: vfs_syscalls.c,v 1.79 1997/10/28 10:29:55 bde Exp $
40 */
41
42/*
43 * XXX - The following is required because of some magic done
44 * in getdirentries() below which is only done if the translucent
45 * filesystem `UNION' is compiled into the kernel.  This is broken,
46 * but I don't have time to study the code deeply enough to understand
47 * what's going on and determine an appropriate fix.  -GAW
48 */
49#include "opt_union.h"
50
51#include <sys/param.h>
52#include <sys/systm.h>
53#include <sys/sysent.h>
54#include <sys/sysproto.h>
55#include <sys/namei.h>
56#include <sys/filedesc.h>
57#include <sys/kernel.h>
58#include <sys/fcntl.h>
59#include <sys/file.h>
60#include <sys/stat.h>
61#include <sys/unistd.h>
62#include <sys/vnode.h>
63#include <sys/malloc.h>
64#include <sys/mount.h>
65#include <sys/proc.h>
66#include <sys/dirent.h>
67
68#ifdef UNION
69#include <miscfs/union/union.h>
70#endif
71
72#include <vm/vm.h>
73#include <vm/vm_object.h>
74#include <vm/vm_extern.h>
75#include <sys/sysctl.h>
76
77static int change_dir __P((struct nameidata *ndp, struct proc *p));
78static void checkdirs __P((struct vnode *olddp));
79
80static int	usermount = 0;	/* if 1, non-root can mount fs. */
81
82SYSCTL_INT(_vfs, OID_AUTO, usermount, CTLFLAG_RW, &usermount, 0, "");
83
84/*
85 * Virtual File System System Calls
86 */
87
88/*
89 * Mount a file system.
90 */
91#ifndef _SYS_SYSPROTO_H_
92struct mount_args {
93	char	*type;
94	char	*path;
95	int	flags;
96	caddr_t	data;
97};
98#endif
99/* ARGSUSED */
100int
101mount(p, uap)
102	struct proc *p;
103	register struct mount_args /* {
104		syscallarg(char *) type;
105		syscallarg(char *) path;
106		syscallarg(int) flags;
107		syscallarg(caddr_t) data;
108	} */ *uap;
109{
110	struct vnode *vp;
111	struct mount *mp;
112	struct vfsconf *vfsp;
113	int error, flag = 0;
114	struct vattr va;
115	u_long fstypenum;
116	struct nameidata nd;
117	char fstypename[MFSNAMELEN];
118
119	if (usermount == 0 && (error = suser(p->p_ucred, &p->p_acflag)))
120		return (error);
121
122	/*
123	 * Get vnode to be covered
124	 */
125	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
126	    SCARG(uap, path), p);
127	if (error = namei(&nd))
128		return (error);
129	vp = nd.ni_vp;
130	if (SCARG(uap, flags) & MNT_UPDATE) {
131		if ((vp->v_flag & VROOT) == 0) {
132			vput(vp);
133			return (EINVAL);
134		}
135		mp = vp->v_mount;
136		flag = mp->mnt_flag;
137		/*
138		 * We only allow the filesystem to be reloaded if it
139		 * is currently mounted read-only.
140		 */
141		if ((SCARG(uap, flags) & MNT_RELOAD) &&
142		    ((mp->mnt_flag & MNT_RDONLY) == 0)) {
143			vput(vp);
144			return (EOPNOTSUPP);	/* Needs translation */
145		}
146		mp->mnt_flag |=
147		    SCARG(uap, flags) & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
148		/*
149		 * Only root, or the user that did the original mount is
150		 * permitted to update it.
151		 */
152		if (mp->mnt_stat.f_owner != p->p_ucred->cr_uid &&
153		    (error = suser(p->p_ucred, &p->p_acflag))) {
154			vput(vp);
155			return (error);
156		}
157		/*
158		 * Do not allow NFS export by non-root users. Silently
159		 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
160		 */
161		if (p->p_ucred->cr_uid != 0) {
162			if (SCARG(uap, flags) & MNT_EXPORTED) {
163				vput(vp);
164				return (EPERM);
165			}
166			SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
167		}
168		if (vfs_busy(mp, LK_NOWAIT, 0, p)) {
169			vput(vp);
170			return (EBUSY);
171		}
172		VOP_UNLOCK(vp, 0, p);
173		goto update;
174	}
175	/*
176	 * If the user is not root, ensure that they own the directory
177	 * onto which we are attempting to mount.
178	 */
179	if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)) ||
180	    (va.va_uid != p->p_ucred->cr_uid &&
181	     (error = suser(p->p_ucred, &p->p_acflag)))) {
182		vput(vp);
183		return (error);
184	}
185	/*
186	 * Do not allow NFS export by non-root users. Silently
187	 * enforce MNT_NOSUID and MNT_NODEV for non-root users.
188	 */
189	if (p->p_ucred->cr_uid != 0) {
190		if (SCARG(uap, flags) & MNT_EXPORTED) {
191			vput(vp);
192			return (EPERM);
193		}
194		SCARG(uap, flags) |= MNT_NOSUID | MNT_NODEV;
195	}
196	if (error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0))
197		return (error);
198	if (vp->v_type != VDIR) {
199		vput(vp);
200		return (ENOTDIR);
201	}
202#ifdef COMPAT_43
203	/*
204	 * Historically filesystem types were identified by number. If we
205	 * get an integer for the filesystem type instead of a string, we
206	 * check to see if it matches one of the historic filesystem types.
207	 */
208	fstypenum = (u_long)SCARG(uap, type);
209	if (fstypenum < maxvfsconf) {
210		for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
211			if (vfsp->vfc_typenum == fstypenum)
212				break;
213		if (vfsp == NULL) {
214			vput(vp);
215			return (ENODEV);
216		}
217		strncpy(fstypename, vfsp->vfc_name, MFSNAMELEN);
218	} else
219#endif /* COMPAT_43 */
220	if (error = copyinstr(SCARG(uap, type), fstypename, MFSNAMELEN, NULL)) {
221		vput(vp);
222		return (error);
223	}
224	for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
225		if (!strcmp(vfsp->vfc_name, fstypename))
226			break;
227	if (vfsp == NULL) {
228		vput(vp);
229		return (ENODEV);
230	}
231	if (vp->v_mountedhere != NULL) {
232		vput(vp);
233		return (EBUSY);
234	}
235
236	/*
237	 * Allocate and initialize the filesystem.
238	 */
239	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
240		M_MOUNT, M_WAITOK);
241	bzero((char *)mp, (u_long)sizeof(struct mount));
242	lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, 0);
243	(void)vfs_busy(mp, LK_NOWAIT, 0, p);
244	mp->mnt_op = vfsp->vfc_vfsops;
245	mp->mnt_vfc = vfsp;
246	vfsp->vfc_refcount++;
247	mp->mnt_stat.f_type = vfsp->vfc_typenum;
248	mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
249	strncpy(mp->mnt_stat.f_fstypename, vfsp->vfc_name, MFSNAMELEN);
250	vp->v_mountedhere = mp;
251	mp->mnt_vnodecovered = vp;
252	mp->mnt_stat.f_owner = p->p_ucred->cr_uid;
253update:
254	/*
255	 * Set the mount level flags.
256	 */
257	if (SCARG(uap, flags) & MNT_RDONLY)
258		mp->mnt_flag |= MNT_RDONLY;
259	else if (mp->mnt_flag & MNT_RDONLY)
260		mp->mnt_flag |= MNT_WANTRDWR;
261	mp->mnt_flag &=~ (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
262	    MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_NOATIME |
263	    MNT_NOCLUSTERR | MNT_NOCLUSTERW);
264	mp->mnt_flag |= SCARG(uap, flags) & (MNT_NOSUID | MNT_NOEXEC |
265	    MNT_NODEV | MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC | MNT_FORCE |
266	    MNT_NOATIME | MNT_NOCLUSTERR | MNT_NOCLUSTERW);
267	/*
268	 * Mount the filesystem.
269	 */
270	error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p);
271	if (mp->mnt_flag & MNT_UPDATE) {
272		vrele(vp);
273		if (mp->mnt_flag & MNT_WANTRDWR)
274			mp->mnt_flag &= ~MNT_RDONLY;
275		mp->mnt_flag &=~
276		    (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_WANTRDWR);
277		if (error)
278			mp->mnt_flag = flag;
279		vfs_unbusy(mp, p);
280		return (error);
281	}
282	/*
283	 * Put the new filesystem on the mount list after root.
284	 */
285	cache_purge(vp);
286	if (!error) {
287		simple_lock(&mountlist_slock);
288		CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
289		simple_unlock(&mountlist_slock);
290		checkdirs(vp);
291		VOP_UNLOCK(vp, 0, p);
292		vfs_unbusy(mp, p);
293		if (error = VFS_START(mp, 0, p))
294			vrele(vp);
295	} else {
296		mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
297		mp->mnt_vfc->vfc_refcount--;
298		vfs_unbusy(mp, p);
299		free((caddr_t)mp, M_MOUNT);
300		vput(vp);
301	}
302	return (error);
303}
304
305/*
306 * Scan all active processes to see if any of them have a current
307 * or root directory onto which the new filesystem has just been
308 * mounted. If so, replace them with the new mount point.
309 */
310static void
311checkdirs(olddp)
312	struct vnode *olddp;
313{
314	struct filedesc *fdp;
315	struct vnode *newdp;
316	struct proc *p;
317
318	if (olddp->v_usecount == 1)
319		return;
320	if (VFS_ROOT(olddp->v_mountedhere, &newdp))
321		panic("mount: lost mount");
322	for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
323		fdp = p->p_fd;
324		if (fdp->fd_cdir == olddp) {
325			vrele(fdp->fd_cdir);
326			VREF(newdp);
327			fdp->fd_cdir = newdp;
328		}
329		if (fdp->fd_rdir == olddp) {
330			vrele(fdp->fd_rdir);
331			VREF(newdp);
332			fdp->fd_rdir = newdp;
333		}
334	}
335	if (rootvnode == olddp) {
336		vrele(rootvnode);
337		VREF(newdp);
338		rootvnode = newdp;
339	}
340	vput(newdp);
341}
342
343/*
344 * Unmount a file system.
345 *
346 * Note: unmount takes a path to the vnode mounted on as argument,
347 * not special file (as before).
348 */
349#ifndef _SYS_SYSPROTO_H_
350struct unmount_args {
351	char	*path;
352	int	flags;
353};
354#endif
355/* ARGSUSED */
356int
357unmount(p, uap)
358	struct proc *p;
359	register struct unmount_args /* {
360		syscallarg(char *) path;
361		syscallarg(int) flags;
362	} */ *uap;
363{
364	register struct vnode *vp;
365	struct mount *mp;
366	int error;
367	struct nameidata nd;
368
369	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
370	    SCARG(uap, path), p);
371	if (error = namei(&nd))
372		return (error);
373	vp = nd.ni_vp;
374	mp = vp->v_mount;
375
376	/*
377	 * Only root, or the user that did the original mount is
378	 * permitted to unmount this filesystem.
379	 */
380	if ((mp->mnt_stat.f_owner != p->p_ucred->cr_uid) &&
381	    (error = suser(p->p_ucred, &p->p_acflag))) {
382		vput(vp);
383		return (error);
384	}
385
386	/*
387	 * Don't allow unmounting the root file system.
388	 */
389	if (mp->mnt_flag & MNT_ROOTFS) {
390		vput(vp);
391		return (EINVAL);
392	}
393
394	/*
395	 * Must be the root of the filesystem
396	 */
397	if ((vp->v_flag & VROOT) == 0) {
398		vput(vp);
399		return (EINVAL);
400	}
401	vput(vp);
402	return (dounmount(mp, SCARG(uap, flags), p));
403}
404
405/*
406 * Do the actual file system unmount.
407 */
408int
409dounmount(mp, flags, p)
410	register struct mount *mp;
411	int flags;
412	struct proc *p;
413{
414	struct vnode *coveredvp;
415	int error;
416
417	simple_lock(&mountlist_slock);
418	mp->mnt_flag |= MNT_UNMOUNT;
419	lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK, &mountlist_slock, p);
420
421	if (mp->mnt_flag & MNT_EXPUBLIC)
422		vfs_setpublicfs(NULL, NULL, NULL);
423
424	mp->mnt_flag &=~ MNT_ASYNC;
425	vfs_msync(mp, MNT_NOWAIT);
426	vnode_pager_umount(mp);	/* release cached vnodes */
427	cache_purgevfs(mp);	/* remove cache entries for this file sys */
428	if (((mp->mnt_flag & MNT_RDONLY) ||
429	     (error = VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p)) == 0) ||
430	    (flags & MNT_FORCE))
431		error = VFS_UNMOUNT(mp, flags, p);
432	simple_lock(&mountlist_slock);
433	if (error) {
434		mp->mnt_flag &= ~MNT_UNMOUNT;
435		lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK | LK_REENABLE,
436		    &mountlist_slock, p);
437		return (error);
438	}
439	CIRCLEQ_REMOVE(&mountlist, mp, mnt_list);
440	if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {
441		coveredvp->v_mountedhere = (struct mount *)0;
442		vrele(coveredvp);
443	}
444	mp->mnt_vfc->vfc_refcount--;
445	if (mp->mnt_vnodelist.lh_first != NULL)
446		panic("unmount: dangling vnode");
447	lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_slock, p);
448	if (mp->mnt_flag & MNT_MWAIT)
449		wakeup((caddr_t)mp);
450	free((caddr_t)mp, M_MOUNT);
451	return (0);
452}
453
454/*
455 * Sync each mounted filesystem.
456 */
457#ifndef _SYS_SYSPROTO_H_
458struct sync_args {
459        int     dummy;
460};
461#endif
462
463#ifdef DEBUG
464int syncprt = 0;
465SYSCTL_INT(_debug, 0, syncprt, CTLFLAG_RW, &syncprt, 0, "");
466#endif
467
468/* ARGSUSED */
469int
470sync(p, uap)
471	struct proc *p;
472	struct sync_args *uap;
473{
474	register struct mount *mp, *nmp;
475	int asyncflag;
476
477	simple_lock(&mountlist_slock);
478	for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
479		if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
480			nmp = mp->mnt_list.cqe_next;
481			continue;
482		}
483		if ((mp->mnt_flag & MNT_RDONLY) == 0) {
484			asyncflag = mp->mnt_flag & MNT_ASYNC;
485			mp->mnt_flag &= ~MNT_ASYNC;
486			vfs_msync(mp, MNT_NOWAIT);
487			VFS_SYNC(mp, MNT_NOWAIT, p != NULL ? p->p_ucred : NOCRED, p);
488			if (asyncflag)
489				mp->mnt_flag |= MNT_ASYNC;
490		}
491		simple_lock(&mountlist_slock);
492		nmp = mp->mnt_list.cqe_next;
493		vfs_unbusy(mp, p);
494	}
495	simple_unlock(&mountlist_slock);
496#if 0
497/*
498 * XXX don't call vfs_bufstats() yet because that routine
499 * was not imported in the Lite2 merge.
500 */
501#ifdef DIAGNOSTIC
502	if (syncprt)
503		vfs_bufstats();
504#endif /* DIAGNOSTIC */
505#endif
506	return (0);
507}
508
509/*
510 * Change filesystem quotas.
511 */
512#ifndef _SYS_SYSPROTO_H_
513struct quotactl_args {
514	char *path;
515	int cmd;
516	int uid;
517	caddr_t arg;
518};
519#endif
520/* ARGSUSED */
521int
522quotactl(p, uap)
523	struct proc *p;
524	register struct quotactl_args /* {
525		syscallarg(char *) path;
526		syscallarg(int) cmd;
527		syscallarg(int) uid;
528		syscallarg(caddr_t) arg;
529	} */ *uap;
530{
531	register struct mount *mp;
532	int error;
533	struct nameidata nd;
534
535	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
536	if (error = namei(&nd))
537		return (error);
538	mp = nd.ni_vp->v_mount;
539	vrele(nd.ni_vp);
540	return (VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
541	    SCARG(uap, arg), p));
542}
543
544/*
545 * Get filesystem statistics.
546 */
547#ifndef _SYS_SYSPROTO_H_
548struct statfs_args {
549	char *path;
550	struct statfs *buf;
551};
552#endif
553/* ARGSUSED */
554int
555statfs(p, uap)
556	struct proc *p;
557	register struct statfs_args /* {
558		syscallarg(char *) path;
559		syscallarg(struct statfs *) buf;
560	} */ *uap;
561{
562	register struct mount *mp;
563	register struct statfs *sp;
564	int error;
565	struct nameidata nd;
566	struct statfs sb;
567
568	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
569	if (error = namei(&nd))
570		return (error);
571	mp = nd.ni_vp->v_mount;
572	sp = &mp->mnt_stat;
573	vrele(nd.ni_vp);
574	error = VFS_STATFS(mp, sp, p);
575	if (error)
576		return (error);
577	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
578	if (p->p_ucred->cr_uid != 0) {
579		bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
580		sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
581		sp = &sb;
582	}
583	return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
584}
585
586/*
587 * Get filesystem statistics.
588 */
589#ifndef _SYS_SYSPROTO_H_
590struct fstatfs_args {
591	int fd;
592	struct statfs *buf;
593};
594#endif
595/* ARGSUSED */
596int
597fstatfs(p, uap)
598	struct proc *p;
599	register struct fstatfs_args /* {
600		syscallarg(int) fd;
601		syscallarg(struct statfs *) buf;
602	} */ *uap;
603{
604	struct file *fp;
605	struct mount *mp;
606	register struct statfs *sp;
607	int error;
608	struct statfs sb;
609
610	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
611		return (error);
612	mp = ((struct vnode *)fp->f_data)->v_mount;
613	sp = &mp->mnt_stat;
614	error = VFS_STATFS(mp, sp, p);
615	if (error)
616		return (error);
617	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
618	if (p->p_ucred->cr_uid != 0) {
619		bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
620		sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
621		sp = &sb;
622	}
623	return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
624}
625
626/*
627 * Get statistics on all filesystems.
628 */
629#ifndef _SYS_SYSPROTO_H_
630struct getfsstat_args {
631	struct statfs *buf;
632	long bufsize;
633	int flags;
634};
635#endif
636int
637getfsstat(p, uap)
638	struct proc *p;
639	register struct getfsstat_args /* {
640		syscallarg(struct statfs *) buf;
641		syscallarg(long) bufsize;
642		syscallarg(int) flags;
643	} */ *uap;
644{
645	register struct mount *mp, *nmp;
646	register struct statfs *sp;
647	caddr_t sfsp;
648	long count, maxcount, error;
649
650	maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
651	sfsp = (caddr_t)SCARG(uap, buf);
652	count = 0;
653	simple_lock(&mountlist_slock);
654	for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
655		if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) {
656			nmp = mp->mnt_list.cqe_next;
657			continue;
658		}
659		if (sfsp && count < maxcount) {
660			sp = &mp->mnt_stat;
661			/*
662			 * If MNT_NOWAIT is specified, do not refresh the
663			 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
664			 */
665			if (((SCARG(uap, flags) & MNT_NOWAIT) == 0 ||
666			    (SCARG(uap, flags) & MNT_WAIT)) &&
667			    (error = VFS_STATFS(mp, sp, p))) {
668				simple_lock(&mountlist_slock);
669				nmp = mp->mnt_list.cqe_next;
670				vfs_unbusy(mp, p);
671				continue;
672			}
673			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
674			error = copyout((caddr_t)sp, sfsp, sizeof(*sp));
675			if (error) {
676				vfs_unbusy(mp, p);
677				return (error);
678			}
679			sfsp += sizeof(*sp);
680		}
681		count++;
682		simple_lock(&mountlist_slock);
683		nmp = mp->mnt_list.cqe_next;
684		vfs_unbusy(mp, p);
685	}
686	simple_unlock(&mountlist_slock);
687	if (sfsp && count > maxcount)
688		p->p_retval[0] = maxcount;
689	else
690		p->p_retval[0] = count;
691	return (0);
692}
693
694/*
695 * Change current working directory to a given file descriptor.
696 */
697#ifndef _SYS_SYSPROTO_H_
698struct fchdir_args {
699	int	fd;
700};
701#endif
702/* ARGSUSED */
703int
704fchdir(p, uap)
705	struct proc *p;
706	struct fchdir_args /* {
707		syscallarg(int) fd;
708	} */ *uap;
709{
710	register struct filedesc *fdp = p->p_fd;
711	struct vnode *vp, *tdp;
712	struct mount *mp;
713	struct file *fp;
714	int error;
715
716	if (error = getvnode(fdp, SCARG(uap, fd), &fp))
717		return (error);
718	vp = (struct vnode *)fp->f_data;
719	VREF(vp);
720	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
721	if (vp->v_type != VDIR)
722		error = ENOTDIR;
723	else
724		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
725	while (!error && (mp = vp->v_mountedhere) != NULL) {
726		if (vfs_busy(mp, 0, 0, p))
727			continue;
728		error = VFS_ROOT(mp, &tdp);
729		vfs_unbusy(mp, p);
730		if (error)
731			break;
732		vput(vp);
733		vp = tdp;
734	}
735	if (error) {
736		vput(vp);
737		return (error);
738	}
739	VOP_UNLOCK(vp, 0, p);
740	vrele(fdp->fd_cdir);
741	fdp->fd_cdir = vp;
742	return (0);
743}
744
745/*
746 * Change current working directory (``.'').
747 */
748#ifndef _SYS_SYSPROTO_H_
749struct chdir_args {
750	char	*path;
751};
752#endif
753/* ARGSUSED */
754int
755chdir(p, uap)
756	struct proc *p;
757	struct chdir_args /* {
758		syscallarg(char *) path;
759	} */ *uap;
760{
761	register struct filedesc *fdp = p->p_fd;
762	int error;
763	struct nameidata nd;
764
765	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
766	    SCARG(uap, path), p);
767	if (error = change_dir(&nd, p))
768		return (error);
769	vrele(fdp->fd_cdir);
770	fdp->fd_cdir = nd.ni_vp;
771	return (0);
772}
773
774/*
775 * Change notion of root (``/'') directory.
776 */
777#ifndef _SYS_SYSPROTO_H_
778struct chroot_args {
779	char	*path;
780};
781#endif
782/* ARGSUSED */
783int
784chroot(p, uap)
785	struct proc *p;
786	struct chroot_args /* {
787		syscallarg(char *) path;
788	} */ *uap;
789{
790	register struct filedesc *fdp = p->p_fd;
791	int error;
792	struct nameidata nd;
793
794	error = suser(p->p_ucred, &p->p_acflag);
795	if (error)
796		return (error);
797	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
798	    SCARG(uap, path), p);
799	if (error = change_dir(&nd, p))
800		return (error);
801	if (fdp->fd_rdir != NULL)
802		vrele(fdp->fd_rdir);
803	fdp->fd_rdir = nd.ni_vp;
804	return (0);
805}
806
807/*
808 * Common routine for chroot and chdir.
809 */
810static int
811change_dir(ndp, p)
812	register struct nameidata *ndp;
813	struct proc *p;
814{
815	struct vnode *vp;
816	int error;
817
818	error = namei(ndp);
819	if (error)
820		return (error);
821	vp = ndp->ni_vp;
822	if (vp->v_type != VDIR)
823		error = ENOTDIR;
824	else
825		error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
826	if (error)
827		vput(vp);
828	else
829		VOP_UNLOCK(vp, 0, p);
830	return (error);
831}
832
833/*
834 * Check permissions, allocate an open file structure,
835 * and call the device open routine if any.
836 */
837#ifndef _SYS_SYSPROTO_H_
838struct open_args {
839	char	*path;
840	int	flags;
841	int	mode;
842};
843#endif
844int
845open(p, uap)
846	struct proc *p;
847	register struct open_args /* {
848		syscallarg(char *) path;
849		syscallarg(int) flags;
850		syscallarg(int) mode;
851	} */ *uap;
852{
853	register struct filedesc *fdp = p->p_fd;
854	register struct file *fp;
855	register struct vnode *vp;
856	int cmode, flags, oflags;
857	struct file *nfp;
858	int type, indx, error;
859	struct flock lf;
860	struct nameidata nd;
861
862	oflags = SCARG(uap, flags);
863	if ((oflags & O_ACCMODE) == O_ACCMODE)
864		return (EINVAL);
865	flags = FFLAGS(oflags);
866	error = falloc(p, &nfp, &indx);
867	if (error)
868		return (error);
869	fp = nfp;
870	cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
871	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
872	p->p_dupfd = -indx - 1;			/* XXX check for fdopen */
873	error = vn_open(&nd, flags, cmode);
874	if (error) {
875		ffree(fp);
876		if ((error == ENODEV || error == ENXIO) &&
877		    p->p_dupfd >= 0 &&			/* XXX from fdopen */
878		    (error =
879			dupfdopen(fdp, indx, p->p_dupfd, flags, error)) == 0) {
880			p->p_retval[0] = indx;
881			return (0);
882		}
883		if (error == ERESTART)
884			error = EINTR;
885		fdp->fd_ofiles[indx] = NULL;
886		return (error);
887	}
888	p->p_dupfd = 0;
889	vp = nd.ni_vp;
890
891	fp->f_flag = flags & FMASK;
892	fp->f_type = (vp->v_type == VFIFO ? DTYPE_FIFO : DTYPE_VNODE);
893	fp->f_ops = &vnops;
894	fp->f_data = (caddr_t)vp;
895	if (flags & (O_EXLOCK | O_SHLOCK)) {
896		lf.l_whence = SEEK_SET;
897		lf.l_start = 0;
898		lf.l_len = 0;
899		if (flags & O_EXLOCK)
900			lf.l_type = F_WRLCK;
901		else
902			lf.l_type = F_RDLCK;
903		type = F_FLOCK;
904		if ((flags & FNONBLOCK) == 0)
905			type |= F_WAIT;
906		VOP_UNLOCK(vp, 0, p);
907		if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
908			(void) vn_close(vp, fp->f_flag, fp->f_cred, p);
909			ffree(fp);
910			fdp->fd_ofiles[indx] = NULL;
911			return (error);
912		}
913		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
914		fp->f_flag |= FHASLOCK;
915	}
916	VOP_UNLOCK(vp, 0, p);
917	p->p_retval[0] = indx;
918	return (0);
919}
920
921#ifdef COMPAT_43
922/*
923 * Create a file.
924 */
925#ifndef _SYS_SYSPROTO_H_
926struct ocreat_args {
927	char	*path;
928	int	mode;
929};
930#endif
931int
932ocreat(p, uap)
933	struct proc *p;
934	register struct ocreat_args /* {
935		syscallarg(char *) path;
936		syscallarg(int) mode;
937	} */ *uap;
938{
939	struct open_args /* {
940		syscallarg(char *) path;
941		syscallarg(int) flags;
942		syscallarg(int) mode;
943	} */ nuap;
944
945	SCARG(&nuap, path) = SCARG(uap, path);
946	SCARG(&nuap, mode) = SCARG(uap, mode);
947	SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
948	return (open(p, &nuap));
949}
950#endif /* COMPAT_43 */
951
952/*
953 * Create a special file.
954 */
955#ifndef _SYS_SYSPROTO_H_
956struct mknod_args {
957	char	*path;
958	int	mode;
959	int	dev;
960};
961#endif
962/* ARGSUSED */
963int
964mknod(p, uap)
965	struct proc *p;
966	register struct mknod_args /* {
967		syscallarg(char *) path;
968		syscallarg(int) mode;
969		syscallarg(int) dev;
970	} */ *uap;
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	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mknod");
1032	ASSERT_VOP_UNLOCKED(nd.ni_vp, "mknod");
1033	return (error);
1034}
1035
1036/*
1037 * Create a named pipe.
1038 */
1039#ifndef _SYS_SYSPROTO_H_
1040struct mkfifo_args {
1041	char	*path;
1042	int	mode;
1043};
1044#endif
1045/* ARGSUSED */
1046int
1047mkfifo(p, uap)
1048	struct proc *p;
1049	register struct mkfifo_args /* {
1050		syscallarg(char *) path;
1051		syscallarg(int) mode;
1052	} */ *uap;
1053{
1054	struct vattr vattr;
1055	int error;
1056	struct nameidata nd;
1057
1058	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
1059	if (error = namei(&nd))
1060		return (error);
1061	if (nd.ni_vp != NULL) {
1062		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1063		if (nd.ni_dvp == nd.ni_vp)
1064			vrele(nd.ni_dvp);
1065		else
1066			vput(nd.ni_dvp);
1067		vrele(nd.ni_vp);
1068		return (EEXIST);
1069	}
1070	VATTR_NULL(&vattr);
1071	vattr.va_type = VFIFO;
1072	vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ p->p_fd->fd_cmask;
1073	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1074	return (VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr));
1075}
1076
1077/*
1078 * Make a hard file link.
1079 */
1080#ifndef _SYS_SYSPROTO_H_
1081struct link_args {
1082	char	*path;
1083	char	*link;
1084};
1085#endif
1086/* ARGSUSED */
1087int
1088link(p, uap)
1089	struct proc *p;
1090	register struct link_args /* {
1091		syscallarg(char *) path;
1092		syscallarg(char *) link;
1093	} */ *uap;
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	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "link");
1128	ASSERT_VOP_UNLOCKED(nd.ni_vp, "link");
1129	return (error);
1130}
1131
1132/*
1133 * Make a symbolic link.
1134 */
1135#ifndef _SYS_SYSPROTO_H_
1136struct symlink_args {
1137	char	*path;
1138	char	*link;
1139};
1140#endif
1141/* ARGSUSED */
1142int
1143symlink(p, uap)
1144	struct proc *p;
1145	register struct symlink_args /* {
1146		syscallarg(char *) path;
1147		syscallarg(char *) link;
1148	} */ *uap;
1149{
1150	struct vattr vattr;
1151	char *path;
1152	int error;
1153	struct nameidata nd;
1154
1155	path = zalloc(namei_zone);
1156	if (error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL))
1157		goto out;
1158	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, link), p);
1159	if (error = namei(&nd))
1160		goto out;
1161	if (nd.ni_vp) {
1162		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1163		if (nd.ni_dvp == nd.ni_vp)
1164			vrele(nd.ni_dvp);
1165		else
1166			vput(nd.ni_dvp);
1167		vrele(nd.ni_vp);
1168		error = EEXIST;
1169		goto out;
1170	}
1171	VATTR_NULL(&vattr);
1172	vattr.va_mode = ACCESSPERMS &~ p->p_fd->fd_cmask;
1173	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1174	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1175	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "symlink");
1176	ASSERT_VOP_UNLOCKED(nd.ni_vp, "symlink");
1177out:
1178	zfree(namei_zone, path);
1179	return (error);
1180}
1181
1182/*
1183 * Delete a whiteout from the filesystem.
1184 */
1185/* ARGSUSED */
1186int
1187undelete(p, uap)
1188	struct proc *p;
1189	register struct undelete_args /* {
1190		syscallarg(char *) path;
1191	} */ *uap;
1192{
1193	int error;
1194	struct nameidata nd;
1195
1196	NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
1197	    SCARG(uap, path), p);
1198	error = namei(&nd);
1199	if (error)
1200		return (error);
1201
1202	if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
1203		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1204		if (nd.ni_dvp == nd.ni_vp)
1205			vrele(nd.ni_dvp);
1206		else
1207			vput(nd.ni_dvp);
1208		if (nd.ni_vp)
1209			vrele(nd.ni_vp);
1210		return (EEXIST);
1211	}
1212
1213	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1214	if (error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE))
1215		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1216	vput(nd.ni_dvp);
1217	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "undelete");
1218	ASSERT_VOP_UNLOCKED(nd.ni_vp, "undelete");
1219	return (error);
1220}
1221
1222/*
1223 * Delete a name from the filesystem.
1224 */
1225#ifndef _SYS_SYSPROTO_H_
1226struct unlink_args {
1227	char	*path;
1228};
1229#endif
1230/* ARGSUSED */
1231int
1232unlink(p, uap)
1233	struct proc *p;
1234	struct unlink_args /* {
1235		syscallarg(char *) path;
1236	} */ *uap;
1237{
1238	register struct vnode *vp;
1239	int error;
1240	struct nameidata nd;
1241
1242	NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
1243	if (error = namei(&nd))
1244		return (error);
1245	vp = nd.ni_vp;
1246	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1247	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1248
1249	if (vp->v_type == VDIR)
1250		error = EPERM;		/* POSIX */
1251	else {
1252		/*
1253		 * The root of a mounted filesystem cannot be deleted.
1254		 *
1255		 * XXX: can this only be a VDIR case?
1256		 */
1257		if (vp->v_flag & VROOT)
1258			error = EBUSY;
1259		else
1260			(void) vnode_pager_uncache(vp, p);
1261	}
1262
1263	if (!error) {
1264		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
1265		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1266	} else {
1267		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1268		if (nd.ni_dvp == vp)
1269			vrele(nd.ni_dvp);
1270		else
1271			vput(nd.ni_dvp);
1272		if (vp != NULLVP)
1273			vput(vp);
1274	}
1275	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "unlink");
1276	ASSERT_VOP_UNLOCKED(nd.ni_vp, "unlink");
1277	return (error);
1278}
1279
1280/*
1281 * Reposition read/write file offset.
1282 */
1283#ifndef _SYS_SYSPROTO_H_
1284struct lseek_args {
1285	int	fd;
1286	int	pad;
1287	off_t	offset;
1288	int	whence;
1289};
1290#endif
1291int
1292lseek(p, uap)
1293	struct proc *p;
1294	register struct lseek_args /* {
1295		syscallarg(int) fd;
1296		syscallarg(int) pad;
1297		syscallarg(off_t) offset;
1298		syscallarg(int) whence;
1299	} */ *uap;
1300{
1301	struct ucred *cred = p->p_ucred;
1302	register struct filedesc *fdp = p->p_fd;
1303	register struct file *fp;
1304	struct vattr vattr;
1305	int error;
1306
1307	if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
1308	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
1309		return (EBADF);
1310	if (fp->f_type != DTYPE_VNODE)
1311		return (ESPIPE);
1312	switch (SCARG(uap, whence)) {
1313	case L_INCR:
1314		fp->f_offset += SCARG(uap, offset);
1315		break;
1316	case L_XTND:
1317		error=VOP_GETATTR((struct vnode *)fp->f_data, &vattr, cred, p);
1318		if (error)
1319			return (error);
1320		fp->f_offset = SCARG(uap, offset) + vattr.va_size;
1321		break;
1322	case L_SET:
1323		fp->f_offset = SCARG(uap, offset);
1324		break;
1325	default:
1326		return (EINVAL);
1327	}
1328	*(off_t *)(p->p_retval) = fp->f_offset;
1329	return (0);
1330}
1331
1332#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1333/*
1334 * Reposition read/write file offset.
1335 */
1336#ifndef _SYS_SYSPROTO_H_
1337struct olseek_args {
1338	int	fd;
1339	long	offset;
1340	int	whence;
1341};
1342#endif
1343int
1344olseek(p, uap)
1345	struct proc *p;
1346	register struct olseek_args /* {
1347		syscallarg(int) fd;
1348		syscallarg(long) offset;
1349		syscallarg(int) whence;
1350	} */ *uap;
1351{
1352	struct lseek_args /* {
1353		syscallarg(int) fd;
1354		syscallarg(int) pad;
1355		syscallarg(off_t) offset;
1356		syscallarg(int) whence;
1357	} */ nuap;
1358	int error;
1359
1360	SCARG(&nuap, fd) = SCARG(uap, fd);
1361	SCARG(&nuap, offset) = SCARG(uap, offset);
1362	SCARG(&nuap, whence) = SCARG(uap, whence);
1363	error = lseek(p, &nuap);
1364	return (error);
1365}
1366#endif /* COMPAT_43 */
1367
1368/*
1369 * Check access permissions.
1370 */
1371#ifndef _SYS_SYSPROTO_H_
1372struct access_args {
1373	char	*path;
1374	int	flags;
1375};
1376#endif
1377int
1378access(p, uap)
1379	struct proc *p;
1380	register struct access_args /* {
1381		syscallarg(char *) path;
1382		syscallarg(int) flags;
1383	} */ *uap;
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)
1432	struct proc *p;
1433	register struct ostat_args /* {
1434		syscallarg(char *) path;
1435		syscallarg(struct ostat *) ub;
1436	} */ *uap;
1437{
1438	struct stat sb;
1439	struct ostat osb;
1440	int error;
1441	struct nameidata nd;
1442
1443	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1444	    SCARG(uap, path), p);
1445	if (error = namei(&nd))
1446		return (error);
1447	error = vn_stat(nd.ni_vp, &sb, p);
1448	vput(nd.ni_vp);
1449	if (error)
1450		return (error);
1451	cvtstat(&sb, &osb);
1452	error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
1453	return (error);
1454}
1455
1456/*
1457 * Get file status; this version does not follow links.
1458 */
1459#ifndef _SYS_SYSPROTO_H_
1460struct olstat_args {
1461	char	*path;
1462	struct ostat *ub;
1463};
1464#endif
1465/* ARGSUSED */
1466int
1467olstat(p, uap)
1468	struct proc *p;
1469	register struct olstat_args /* {
1470		syscallarg(char *) path;
1471		syscallarg(struct ostat *) ub;
1472	} */ *uap;
1473{
1474	struct vnode *vp;
1475	struct stat sb;
1476	struct ostat osb;
1477	int error;
1478	struct nameidata nd;
1479
1480	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
1481	    SCARG(uap, path), p);
1482	if (error = namei(&nd))
1483		return (error);
1484	vp = nd.ni_vp;
1485	error = vn_stat(vp, &sb, p);
1486	if (vp->v_type == VLNK)
1487		sb.st_mode |= S_IFLNK | ACCESSPERMS;	/* 0777 */
1488	vput(vp);
1489	if (error)
1490		return (error);
1491	cvtstat(&sb, &osb);
1492	error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
1493	return (error);
1494}
1495
1496/*
1497 * Convert from an old to a new stat structure.
1498 */
1499void
1500cvtstat(st, ost)
1501	struct stat *st;
1502	struct ostat *ost;
1503{
1504
1505	ost->st_dev = st->st_dev;
1506	ost->st_ino = st->st_ino;
1507	ost->st_mode = st->st_mode;
1508	ost->st_nlink = st->st_nlink;
1509	ost->st_uid = st->st_uid;
1510	ost->st_gid = st->st_gid;
1511	ost->st_rdev = st->st_rdev;
1512	if (st->st_size < (quad_t)1 << 32)
1513		ost->st_size = st->st_size;
1514	else
1515		ost->st_size = -2;
1516	ost->st_atime = st->st_atime;
1517	ost->st_mtime = st->st_mtime;
1518	ost->st_ctime = st->st_ctime;
1519	ost->st_blksize = st->st_blksize;
1520	ost->st_blocks = st->st_blocks;
1521	ost->st_flags = st->st_flags;
1522	ost->st_gen = st->st_gen;
1523}
1524#endif /* COMPAT_43 || COMPAT_SUNOS */
1525
1526/*
1527 * Get file status; this version follows links.
1528 */
1529#ifndef _SYS_SYSPROTO_H_
1530struct stat_args {
1531	char	*path;
1532	struct stat *ub;
1533};
1534#endif
1535/* ARGSUSED */
1536int
1537stat(p, uap)
1538	struct proc *p;
1539	register struct stat_args /* {
1540		syscallarg(char *) path;
1541		syscallarg(struct stat *) ub;
1542	} */ *uap;
1543{
1544	struct stat sb;
1545	int error;
1546	struct nameidata nd;
1547
1548	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1549	    SCARG(uap, path), p);
1550	if (error = namei(&nd))
1551		return (error);
1552	error = vn_stat(nd.ni_vp, &sb, p);
1553	vput(nd.ni_vp);
1554	if (error)
1555		return (error);
1556	error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
1557	return (error);
1558}
1559
1560/*
1561 * Get file status; this version does not follow links.
1562 */
1563#ifndef _SYS_SYSPROTO_H_
1564struct lstat_args {
1565	char	*path;
1566	struct stat *ub;
1567};
1568#endif
1569/* ARGSUSED */
1570int
1571lstat(p, uap)
1572	struct proc *p;
1573	register struct lstat_args /* {
1574		syscallarg(char *) path;
1575		syscallarg(struct stat *) ub;
1576	} */ *uap;
1577{
1578	int error;
1579	struct vnode *vp;
1580	struct stat sb;
1581	struct nameidata nd;
1582
1583	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
1584	    SCARG(uap, path), p);
1585	if (error = namei(&nd))
1586		return (error);
1587	vp = nd.ni_vp;
1588	error = vn_stat(vp, &sb, p);
1589	if (vp->v_type == VLNK)
1590		sb.st_mode |= S_IFLNK | ACCESSPERMS;	/* 0777 */
1591	vput(vp);
1592	if (error)
1593		return (error);
1594	error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
1595	return (error);
1596}
1597
1598/*
1599 * Get configurable pathname variables.
1600 */
1601#ifndef _SYS_SYSPROTO_H_
1602struct pathconf_args {
1603	char	*path;
1604	int	name;
1605};
1606#endif
1607/* ARGSUSED */
1608int
1609pathconf(p, uap)
1610	struct proc *p;
1611	register struct pathconf_args /* {
1612		syscallarg(char *) path;
1613		syscallarg(int) name;
1614	} */ *uap;
1615{
1616	int error;
1617	struct nameidata nd;
1618
1619	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1620	    SCARG(uap, path), p);
1621	if (error = namei(&nd))
1622		return (error);
1623	error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), p->p_retval);
1624	vput(nd.ni_vp);
1625	return (error);
1626}
1627
1628/*
1629 * Return target name of a symbolic link.
1630 */
1631#ifndef _SYS_SYSPROTO_H_
1632struct readlink_args {
1633	char	*path;
1634	char	*buf;
1635	int	count;
1636};
1637#endif
1638/* ARGSUSED */
1639int
1640readlink(p, uap)
1641	struct proc *p;
1642	register struct readlink_args /* {
1643		syscallarg(char *) path;
1644		syscallarg(char *) buf;
1645		syscallarg(int) count;
1646	} */ *uap;
1647{
1648	register struct vnode *vp;
1649	struct iovec aiov;
1650	struct uio auio;
1651	int error;
1652	struct nameidata nd;
1653
1654	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
1655	    SCARG(uap, path), p);
1656	if (error = namei(&nd))
1657		return (error);
1658	vp = nd.ni_vp;
1659	if (vp->v_type != VLNK)
1660		error = EINVAL;
1661	else {
1662		aiov.iov_base = SCARG(uap, buf);
1663		aiov.iov_len = SCARG(uap, count);
1664		auio.uio_iov = &aiov;
1665		auio.uio_iovcnt = 1;
1666		auio.uio_offset = 0;
1667		auio.uio_rw = UIO_READ;
1668		auio.uio_segflg = UIO_USERSPACE;
1669		auio.uio_procp = p;
1670		auio.uio_resid = SCARG(uap, count);
1671		error = VOP_READLINK(vp, &auio, p->p_ucred);
1672	}
1673	vput(vp);
1674	p->p_retval[0] = SCARG(uap, count) - auio.uio_resid;
1675	return (error);
1676}
1677
1678/*
1679 * Change flags of a file given a path name.
1680 */
1681#ifndef _SYS_SYSPROTO_H_
1682struct chflags_args {
1683	char	*path;
1684	int	flags;
1685};
1686#endif
1687/* ARGSUSED */
1688int
1689chflags(p, uap)
1690	struct proc *p;
1691	register struct chflags_args /* {
1692		syscallarg(char *) path;
1693		syscallarg(int) flags;
1694	} */ *uap;
1695{
1696	register struct vnode *vp;
1697	struct vattr vattr;
1698	int error;
1699	struct nameidata nd;
1700
1701	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1702	if (error = namei(&nd))
1703		return (error);
1704	vp = nd.ni_vp;
1705	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1706	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1707	VATTR_NULL(&vattr);
1708	vattr.va_flags = SCARG(uap, flags);
1709	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1710	vput(vp);
1711	return (error);
1712}
1713
1714/*
1715 * Change flags of a file given a file descriptor.
1716 */
1717#ifndef _SYS_SYSPROTO_H_
1718struct fchflags_args {
1719	int	fd;
1720	int	flags;
1721};
1722#endif
1723/* ARGSUSED */
1724int
1725fchflags(p, uap)
1726	struct proc *p;
1727	register struct fchflags_args /* {
1728		syscallarg(int) fd;
1729		syscallarg(int) flags;
1730	} */ *uap;
1731{
1732	struct vattr vattr;
1733	struct vnode *vp;
1734	struct file *fp;
1735	int error;
1736
1737	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
1738		return (error);
1739	vp = (struct vnode *)fp->f_data;
1740	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1741	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1742	VATTR_NULL(&vattr);
1743	vattr.va_flags = SCARG(uap, flags);
1744	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1745	VOP_UNLOCK(vp, 0, p);
1746	return (error);
1747}
1748
1749/*
1750 * Change mode of a file given path name.
1751 */
1752#ifndef _SYS_SYSPROTO_H_
1753struct chmod_args {
1754	char	*path;
1755	int	mode;
1756};
1757#endif
1758/* ARGSUSED */
1759int
1760chmod(p, uap)
1761	struct proc *p;
1762	register struct chmod_args /* {
1763		syscallarg(char *) path;
1764		syscallarg(int) mode;
1765	} */ *uap;
1766{
1767	register struct vnode *vp;
1768	struct vattr vattr;
1769	int error;
1770	struct nameidata nd;
1771
1772	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1773	if (error = namei(&nd))
1774		return (error);
1775	vp = nd.ni_vp;
1776	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1777	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1778	VATTR_NULL(&vattr);
1779	vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
1780	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1781	vput(vp);
1782	return (error);
1783}
1784
1785/*
1786 * Change mode of a file given a file descriptor.
1787 */
1788#ifndef _SYS_SYSPROTO_H_
1789struct fchmod_args {
1790	int	fd;
1791	int	mode;
1792};
1793#endif
1794/* ARGSUSED */
1795int
1796fchmod(p, uap)
1797	struct proc *p;
1798	register struct fchmod_args /* {
1799		syscallarg(int) fd;
1800		syscallarg(int) mode;
1801	} */ *uap;
1802{
1803	struct vattr vattr;
1804	struct vnode *vp;
1805	struct file *fp;
1806	int error;
1807
1808	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
1809		return (error);
1810	vp = (struct vnode *)fp->f_data;
1811	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1812	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1813	VATTR_NULL(&vattr);
1814	vattr.va_mode = SCARG(uap, mode) & ALLPERMS;
1815	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1816	VOP_UNLOCK(vp, 0, p);
1817	return (error);
1818}
1819
1820/*
1821 * Set ownership given a path name.
1822 */
1823#ifndef _SYS_SYSPROTO_H_
1824struct chown_args {
1825	char	*path;
1826	int	uid;
1827	int	gid;
1828};
1829#endif
1830/* ARGSUSED */
1831int
1832chown(p, uap)
1833	struct proc *p;
1834	register struct chown_args /* {
1835		syscallarg(char *) path;
1836		syscallarg(int) uid;
1837		syscallarg(int) gid;
1838	} */ *uap;
1839{
1840	register struct vnode *vp;
1841	struct vattr vattr;
1842	int error;
1843	struct nameidata nd;
1844
1845	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1846	if (error = namei(&nd))
1847		return (error);
1848	vp = nd.ni_vp;
1849	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1850	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1851	VATTR_NULL(&vattr);
1852	vattr.va_uid = SCARG(uap, uid);
1853	vattr.va_gid = SCARG(uap, gid);
1854	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1855	vput(vp);
1856	return (error);
1857}
1858
1859/*
1860 * Set ownership given a path name, do not cross symlinks.
1861 */
1862#ifndef _SYS_SYSPROTO_H_
1863struct lchown_args {
1864	char	*path;
1865	int	uid;
1866	int	gid;
1867};
1868#endif
1869/* ARGSUSED */
1870int
1871lchown(p, uap)
1872	struct proc *p;
1873	register struct lchown_args /* {
1874		syscallarg(char *) path;
1875		syscallarg(int) uid;
1876		syscallarg(int) gid;
1877	} */ *uap;
1878{
1879	register struct vnode *vp;
1880	struct vattr vattr;
1881	int error;
1882	struct nameidata nd;
1883
1884	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1885	if (error = namei(&nd))
1886		return (error);
1887	vp = nd.ni_vp;
1888	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1889	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1890	VATTR_NULL(&vattr);
1891	vattr.va_uid = SCARG(uap, uid);
1892	vattr.va_gid = SCARG(uap, gid);
1893	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1894	vput(vp);
1895	return (error);
1896}
1897
1898/*
1899 * Set ownership given a file descriptor.
1900 */
1901#ifndef _SYS_SYSPROTO_H_
1902struct fchown_args {
1903	int	fd;
1904	int	uid;
1905	int	gid;
1906};
1907#endif
1908/* ARGSUSED */
1909int
1910fchown(p, uap)
1911	struct proc *p;
1912	register struct fchown_args /* {
1913		syscallarg(int) fd;
1914		syscallarg(int) uid;
1915		syscallarg(int) gid;
1916	} */ *uap;
1917{
1918	struct vattr vattr;
1919	struct vnode *vp;
1920	struct file *fp;
1921	int error;
1922
1923	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
1924		return (error);
1925	vp = (struct vnode *)fp->f_data;
1926	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1927	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1928	VATTR_NULL(&vattr);
1929	vattr.va_uid = SCARG(uap, uid);
1930	vattr.va_gid = SCARG(uap, gid);
1931	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1932	VOP_UNLOCK(vp, 0, p);
1933	return (error);
1934}
1935
1936/*
1937 * Set the access and modification times of a file.
1938 */
1939#ifndef _SYS_SYSPROTO_H_
1940struct utimes_args {
1941	char	*path;
1942	struct	timeval *tptr;
1943};
1944#endif
1945/* ARGSUSED */
1946int
1947utimes(p, uap)
1948	struct proc *p;
1949	register struct utimes_args /* {
1950		syscallarg(char *) path;
1951		syscallarg(struct timeval *) tptr;
1952	} */ *uap;
1953{
1954	register struct vnode *vp;
1955	struct timeval tv[2];
1956	struct vattr vattr;
1957	int error;
1958	struct nameidata nd;
1959
1960	VATTR_NULL(&vattr);
1961	if (SCARG(uap, tptr) == NULL) {
1962		microtime(&tv[0]);
1963		tv[1] = tv[0];
1964		vattr.va_vaflags |= VA_UTIMES_NULL;
1965	} else if (error = copyin((caddr_t)SCARG(uap, tptr), (caddr_t)tv,
1966	    sizeof (tv)))
1967  		return (error);
1968	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
1969	if (error = namei(&nd))
1970		return (error);
1971	vp = nd.ni_vp;
1972	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
1973	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
1974	vattr.va_atime.tv_sec = tv[0].tv_sec;
1975	vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000;
1976	vattr.va_mtime.tv_sec = tv[1].tv_sec;
1977	vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000;
1978	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
1979	vput(vp);
1980	return (error);
1981}
1982
1983/*
1984 * Truncate a file given its path name.
1985 */
1986#ifndef _SYS_SYSPROTO_H_
1987struct truncate_args {
1988	char	*path;
1989	int	pad;
1990	off_t	length;
1991};
1992#endif
1993/* ARGSUSED */
1994int
1995truncate(p, uap)
1996	struct proc *p;
1997	register struct truncate_args /* {
1998		syscallarg(char *) path;
1999		syscallarg(int) pad;
2000		syscallarg(off_t) length;
2001	} */ *uap;
2002{
2003	register struct vnode *vp;
2004	struct vattr vattr;
2005	int error;
2006	struct nameidata nd;
2007
2008	if (uap->length < 0)
2009		return(EINVAL);
2010	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2011	if (error = namei(&nd))
2012		return (error);
2013	vp = nd.ni_vp;
2014	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2015	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2016	if (vp->v_type == VDIR)
2017		error = EISDIR;
2018	else if ((error = vn_writechk(vp)) == 0 &&
2019	    (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) == 0) {
2020		VATTR_NULL(&vattr);
2021		vattr.va_size = SCARG(uap, length);
2022		error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
2023	}
2024	vput(vp);
2025	return (error);
2026}
2027
2028/*
2029 * Truncate a file given a file descriptor.
2030 */
2031#ifndef _SYS_SYSPROTO_H_
2032struct ftruncate_args {
2033	int	fd;
2034	int	pad;
2035	off_t	length;
2036};
2037#endif
2038/* ARGSUSED */
2039int
2040ftruncate(p, uap)
2041	struct proc *p;
2042	register struct ftruncate_args /* {
2043		syscallarg(int) fd;
2044		syscallarg(int) pad;
2045		syscallarg(off_t) length;
2046	} */ *uap;
2047{
2048	struct vattr vattr;
2049	struct vnode *vp;
2050	struct file *fp;
2051	int error;
2052
2053	if (uap->length < 0)
2054		return(EINVAL);
2055	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
2056		return (error);
2057	if ((fp->f_flag & FWRITE) == 0)
2058		return (EINVAL);
2059	vp = (struct vnode *)fp->f_data;
2060	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2061	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2062	if (vp->v_type == VDIR)
2063		error = EISDIR;
2064	else if ((error = vn_writechk(vp)) == 0) {
2065		VATTR_NULL(&vattr);
2066		vattr.va_size = SCARG(uap, length);
2067		error = VOP_SETATTR(vp, &vattr, fp->f_cred, p);
2068	}
2069	VOP_UNLOCK(vp, 0, p);
2070	return (error);
2071}
2072
2073#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
2074/*
2075 * Truncate a file given its path name.
2076 */
2077#ifndef _SYS_SYSPROTO_H_
2078struct otruncate_args {
2079	char	*path;
2080	long	length;
2081};
2082#endif
2083/* ARGSUSED */
2084int
2085otruncate(p, uap)
2086	struct proc *p;
2087	register struct otruncate_args /* {
2088		syscallarg(char *) path;
2089		syscallarg(long) length;
2090	} */ *uap;
2091{
2092	struct truncate_args /* {
2093		syscallarg(char *) path;
2094		syscallarg(int) pad;
2095		syscallarg(off_t) length;
2096	} */ nuap;
2097
2098	SCARG(&nuap, path) = SCARG(uap, path);
2099	SCARG(&nuap, length) = SCARG(uap, length);
2100	return (truncate(p, &nuap));
2101}
2102
2103/*
2104 * Truncate a file given a file descriptor.
2105 */
2106#ifndef _SYS_SYSPROTO_H_
2107struct oftruncate_args {
2108	int	fd;
2109	long	length;
2110};
2111#endif
2112/* ARGSUSED */
2113int
2114oftruncate(p, uap)
2115	struct proc *p;
2116	register struct oftruncate_args /* {
2117		syscallarg(int) fd;
2118		syscallarg(long) length;
2119	} */ *uap;
2120{
2121	struct ftruncate_args /* {
2122		syscallarg(int) fd;
2123		syscallarg(int) pad;
2124		syscallarg(off_t) length;
2125	} */ nuap;
2126
2127	SCARG(&nuap, fd) = SCARG(uap, fd);
2128	SCARG(&nuap, length) = SCARG(uap, length);
2129	return (ftruncate(p, &nuap));
2130}
2131#endif /* COMPAT_43 || COMPAT_SUNOS */
2132
2133/*
2134 * Sync an open file.
2135 */
2136#ifndef _SYS_SYSPROTO_H_
2137struct fsync_args {
2138	int	fd;
2139};
2140#endif
2141/* ARGSUSED */
2142int
2143fsync(p, uap)
2144	struct proc *p;
2145	struct fsync_args /* {
2146		syscallarg(int) fd;
2147	} */ *uap;
2148{
2149	register struct vnode *vp;
2150	struct file *fp;
2151	int error;
2152
2153	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
2154		return (error);
2155	vp = (struct vnode *)fp->f_data;
2156	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2157	if (vp->v_object) {
2158		vm_object_page_clean(vp->v_object, 0, 0 ,0, FALSE);
2159	}
2160	error = VOP_FSYNC(vp, fp->f_cred,
2161		(vp->v_mount && (vp->v_mount->mnt_flag & MNT_ASYNC)) ?
2162		MNT_NOWAIT : MNT_WAIT, p);
2163	VOP_UNLOCK(vp, 0, p);
2164	return (error);
2165}
2166
2167/*
2168 * Rename files.  Source and destination must either both be directories,
2169 * or both not be directories.  If target is a directory, it must be empty.
2170 */
2171#ifndef _SYS_SYSPROTO_H_
2172struct rename_args {
2173	char	*from;
2174	char	*to;
2175};
2176#endif
2177/* ARGSUSED */
2178int
2179rename(p, uap)
2180	struct proc *p;
2181	register struct rename_args /* {
2182		syscallarg(char *) from;
2183		syscallarg(char *) to;
2184	} */ *uap;
2185{
2186	register struct vnode *tvp, *fvp, *tdvp;
2187	struct nameidata fromnd, tond;
2188	int error;
2189
2190	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
2191	    SCARG(uap, from), p);
2192	if (error = namei(&fromnd))
2193		return (error);
2194	fvp = fromnd.ni_vp;
2195	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART,
2196	    UIO_USERSPACE, SCARG(uap, to), p);
2197	if (fromnd.ni_vp->v_type == VDIR)
2198		tond.ni_cnd.cn_flags |= WILLBEDIR;
2199	if (error = namei(&tond)) {
2200		/* Translate error code for rename("dir1", "dir2/."). */
2201		if (error == EISDIR && fvp->v_type == VDIR)
2202			error = EINVAL;
2203		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2204		vrele(fromnd.ni_dvp);
2205		vrele(fvp);
2206		goto out1;
2207	}
2208	tdvp = tond.ni_dvp;
2209	tvp = tond.ni_vp;
2210	if (tvp != NULL) {
2211		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
2212			error = ENOTDIR;
2213			goto out;
2214		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
2215			error = EISDIR;
2216			goto out;
2217		}
2218	}
2219	if (fvp == tdvp)
2220		error = EINVAL;
2221	/*
2222	 * If source is the same as the destination (that is the
2223	 * same inode number with the same name in the same directory),
2224	 * then there is nothing to do.
2225	 */
2226	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
2227	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
2228	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
2229	      fromnd.ni_cnd.cn_namelen))
2230		error = -1;
2231out:
2232	if (!error) {
2233		VOP_LEASE(tdvp, p, p->p_ucred, LEASE_WRITE);
2234		if (fromnd.ni_dvp != tdvp)
2235			VOP_LEASE(fromnd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2236		if (tvp) {
2237			VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE);
2238			(void) vnode_pager_uncache(tvp, p);
2239		}
2240		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
2241				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
2242	} else {
2243		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
2244		if (tdvp == tvp)
2245			vrele(tdvp);
2246		else
2247			vput(tdvp);
2248		if (tvp)
2249			vput(tvp);
2250		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
2251		vrele(fromnd.ni_dvp);
2252		vrele(fvp);
2253	}
2254	vrele(tond.ni_startdir);
2255	ASSERT_VOP_UNLOCKED(fromnd.ni_dvp, "rename");
2256	ASSERT_VOP_UNLOCKED(fromnd.ni_vp, "rename");
2257	ASSERT_VOP_UNLOCKED(tond.ni_dvp, "rename");
2258	ASSERT_VOP_UNLOCKED(tond.ni_vp, "rename");
2259	zfree(namei_zone, tond.ni_cnd.cn_pnbuf);
2260out1:
2261	if (fromnd.ni_startdir)
2262		vrele(fromnd.ni_startdir);
2263	zfree(namei_zone, fromnd.ni_cnd.cn_pnbuf);
2264	if (error == -1)
2265		return (0);
2266	return (error);
2267}
2268
2269/*
2270 * Make a directory file.
2271 */
2272#ifndef _SYS_SYSPROTO_H_
2273struct mkdir_args {
2274	char	*path;
2275	int	mode;
2276};
2277#endif
2278/* ARGSUSED */
2279int
2280mkdir(p, uap)
2281	struct proc *p;
2282	register struct mkdir_args /* {
2283		syscallarg(char *) path;
2284		syscallarg(int) mode;
2285	} */ *uap;
2286{
2287	register struct vnode *vp;
2288	struct vattr vattr;
2289	int error;
2290	struct nameidata nd;
2291
2292	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), p);
2293	nd.ni_cnd.cn_flags |= WILLBEDIR;
2294	if (error = namei(&nd))
2295		return (error);
2296	vp = nd.ni_vp;
2297	if (vp != NULL) {
2298		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2299		if (nd.ni_dvp == vp)
2300			vrele(nd.ni_dvp);
2301		else
2302			vput(nd.ni_dvp);
2303		vrele(vp);
2304		return (EEXIST);
2305	}
2306	VATTR_NULL(&vattr);
2307	vattr.va_type = VDIR;
2308	vattr.va_mode = (SCARG(uap, mode) & ACCESSPERMS) &~ p->p_fd->fd_cmask;
2309	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2310	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
2311	if (!error)
2312		vput(nd.ni_vp);
2313	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mkdir");
2314	ASSERT_VOP_UNLOCKED(nd.ni_vp, "mkdir");
2315	return (error);
2316}
2317
2318/*
2319 * Remove a directory file.
2320 */
2321#ifndef _SYS_SYSPROTO_H_
2322struct rmdir_args {
2323	char	*path;
2324};
2325#endif
2326/* ARGSUSED */
2327int
2328rmdir(p, uap)
2329	struct proc *p;
2330	struct rmdir_args /* {
2331		syscallarg(char *) path;
2332	} */ *uap;
2333{
2334	register struct vnode *vp;
2335	int error;
2336	struct nameidata nd;
2337
2338	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
2339	    SCARG(uap, path), p);
2340	if (error = namei(&nd))
2341		return (error);
2342	vp = nd.ni_vp;
2343	if (vp->v_type != VDIR) {
2344		error = ENOTDIR;
2345		goto out;
2346	}
2347	/*
2348	 * No rmdir "." please.
2349	 */
2350	if (nd.ni_dvp == vp) {
2351		error = EINVAL;
2352		goto out;
2353	}
2354	/*
2355	 * The root of a mounted filesystem cannot be deleted.
2356	 */
2357	if (vp->v_flag & VROOT)
2358		error = EBUSY;
2359out:
2360	if (!error) {
2361		VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
2362		VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
2363		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2364	} else {
2365		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2366		if (nd.ni_dvp == vp)
2367			vrele(nd.ni_dvp);
2368		else
2369			vput(nd.ni_dvp);
2370		vput(vp);
2371	}
2372	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "rmdir");
2373	ASSERT_VOP_UNLOCKED(nd.ni_vp, "rmdir");
2374	return (error);
2375}
2376
2377#ifdef COMPAT_43
2378/*
2379 * Read a block of directory entries in a file system independent format.
2380 */
2381#ifndef _SYS_SYSPROTO_H_
2382struct ogetdirentries_args {
2383	int	fd;
2384	char	*buf;
2385	u_int	count;
2386	long	*basep;
2387};
2388#endif
2389int
2390ogetdirentries(p, uap)
2391	struct proc *p;
2392	register struct ogetdirentries_args /* {
2393		syscallarg(int) fd;
2394		syscallarg(char *) buf;
2395		syscallarg(u_int) count;
2396		syscallarg(long *) basep;
2397	} */ *uap;
2398{
2399	register struct vnode *vp;
2400	struct file *fp;
2401	struct uio auio, kuio;
2402	struct iovec aiov, kiov;
2403	struct dirent *dp, *edp;
2404	caddr_t dirbuf;
2405	int error, eofflag, readcnt;
2406	long loff;
2407
2408	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
2409		return (error);
2410	if ((fp->f_flag & FREAD) == 0)
2411		return (EBADF);
2412	vp = (struct vnode *)fp->f_data;
2413unionread:
2414	if (vp->v_type != VDIR)
2415		return (EINVAL);
2416	aiov.iov_base = SCARG(uap, buf);
2417	aiov.iov_len = SCARG(uap, count);
2418	auio.uio_iov = &aiov;
2419	auio.uio_iovcnt = 1;
2420	auio.uio_rw = UIO_READ;
2421	auio.uio_segflg = UIO_USERSPACE;
2422	auio.uio_procp = p;
2423	auio.uio_resid = SCARG(uap, count);
2424	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2425	loff = auio.uio_offset = fp->f_offset;
2426#	if (BYTE_ORDER != LITTLE_ENDIAN)
2427		if (vp->v_mount->mnt_maxsymlinklen <= 0) {
2428			error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
2429			    NULL, NULL);
2430			fp->f_offset = auio.uio_offset;
2431		} else
2432#	endif
2433	{
2434		kuio = auio;
2435		kuio.uio_iov = &kiov;
2436		kuio.uio_segflg = UIO_SYSSPACE;
2437		kiov.iov_len = SCARG(uap, count);
2438		MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK);
2439		kiov.iov_base = dirbuf;
2440		error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
2441			    NULL, NULL);
2442		fp->f_offset = kuio.uio_offset;
2443		if (error == 0) {
2444			readcnt = SCARG(uap, count) - kuio.uio_resid;
2445			edp = (struct dirent *)&dirbuf[readcnt];
2446			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
2447#				if (BYTE_ORDER == LITTLE_ENDIAN)
2448					/*
2449					 * The expected low byte of
2450					 * dp->d_namlen is our dp->d_type.
2451					 * The high MBZ byte of dp->d_namlen
2452					 * is our dp->d_namlen.
2453					 */
2454					dp->d_type = dp->d_namlen;
2455					dp->d_namlen = 0;
2456#				else
2457					/*
2458					 * The dp->d_type is the high byte
2459					 * of the expected dp->d_namlen,
2460					 * so must be zero'ed.
2461					 */
2462					dp->d_type = 0;
2463#				endif
2464				if (dp->d_reclen > 0) {
2465					dp = (struct dirent *)
2466					    ((char *)dp + dp->d_reclen);
2467				} else {
2468					error = EIO;
2469					break;
2470				}
2471			}
2472			if (dp >= edp)
2473				error = uiomove(dirbuf, readcnt, &auio);
2474		}
2475		FREE(dirbuf, M_TEMP);
2476	}
2477	VOP_UNLOCK(vp, 0, p);
2478	if (error)
2479		return (error);
2480
2481#ifdef UNION
2482{
2483	if ((SCARG(uap, count) == auio.uio_resid) &&
2484	    (vp->v_op == union_vnodeop_p)) {
2485		struct vnode *lvp;
2486
2487		lvp = union_dircache(vp, p);
2488		if (lvp != NULLVP) {
2489			struct vattr va;
2490
2491			/*
2492			 * If the directory is opaque,
2493			 * then don't show lower entries
2494			 */
2495			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
2496			if (va.va_flags & OPAQUE) {
2497				vput(lvp);
2498				lvp = NULL;
2499			}
2500		}
2501
2502		if (lvp != NULLVP) {
2503			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
2504			if (error) {
2505				vput(lvp);
2506				return (error);
2507			}
2508			VOP_UNLOCK(lvp, 0, p);
2509			fp->f_data = (caddr_t) lvp;
2510			fp->f_offset = 0;
2511			error = vn_close(vp, FREAD, fp->f_cred, p);
2512			if (error)
2513				return (error);
2514			vp = lvp;
2515			goto unionread;
2516		}
2517	}
2518}
2519#endif /* UNION */
2520
2521	if ((SCARG(uap, count) == auio.uio_resid) &&
2522	    (vp->v_flag & VROOT) &&
2523	    (vp->v_mount->mnt_flag & MNT_UNION)) {
2524		struct vnode *tvp = vp;
2525		vp = vp->v_mount->mnt_vnodecovered;
2526		VREF(vp);
2527		fp->f_data = (caddr_t) vp;
2528		fp->f_offset = 0;
2529		vrele(tvp);
2530		goto unionread;
2531	}
2532	error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
2533	    sizeof(long));
2534	p->p_retval[0] = SCARG(uap, count) - auio.uio_resid;
2535	return (error);
2536}
2537#endif /* COMPAT_43 */
2538
2539/*
2540 * Read a block of directory entries in a file system independent format.
2541 */
2542#ifndef _SYS_SYSPROTO_H_
2543struct getdirentries_args {
2544	int	fd;
2545	char	*buf;
2546	u_int	count;
2547	long	*basep;
2548};
2549#endif
2550int
2551getdirentries(p, uap)
2552	struct proc *p;
2553	register struct getdirentries_args /* {
2554		syscallarg(int) fd;
2555		syscallarg(char *) buf;
2556		syscallarg(u_int) count;
2557		syscallarg(long *) basep;
2558	} */ *uap;
2559{
2560	register struct vnode *vp;
2561	struct file *fp;
2562	struct uio auio;
2563	struct iovec aiov;
2564	long loff;
2565	int error, eofflag;
2566
2567	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp))
2568		return (error);
2569	if ((fp->f_flag & FREAD) == 0)
2570		return (EBADF);
2571	vp = (struct vnode *)fp->f_data;
2572unionread:
2573	if (vp->v_type != VDIR)
2574		return (EINVAL);
2575	aiov.iov_base = SCARG(uap, buf);
2576	aiov.iov_len = SCARG(uap, count);
2577	auio.uio_iov = &aiov;
2578	auio.uio_iovcnt = 1;
2579	auio.uio_rw = UIO_READ;
2580	auio.uio_segflg = UIO_USERSPACE;
2581	auio.uio_procp = p;
2582	auio.uio_resid = SCARG(uap, count);
2583	/* vn_lock(vp, LK_SHARED | LK_RETRY, p); */
2584	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
2585	loff = auio.uio_offset = fp->f_offset;
2586	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, NULL);
2587	fp->f_offset = auio.uio_offset;
2588	VOP_UNLOCK(vp, 0, p);
2589	if (error)
2590		return (error);
2591
2592#ifdef UNION
2593{
2594	if ((SCARG(uap, count) == auio.uio_resid) &&
2595	    (vp->v_op == union_vnodeop_p)) {
2596		struct vnode *lvp;
2597
2598		lvp = union_dircache(vp, p);
2599		if (lvp != NULLVP) {
2600			struct vattr va;
2601
2602			/*
2603			 * If the directory is opaque,
2604			 * then don't show lower entries
2605			 */
2606			error = VOP_GETATTR(vp, &va, fp->f_cred, p);
2607			if (va.va_flags & OPAQUE) {
2608				vput(lvp);
2609				lvp = NULL;
2610			}
2611		}
2612
2613		if (lvp != NULLVP) {
2614			error = VOP_OPEN(lvp, FREAD, fp->f_cred, p);
2615			if (error) {
2616				vput(lvp);
2617				return (error);
2618			}
2619			VOP_UNLOCK(lvp, 0, p);
2620			fp->f_data = (caddr_t) lvp;
2621			fp->f_offset = 0;
2622			error = vn_close(vp, FREAD, fp->f_cred, p);
2623			if (error)
2624				return (error);
2625			vp = lvp;
2626			goto unionread;
2627		}
2628	}
2629}
2630#endif /* UNION */
2631
2632	if ((SCARG(uap, count) == auio.uio_resid) &&
2633	    (vp->v_flag & VROOT) &&
2634	    (vp->v_mount->mnt_flag & MNT_UNION)) {
2635		struct vnode *tvp = vp;
2636		vp = vp->v_mount->mnt_vnodecovered;
2637		VREF(vp);
2638		fp->f_data = (caddr_t) vp;
2639		fp->f_offset = 0;
2640		vrele(tvp);
2641		goto unionread;
2642	}
2643	error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
2644	    sizeof(long));
2645	p->p_retval[0] = SCARG(uap, count) - auio.uio_resid;
2646	return (error);
2647}
2648
2649/*
2650 * Set the mode mask for creation of filesystem nodes.
2651 */
2652#ifndef _SYS_SYSPROTO_H_
2653struct umask_args {
2654	int	newmask;
2655};
2656#endif
2657int
2658umask(p, uap)
2659	struct proc *p;
2660	struct umask_args /* {
2661		syscallarg(int) newmask;
2662	} */ *uap;
2663{
2664	register struct filedesc *fdp;
2665
2666	fdp = p->p_fd;
2667	p->p_retval[0] = fdp->fd_cmask;
2668	fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS;
2669	return (0);
2670}
2671
2672/*
2673 * Void all references to file by ripping underlying filesystem
2674 * away from vnode.
2675 */
2676#ifndef _SYS_SYSPROTO_H_
2677struct revoke_args {
2678	char	*path;
2679};
2680#endif
2681/* ARGSUSED */
2682int
2683revoke(p, uap)
2684	struct proc *p;
2685	register struct revoke_args /* {
2686		syscallarg(char *) path;
2687	} */ *uap;
2688{
2689	register struct vnode *vp;
2690	struct vattr vattr;
2691	int error;
2692	struct nameidata nd;
2693
2694	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), p);
2695	if (error = namei(&nd))
2696		return (error);
2697	vp = nd.ni_vp;
2698	if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
2699		goto out;
2700	if (p->p_ucred->cr_uid != vattr.va_uid &&
2701	    (error = suser(p->p_ucred, &p->p_acflag)))
2702		goto out;
2703	if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
2704		VOP_REVOKE(vp, REVOKEALL);
2705out:
2706	vrele(vp);
2707	return (error);
2708}
2709
2710/*
2711 * Convert a user file descriptor to a kernel file entry.
2712 */
2713int
2714getvnode(fdp, fd, fpp)
2715	struct filedesc *fdp;
2716	int fd;
2717	struct file **fpp;
2718{
2719	struct file *fp;
2720
2721	if ((u_int)fd >= fdp->fd_nfiles ||
2722	    (fp = fdp->fd_ofiles[fd]) == NULL)
2723		return (EBADF);
2724	if (fp->f_type != DTYPE_VNODE && fp->f_type != DTYPE_FIFO)
2725		return (EINVAL);
2726	*fpp = fp;
2727	return (0);
2728}
2729#ifndef _SYS_SYSPROTO_H_
2730struct  __getcwd_args {
2731	u_char	*buf;
2732	u_int	buflen;
2733};
2734#endif
2735#define STATNODE(mode, name, var) \
2736	SYSCTL_INT(_vfs_cache, OID_AUTO, name, mode, var, 0, "");
2737
2738static int disablecwd;
2739SYSCTL_INT(_debug, OID_AUTO, disablecwd, CTLFLAG_RW, &disablecwd, 0, "");
2740
2741static u_long numcwdcalls; STATNODE(CTLFLAG_RD, numcwdcalls, &numcwdcalls);
2742static u_long numcwdfail1; STATNODE(CTLFLAG_RD, numcwdfail1, &numcwdfail1);
2743static u_long numcwdfail2; STATNODE(CTLFLAG_RD, numcwdfail2, &numcwdfail2);
2744static u_long numcwdfail3; STATNODE(CTLFLAG_RD, numcwdfail3, &numcwdfail3);
2745static u_long numcwdfail4; STATNODE(CTLFLAG_RD, numcwdfail4, &numcwdfail4);
2746static u_long numcwdfound; STATNODE(CTLFLAG_RD, numcwdfound, &numcwdfound);
2747int
2748__getcwd(p, uap)
2749	struct proc *p;
2750	struct __getcwd_args *uap;
2751{
2752	struct filedesc *fdp;
2753	struct vnode *vp;
2754	struct namecache *ncp;
2755	char *buf, *bp;
2756	int i, j, error;
2757
2758	if (disablecwd)
2759		return (ENODEV);
2760	fdp = p->p_fd;
2761	j = 0;
2762	error = 0;
2763	if (uap->buflen < 2)
2764		return (EINVAL);
2765	if (uap->buflen > MAXPATHLEN)
2766		uap->buflen = MAXPATHLEN;
2767	buf = bp = malloc(uap->buflen, M_TEMP, M_WAITOK);
2768	bp += uap->buflen - 1;
2769	*bp = '\0';
2770	numcwdcalls++;
2771	for (vp = fdp->fd_cdir; vp != fdp->fd_rdir && vp != rootvnode;) {
2772		if (vp->v_flag & VROOT) {
2773			vp = vp->v_mount->mnt_vnodecovered;
2774			continue;
2775		}
2776		if (vp->v_dd->v_id != vp->v_ddid) {
2777			numcwdfail1++;
2778			free(buf, M_TEMP);
2779			return (ENOTDIR);
2780		}
2781		ncp = TAILQ_FIRST(&vp->v_cache_dst);
2782		if (!ncp) {
2783			numcwdfail2++;
2784			free(buf, M_TEMP);
2785			return (ENOENT);
2786		}
2787		if (ncp->nc_dvp != vp->v_dd) {
2788			numcwdfail3++;
2789			free(buf, M_TEMP);
2790			return (EBADF);
2791		}
2792		for (i=ncp->nc_nlen - 1; i >= 0; i--) {
2793			if (bp == buf) {
2794				numcwdfail4++;
2795				free(buf, M_TEMP);
2796				return (ENOMEM);
2797			}
2798			*--bp = ncp->nc_name[i];
2799		}
2800		if (bp == buf) {
2801			numcwdfail4++;
2802			free(buf, M_TEMP);
2803			return (ENOMEM);
2804		}
2805		*--bp = '/';
2806		j++;
2807		vp = vp->v_dd;
2808	}
2809	if (!j) {
2810		if (bp == buf) {
2811			numcwdfail4++;
2812			free(buf, M_TEMP);
2813			return (ENOMEM);
2814		}
2815		*--bp = '/';
2816	}
2817	numcwdfound++;
2818	error = copyout(bp, uap->buf, strlen(bp) + 1);
2819	free(buf, M_TEMP);
2820	return (error);
2821}
2822