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