vfs_extattr.c revision 92130
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 * $FreeBSD: head/sys/kern/vfs_extattr.c 92130 2002-03-12 04:00:11Z jeff $
40 */
41
42/* For 4.3 integer FS ID compatibility */
43#include "opt_compat.h"
44#include "opt_ffs.h"
45
46#include <sys/param.h>
47#include <sys/systm.h>
48#include <sys/bio.h>
49#include <sys/buf.h>
50#include <sys/sysent.h>
51#include <sys/malloc.h>
52#include <sys/mount.h>
53#include <sys/mutex.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/linker.h>
61#include <sys/stat.h>
62#include <sys/sx.h>
63#include <sys/unistd.h>
64#include <sys/vnode.h>
65#include <sys/proc.h>
66#include <sys/dirent.h>
67#include <sys/extattr.h>
68#include <sys/jail.h>
69#include <sys/sysctl.h>
70
71#include <machine/limits.h>
72
73#include <vm/vm.h>
74#include <vm/vm_object.h>
75#include <vm/vm_zone.h>
76#include <vm/vm_page.h>
77
78static int change_dir __P((struct nameidata *ndp, struct thread *td));
79static void checkdirs __P((struct vnode *olddp, struct vnode *newdp));
80static int chroot_refuse_vdir_fds __P((struct filedesc *fdp));
81static int getutimes __P((const struct timeval *, struct timespec *));
82static int setfown __P((struct thread *td, struct vnode *, uid_t, gid_t));
83static int setfmode __P((struct thread *td, struct vnode *, int));
84static int setfflags __P((struct thread *td, struct vnode *, int));
85static int setutimes __P((struct thread *td, struct vnode *,
86    const struct timespec *, int));
87static int vn_access __P((struct vnode *vp, int user_flags, struct ucred *cred,
88    struct thread *td));
89
90static int	usermount = 0;	/* if 1, non-root can mount fs. */
91
92int (*union_dircheckp) __P((struct thread *td, struct vnode **, struct file *));
93
94SYSCTL_INT(_vfs, OID_AUTO, usermount, CTLFLAG_RW, &usermount, 0, "");
95
96/*
97 * Virtual File System System Calls
98 */
99
100#ifndef _SYS_SYSPROTO_H_
101struct nmount_args {
102	struct iovec    *iovp;
103	unsigned int    iovcnt;
104	int             flags;
105	};
106#endif
107/* ARGSUSED */
108int
109nmount(td, uap)
110	struct thread *td;
111	struct nmount_args /* {
112		syscallarg(struct iovec *) iovp;
113		syscallarg(unsigned int) iovcnt;
114		syscallarg(int) flags;
115	} */ *uap;
116{
117
118	return(EOPNOTSUPP);
119}
120
121/*
122 * Mount a file system.
123 */
124#ifndef _SYS_SYSPROTO_H_
125struct mount_args {
126	char	*type;
127	char	*path;
128	int	flags;
129	caddr_t	data;
130};
131#endif
132/* ARGSUSED */
133int
134mount(td, uap)
135	struct thread *td;
136	struct mount_args /* {
137		syscallarg(char *) type;
138		syscallarg(char *) path;
139		syscallarg(int) flags;
140		syscallarg(caddr_t) data;
141	} */ *uap;
142{
143	char *fstype;
144	char *fspath;
145	int error;
146
147	fstype = malloc(MFSNAMELEN, M_TEMP, M_WAITOK | M_ZERO);
148	fspath = malloc(MNAMELEN, M_TEMP, M_WAITOK | M_ZERO);
149
150	/*
151	 * vfs_mount() actually takes a kernel string for `type' and
152	 * `path' now, so extract them.
153	 */
154	error = copyinstr(SCARG(uap, type), fstype, MFSNAMELEN, NULL);
155	if (error)
156		goto finish;
157	error = copyinstr(SCARG(uap, path), fspath, MNAMELEN, NULL);
158	if (error)
159		goto finish;
160	error = vfs_mount(td, fstype, fspath, SCARG(uap, flags),
161	    SCARG(uap, data));
162finish:
163	free(fstype, M_TEMP);
164	free(fspath, M_TEMP);
165	return (error);
166}
167
168/*
169 * vfs_mount(): actually attempt a filesystem mount.
170 *
171 * This routine is designed to be a "generic" entry point for routines
172 * that wish to mount a filesystem. All parameters except `fsdata' are
173 * pointers into kernel space. `fsdata' is currently still a pointer
174 * into userspace.
175 */
176int
177vfs_mount(td, fstype, fspath, fsflags, fsdata)
178	struct thread *td;
179	const char *fstype;
180	char *fspath;
181	int fsflags;
182	void *fsdata;
183{
184	struct vnode *vp;
185	struct mount *mp;
186	struct vfsconf *vfsp;
187	int error, flag = 0, flag2 = 0;
188	struct vattr va;
189	struct nameidata nd;
190
191	/*
192	 * Be ultra-paranoid about making sure the type and fspath
193	 * variables will fit in our mp buffers, including the
194	 * terminating NUL.
195	 */
196	if ((strlen(fstype) >= MFSNAMELEN - 1) ||
197	    (strlen(fspath) >= MNAMELEN - 1))
198		return (ENAMETOOLONG);
199
200	if (usermount == 0) {
201		error = suser_td(td);
202		if (error)
203			return (error);
204	}
205	/*
206	 * Do not allow NFS export by non-root users.
207	 */
208	if (fsflags & MNT_EXPORTED) {
209		error = suser_td(td);
210		if (error)
211			return (error);
212	}
213	/*
214	 * Silently enforce MNT_NOSUID and MNT_NODEV for non-root users
215	 */
216	if (suser_xxx(td->td_ucred, 0, 0))
217		fsflags |= MNT_NOSUID | MNT_NODEV;
218	/*
219	 * Get vnode to be covered
220	 */
221	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspath, td);
222	if ((error = namei(&nd)) != 0)
223		return (error);
224	NDFREE(&nd, NDF_ONLY_PNBUF);
225	vp = nd.ni_vp;
226	if (fsflags & MNT_UPDATE) {
227		if ((vp->v_flag & VROOT) == 0) {
228			vput(vp);
229			return (EINVAL);
230		}
231		mp = vp->v_mount;
232		flag = mp->mnt_flag;
233		flag2 = mp->mnt_kern_flag;
234		/*
235		 * We only allow the filesystem to be reloaded if it
236		 * is currently mounted read-only.
237		 */
238		if ((fsflags & MNT_RELOAD) &&
239		    ((mp->mnt_flag & MNT_RDONLY) == 0)) {
240			vput(vp);
241			return (EOPNOTSUPP);	/* Needs translation */
242		}
243		/*
244		 * Only root, or the user that did the original mount is
245		 * permitted to update it.
246		 */
247		if (mp->mnt_stat.f_owner != td->td_ucred->cr_uid) {
248			error = suser_td(td);
249			if (error) {
250				vput(vp);
251				return (error);
252			}
253		}
254		if (vfs_busy(mp, LK_NOWAIT, 0, td)) {
255			vput(vp);
256			return (EBUSY);
257		}
258		mtx_lock(&vp->v_interlock);
259		if ((vp->v_flag & VMOUNT) != 0 ||
260		    vp->v_mountedhere != NULL) {
261			mtx_unlock(&vp->v_interlock);
262			vfs_unbusy(mp, td);
263			vput(vp);
264			return (EBUSY);
265		}
266		vp->v_flag |= VMOUNT;
267		mtx_unlock(&vp->v_interlock);
268		mp->mnt_flag |= fsflags &
269		    (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_SNAPSHOT);
270		VOP_UNLOCK(vp, 0, td);
271		goto update;
272	}
273	/*
274	 * If the user is not root, ensure that they own the directory
275	 * onto which we are attempting to mount.
276	 */
277	error = VOP_GETATTR(vp, &va, td->td_ucred, td);
278	if (error) {
279		vput(vp);
280		return (error);
281	}
282	if (va.va_uid != td->td_ucred->cr_uid) {
283		error = suser_td(td);
284		if (error) {
285			vput(vp);
286			return (error);
287		}
288	}
289	if ((error = vinvalbuf(vp, V_SAVE, td->td_ucred, td, 0, 0))
290	    != 0) {
291		vput(vp);
292		return (error);
293	}
294	if (vp->v_type != VDIR) {
295		vput(vp);
296		return (ENOTDIR);
297	}
298	for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
299		if (!strcmp(vfsp->vfc_name, fstype))
300			break;
301	if (vfsp == NULL) {
302		linker_file_t lf;
303
304		/* Only load modules for root (very important!) */
305		error = suser_td(td);
306		if (error) {
307			vput(vp);
308			return error;
309		}
310		error = linker_load_file(fstype, &lf);
311		if (error || lf == NULL) {
312			vput(vp);
313			if (lf == NULL)
314				error = ENODEV;
315			return error;
316		}
317		lf->userrefs++;
318		/* lookup again, see if the VFS was loaded */
319		for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
320			if (!strcmp(vfsp->vfc_name, fstype))
321				break;
322		if (vfsp == NULL) {
323			lf->userrefs--;
324			linker_file_unload(lf);
325			vput(vp);
326			return (ENODEV);
327		}
328	}
329	mtx_lock(&vp->v_interlock);
330	if ((vp->v_flag & VMOUNT) != 0 ||
331	    vp->v_mountedhere != NULL) {
332		mtx_unlock(&vp->v_interlock);
333		vput(vp);
334		return (EBUSY);
335	}
336	vp->v_flag |= VMOUNT;
337	mtx_unlock(&vp->v_interlock);
338
339	/*
340	 * Allocate and initialize the filesystem.
341	 */
342	mp = malloc(sizeof(struct mount), M_MOUNT, M_WAITOK | M_ZERO);
343	TAILQ_INIT(&mp->mnt_nvnodelist);
344	TAILQ_INIT(&mp->mnt_reservedvnlist);
345	lockinit(&mp->mnt_lock, PVFS, "vfslock", 0, LK_NOPAUSE);
346	(void)vfs_busy(mp, LK_NOWAIT, 0, td);
347	mp->mnt_op = vfsp->vfc_vfsops;
348	mp->mnt_vfc = vfsp;
349	vfsp->vfc_refcount++;
350	mp->mnt_stat.f_type = vfsp->vfc_typenum;
351	mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
352	strncpy(mp->mnt_stat.f_fstypename, fstype, MFSNAMELEN);
353	mp->mnt_stat.f_fstypename[MFSNAMELEN - 1] = '\0';
354	mp->mnt_vnodecovered = vp;
355	mp->mnt_stat.f_owner = td->td_ucred->cr_uid;
356	strncpy(mp->mnt_stat.f_mntonname, fspath, MNAMELEN);
357	mp->mnt_stat.f_mntonname[MNAMELEN - 1] = '\0';
358	mp->mnt_iosize_max = DFLTPHYS;
359	VOP_UNLOCK(vp, 0, td);
360update:
361	/*
362	 * Set the mount level flags.
363	 */
364	if (fsflags & MNT_RDONLY)
365		mp->mnt_flag |= MNT_RDONLY;
366	else if (mp->mnt_flag & MNT_RDONLY)
367		mp->mnt_kern_flag |= MNTK_WANTRDWR;
368	mp->mnt_flag &=~ MNT_UPDATEMASK;
369	mp->mnt_flag |= fsflags & (MNT_UPDATEMASK | MNT_FORCE);
370	/*
371	 * Mount the filesystem.
372	 * XXX The final recipients of VFS_MOUNT just overwrite the ndp they
373	 * get.  No freeing of cn_pnbuf.
374	 */
375	error = VFS_MOUNT(mp, fspath, fsdata, &nd, td);
376	if (mp->mnt_flag & MNT_UPDATE) {
377		if (mp->mnt_kern_flag & MNTK_WANTRDWR)
378			mp->mnt_flag &= ~MNT_RDONLY;
379		mp->mnt_flag &=~
380		    (MNT_UPDATE | MNT_RELOAD | MNT_FORCE | MNT_SNAPSHOT);
381		mp->mnt_kern_flag &=~ MNTK_WANTRDWR;
382		if (error) {
383			mp->mnt_flag = flag;
384			mp->mnt_kern_flag = flag2;
385		}
386		if ((mp->mnt_flag & MNT_RDONLY) == 0) {
387			if (mp->mnt_syncer == NULL)
388				error = vfs_allocate_syncvnode(mp);
389		} else {
390			if (mp->mnt_syncer != NULL)
391				vrele(mp->mnt_syncer);
392			mp->mnt_syncer = NULL;
393		}
394		vfs_unbusy(mp, td);
395		mtx_lock(&vp->v_interlock);
396		vp->v_flag &= ~VMOUNT;
397		mtx_unlock(&vp->v_interlock);
398		vrele(vp);
399		return (error);
400	}
401	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
402	/*
403	 * Put the new filesystem on the mount list after root.
404	 */
405	cache_purge(vp);
406	if (!error) {
407		struct vnode *newdp;
408
409		mtx_lock(&vp->v_interlock);
410		vp->v_flag &= ~VMOUNT;
411		vp->v_mountedhere = mp;
412		mtx_unlock(&vp->v_interlock);
413		mtx_lock(&mountlist_mtx);
414		TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
415		mtx_unlock(&mountlist_mtx);
416		if (VFS_ROOT(mp, &newdp))
417			panic("mount: lost mount");
418		checkdirs(vp, newdp);
419		vput(newdp);
420		VOP_UNLOCK(vp, 0, td);
421		if ((mp->mnt_flag & MNT_RDONLY) == 0)
422			error = vfs_allocate_syncvnode(mp);
423		vfs_unbusy(mp, td);
424		if ((error = VFS_START(mp, 0, td)) != 0)
425			vrele(vp);
426	} else {
427		mtx_lock(&vp->v_interlock);
428		vp->v_flag &= ~VMOUNT;
429		mtx_unlock(&vp->v_interlock);
430		mp->mnt_vfc->vfc_refcount--;
431		vfs_unbusy(mp, td);
432		free((caddr_t)mp, M_MOUNT);
433		vput(vp);
434	}
435	return (error);
436}
437
438/*
439 * Scan all active processes to see if any of them have a current
440 * or root directory of `olddp'. If so, replace them with the new
441 * mount point.
442 */
443static void
444checkdirs(olddp, newdp)
445	struct vnode *olddp, *newdp;
446{
447	struct filedesc *fdp;
448	struct proc *p;
449
450	if (olddp->v_usecount == 1)
451		return;
452	sx_slock(&allproc_lock);
453	LIST_FOREACH(p, &allproc, p_list) {
454		fdp = p->p_fd;
455		if (fdp == NULL)
456			continue;
457		FILEDESC_LOCK(fdp);
458		if (fdp->fd_cdir == olddp) {
459			VREF(newdp);
460			fdp->fd_cdir = newdp;
461			FILEDESC_UNLOCK(fdp);
462			vrele(olddp);
463			FILEDESC_LOCK(fdp);
464		}
465		if (fdp->fd_rdir == olddp) {
466			VREF(newdp);
467			fdp->fd_rdir = newdp;
468			FILEDESC_UNLOCK(fdp);
469			vrele(olddp);
470		} else
471			FILEDESC_UNLOCK(fdp);
472	}
473	sx_sunlock(&allproc_lock);
474	if (rootvnode == olddp) {
475		vrele(rootvnode);
476		VREF(newdp);
477		rootvnode = newdp;
478	}
479}
480
481/*
482 * Unmount a file system.
483 *
484 * Note: unmount takes a path to the vnode mounted on as argument,
485 * not special file (as before).
486 */
487#ifndef _SYS_SYSPROTO_H_
488struct unmount_args {
489	char	*path;
490	int	flags;
491};
492#endif
493/* ARGSUSED */
494int
495unmount(td, uap)
496	struct thread *td;
497	register struct unmount_args /* {
498		syscallarg(char *) path;
499		syscallarg(int) flags;
500	} */ *uap;
501{
502	register struct vnode *vp;
503	struct mount *mp;
504	int error;
505	struct nameidata nd;
506
507	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
508	    SCARG(uap, path), td);
509	if ((error = namei(&nd)) != 0)
510		return (error);
511	vp = nd.ni_vp;
512	NDFREE(&nd, NDF_ONLY_PNBUF);
513	mp = vp->v_mount;
514
515	/*
516	 * Only root, or the user that did the original mount is
517	 * permitted to unmount this filesystem.
518	 */
519	if (mp->mnt_stat.f_owner != td->td_ucred->cr_uid) {
520		error = suser_td(td);
521		if (error) {
522			vput(vp);
523			return (error);
524		}
525	}
526
527	/*
528	 * Don't allow unmounting the root file system.
529	 */
530	if (mp->mnt_flag & MNT_ROOTFS) {
531		vput(vp);
532		return (EINVAL);
533	}
534
535	/*
536	 * Must be the root of the filesystem
537	 */
538	if ((vp->v_flag & VROOT) == 0) {
539		vput(vp);
540		return (EINVAL);
541	}
542	vput(vp);
543	return (dounmount(mp, SCARG(uap, flags), td));
544}
545
546/*
547 * Do the actual file system unmount.
548 */
549int
550dounmount(mp, flags, td)
551	struct mount *mp;
552	int flags;
553	struct thread *td;
554{
555	struct vnode *coveredvp, *fsrootvp;
556	int error;
557	int async_flag;
558
559	mtx_lock(&mountlist_mtx);
560	mp->mnt_kern_flag |= MNTK_UNMOUNT;
561	error = lockmgr(&mp->mnt_lock, LK_DRAIN | LK_INTERLOCK |
562	    ((flags & MNT_FORCE) ? 0 : LK_NOWAIT), &mountlist_mtx, td);
563	if (error) {
564		mp->mnt_kern_flag &= ~MNTK_UNMOUNT;
565		if (mp->mnt_kern_flag & MNTK_MWAIT)
566			wakeup((caddr_t)mp);
567		return (error);
568	}
569	vn_start_write(NULL, &mp, V_WAIT);
570
571	if (mp->mnt_flag & MNT_EXPUBLIC)
572		vfs_setpublicfs(NULL, NULL, NULL);
573
574	vfs_msync(mp, MNT_WAIT);
575	async_flag = mp->mnt_flag & MNT_ASYNC;
576	mp->mnt_flag &=~ MNT_ASYNC;
577	cache_purgevfs(mp);	/* remove cache entries for this file sys */
578	if (mp->mnt_syncer != NULL)
579		vrele(mp->mnt_syncer);
580	/* Move process cdir/rdir refs on fs root to underlying vnode. */
581	if (VFS_ROOT(mp, &fsrootvp) == 0) {
582		if (mp->mnt_vnodecovered != NULL)
583			checkdirs(fsrootvp, mp->mnt_vnodecovered);
584		if (fsrootvp == rootvnode) {
585			vrele(rootvnode);
586			rootvnode = NULL;
587		}
588		vput(fsrootvp);
589	}
590	if (((mp->mnt_flag & MNT_RDONLY) ||
591	     (error = VFS_SYNC(mp, MNT_WAIT, td->td_ucred, td)) == 0) ||
592	    (flags & MNT_FORCE)) {
593		error = VFS_UNMOUNT(mp, flags, td);
594	}
595	vn_finished_write(mp);
596	if (error) {
597		/* Undo cdir/rdir and rootvnode changes made above. */
598		if (VFS_ROOT(mp, &fsrootvp) == 0) {
599			if (mp->mnt_vnodecovered != NULL)
600				checkdirs(mp->mnt_vnodecovered, fsrootvp);
601			if (rootvnode == NULL) {
602				rootvnode = fsrootvp;
603				vref(rootvnode);
604			}
605			vput(fsrootvp);
606		}
607		if ((mp->mnt_flag & MNT_RDONLY) == 0 && mp->mnt_syncer == NULL)
608			(void) vfs_allocate_syncvnode(mp);
609		mtx_lock(&mountlist_mtx);
610		mp->mnt_kern_flag &= ~MNTK_UNMOUNT;
611		mp->mnt_flag |= async_flag;
612		lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK,
613		    &mountlist_mtx, td);
614		if (mp->mnt_kern_flag & MNTK_MWAIT)
615			wakeup((caddr_t)mp);
616		return (error);
617	}
618	mtx_lock(&mountlist_mtx);
619	TAILQ_REMOVE(&mountlist, mp, mnt_list);
620	if ((coveredvp = mp->mnt_vnodecovered) != NULL)
621		coveredvp->v_mountedhere = NULL;
622	mp->mnt_vfc->vfc_refcount--;
623	if (!TAILQ_EMPTY(&mp->mnt_nvnodelist))
624		panic("unmount: dangling vnode");
625	lockmgr(&mp->mnt_lock, LK_RELEASE | LK_INTERLOCK, &mountlist_mtx, td);
626	lockdestroy(&mp->mnt_lock);
627	if (coveredvp != NULL)
628		vrele(coveredvp);
629	if (mp->mnt_kern_flag & MNTK_MWAIT)
630		wakeup((caddr_t)mp);
631	free((caddr_t)mp, M_MOUNT);
632	return (0);
633}
634
635/*
636 * Sync each mounted filesystem.
637 */
638#ifndef _SYS_SYSPROTO_H_
639struct sync_args {
640        int     dummy;
641};
642#endif
643
644#ifdef DEBUG
645static int syncprt = 0;
646SYSCTL_INT(_debug, OID_AUTO, syncprt, CTLFLAG_RW, &syncprt, 0, "");
647#endif
648
649/* ARGSUSED */
650int
651sync(td, uap)
652	struct thread *td;
653	struct sync_args *uap;
654{
655	struct mount *mp, *nmp;
656	int asyncflag;
657
658	mtx_lock(&mountlist_mtx);
659	for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
660		if (vfs_busy(mp, LK_NOWAIT, &mountlist_mtx, td)) {
661			nmp = TAILQ_NEXT(mp, mnt_list);
662			continue;
663		}
664		if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
665		    vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
666			asyncflag = mp->mnt_flag & MNT_ASYNC;
667			mp->mnt_flag &= ~MNT_ASYNC;
668			vfs_msync(mp, MNT_NOWAIT);
669			VFS_SYNC(mp, MNT_NOWAIT,
670			    ((td != NULL) ? td->td_ucred : NOCRED), td);
671			mp->mnt_flag |= asyncflag;
672			vn_finished_write(mp);
673		}
674		mtx_lock(&mountlist_mtx);
675		nmp = TAILQ_NEXT(mp, mnt_list);
676		vfs_unbusy(mp, td);
677	}
678	mtx_unlock(&mountlist_mtx);
679#if 0
680/*
681 * XXX don't call vfs_bufstats() yet because that routine
682 * was not imported in the Lite2 merge.
683 */
684#ifdef DIAGNOSTIC
685	if (syncprt)
686		vfs_bufstats();
687#endif /* DIAGNOSTIC */
688#endif
689	return (0);
690}
691
692/* XXX PRISON: could be per prison flag */
693static int prison_quotas;
694#if 0
695SYSCTL_INT(_kern_prison, OID_AUTO, quotas, CTLFLAG_RW, &prison_quotas, 0, "");
696#endif
697
698/*
699 * Change filesystem quotas.
700 */
701#ifndef _SYS_SYSPROTO_H_
702struct quotactl_args {
703	char *path;
704	int cmd;
705	int uid;
706	caddr_t arg;
707};
708#endif
709/* ARGSUSED */
710int
711quotactl(td, uap)
712	struct thread *td;
713	register struct quotactl_args /* {
714		syscallarg(char *) path;
715		syscallarg(int) cmd;
716		syscallarg(int) uid;
717		syscallarg(caddr_t) arg;
718	} */ *uap;
719{
720	struct mount *mp;
721	int error;
722	struct nameidata nd;
723
724	if (jailed(td->td_ucred) && !prison_quotas)
725		return (EPERM);
726	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
727	if ((error = namei(&nd)) != 0)
728		return (error);
729	NDFREE(&nd, NDF_ONLY_PNBUF);
730	error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
731	vrele(nd.ni_vp);
732	if (error)
733		return (error);
734	error = VFS_QUOTACTL(mp, SCARG(uap, cmd), SCARG(uap, uid),
735	    SCARG(uap, arg), td);
736	vn_finished_write(mp);
737	return (error);
738}
739
740/*
741 * Get filesystem statistics.
742 */
743#ifndef _SYS_SYSPROTO_H_
744struct statfs_args {
745	char *path;
746	struct statfs *buf;
747};
748#endif
749/* ARGSUSED */
750int
751statfs(td, uap)
752	struct thread *td;
753	register struct statfs_args /* {
754		syscallarg(char *) path;
755		syscallarg(struct statfs *) buf;
756	} */ *uap;
757{
758	register struct mount *mp;
759	register struct statfs *sp;
760	int error;
761	struct nameidata nd;
762	struct statfs sb;
763
764	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
765	if ((error = namei(&nd)) != 0)
766		return (error);
767	mp = nd.ni_vp->v_mount;
768	sp = &mp->mnt_stat;
769	NDFREE(&nd, NDF_ONLY_PNBUF);
770	vrele(nd.ni_vp);
771	error = VFS_STATFS(mp, sp, td);
772	if (error)
773		return (error);
774	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
775	if (suser_xxx(td->td_ucred, 0, 0)) {
776		bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
777		sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
778		sp = &sb;
779	}
780	return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
781}
782
783/*
784 * Get filesystem statistics.
785 */
786#ifndef _SYS_SYSPROTO_H_
787struct fstatfs_args {
788	int fd;
789	struct statfs *buf;
790};
791#endif
792/* ARGSUSED */
793int
794fstatfs(td, uap)
795	struct thread *td;
796	register struct fstatfs_args /* {
797		syscallarg(int) fd;
798		syscallarg(struct statfs *) buf;
799	} */ *uap;
800{
801	struct file *fp;
802	struct mount *mp;
803	register struct statfs *sp;
804	int error;
805	struct statfs sb;
806
807	if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
808		return (error);
809	mp = ((struct vnode *)fp->f_data)->v_mount;
810	fdrop(fp, td);
811	if (mp == NULL)
812		return (EBADF);
813	sp = &mp->mnt_stat;
814	error = VFS_STATFS(mp, sp, td);
815	if (error)
816		return (error);
817	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
818	if (suser_xxx(td->td_ucred, 0, 0)) {
819		bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
820		sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
821		sp = &sb;
822	}
823	return (copyout((caddr_t)sp, (caddr_t)SCARG(uap, buf), sizeof(*sp)));
824}
825
826/*
827 * Get statistics on all filesystems.
828 */
829#ifndef _SYS_SYSPROTO_H_
830struct getfsstat_args {
831	struct statfs *buf;
832	long bufsize;
833	int flags;
834};
835#endif
836int
837getfsstat(td, uap)
838	struct thread *td;
839	register struct getfsstat_args /* {
840		syscallarg(struct statfs *) buf;
841		syscallarg(long) bufsize;
842		syscallarg(int) flags;
843	} */ *uap;
844{
845	register struct mount *mp, *nmp;
846	register struct statfs *sp;
847	caddr_t sfsp;
848	long count, maxcount, error;
849
850	maxcount = SCARG(uap, bufsize) / sizeof(struct statfs);
851	sfsp = (caddr_t)SCARG(uap, buf);
852	count = 0;
853	mtx_lock(&mountlist_mtx);
854	for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
855		if (vfs_busy(mp, LK_NOWAIT, &mountlist_mtx, td)) {
856			nmp = TAILQ_NEXT(mp, mnt_list);
857			continue;
858		}
859		if (sfsp && count < maxcount) {
860			sp = &mp->mnt_stat;
861			/*
862			 * If MNT_NOWAIT or MNT_LAZY is specified, do not
863			 * refresh the fsstat cache. MNT_NOWAIT or MNT_LAZY
864			 * overrides MNT_WAIT.
865			 */
866			if (((SCARG(uap, flags) & (MNT_LAZY|MNT_NOWAIT)) == 0 ||
867			    (SCARG(uap, flags) & MNT_WAIT)) &&
868			    (error = VFS_STATFS(mp, sp, td))) {
869				mtx_lock(&mountlist_mtx);
870				nmp = TAILQ_NEXT(mp, mnt_list);
871				vfs_unbusy(mp, td);
872				continue;
873			}
874			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
875			error = copyout((caddr_t)sp, sfsp, sizeof(*sp));
876			if (error) {
877				vfs_unbusy(mp, td);
878				return (error);
879			}
880			sfsp += sizeof(*sp);
881		}
882		count++;
883		mtx_lock(&mountlist_mtx);
884		nmp = TAILQ_NEXT(mp, mnt_list);
885		vfs_unbusy(mp, td);
886	}
887	mtx_unlock(&mountlist_mtx);
888	if (sfsp && count > maxcount)
889		td->td_retval[0] = maxcount;
890	else
891		td->td_retval[0] = count;
892	return (0);
893}
894
895/*
896 * Change current working directory to a given file descriptor.
897 */
898#ifndef _SYS_SYSPROTO_H_
899struct fchdir_args {
900	int	fd;
901};
902#endif
903/* ARGSUSED */
904int
905fchdir(td, uap)
906	struct thread *td;
907	struct fchdir_args /* {
908		syscallarg(int) fd;
909	} */ *uap;
910{
911	register struct filedesc *fdp = td->td_proc->p_fd;
912	struct vnode *vp, *tdp, *vpold;
913	struct mount *mp;
914	struct file *fp;
915	int error;
916
917	if ((error = getvnode(fdp, SCARG(uap, fd), &fp)) != 0)
918		return (error);
919	vp = (struct vnode *)fp->f_data;
920	VREF(vp);
921	fdrop(fp, td);
922	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
923	if (vp->v_type != VDIR)
924		error = ENOTDIR;
925	else
926		error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td);
927	while (!error && (mp = vp->v_mountedhere) != NULL) {
928		if (vfs_busy(mp, 0, 0, td))
929			continue;
930		error = VFS_ROOT(mp, &tdp);
931		vfs_unbusy(mp, td);
932		if (error)
933			break;
934		vput(vp);
935		vp = tdp;
936	}
937	if (error) {
938		vput(vp);
939		return (error);
940	}
941	VOP_UNLOCK(vp, 0, td);
942	FILEDESC_LOCK(fdp);
943	vpold = fdp->fd_cdir;
944	fdp->fd_cdir = vp;
945	FILEDESC_UNLOCK(fdp);
946	vrele(vpold);
947	return (0);
948}
949
950/*
951 * Change current working directory (``.'').
952 */
953#ifndef _SYS_SYSPROTO_H_
954struct chdir_args {
955	char	*path;
956};
957#endif
958/* ARGSUSED */
959int
960chdir(td, uap)
961	struct thread *td;
962	struct chdir_args /* {
963		syscallarg(char *) path;
964	} */ *uap;
965{
966	register struct filedesc *fdp = td->td_proc->p_fd;
967	int error;
968	struct nameidata nd;
969	struct vnode *vp;
970
971	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
972	    SCARG(uap, path), td);
973	if ((error = change_dir(&nd, td)) != 0)
974		return (error);
975	NDFREE(&nd, NDF_ONLY_PNBUF);
976	FILEDESC_LOCK(fdp);
977	vp = fdp->fd_cdir;
978	fdp->fd_cdir = nd.ni_vp;
979	FILEDESC_UNLOCK(fdp);
980	vrele(vp);
981	return (0);
982}
983
984/*
985 * Helper function for raised chroot(2) security function:  Refuse if
986 * any filedescriptors are open directories.
987 */
988static int
989chroot_refuse_vdir_fds(fdp)
990	struct filedesc *fdp;
991{
992	struct vnode *vp;
993	struct file *fp;
994	int fd;
995
996	FILEDESC_LOCK(fdp);
997	for (fd = 0; fd < fdp->fd_nfiles ; fd++) {
998		fp = fget_locked(fdp, fd);
999		if (fp == NULL)
1000			continue;
1001		if (fp->f_type == DTYPE_VNODE) {
1002			vp = (struct vnode *)fp->f_data;
1003			if (vp->v_type == VDIR) {
1004				FILEDESC_UNLOCK(fdp);
1005				return (EPERM);
1006			}
1007		}
1008	}
1009	FILEDESC_UNLOCK(fdp);
1010	return (0);
1011}
1012
1013/*
1014 * This sysctl determines if we will allow a process to chroot(2) if it
1015 * has a directory open:
1016 *	0: disallowed for all processes.
1017 *	1: allowed for processes that were not already chroot(2)'ed.
1018 *	2: allowed for all processes.
1019 */
1020
1021static int chroot_allow_open_directories = 1;
1022
1023SYSCTL_INT(_kern, OID_AUTO, chroot_allow_open_directories, CTLFLAG_RW,
1024     &chroot_allow_open_directories, 0, "");
1025
1026/*
1027 * Change notion of root (``/'') directory.
1028 */
1029#ifndef _SYS_SYSPROTO_H_
1030struct chroot_args {
1031	char	*path;
1032};
1033#endif
1034/* ARGSUSED */
1035int
1036chroot(td, uap)
1037	struct thread *td;
1038	struct chroot_args /* {
1039		syscallarg(char *) path;
1040	} */ *uap;
1041{
1042	register struct filedesc *fdp = td->td_proc->p_fd;
1043	int error;
1044	struct nameidata nd;
1045	struct vnode *vp;
1046
1047	error = suser_xxx(0, td->td_proc, PRISON_ROOT);
1048	if (error)
1049		return (error);
1050	FILEDESC_LOCK(fdp);
1051	if (chroot_allow_open_directories == 0 ||
1052	    (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) {
1053		FILEDESC_UNLOCK(fdp);
1054		error = chroot_refuse_vdir_fds(fdp);
1055	} else
1056		FILEDESC_UNLOCK(fdp);
1057	if (error)
1058		return (error);
1059	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
1060	    SCARG(uap, path), td);
1061	if ((error = change_dir(&nd, td)) != 0)
1062		return (error);
1063	NDFREE(&nd, NDF_ONLY_PNBUF);
1064	FILEDESC_LOCK(fdp);
1065	vp = fdp->fd_rdir;
1066	fdp->fd_rdir = nd.ni_vp;
1067	if (!fdp->fd_jdir) {
1068		fdp->fd_jdir = nd.ni_vp;
1069                VREF(fdp->fd_jdir);
1070	}
1071	FILEDESC_UNLOCK(fdp);
1072	vrele(vp);
1073	return (0);
1074}
1075
1076/*
1077 * Common routine for chroot and chdir.
1078 */
1079static int
1080change_dir(ndp, td)
1081	register struct nameidata *ndp;
1082	struct thread *td;
1083{
1084	struct vnode *vp;
1085	int error;
1086
1087	error = namei(ndp);
1088	if (error)
1089		return (error);
1090	vp = ndp->ni_vp;
1091	if (vp->v_type != VDIR)
1092		error = ENOTDIR;
1093	else
1094		error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td);
1095	if (error)
1096		vput(vp);
1097	else
1098		VOP_UNLOCK(vp, 0, td);
1099	return (error);
1100}
1101
1102/*
1103 * Check permissions, allocate an open file structure,
1104 * and call the device open routine if any.
1105 */
1106#ifndef _SYS_SYSPROTO_H_
1107struct open_args {
1108	char	*path;
1109	int	flags;
1110	int	mode;
1111};
1112#endif
1113int
1114open(td, uap)
1115	struct thread *td;
1116	register struct open_args /* {
1117		syscallarg(char *) path;
1118		syscallarg(int) flags;
1119		syscallarg(int) mode;
1120	} */ *uap;
1121{
1122	struct proc *p = td->td_proc;
1123	struct filedesc *fdp = p->p_fd;
1124	struct file *fp;
1125	struct vnode *vp;
1126	struct vattr vat;
1127	struct mount *mp;
1128	int cmode, flags, oflags;
1129	struct file *nfp;
1130	int type, indx, error;
1131	struct flock lf;
1132	struct nameidata nd;
1133
1134	oflags = SCARG(uap, flags);
1135	if ((oflags & O_ACCMODE) == O_ACCMODE)
1136		return (EINVAL);
1137	flags = FFLAGS(oflags);
1138	error = falloc(td, &nfp, &indx);
1139	if (error)
1140		return (error);
1141	fp = nfp;
1142	FILEDESC_LOCK(fdp);
1143	cmode = ((SCARG(uap, mode) &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
1144	FILEDESC_UNLOCK(fdp);
1145	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
1146	td->td_dupfd = -indx - 1;		/* XXX check for fdopen */
1147	/*
1148	 * Bump the ref count to prevent another process from closing
1149	 * the descriptor while we are blocked in vn_open()
1150	 */
1151	fhold(fp);
1152	error = vn_open(&nd, &flags, cmode);
1153	if (error) {
1154		/*
1155		 * release our own reference
1156		 */
1157		fdrop(fp, td);
1158
1159		/*
1160		 * handle special fdopen() case.  bleh.  dupfdopen() is
1161		 * responsible for dropping the old contents of ofiles[indx]
1162		 * if it succeeds.
1163		 */
1164		if ((error == ENODEV || error == ENXIO) &&
1165		    td->td_dupfd >= 0 &&		/* XXX from fdopen */
1166		    (error =
1167			dupfdopen(td, fdp, indx, td->td_dupfd, flags, error)) == 0) {
1168			td->td_retval[0] = indx;
1169			return (0);
1170		}
1171		/*
1172		 * Clean up the descriptor, but only if another thread hadn't
1173		 * replaced or closed it.
1174		 */
1175		FILEDESC_LOCK(fdp);
1176		if (fdp->fd_ofiles[indx] == fp) {
1177			fdp->fd_ofiles[indx] = NULL;
1178			FILEDESC_UNLOCK(fdp);
1179			fdrop(fp, td);
1180		} else
1181			FILEDESC_UNLOCK(fdp);
1182
1183		if (error == ERESTART)
1184			error = EINTR;
1185		return (error);
1186	}
1187	td->td_dupfd = 0;
1188	NDFREE(&nd, NDF_ONLY_PNBUF);
1189	vp = nd.ni_vp;
1190
1191	/*
1192	 * There should be 2 references on the file, one from the descriptor
1193	 * table, and one for us.
1194	 *
1195	 * Handle the case where someone closed the file (via its file
1196	 * descriptor) while we were blocked.  The end result should look
1197	 * like opening the file succeeded but it was immediately closed.
1198	 */
1199	FILEDESC_LOCK(fdp);
1200	FILE_LOCK(fp);
1201	if (fp->f_count == 1) {
1202		KASSERT(fdp->fd_ofiles[indx] != fp,
1203		    ("Open file descriptor lost all refs"));
1204		FILEDESC_UNLOCK(fdp);
1205		FILE_UNLOCK(fp);
1206		VOP_UNLOCK(vp, 0, td);
1207		vn_close(vp, flags & FMASK, fp->f_cred, td);
1208		fdrop(fp, td);
1209		td->td_retval[0] = indx;
1210		return 0;
1211	}
1212
1213	fp->f_data = (caddr_t)vp;
1214	fp->f_flag = flags & FMASK;
1215	fp->f_ops = &vnops;
1216	fp->f_type = (vp->v_type == VFIFO ? DTYPE_FIFO : DTYPE_VNODE);
1217	FILEDESC_UNLOCK(fdp);
1218	FILE_UNLOCK(fp);
1219	VOP_UNLOCK(vp, 0, td);
1220	if (flags & (O_EXLOCK | O_SHLOCK)) {
1221		lf.l_whence = SEEK_SET;
1222		lf.l_start = 0;
1223		lf.l_len = 0;
1224		if (flags & O_EXLOCK)
1225			lf.l_type = F_WRLCK;
1226		else
1227			lf.l_type = F_RDLCK;
1228		type = F_FLOCK;
1229		if ((flags & FNONBLOCK) == 0)
1230			type |= F_WAIT;
1231		if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) != 0)
1232			goto bad;
1233		fp->f_flag |= FHASLOCK;
1234	}
1235	if (flags & O_TRUNC) {
1236		if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
1237			goto bad;
1238		VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
1239		VATTR_NULL(&vat);
1240		vat.va_size = 0;
1241		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
1242		error = VOP_SETATTR(vp, &vat, td->td_ucred, td);
1243		VOP_UNLOCK(vp, 0, td);
1244		vn_finished_write(mp);
1245		if (error)
1246			goto bad;
1247	}
1248	/* assert that vn_open created a backing object if one is needed */
1249	KASSERT(!vn_canvmio(vp) || VOP_GETVOBJECT(vp, NULL) == 0,
1250		("open: vmio vnode has no backing object after vn_open"));
1251	/*
1252	 * Release our private reference, leaving the one associated with
1253	 * the descriptor table intact.
1254	 */
1255	fdrop(fp, td);
1256	td->td_retval[0] = indx;
1257	return (0);
1258bad:
1259	FILEDESC_LOCK(fdp);
1260	if (fdp->fd_ofiles[indx] == fp) {
1261		fdp->fd_ofiles[indx] = NULL;
1262		FILEDESC_UNLOCK(fdp);
1263		fdrop(fp, td);
1264	} else
1265		FILEDESC_UNLOCK(fdp);
1266	return (error);
1267}
1268
1269#ifdef COMPAT_43
1270/*
1271 * Create a file.
1272 */
1273#ifndef _SYS_SYSPROTO_H_
1274struct ocreat_args {
1275	char	*path;
1276	int	mode;
1277};
1278#endif
1279int
1280ocreat(td, uap)
1281	struct thread *td;
1282	register struct ocreat_args /* {
1283		syscallarg(char *) path;
1284		syscallarg(int) mode;
1285	} */ *uap;
1286{
1287	struct open_args /* {
1288		syscallarg(char *) path;
1289		syscallarg(int) flags;
1290		syscallarg(int) mode;
1291	} */ nuap;
1292
1293	SCARG(&nuap, path) = SCARG(uap, path);
1294	SCARG(&nuap, mode) = SCARG(uap, mode);
1295	SCARG(&nuap, flags) = O_WRONLY | O_CREAT | O_TRUNC;
1296	return (open(td, &nuap));
1297}
1298#endif /* COMPAT_43 */
1299
1300/*
1301 * Create a special file.
1302 */
1303#ifndef _SYS_SYSPROTO_H_
1304struct mknod_args {
1305	char	*path;
1306	int	mode;
1307	int	dev;
1308};
1309#endif
1310/* ARGSUSED */
1311int
1312mknod(td, uap)
1313	struct thread *td;
1314	register struct mknod_args /* {
1315		syscallarg(char *) path;
1316		syscallarg(int) mode;
1317		syscallarg(int) dev;
1318	} */ *uap;
1319{
1320	struct vnode *vp;
1321	struct mount *mp;
1322	struct vattr vattr;
1323	int error;
1324	int whiteout = 0;
1325	struct nameidata nd;
1326
1327	switch (SCARG(uap, mode) & S_IFMT) {
1328	case S_IFCHR:
1329	case S_IFBLK:
1330		error = suser_td(td);
1331		break;
1332	default:
1333		error = suser_xxx(0, td->td_proc, PRISON_ROOT);
1334		break;
1335	}
1336	if (error)
1337		return (error);
1338restart:
1339	bwillwrite();
1340	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), td);
1341	if ((error = namei(&nd)) != 0)
1342		return (error);
1343	vp = nd.ni_vp;
1344	if (vp != NULL) {
1345		vrele(vp);
1346		error = EEXIST;
1347	} else {
1348		VATTR_NULL(&vattr);
1349		FILEDESC_LOCK(td->td_proc->p_fd);
1350		vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ td->td_proc->p_fd->fd_cmask;
1351		FILEDESC_UNLOCK(td->td_proc->p_fd);
1352		vattr.va_rdev = SCARG(uap, dev);
1353		whiteout = 0;
1354
1355		switch (SCARG(uap, mode) & S_IFMT) {
1356		case S_IFMT:	/* used by badsect to flag bad sectors */
1357			vattr.va_type = VBAD;
1358			break;
1359		case S_IFCHR:
1360			vattr.va_type = VCHR;
1361			break;
1362		case S_IFBLK:
1363			vattr.va_type = VBLK;
1364			break;
1365		case S_IFWHT:
1366			whiteout = 1;
1367			break;
1368		default:
1369			error = EINVAL;
1370			break;
1371		}
1372	}
1373	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1374		NDFREE(&nd, NDF_ONLY_PNBUF);
1375		vput(nd.ni_dvp);
1376		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1377			return (error);
1378		goto restart;
1379	}
1380	if (!error) {
1381		VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
1382		if (whiteout)
1383			error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
1384		else {
1385			error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
1386						&nd.ni_cnd, &vattr);
1387			if (error == 0)
1388				vput(nd.ni_vp);
1389		}
1390	}
1391	NDFREE(&nd, NDF_ONLY_PNBUF);
1392	vput(nd.ni_dvp);
1393	vn_finished_write(mp);
1394	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mknod");
1395	ASSERT_VOP_UNLOCKED(nd.ni_vp, "mknod");
1396	return (error);
1397}
1398
1399/*
1400 * Create a named pipe.
1401 */
1402#ifndef _SYS_SYSPROTO_H_
1403struct mkfifo_args {
1404	char	*path;
1405	int	mode;
1406};
1407#endif
1408/* ARGSUSED */
1409int
1410mkfifo(td, uap)
1411	struct thread *td;
1412	register struct mkfifo_args /* {
1413		syscallarg(char *) path;
1414		syscallarg(int) mode;
1415	} */ *uap;
1416{
1417	struct mount *mp;
1418	struct vattr vattr;
1419	int error;
1420	struct nameidata nd;
1421
1422restart:
1423	bwillwrite();
1424	NDINIT(&nd, CREATE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), td);
1425	if ((error = namei(&nd)) != 0)
1426		return (error);
1427	if (nd.ni_vp != NULL) {
1428		NDFREE(&nd, NDF_ONLY_PNBUF);
1429		vrele(nd.ni_vp);
1430		vput(nd.ni_dvp);
1431		return (EEXIST);
1432	}
1433	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1434		NDFREE(&nd, NDF_ONLY_PNBUF);
1435		vput(nd.ni_dvp);
1436		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1437			return (error);
1438		goto restart;
1439	}
1440	VATTR_NULL(&vattr);
1441	vattr.va_type = VFIFO;
1442	FILEDESC_LOCK(td->td_proc->p_fd);
1443	vattr.va_mode = (SCARG(uap, mode) & ALLPERMS) &~ td->td_proc->p_fd->fd_cmask;
1444	FILEDESC_UNLOCK(td->td_proc->p_fd);
1445	VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
1446	error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
1447	if (error == 0)
1448		vput(nd.ni_vp);
1449	NDFREE(&nd, NDF_ONLY_PNBUF);
1450	vput(nd.ni_dvp);
1451	vn_finished_write(mp);
1452	return (error);
1453}
1454
1455/*
1456 * Make a hard file link.
1457 */
1458#ifndef _SYS_SYSPROTO_H_
1459struct link_args {
1460	char	*path;
1461	char	*link;
1462};
1463#endif
1464/* ARGSUSED */
1465int
1466link(td, uap)
1467	struct thread *td;
1468	register struct link_args /* {
1469		syscallarg(char *) path;
1470		syscallarg(char *) link;
1471	} */ *uap;
1472{
1473	struct vnode *vp;
1474	struct mount *mp;
1475	struct nameidata nd;
1476	int error;
1477
1478	bwillwrite();
1479	NDINIT(&nd, LOOKUP, FOLLOW|NOOBJ, UIO_USERSPACE, SCARG(uap, path), td);
1480	if ((error = namei(&nd)) != 0)
1481		return (error);
1482	NDFREE(&nd, NDF_ONLY_PNBUF);
1483	vp = nd.ni_vp;
1484	if (vp->v_type == VDIR) {
1485		vrele(vp);
1486		return (EPERM);		/* POSIX */
1487	}
1488	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
1489		vrele(vp);
1490		return (error);
1491	}
1492	NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), td);
1493	if ((error = namei(&nd)) == 0) {
1494		if (nd.ni_vp != NULL) {
1495			vrele(nd.ni_vp);
1496			error = EEXIST;
1497		} else {
1498			VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
1499			VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
1500			error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
1501		}
1502		NDFREE(&nd, NDF_ONLY_PNBUF);
1503		vput(nd.ni_dvp);
1504	}
1505	vrele(vp);
1506	vn_finished_write(mp);
1507	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "link");
1508	ASSERT_VOP_UNLOCKED(nd.ni_vp, "link");
1509	return (error);
1510}
1511
1512/*
1513 * Make a symbolic link.
1514 */
1515#ifndef _SYS_SYSPROTO_H_
1516struct symlink_args {
1517	char	*path;
1518	char	*link;
1519};
1520#endif
1521/* ARGSUSED */
1522int
1523symlink(td, uap)
1524	struct thread *td;
1525	register struct symlink_args /* {
1526		syscallarg(char *) path;
1527		syscallarg(char *) link;
1528	} */ *uap;
1529{
1530	struct mount *mp;
1531	struct vattr vattr;
1532	char *path;
1533	int error;
1534	struct nameidata nd;
1535
1536	path = zalloc(namei_zone);
1537	if ((error = copyinstr(SCARG(uap, path), path, MAXPATHLEN, NULL)) != 0)
1538		goto out;
1539restart:
1540	bwillwrite();
1541	NDINIT(&nd, CREATE, LOCKPARENT|NOOBJ, UIO_USERSPACE, SCARG(uap, link), td);
1542	if ((error = namei(&nd)) != 0)
1543		goto out;
1544	if (nd.ni_vp) {
1545		NDFREE(&nd, NDF_ONLY_PNBUF);
1546		vrele(nd.ni_vp);
1547		vput(nd.ni_dvp);
1548		error = EEXIST;
1549		goto out;
1550	}
1551	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1552		NDFREE(&nd, NDF_ONLY_PNBUF);
1553		vput(nd.ni_dvp);
1554		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1555			return (error);
1556		goto restart;
1557	}
1558	VATTR_NULL(&vattr);
1559	FILEDESC_LOCK(td->td_proc->p_fd);
1560	vattr.va_mode = ACCESSPERMS &~ td->td_proc->p_fd->fd_cmask;
1561	FILEDESC_UNLOCK(td->td_proc->p_fd);
1562	VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
1563	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, path);
1564	NDFREE(&nd, NDF_ONLY_PNBUF);
1565	if (error == 0)
1566		vput(nd.ni_vp);
1567	vput(nd.ni_dvp);
1568	vn_finished_write(mp);
1569	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "symlink");
1570	ASSERT_VOP_UNLOCKED(nd.ni_vp, "symlink");
1571out:
1572	zfree(namei_zone, path);
1573	return (error);
1574}
1575
1576/*
1577 * Delete a whiteout from the filesystem.
1578 */
1579/* ARGSUSED */
1580int
1581undelete(td, uap)
1582	struct thread *td;
1583	register struct undelete_args /* {
1584		syscallarg(char *) path;
1585	} */ *uap;
1586{
1587	int error;
1588	struct mount *mp;
1589	struct nameidata nd;
1590
1591restart:
1592	bwillwrite();
1593	NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
1594	    SCARG(uap, path), td);
1595	error = namei(&nd);
1596	if (error)
1597		return (error);
1598
1599	if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
1600		NDFREE(&nd, NDF_ONLY_PNBUF);
1601		if (nd.ni_vp)
1602			vrele(nd.ni_vp);
1603		vput(nd.ni_dvp);
1604		return (EEXIST);
1605	}
1606	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1607		NDFREE(&nd, NDF_ONLY_PNBUF);
1608		vput(nd.ni_dvp);
1609		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1610			return (error);
1611		goto restart;
1612	}
1613	VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
1614	error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE);
1615	NDFREE(&nd, NDF_ONLY_PNBUF);
1616	vput(nd.ni_dvp);
1617	vn_finished_write(mp);
1618	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "undelete");
1619	ASSERT_VOP_UNLOCKED(nd.ni_vp, "undelete");
1620	return (error);
1621}
1622
1623/*
1624 * Delete a name from the filesystem.
1625 */
1626#ifndef _SYS_SYSPROTO_H_
1627struct unlink_args {
1628	char	*path;
1629};
1630#endif
1631/* ARGSUSED */
1632int
1633unlink(td, uap)
1634	struct thread *td;
1635	struct unlink_args /* {
1636		syscallarg(char *) path;
1637	} */ *uap;
1638{
1639	struct mount *mp;
1640	struct vnode *vp;
1641	int error;
1642	struct nameidata nd;
1643
1644restart:
1645	bwillwrite();
1646	NDINIT(&nd, DELETE, LOCKPARENT, UIO_USERSPACE, SCARG(uap, path), td);
1647	if ((error = namei(&nd)) != 0)
1648		return (error);
1649	vp = nd.ni_vp;
1650	if (vp->v_type == VDIR)
1651		error = EPERM;		/* POSIX */
1652	else {
1653		/*
1654		 * The root of a mounted filesystem cannot be deleted.
1655		 *
1656		 * XXX: can this only be a VDIR case?
1657		 */
1658		if (vp->v_flag & VROOT)
1659			error = EBUSY;
1660	}
1661	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1662		NDFREE(&nd, NDF_ONLY_PNBUF);
1663		vrele(vp);
1664		vput(nd.ni_dvp);
1665		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1666			return (error);
1667		goto restart;
1668	}
1669	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
1670	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
1671	if (!error) {
1672		VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
1673		error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd);
1674	}
1675	NDFREE(&nd, NDF_ONLY_PNBUF);
1676	vput(nd.ni_dvp);
1677	vput(vp);
1678	vn_finished_write(mp);
1679	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "unlink");
1680	ASSERT_VOP_UNLOCKED(nd.ni_vp, "unlink");
1681	return (error);
1682}
1683
1684/*
1685 * Reposition read/write file offset.
1686 */
1687#ifndef _SYS_SYSPROTO_H_
1688struct lseek_args {
1689	int	fd;
1690	int	pad;
1691	off_t	offset;
1692	int	whence;
1693};
1694#endif
1695int
1696lseek(td, uap)
1697	struct thread *td;
1698	register struct lseek_args /* {
1699		syscallarg(int) fd;
1700		syscallarg(int) pad;
1701		syscallarg(off_t) offset;
1702		syscallarg(int) whence;
1703	} */ *uap;
1704{
1705	struct ucred *cred = td->td_ucred;
1706	struct file *fp;
1707	struct vnode *vp;
1708	struct vattr vattr;
1709	off_t offset;
1710	int error, noneg;
1711
1712	if ((error = fget(td, uap->fd, &fp)) != 0)
1713		return (error);
1714	if (fp->f_type != DTYPE_VNODE) {
1715		fdrop(fp, td);
1716		return (ESPIPE);
1717	}
1718	vp = (struct vnode *)fp->f_data;
1719	noneg = (vp->v_type != VCHR);
1720	offset = SCARG(uap, offset);
1721	switch (SCARG(uap, whence)) {
1722	case L_INCR:
1723		if (noneg &&
1724		    (fp->f_offset < 0 ||
1725		     (offset > 0 && fp->f_offset > OFF_MAX - offset)))
1726			return (EOVERFLOW);
1727		offset += fp->f_offset;
1728		break;
1729	case L_XTND:
1730		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
1731		error = VOP_GETATTR(vp, &vattr, cred, td);
1732		VOP_UNLOCK(vp, 0, td);
1733		if (error)
1734			return (error);
1735		if (noneg &&
1736		    (vattr.va_size > OFF_MAX ||
1737		     (offset > 0 && vattr.va_size > OFF_MAX - offset)))
1738			return (EOVERFLOW);
1739		offset += vattr.va_size;
1740		break;
1741	case L_SET:
1742		break;
1743	default:
1744		fdrop(fp, td);
1745		return (EINVAL);
1746	}
1747	if (noneg && offset < 0)
1748		return (EINVAL);
1749	fp->f_offset = offset;
1750	*(off_t *)(td->td_retval) = fp->f_offset;
1751	fdrop(fp, td);
1752	return (0);
1753}
1754
1755#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1756/*
1757 * Reposition read/write file offset.
1758 */
1759#ifndef _SYS_SYSPROTO_H_
1760struct olseek_args {
1761	int	fd;
1762	long	offset;
1763	int	whence;
1764};
1765#endif
1766int
1767olseek(td, uap)
1768	struct thread *td;
1769	register struct olseek_args /* {
1770		syscallarg(int) fd;
1771		syscallarg(long) offset;
1772		syscallarg(int) whence;
1773	} */ *uap;
1774{
1775	struct lseek_args /* {
1776		syscallarg(int) fd;
1777		syscallarg(int) pad;
1778		syscallarg(off_t) offset;
1779		syscallarg(int) whence;
1780	} */ nuap;
1781	int error;
1782
1783	SCARG(&nuap, fd) = SCARG(uap, fd);
1784	SCARG(&nuap, offset) = SCARG(uap, offset);
1785	SCARG(&nuap, whence) = SCARG(uap, whence);
1786	error = lseek(td, &nuap);
1787	return (error);
1788}
1789#endif /* COMPAT_43 */
1790
1791/*
1792 * Check access permissions using passed credentials.
1793 */
1794static int
1795vn_access(vp, user_flags, cred, td)
1796	struct vnode	*vp;
1797	int		user_flags;
1798	struct ucred	*cred;
1799	struct thread	*td;
1800{
1801	int error, flags;
1802
1803	/* Flags == 0 means only check for existence. */
1804	error = 0;
1805	if (user_flags) {
1806		flags = 0;
1807		if (user_flags & R_OK)
1808			flags |= VREAD;
1809		if (user_flags & W_OK)
1810			flags |= VWRITE;
1811		if (user_flags & X_OK)
1812			flags |= VEXEC;
1813		if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
1814			error = VOP_ACCESS(vp, flags, cred, td);
1815	}
1816	return (error);
1817}
1818
1819/*
1820 * Check access permissions using "real" credentials.
1821 */
1822#ifndef _SYS_SYSPROTO_H_
1823struct access_args {
1824	char	*path;
1825	int	flags;
1826};
1827#endif
1828int
1829access(td, uap)
1830	struct thread *td;
1831	register struct access_args /* {
1832		syscallarg(char *) path;
1833		syscallarg(int) flags;
1834	} */ *uap;
1835{
1836	struct ucred *cred, *tmpcred;
1837	register struct vnode *vp;
1838	int error;
1839	struct nameidata nd;
1840
1841	/*
1842	 * Create and modify a temporary credential instead of one that
1843	 * is potentially shared.  This could also mess up socket
1844	 * buffer accounting which can run in an interrupt context.
1845	 *
1846	 * XXX - Depending on how "threads" are finally implemented, it
1847	 * may be better to explicitly pass the credential to namei()
1848	 * rather than to modify the potentially shared process structure.
1849	 */
1850	cred = td->td_ucred;
1851	tmpcred = crdup(cred);
1852	tmpcred->cr_uid = cred->cr_ruid;
1853	tmpcred->cr_groups[0] = cred->cr_rgid;
1854	td->td_ucred = tmpcred;
1855	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1856	    SCARG(uap, path), td);
1857	if ((error = namei(&nd)) != 0)
1858		goto out1;
1859	vp = nd.ni_vp;
1860
1861	error = vn_access(vp, SCARG(uap, flags), tmpcred, td);
1862	NDFREE(&nd, NDF_ONLY_PNBUF);
1863	vput(vp);
1864out1:
1865	td->td_ucred = cred;
1866	crfree(tmpcred);
1867	return (error);
1868}
1869
1870/*
1871 * Check access permissions using "effective" credentials.
1872 */
1873#ifndef _SYS_SYSPROTO_H_
1874struct eaccess_args {
1875	char	*path;
1876	int	flags;
1877};
1878#endif
1879int
1880eaccess(td, uap)
1881	struct thread *td;
1882	register struct eaccess_args /* {
1883		syscallarg(char *) path;
1884		syscallarg(int) flags;
1885	} */ *uap;
1886{
1887	struct nameidata nd;
1888	struct vnode *vp;
1889	int error;
1890
1891	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1892	    SCARG(uap, path), td);
1893	if ((error = namei(&nd)) != 0)
1894		return (error);
1895	vp = nd.ni_vp;
1896
1897	error = vn_access(vp, SCARG(uap, flags), td->td_ucred, td);
1898	NDFREE(&nd, NDF_ONLY_PNBUF);
1899	vput(vp);
1900	return (error);
1901}
1902
1903#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1904/*
1905 * Get file status; this version follows links.
1906 */
1907#ifndef _SYS_SYSPROTO_H_
1908struct ostat_args {
1909	char	*path;
1910	struct ostat *ub;
1911};
1912#endif
1913/* ARGSUSED */
1914int
1915ostat(td, uap)
1916	struct thread *td;
1917	register struct ostat_args /* {
1918		syscallarg(char *) path;
1919		syscallarg(struct ostat *) ub;
1920	} */ *uap;
1921{
1922	struct stat sb;
1923	struct ostat osb;
1924	int error;
1925	struct nameidata nd;
1926
1927	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1928	    SCARG(uap, path), td);
1929	if ((error = namei(&nd)) != 0)
1930		return (error);
1931	NDFREE(&nd, NDF_ONLY_PNBUF);
1932	error = vn_stat(nd.ni_vp, &sb, td);
1933	vput(nd.ni_vp);
1934	if (error)
1935		return (error);
1936	cvtstat(&sb, &osb);
1937	error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
1938	return (error);
1939}
1940
1941/*
1942 * Get file status; this version does not follow links.
1943 */
1944#ifndef _SYS_SYSPROTO_H_
1945struct olstat_args {
1946	char	*path;
1947	struct ostat *ub;
1948};
1949#endif
1950/* ARGSUSED */
1951int
1952olstat(td, uap)
1953	struct thread *td;
1954	register struct olstat_args /* {
1955		syscallarg(char *) path;
1956		syscallarg(struct ostat *) ub;
1957	} */ *uap;
1958{
1959	struct vnode *vp;
1960	struct stat sb;
1961	struct ostat osb;
1962	int error;
1963	struct nameidata nd;
1964
1965	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1966	    SCARG(uap, path), td);
1967	if ((error = namei(&nd)) != 0)
1968		return (error);
1969	vp = nd.ni_vp;
1970	error = vn_stat(vp, &sb, td);
1971	NDFREE(&nd, NDF_ONLY_PNBUF);
1972	vput(vp);
1973	if (error)
1974		return (error);
1975	cvtstat(&sb, &osb);
1976	error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
1977	return (error);
1978}
1979
1980/*
1981 * Convert from an old to a new stat structure.
1982 */
1983void
1984cvtstat(st, ost)
1985	struct stat *st;
1986	struct ostat *ost;
1987{
1988
1989	ost->st_dev = st->st_dev;
1990	ost->st_ino = st->st_ino;
1991	ost->st_mode = st->st_mode;
1992	ost->st_nlink = st->st_nlink;
1993	ost->st_uid = st->st_uid;
1994	ost->st_gid = st->st_gid;
1995	ost->st_rdev = st->st_rdev;
1996	if (st->st_size < (quad_t)1 << 32)
1997		ost->st_size = st->st_size;
1998	else
1999		ost->st_size = -2;
2000	ost->st_atime = st->st_atime;
2001	ost->st_mtime = st->st_mtime;
2002	ost->st_ctime = st->st_ctime;
2003	ost->st_blksize = st->st_blksize;
2004	ost->st_blocks = st->st_blocks;
2005	ost->st_flags = st->st_flags;
2006	ost->st_gen = st->st_gen;
2007}
2008#endif /* COMPAT_43 || COMPAT_SUNOS */
2009
2010/*
2011 * Get file status; this version follows links.
2012 */
2013#ifndef _SYS_SYSPROTO_H_
2014struct stat_args {
2015	char	*path;
2016	struct stat *ub;
2017};
2018#endif
2019/* ARGSUSED */
2020int
2021stat(td, uap)
2022	struct thread *td;
2023	register struct stat_args /* {
2024		syscallarg(char *) path;
2025		syscallarg(struct stat *) ub;
2026	} */ *uap;
2027{
2028	struct stat sb;
2029	int error;
2030	struct nameidata nd;
2031
2032#ifdef LOOKUP_SHARED
2033	NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | NOOBJ,
2034	    UIO_USERSPACE, SCARG(uap, path), td);
2035#else
2036	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
2037	    SCARG(uap, path), td);
2038#endif
2039	if ((error = namei(&nd)) != 0)
2040		return (error);
2041	error = vn_stat(nd.ni_vp, &sb, td);
2042	NDFREE(&nd, NDF_ONLY_PNBUF);
2043	vput(nd.ni_vp);
2044	if (error)
2045		return (error);
2046	error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
2047	return (error);
2048}
2049
2050/*
2051 * Get file status; this version does not follow links.
2052 */
2053#ifndef _SYS_SYSPROTO_H_
2054struct lstat_args {
2055	char	*path;
2056	struct stat *ub;
2057};
2058#endif
2059/* ARGSUSED */
2060int
2061lstat(td, uap)
2062	struct thread *td;
2063	register struct lstat_args /* {
2064		syscallarg(char *) path;
2065		syscallarg(struct stat *) ub;
2066	} */ *uap;
2067{
2068	int error;
2069	struct vnode *vp;
2070	struct stat sb;
2071	struct nameidata nd;
2072
2073	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
2074	    SCARG(uap, path), td);
2075	if ((error = namei(&nd)) != 0)
2076		return (error);
2077	vp = nd.ni_vp;
2078	error = vn_stat(vp, &sb, td);
2079	NDFREE(&nd, NDF_ONLY_PNBUF);
2080	vput(vp);
2081	if (error)
2082		return (error);
2083	error = copyout((caddr_t)&sb, (caddr_t)SCARG(uap, ub), sizeof (sb));
2084	return (error);
2085}
2086
2087/*
2088 * Implementation of the NetBSD stat() function.
2089 * XXX This should probably be collapsed with the FreeBSD version,
2090 * as the differences are only due to vn_stat() clearing spares at
2091 * the end of the structures.  vn_stat could be split to avoid this,
2092 * and thus collapse the following to close to zero code.
2093 */
2094void
2095cvtnstat(sb, nsb)
2096	struct stat *sb;
2097	struct nstat *nsb;
2098{
2099	nsb->st_dev = sb->st_dev;
2100	nsb->st_ino = sb->st_ino;
2101	nsb->st_mode = sb->st_mode;
2102	nsb->st_nlink = sb->st_nlink;
2103	nsb->st_uid = sb->st_uid;
2104	nsb->st_gid = sb->st_gid;
2105	nsb->st_rdev = sb->st_rdev;
2106	nsb->st_atimespec = sb->st_atimespec;
2107	nsb->st_mtimespec = sb->st_mtimespec;
2108	nsb->st_ctimespec = sb->st_ctimespec;
2109	nsb->st_size = sb->st_size;
2110	nsb->st_blocks = sb->st_blocks;
2111	nsb->st_blksize = sb->st_blksize;
2112	nsb->st_flags = sb->st_flags;
2113	nsb->st_gen = sb->st_gen;
2114	nsb->st_qspare[0] = sb->st_qspare[0];
2115	nsb->st_qspare[1] = sb->st_qspare[1];
2116}
2117
2118#ifndef _SYS_SYSPROTO_H_
2119struct nstat_args {
2120	char	*path;
2121	struct nstat *ub;
2122};
2123#endif
2124/* ARGSUSED */
2125int
2126nstat(td, uap)
2127	struct thread *td;
2128	register struct nstat_args /* {
2129		syscallarg(char *) path;
2130		syscallarg(struct nstat *) ub;
2131	} */ *uap;
2132{
2133	struct stat sb;
2134	struct nstat nsb;
2135	int error;
2136	struct nameidata nd;
2137
2138	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
2139	    SCARG(uap, path), td);
2140	if ((error = namei(&nd)) != 0)
2141		return (error);
2142	NDFREE(&nd, NDF_ONLY_PNBUF);
2143	error = vn_stat(nd.ni_vp, &sb, td);
2144	vput(nd.ni_vp);
2145	if (error)
2146		return (error);
2147	cvtnstat(&sb, &nsb);
2148	error = copyout((caddr_t)&nsb, (caddr_t)SCARG(uap, ub), sizeof (nsb));
2149	return (error);
2150}
2151
2152/*
2153 * NetBSD lstat.  Get file status; this version does not follow links.
2154 */
2155#ifndef _SYS_SYSPROTO_H_
2156struct lstat_args {
2157	char	*path;
2158	struct stat *ub;
2159};
2160#endif
2161/* ARGSUSED */
2162int
2163nlstat(td, uap)
2164	struct thread *td;
2165	register struct nlstat_args /* {
2166		syscallarg(char *) path;
2167		syscallarg(struct nstat *) ub;
2168	} */ *uap;
2169{
2170	int error;
2171	struct vnode *vp;
2172	struct stat sb;
2173	struct nstat nsb;
2174	struct nameidata nd;
2175
2176	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
2177	    SCARG(uap, path), td);
2178	if ((error = namei(&nd)) != 0)
2179		return (error);
2180	vp = nd.ni_vp;
2181	NDFREE(&nd, NDF_ONLY_PNBUF);
2182	error = vn_stat(vp, &sb, td);
2183	vput(vp);
2184	if (error)
2185		return (error);
2186	cvtnstat(&sb, &nsb);
2187	error = copyout((caddr_t)&nsb, (caddr_t)SCARG(uap, ub), sizeof (nsb));
2188	return (error);
2189}
2190
2191/*
2192 * Get configurable pathname variables.
2193 */
2194#ifndef _SYS_SYSPROTO_H_
2195struct pathconf_args {
2196	char	*path;
2197	int	name;
2198};
2199#endif
2200/* ARGSUSED */
2201int
2202pathconf(td, uap)
2203	struct thread *td;
2204	register struct pathconf_args /* {
2205		syscallarg(char *) path;
2206		syscallarg(int) name;
2207	} */ *uap;
2208{
2209	int error;
2210	struct nameidata nd;
2211
2212	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
2213	    SCARG(uap, path), td);
2214	if ((error = namei(&nd)) != 0)
2215		return (error);
2216	NDFREE(&nd, NDF_ONLY_PNBUF);
2217	error = VOP_PATHCONF(nd.ni_vp, SCARG(uap, name), td->td_retval);
2218	vput(nd.ni_vp);
2219	return (error);
2220}
2221
2222/*
2223 * Return target name of a symbolic link.
2224 */
2225#ifndef _SYS_SYSPROTO_H_
2226struct readlink_args {
2227	char	*path;
2228	char	*buf;
2229	int	count;
2230};
2231#endif
2232/* ARGSUSED */
2233int
2234readlink(td, uap)
2235	struct thread *td;
2236	register struct readlink_args /* {
2237		syscallarg(char *) path;
2238		syscallarg(char *) buf;
2239		syscallarg(int) count;
2240	} */ *uap;
2241{
2242	register struct vnode *vp;
2243	struct iovec aiov;
2244	struct uio auio;
2245	int error;
2246	struct nameidata nd;
2247
2248	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
2249	    SCARG(uap, path), td);
2250	if ((error = namei(&nd)) != 0)
2251		return (error);
2252	NDFREE(&nd, NDF_ONLY_PNBUF);
2253	vp = nd.ni_vp;
2254	if (vp->v_type != VLNK)
2255		error = EINVAL;
2256	else {
2257		aiov.iov_base = SCARG(uap, buf);
2258		aiov.iov_len = SCARG(uap, count);
2259		auio.uio_iov = &aiov;
2260		auio.uio_iovcnt = 1;
2261		auio.uio_offset = 0;
2262		auio.uio_rw = UIO_READ;
2263		auio.uio_segflg = UIO_USERSPACE;
2264		auio.uio_td = td;
2265		auio.uio_resid = SCARG(uap, count);
2266		error = VOP_READLINK(vp, &auio, td->td_ucred);
2267	}
2268	vput(vp);
2269	td->td_retval[0] = SCARG(uap, count) - auio.uio_resid;
2270	return (error);
2271}
2272
2273/*
2274 * Common implementation code for chflags() and fchflags().
2275 */
2276static int
2277setfflags(td, vp, flags)
2278	struct thread *td;
2279	struct vnode *vp;
2280	int flags;
2281{
2282	int error;
2283	struct mount *mp;
2284	struct vattr vattr;
2285
2286	/*
2287	 * Prevent non-root users from setting flags on devices.  When
2288	 * a device is reused, users can retain ownership of the device
2289	 * if they are allowed to set flags and programs assume that
2290	 * chown can't fail when done as root.
2291	 */
2292	if (vp->v_type == VCHR || vp->v_type == VBLK) {
2293		error = suser_xxx(td->td_ucred, td->td_proc, PRISON_ROOT);
2294		if (error)
2295			return (error);
2296	}
2297
2298	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2299		return (error);
2300	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
2301	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2302	VATTR_NULL(&vattr);
2303	vattr.va_flags = flags;
2304	error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
2305	VOP_UNLOCK(vp, 0, td);
2306	vn_finished_write(mp);
2307	return (error);
2308}
2309
2310/*
2311 * Change flags of a file given a path name.
2312 */
2313#ifndef _SYS_SYSPROTO_H_
2314struct chflags_args {
2315	char	*path;
2316	int	flags;
2317};
2318#endif
2319/* ARGSUSED */
2320int
2321chflags(td, uap)
2322	struct thread *td;
2323	register struct chflags_args /* {
2324		syscallarg(char *) path;
2325		syscallarg(int) flags;
2326	} */ *uap;
2327{
2328	int error;
2329	struct nameidata nd;
2330
2331	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2332	if ((error = namei(&nd)) != 0)
2333		return (error);
2334	NDFREE(&nd, NDF_ONLY_PNBUF);
2335	error = setfflags(td, nd.ni_vp, SCARG(uap, flags));
2336	vrele(nd.ni_vp);
2337	return error;
2338}
2339
2340/*
2341 * Change flags of a file given a file descriptor.
2342 */
2343#ifndef _SYS_SYSPROTO_H_
2344struct fchflags_args {
2345	int	fd;
2346	int	flags;
2347};
2348#endif
2349/* ARGSUSED */
2350int
2351fchflags(td, uap)
2352	struct thread *td;
2353	register struct fchflags_args /* {
2354		syscallarg(int) fd;
2355		syscallarg(int) flags;
2356	} */ *uap;
2357{
2358	struct file *fp;
2359	int error;
2360
2361	if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2362		return (error);
2363	error = setfflags(td, (struct vnode *) fp->f_data, SCARG(uap, flags));
2364	fdrop(fp, td);
2365	return (error);
2366}
2367
2368/*
2369 * Common implementation code for chmod(), lchmod() and fchmod().
2370 */
2371static int
2372setfmode(td, vp, mode)
2373	struct thread *td;
2374	struct vnode *vp;
2375	int mode;
2376{
2377	int error;
2378	struct mount *mp;
2379	struct vattr vattr;
2380
2381	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2382		return (error);
2383	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
2384	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2385	VATTR_NULL(&vattr);
2386	vattr.va_mode = mode & ALLPERMS;
2387	error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
2388	VOP_UNLOCK(vp, 0, td);
2389	vn_finished_write(mp);
2390	return error;
2391}
2392
2393/*
2394 * Change mode of a file given path name.
2395 */
2396#ifndef _SYS_SYSPROTO_H_
2397struct chmod_args {
2398	char	*path;
2399	int	mode;
2400};
2401#endif
2402/* ARGSUSED */
2403int
2404chmod(td, uap)
2405	struct thread *td;
2406	register struct chmod_args /* {
2407		syscallarg(char *) path;
2408		syscallarg(int) mode;
2409	} */ *uap;
2410{
2411	int error;
2412	struct nameidata nd;
2413
2414	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2415	if ((error = namei(&nd)) != 0)
2416		return (error);
2417	NDFREE(&nd, NDF_ONLY_PNBUF);
2418	error = setfmode(td, nd.ni_vp, SCARG(uap, mode));
2419	vrele(nd.ni_vp);
2420	return error;
2421}
2422
2423/*
2424 * Change mode of a file given path name (don't follow links.)
2425 */
2426#ifndef _SYS_SYSPROTO_H_
2427struct lchmod_args {
2428	char	*path;
2429	int	mode;
2430};
2431#endif
2432/* ARGSUSED */
2433int
2434lchmod(td, uap)
2435	struct thread *td;
2436	register struct lchmod_args /* {
2437		syscallarg(char *) path;
2438		syscallarg(int) mode;
2439	} */ *uap;
2440{
2441	int error;
2442	struct nameidata nd;
2443
2444	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2445	if ((error = namei(&nd)) != 0)
2446		return (error);
2447	NDFREE(&nd, NDF_ONLY_PNBUF);
2448	error = setfmode(td, nd.ni_vp, SCARG(uap, mode));
2449	vrele(nd.ni_vp);
2450	return error;
2451}
2452
2453/*
2454 * Change mode of a file given a file descriptor.
2455 */
2456#ifndef _SYS_SYSPROTO_H_
2457struct fchmod_args {
2458	int	fd;
2459	int	mode;
2460};
2461#endif
2462/* ARGSUSED */
2463int
2464fchmod(td, uap)
2465	struct thread *td;
2466	register struct fchmod_args /* {
2467		syscallarg(int) fd;
2468		syscallarg(int) mode;
2469	} */ *uap;
2470{
2471	struct file *fp;
2472	struct vnode *vp;
2473	int error;
2474
2475	if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2476		return (error);
2477	vp = (struct vnode *)fp->f_data;
2478	error = setfmode(td, (struct vnode *)fp->f_data, SCARG(uap, mode));
2479	fdrop(fp, td);
2480	return (error);
2481}
2482
2483/*
2484 * Common implementation for chown(), lchown(), and fchown()
2485 */
2486static int
2487setfown(td, vp, uid, gid)
2488	struct thread *td;
2489	struct vnode *vp;
2490	uid_t uid;
2491	gid_t gid;
2492{
2493	int error;
2494	struct mount *mp;
2495	struct vattr vattr;
2496
2497	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2498		return (error);
2499	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
2500	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2501	VATTR_NULL(&vattr);
2502	vattr.va_uid = uid;
2503	vattr.va_gid = gid;
2504	error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
2505	VOP_UNLOCK(vp, 0, td);
2506	vn_finished_write(mp);
2507	return error;
2508}
2509
2510/*
2511 * Set ownership given a path name.
2512 */
2513#ifndef _SYS_SYSPROTO_H_
2514struct chown_args {
2515	char	*path;
2516	int	uid;
2517	int	gid;
2518};
2519#endif
2520/* ARGSUSED */
2521int
2522chown(td, uap)
2523	struct thread *td;
2524	register struct chown_args /* {
2525		syscallarg(char *) path;
2526		syscallarg(int) uid;
2527		syscallarg(int) gid;
2528	} */ *uap;
2529{
2530	int error;
2531	struct nameidata nd;
2532
2533	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2534	if ((error = namei(&nd)) != 0)
2535		return (error);
2536	NDFREE(&nd, NDF_ONLY_PNBUF);
2537	error = setfown(td, nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid));
2538	vrele(nd.ni_vp);
2539	return (error);
2540}
2541
2542/*
2543 * Set ownership given a path name, do not cross symlinks.
2544 */
2545#ifndef _SYS_SYSPROTO_H_
2546struct lchown_args {
2547	char	*path;
2548	int	uid;
2549	int	gid;
2550};
2551#endif
2552/* ARGSUSED */
2553int
2554lchown(td, uap)
2555	struct thread *td;
2556	register struct lchown_args /* {
2557		syscallarg(char *) path;
2558		syscallarg(int) uid;
2559		syscallarg(int) gid;
2560	} */ *uap;
2561{
2562	int error;
2563	struct nameidata nd;
2564
2565	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2566	if ((error = namei(&nd)) != 0)
2567		return (error);
2568	NDFREE(&nd, NDF_ONLY_PNBUF);
2569	error = setfown(td, nd.ni_vp, SCARG(uap, uid), SCARG(uap, gid));
2570	vrele(nd.ni_vp);
2571	return (error);
2572}
2573
2574/*
2575 * Set ownership given a file descriptor.
2576 */
2577#ifndef _SYS_SYSPROTO_H_
2578struct fchown_args {
2579	int	fd;
2580	int	uid;
2581	int	gid;
2582};
2583#endif
2584/* ARGSUSED */
2585int
2586fchown(td, uap)
2587	struct thread *td;
2588	register struct fchown_args /* {
2589		syscallarg(int) fd;
2590		syscallarg(int) uid;
2591		syscallarg(int) gid;
2592	} */ *uap;
2593{
2594	struct file *fp;
2595	struct vnode *vp;
2596	int error;
2597
2598	if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2599		return (error);
2600	vp = (struct vnode *)fp->f_data;
2601	error = setfown(td, (struct vnode *)fp->f_data,
2602		SCARG(uap, uid), SCARG(uap, gid));
2603	fdrop(fp, td);
2604	return (error);
2605}
2606
2607/*
2608 * Common implementation code for utimes(), lutimes(), and futimes().
2609 */
2610static int
2611getutimes(usrtvp, tsp)
2612	const struct timeval *usrtvp;
2613	struct timespec *tsp;
2614{
2615	struct timeval tv[2];
2616	int error;
2617
2618	if (usrtvp == NULL) {
2619		microtime(&tv[0]);
2620		TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]);
2621		tsp[1] = tsp[0];
2622	} else {
2623		if ((error = copyin(usrtvp, tv, sizeof (tv))) != 0)
2624			return (error);
2625		TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]);
2626		TIMEVAL_TO_TIMESPEC(&tv[1], &tsp[1]);
2627	}
2628	return 0;
2629}
2630
2631/*
2632 * Common implementation code for utimes(), lutimes(), and futimes().
2633 */
2634static int
2635setutimes(td, vp, ts, nullflag)
2636	struct thread *td;
2637	struct vnode *vp;
2638	const struct timespec *ts;
2639	int nullflag;
2640{
2641	int error;
2642	struct mount *mp;
2643	struct vattr vattr;
2644
2645	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2646		return (error);
2647	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
2648	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2649	VATTR_NULL(&vattr);
2650	vattr.va_atime = ts[0];
2651	vattr.va_mtime = ts[1];
2652	if (nullflag)
2653		vattr.va_vaflags |= VA_UTIMES_NULL;
2654	error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
2655	VOP_UNLOCK(vp, 0, td);
2656	vn_finished_write(mp);
2657	return error;
2658}
2659
2660/*
2661 * Set the access and modification times of a file.
2662 */
2663#ifndef _SYS_SYSPROTO_H_
2664struct utimes_args {
2665	char	*path;
2666	struct	timeval *tptr;
2667};
2668#endif
2669/* ARGSUSED */
2670int
2671utimes(td, uap)
2672	struct thread *td;
2673	register struct utimes_args /* {
2674		syscallarg(char *) path;
2675		syscallarg(struct timeval *) tptr;
2676	} */ *uap;
2677{
2678	struct timespec ts[2];
2679	struct timeval *usrtvp;
2680	int error;
2681	struct nameidata nd;
2682
2683	usrtvp = SCARG(uap, tptr);
2684	if ((error = getutimes(usrtvp, ts)) != 0)
2685		return (error);
2686	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2687	if ((error = namei(&nd)) != 0)
2688		return (error);
2689	NDFREE(&nd, NDF_ONLY_PNBUF);
2690	error = setutimes(td, nd.ni_vp, ts, usrtvp == NULL);
2691	vrele(nd.ni_vp);
2692	return (error);
2693}
2694
2695/*
2696 * Set the access and modification times of a file.
2697 */
2698#ifndef _SYS_SYSPROTO_H_
2699struct lutimes_args {
2700	char	*path;
2701	struct	timeval *tptr;
2702};
2703#endif
2704/* ARGSUSED */
2705int
2706lutimes(td, uap)
2707	struct thread *td;
2708	register struct lutimes_args /* {
2709		syscallarg(char *) path;
2710		syscallarg(struct timeval *) tptr;
2711	} */ *uap;
2712{
2713	struct timespec ts[2];
2714	struct timeval *usrtvp;
2715	int error;
2716	struct nameidata nd;
2717
2718	usrtvp = SCARG(uap, tptr);
2719	if ((error = getutimes(usrtvp, ts)) != 0)
2720		return (error);
2721	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2722	if ((error = namei(&nd)) != 0)
2723		return (error);
2724	NDFREE(&nd, NDF_ONLY_PNBUF);
2725	error = setutimes(td, nd.ni_vp, ts, usrtvp == NULL);
2726	vrele(nd.ni_vp);
2727	return (error);
2728}
2729
2730/*
2731 * Set the access and modification times of a file.
2732 */
2733#ifndef _SYS_SYSPROTO_H_
2734struct futimes_args {
2735	int	fd;
2736	struct	timeval *tptr;
2737};
2738#endif
2739/* ARGSUSED */
2740int
2741futimes(td, uap)
2742	struct thread *td;
2743	register struct futimes_args /* {
2744		syscallarg(int ) fd;
2745		syscallarg(struct timeval *) tptr;
2746	} */ *uap;
2747{
2748	struct timespec ts[2];
2749	struct file *fp;
2750	struct timeval *usrtvp;
2751	int error;
2752
2753	usrtvp = SCARG(uap, tptr);
2754	if ((error = getutimes(usrtvp, ts)) != 0)
2755		return (error);
2756	if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2757		return (error);
2758	error = setutimes(td, (struct vnode *)fp->f_data, ts, usrtvp == NULL);
2759	fdrop(fp, td);
2760	return (error);
2761}
2762
2763/*
2764 * Truncate a file given its path name.
2765 */
2766#ifndef _SYS_SYSPROTO_H_
2767struct truncate_args {
2768	char	*path;
2769	int	pad;
2770	off_t	length;
2771};
2772#endif
2773/* ARGSUSED */
2774int
2775truncate(td, uap)
2776	struct thread *td;
2777	register struct truncate_args /* {
2778		syscallarg(char *) path;
2779		syscallarg(int) pad;
2780		syscallarg(off_t) length;
2781	} */ *uap;
2782{
2783	struct mount *mp;
2784	struct vnode *vp;
2785	struct vattr vattr;
2786	int error;
2787	struct nameidata nd;
2788
2789	if (uap->length < 0)
2790		return(EINVAL);
2791	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
2792	if ((error = namei(&nd)) != 0)
2793		return (error);
2794	vp = nd.ni_vp;
2795	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
2796		vrele(vp);
2797		return (error);
2798	}
2799	NDFREE(&nd, NDF_ONLY_PNBUF);
2800	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
2801	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2802	if (vp->v_type == VDIR)
2803		error = EISDIR;
2804	else if ((error = vn_writechk(vp)) == 0 &&
2805	    (error = VOP_ACCESS(vp, VWRITE, td->td_ucred, td)) == 0) {
2806		VATTR_NULL(&vattr);
2807		vattr.va_size = SCARG(uap, length);
2808		error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
2809	}
2810	vput(vp);
2811	vn_finished_write(mp);
2812	return (error);
2813}
2814
2815/*
2816 * Truncate a file given a file descriptor.
2817 */
2818#ifndef _SYS_SYSPROTO_H_
2819struct ftruncate_args {
2820	int	fd;
2821	int	pad;
2822	off_t	length;
2823};
2824#endif
2825/* ARGSUSED */
2826int
2827ftruncate(td, uap)
2828	struct thread *td;
2829	register struct ftruncate_args /* {
2830		syscallarg(int) fd;
2831		syscallarg(int) pad;
2832		syscallarg(off_t) length;
2833	} */ *uap;
2834{
2835	struct mount *mp;
2836	struct vattr vattr;
2837	struct vnode *vp;
2838	struct file *fp;
2839	int error;
2840
2841	if (uap->length < 0)
2842		return(EINVAL);
2843	if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2844		return (error);
2845	if ((fp->f_flag & FWRITE) == 0) {
2846		fdrop(fp, td);
2847		return (EINVAL);
2848	}
2849	vp = (struct vnode *)fp->f_data;
2850	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
2851		fdrop(fp, td);
2852		return (error);
2853	}
2854	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
2855	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2856	if (vp->v_type == VDIR)
2857		error = EISDIR;
2858	else if ((error = vn_writechk(vp)) == 0) {
2859		VATTR_NULL(&vattr);
2860		vattr.va_size = SCARG(uap, length);
2861		error = VOP_SETATTR(vp, &vattr, fp->f_cred, td);
2862	}
2863	VOP_UNLOCK(vp, 0, td);
2864	vn_finished_write(mp);
2865	fdrop(fp, td);
2866	return (error);
2867}
2868
2869#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
2870/*
2871 * Truncate a file given its path name.
2872 */
2873#ifndef _SYS_SYSPROTO_H_
2874struct otruncate_args {
2875	char	*path;
2876	long	length;
2877};
2878#endif
2879/* ARGSUSED */
2880int
2881otruncate(td, uap)
2882	struct thread *td;
2883	register struct otruncate_args /* {
2884		syscallarg(char *) path;
2885		syscallarg(long) length;
2886	} */ *uap;
2887{
2888	struct truncate_args /* {
2889		syscallarg(char *) path;
2890		syscallarg(int) pad;
2891		syscallarg(off_t) length;
2892	} */ nuap;
2893
2894	SCARG(&nuap, path) = SCARG(uap, path);
2895	SCARG(&nuap, length) = SCARG(uap, length);
2896	return (truncate(td, &nuap));
2897}
2898
2899/*
2900 * Truncate a file given a file descriptor.
2901 */
2902#ifndef _SYS_SYSPROTO_H_
2903struct oftruncate_args {
2904	int	fd;
2905	long	length;
2906};
2907#endif
2908/* ARGSUSED */
2909int
2910oftruncate(td, uap)
2911	struct thread *td;
2912	register struct oftruncate_args /* {
2913		syscallarg(int) fd;
2914		syscallarg(long) length;
2915	} */ *uap;
2916{
2917	struct ftruncate_args /* {
2918		syscallarg(int) fd;
2919		syscallarg(int) pad;
2920		syscallarg(off_t) length;
2921	} */ nuap;
2922
2923	SCARG(&nuap, fd) = SCARG(uap, fd);
2924	SCARG(&nuap, length) = SCARG(uap, length);
2925	return (ftruncate(td, &nuap));
2926}
2927#endif /* COMPAT_43 || COMPAT_SUNOS */
2928
2929/*
2930 * Sync an open file.
2931 */
2932#ifndef _SYS_SYSPROTO_H_
2933struct fsync_args {
2934	int	fd;
2935};
2936#endif
2937/* ARGSUSED */
2938int
2939fsync(td, uap)
2940	struct thread *td;
2941	struct fsync_args /* {
2942		syscallarg(int) fd;
2943	} */ *uap;
2944{
2945	struct vnode *vp;
2946	struct mount *mp;
2947	struct file *fp;
2948	vm_object_t obj;
2949	int error;
2950
2951	GIANT_REQUIRED;
2952
2953	if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
2954		return (error);
2955	vp = (struct vnode *)fp->f_data;
2956	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
2957		fdrop(fp, td);
2958		return (error);
2959	}
2960	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2961	if (VOP_GETVOBJECT(vp, &obj) == 0) {
2962		vm_object_page_clean(obj, 0, 0, 0);
2963	}
2964	error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, td);
2965#ifdef SOFTUPDATES
2966	if (error == 0 && vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP))
2967	    error = softdep_fsync(vp);
2968#endif
2969
2970	VOP_UNLOCK(vp, 0, td);
2971	vn_finished_write(mp);
2972	fdrop(fp, td);
2973	return (error);
2974}
2975
2976/*
2977 * Rename files.  Source and destination must either both be directories,
2978 * or both not be directories.  If target is a directory, it must be empty.
2979 */
2980#ifndef _SYS_SYSPROTO_H_
2981struct rename_args {
2982	char	*from;
2983	char	*to;
2984};
2985#endif
2986/* ARGSUSED */
2987int
2988rename(td, uap)
2989	struct thread *td;
2990	register struct rename_args /* {
2991		syscallarg(char *) from;
2992		syscallarg(char *) to;
2993	} */ *uap;
2994{
2995	struct mount *mp;
2996	struct vnode *tvp, *fvp, *tdvp;
2997	struct nameidata fromnd, tond;
2998	int error;
2999
3000	bwillwrite();
3001	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
3002	    SCARG(uap, from), td);
3003	if ((error = namei(&fromnd)) != 0)
3004		return (error);
3005	fvp = fromnd.ni_vp;
3006	if ((error = vn_start_write(fvp, &mp, V_WAIT | PCATCH)) != 0) {
3007		NDFREE(&fromnd, NDF_ONLY_PNBUF);
3008		vrele(fromnd.ni_dvp);
3009		vrele(fvp);
3010		goto out1;
3011	}
3012	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | NOOBJ,
3013	    UIO_USERSPACE, SCARG(uap, to), td);
3014	if (fromnd.ni_vp->v_type == VDIR)
3015		tond.ni_cnd.cn_flags |= WILLBEDIR;
3016	if ((error = namei(&tond)) != 0) {
3017		/* Translate error code for rename("dir1", "dir2/."). */
3018		if (error == EISDIR && fvp->v_type == VDIR)
3019			error = EINVAL;
3020		NDFREE(&fromnd, NDF_ONLY_PNBUF);
3021		vrele(fromnd.ni_dvp);
3022		vrele(fvp);
3023		goto out1;
3024	}
3025	tdvp = tond.ni_dvp;
3026	tvp = tond.ni_vp;
3027	if (tvp != NULL) {
3028		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
3029			error = ENOTDIR;
3030			goto out;
3031		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
3032			error = EISDIR;
3033			goto out;
3034		}
3035	}
3036	if (fvp == tdvp)
3037		error = EINVAL;
3038	/*
3039	 * If source is the same as the destination (that is the
3040	 * same inode number with the same name in the same directory),
3041	 * then there is nothing to do.
3042	 */
3043	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
3044	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
3045	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
3046	      fromnd.ni_cnd.cn_namelen))
3047		error = -1;
3048out:
3049	if (!error) {
3050		VOP_LEASE(tdvp, td, td->td_ucred, LEASE_WRITE);
3051		if (fromnd.ni_dvp != tdvp) {
3052			VOP_LEASE(fromnd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
3053		}
3054		if (tvp) {
3055			VOP_LEASE(tvp, td, td->td_ucred, LEASE_WRITE);
3056		}
3057		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
3058				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
3059		NDFREE(&fromnd, NDF_ONLY_PNBUF);
3060		NDFREE(&tond, NDF_ONLY_PNBUF);
3061	} else {
3062		NDFREE(&fromnd, NDF_ONLY_PNBUF);
3063		NDFREE(&tond, NDF_ONLY_PNBUF);
3064		if (tdvp == tvp)
3065			vrele(tdvp);
3066		else
3067			vput(tdvp);
3068		if (tvp)
3069			vput(tvp);
3070		vrele(fromnd.ni_dvp);
3071		vrele(fvp);
3072	}
3073	vrele(tond.ni_startdir);
3074	vn_finished_write(mp);
3075	ASSERT_VOP_UNLOCKED(fromnd.ni_dvp, "rename");
3076	ASSERT_VOP_UNLOCKED(fromnd.ni_vp, "rename");
3077	ASSERT_VOP_UNLOCKED(tond.ni_dvp, "rename");
3078	ASSERT_VOP_UNLOCKED(tond.ni_vp, "rename");
3079out1:
3080	if (fromnd.ni_startdir)
3081		vrele(fromnd.ni_startdir);
3082	if (error == -1)
3083		return (0);
3084	return (error);
3085}
3086
3087/*
3088 * Make a directory file.
3089 */
3090#ifndef _SYS_SYSPROTO_H_
3091struct mkdir_args {
3092	char	*path;
3093	int	mode;
3094};
3095#endif
3096/* ARGSUSED */
3097int
3098mkdir(td, uap)
3099	struct thread *td;
3100	register struct mkdir_args /* {
3101		syscallarg(char *) path;
3102		syscallarg(int) mode;
3103	} */ *uap;
3104{
3105
3106	return vn_mkdir(uap->path, uap->mode, UIO_USERSPACE, td);
3107}
3108
3109int
3110vn_mkdir(path, mode, segflg, td)
3111	char *path;
3112	int mode;
3113	enum uio_seg segflg;
3114	struct thread *td;
3115{
3116	struct mount *mp;
3117	struct vnode *vp;
3118	struct vattr vattr;
3119	int error;
3120	struct nameidata nd;
3121
3122restart:
3123	bwillwrite();
3124	NDINIT(&nd, CREATE, LOCKPARENT, segflg, path, td);
3125	nd.ni_cnd.cn_flags |= WILLBEDIR;
3126	if ((error = namei(&nd)) != 0)
3127		return (error);
3128	vp = nd.ni_vp;
3129	if (vp != NULL) {
3130		NDFREE(&nd, NDF_ONLY_PNBUF);
3131		vrele(vp);
3132		vput(nd.ni_dvp);
3133		return (EEXIST);
3134	}
3135	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
3136		NDFREE(&nd, NDF_ONLY_PNBUF);
3137		vput(nd.ni_dvp);
3138		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
3139			return (error);
3140		goto restart;
3141	}
3142	VATTR_NULL(&vattr);
3143	vattr.va_type = VDIR;
3144	FILEDESC_LOCK(td->td_proc->p_fd);
3145	vattr.va_mode = (mode & ACCESSPERMS) &~ td->td_proc->p_fd->fd_cmask;
3146	FILEDESC_UNLOCK(td->td_proc->p_fd);
3147	VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
3148	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
3149	NDFREE(&nd, NDF_ONLY_PNBUF);
3150	vput(nd.ni_dvp);
3151	if (!error)
3152		vput(nd.ni_vp);
3153	vn_finished_write(mp);
3154	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mkdir");
3155	ASSERT_VOP_UNLOCKED(nd.ni_vp, "mkdir");
3156	return (error);
3157}
3158
3159/*
3160 * Remove a directory file.
3161 */
3162#ifndef _SYS_SYSPROTO_H_
3163struct rmdir_args {
3164	char	*path;
3165};
3166#endif
3167/* ARGSUSED */
3168int
3169rmdir(td, uap)
3170	struct thread *td;
3171	struct rmdir_args /* {
3172		syscallarg(char *) path;
3173	} */ *uap;
3174{
3175	struct mount *mp;
3176	struct vnode *vp;
3177	int error;
3178	struct nameidata nd;
3179
3180restart:
3181	bwillwrite();
3182	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
3183	    SCARG(uap, path), td);
3184	if ((error = namei(&nd)) != 0)
3185		return (error);
3186	vp = nd.ni_vp;
3187	if (vp->v_type != VDIR) {
3188		error = ENOTDIR;
3189		goto out;
3190	}
3191	/*
3192	 * No rmdir "." please.
3193	 */
3194	if (nd.ni_dvp == vp) {
3195		error = EINVAL;
3196		goto out;
3197	}
3198	/*
3199	 * The root of a mounted filesystem cannot be deleted.
3200	 */
3201	if (vp->v_flag & VROOT) {
3202		error = EBUSY;
3203		goto out;
3204	}
3205	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
3206		NDFREE(&nd, NDF_ONLY_PNBUF);
3207		if (nd.ni_dvp == vp)
3208			vrele(nd.ni_dvp);
3209		else
3210			vput(nd.ni_dvp);
3211		vput(vp);
3212		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
3213			return (error);
3214		goto restart;
3215	}
3216	VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
3217	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
3218	error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
3219	vn_finished_write(mp);
3220out:
3221	NDFREE(&nd, NDF_ONLY_PNBUF);
3222	if (nd.ni_dvp == vp)
3223		vrele(nd.ni_dvp);
3224	else
3225		vput(nd.ni_dvp);
3226	vput(vp);
3227	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "rmdir");
3228	ASSERT_VOP_UNLOCKED(nd.ni_vp, "rmdir");
3229	return (error);
3230}
3231
3232#ifdef COMPAT_43
3233/*
3234 * Read a block of directory entries in a file system independent format.
3235 */
3236#ifndef _SYS_SYSPROTO_H_
3237struct ogetdirentries_args {
3238	int	fd;
3239	char	*buf;
3240	u_int	count;
3241	long	*basep;
3242};
3243#endif
3244int
3245ogetdirentries(td, uap)
3246	struct thread *td;
3247	register struct ogetdirentries_args /* {
3248		syscallarg(int) fd;
3249		syscallarg(char *) buf;
3250		syscallarg(u_int) count;
3251		syscallarg(long *) basep;
3252	} */ *uap;
3253{
3254	struct vnode *vp;
3255	struct file *fp;
3256	struct uio auio, kuio;
3257	struct iovec aiov, kiov;
3258	struct dirent *dp, *edp;
3259	caddr_t dirbuf;
3260	int error, eofflag, readcnt;
3261	long loff;
3262
3263	/* XXX arbitrary sanity limit on `count'. */
3264	if (SCARG(uap, count) > 64 * 1024)
3265		return (EINVAL);
3266	if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
3267		return (error);
3268	if ((fp->f_flag & FREAD) == 0) {
3269		fdrop(fp, td);
3270		return (EBADF);
3271	}
3272	vp = (struct vnode *)fp->f_data;
3273unionread:
3274	if (vp->v_type != VDIR) {
3275		fdrop(fp, td);
3276		return (EINVAL);
3277	}
3278	aiov.iov_base = SCARG(uap, buf);
3279	aiov.iov_len = SCARG(uap, count);
3280	auio.uio_iov = &aiov;
3281	auio.uio_iovcnt = 1;
3282	auio.uio_rw = UIO_READ;
3283	auio.uio_segflg = UIO_USERSPACE;
3284	auio.uio_td = td;
3285	auio.uio_resid = SCARG(uap, count);
3286	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3287	loff = auio.uio_offset = fp->f_offset;
3288#	if (BYTE_ORDER != LITTLE_ENDIAN)
3289		if (vp->v_mount->mnt_maxsymlinklen <= 0) {
3290			error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
3291			    NULL, NULL);
3292			fp->f_offset = auio.uio_offset;
3293		} else
3294#	endif
3295	{
3296		kuio = auio;
3297		kuio.uio_iov = &kiov;
3298		kuio.uio_segflg = UIO_SYSSPACE;
3299		kiov.iov_len = SCARG(uap, count);
3300		MALLOC(dirbuf, caddr_t, SCARG(uap, count), M_TEMP, M_WAITOK);
3301		kiov.iov_base = dirbuf;
3302		error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
3303			    NULL, NULL);
3304		fp->f_offset = kuio.uio_offset;
3305		if (error == 0) {
3306			readcnt = SCARG(uap, count) - kuio.uio_resid;
3307			edp = (struct dirent *)&dirbuf[readcnt];
3308			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
3309#				if (BYTE_ORDER == LITTLE_ENDIAN)
3310					/*
3311					 * The expected low byte of
3312					 * dp->d_namlen is our dp->d_type.
3313					 * The high MBZ byte of dp->d_namlen
3314					 * is our dp->d_namlen.
3315					 */
3316					dp->d_type = dp->d_namlen;
3317					dp->d_namlen = 0;
3318#				else
3319					/*
3320					 * The dp->d_type is the high byte
3321					 * of the expected dp->d_namlen,
3322					 * so must be zero'ed.
3323					 */
3324					dp->d_type = 0;
3325#				endif
3326				if (dp->d_reclen > 0) {
3327					dp = (struct dirent *)
3328					    ((char *)dp + dp->d_reclen);
3329				} else {
3330					error = EIO;
3331					break;
3332				}
3333			}
3334			if (dp >= edp)
3335				error = uiomove(dirbuf, readcnt, &auio);
3336		}
3337		FREE(dirbuf, M_TEMP);
3338	}
3339	VOP_UNLOCK(vp, 0, td);
3340	if (error) {
3341		fdrop(fp, td);
3342		return (error);
3343	}
3344	if (SCARG(uap, count) == auio.uio_resid) {
3345		if (union_dircheckp) {
3346			error = union_dircheckp(td, &vp, fp);
3347			if (error == -1)
3348				goto unionread;
3349			if (error) {
3350				fdrop(fp, td);
3351				return (error);
3352			}
3353		}
3354		if ((vp->v_flag & VROOT) &&
3355		    (vp->v_mount->mnt_flag & MNT_UNION)) {
3356			struct vnode *tvp = vp;
3357			vp = vp->v_mount->mnt_vnodecovered;
3358			VREF(vp);
3359			fp->f_data = (caddr_t) vp;
3360			fp->f_offset = 0;
3361			vrele(tvp);
3362			goto unionread;
3363		}
3364	}
3365	error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
3366	    sizeof(long));
3367	fdrop(fp, td);
3368	td->td_retval[0] = SCARG(uap, count) - auio.uio_resid;
3369	return (error);
3370}
3371#endif /* COMPAT_43 */
3372
3373/*
3374 * Read a block of directory entries in a file system independent format.
3375 */
3376#ifndef _SYS_SYSPROTO_H_
3377struct getdirentries_args {
3378	int	fd;
3379	char	*buf;
3380	u_int	count;
3381	long	*basep;
3382};
3383#endif
3384int
3385getdirentries(td, uap)
3386	struct thread *td;
3387	register struct getdirentries_args /* {
3388		syscallarg(int) fd;
3389		syscallarg(char *) buf;
3390		syscallarg(u_int) count;
3391		syscallarg(long *) basep;
3392	} */ *uap;
3393{
3394	struct vnode *vp;
3395	struct file *fp;
3396	struct uio auio;
3397	struct iovec aiov;
3398	long loff;
3399	int error, eofflag;
3400
3401	if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
3402		return (error);
3403	if ((fp->f_flag & FREAD) == 0) {
3404		fdrop(fp, td);
3405		return (EBADF);
3406	}
3407	vp = (struct vnode *)fp->f_data;
3408unionread:
3409	if (vp->v_type != VDIR) {
3410		fdrop(fp, td);
3411		return (EINVAL);
3412	}
3413	aiov.iov_base = SCARG(uap, buf);
3414	aiov.iov_len = SCARG(uap, count);
3415	auio.uio_iov = &aiov;
3416	auio.uio_iovcnt = 1;
3417	auio.uio_rw = UIO_READ;
3418	auio.uio_segflg = UIO_USERSPACE;
3419	auio.uio_td = td;
3420	auio.uio_resid = SCARG(uap, count);
3421	/* vn_lock(vp, LK_SHARED | LK_RETRY, td); */
3422	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3423	loff = auio.uio_offset = fp->f_offset;
3424	error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, NULL);
3425	fp->f_offset = auio.uio_offset;
3426	VOP_UNLOCK(vp, 0, td);
3427	if (error) {
3428		fdrop(fp, td);
3429		return (error);
3430	}
3431	if (SCARG(uap, count) == auio.uio_resid) {
3432		if (union_dircheckp) {
3433			error = union_dircheckp(td, &vp, fp);
3434			if (error == -1)
3435				goto unionread;
3436			if (error) {
3437				fdrop(fp, td);
3438				return (error);
3439			}
3440		}
3441		if ((vp->v_flag & VROOT) &&
3442		    (vp->v_mount->mnt_flag & MNT_UNION)) {
3443			struct vnode *tvp = vp;
3444			vp = vp->v_mount->mnt_vnodecovered;
3445			VREF(vp);
3446			fp->f_data = (caddr_t) vp;
3447			fp->f_offset = 0;
3448			vrele(tvp);
3449			goto unionread;
3450		}
3451	}
3452	if (SCARG(uap, basep) != NULL) {
3453		error = copyout((caddr_t)&loff, (caddr_t)SCARG(uap, basep),
3454		    sizeof(long));
3455	}
3456	td->td_retval[0] = SCARG(uap, count) - auio.uio_resid;
3457	fdrop(fp, td);
3458	return (error);
3459}
3460#ifndef _SYS_SYSPROTO_H_
3461struct getdents_args {
3462	int fd;
3463	char *buf;
3464	size_t count;
3465};
3466#endif
3467int
3468getdents(td, uap)
3469	struct thread *td;
3470	register struct getdents_args /* {
3471		syscallarg(int) fd;
3472		syscallarg(char *) buf;
3473		syscallarg(u_int) count;
3474	} */ *uap;
3475{
3476	struct getdirentries_args ap;
3477	ap.fd = uap->fd;
3478	ap.buf = uap->buf;
3479	ap.count = uap->count;
3480	ap.basep = NULL;
3481	return getdirentries(td, &ap);
3482}
3483
3484/*
3485 * Set the mode mask for creation of filesystem nodes.
3486 *
3487 * MP SAFE
3488 */
3489#ifndef _SYS_SYSPROTO_H_
3490struct umask_args {
3491	int	newmask;
3492};
3493#endif
3494int
3495umask(td, uap)
3496	struct thread *td;
3497	struct umask_args /* {
3498		syscallarg(int) newmask;
3499	} */ *uap;
3500{
3501	register struct filedesc *fdp;
3502
3503	FILEDESC_LOCK(td->td_proc->p_fd);
3504	fdp = td->td_proc->p_fd;
3505	td->td_retval[0] = fdp->fd_cmask;
3506	fdp->fd_cmask = SCARG(uap, newmask) & ALLPERMS;
3507	FILEDESC_UNLOCK(td->td_proc->p_fd);
3508	return (0);
3509}
3510
3511/*
3512 * Void all references to file by ripping underlying filesystem
3513 * away from vnode.
3514 */
3515#ifndef _SYS_SYSPROTO_H_
3516struct revoke_args {
3517	char	*path;
3518};
3519#endif
3520/* ARGSUSED */
3521int
3522revoke(td, uap)
3523	struct thread *td;
3524	register struct revoke_args /* {
3525		syscallarg(char *) path;
3526	} */ *uap;
3527{
3528	struct mount *mp;
3529	struct vnode *vp;
3530	struct vattr vattr;
3531	int error;
3532	struct nameidata nd;
3533
3534	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, SCARG(uap, path),
3535	    td);
3536	if ((error = namei(&nd)) != 0)
3537		return (error);
3538	vp = nd.ni_vp;
3539	NDFREE(&nd, NDF_ONLY_PNBUF);
3540	if (vp->v_type != VCHR) {
3541		vput(vp);
3542		return (EINVAL);
3543	}
3544	error = VOP_GETATTR(vp, &vattr, td->td_ucred, td);
3545	if (error) {
3546		vput(vp);
3547		return (error);
3548	}
3549	VOP_UNLOCK(vp, 0, td);
3550	if (td->td_ucred->cr_uid != vattr.va_uid) {
3551		error = suser_xxx(0, td->td_proc, PRISON_ROOT);
3552		if (error)
3553			goto out;
3554	}
3555	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
3556		goto out;
3557	if (vcount(vp) > 1)
3558		VOP_REVOKE(vp, REVOKEALL);
3559	vn_finished_write(mp);
3560out:
3561	vrele(vp);
3562	return (error);
3563}
3564
3565/*
3566 * Convert a user file descriptor to a kernel file entry.
3567 * The file entry is locked upon returning.
3568 */
3569int
3570getvnode(fdp, fd, fpp)
3571	struct filedesc *fdp;
3572	int fd;
3573	struct file **fpp;
3574{
3575	int error;
3576	struct file *fp;
3577
3578	fp = NULL;
3579	if (fdp == NULL)
3580		error = EBADF;
3581	else {
3582		FILEDESC_LOCK(fdp);
3583		if ((u_int)fd >= fdp->fd_nfiles ||
3584		    (fp = fdp->fd_ofiles[fd]) == NULL)
3585			error = EBADF;
3586		else if (fp->f_type != DTYPE_VNODE && fp->f_type != DTYPE_FIFO) {
3587			fp = NULL;
3588			error = EINVAL;
3589		} else {
3590			fhold(fp);
3591			error = 0;
3592		}
3593		FILEDESC_UNLOCK(fdp);
3594	}
3595	*fpp = fp;
3596	return (error);
3597}
3598/*
3599 * Get (NFS) file handle
3600 */
3601#ifndef _SYS_SYSPROTO_H_
3602struct getfh_args {
3603	char	*fname;
3604	fhandle_t *fhp;
3605};
3606#endif
3607int
3608getfh(td, uap)
3609	struct thread *td;
3610	register struct getfh_args *uap;
3611{
3612	struct nameidata nd;
3613	fhandle_t fh;
3614	register struct vnode *vp;
3615	int error;
3616
3617	/*
3618	 * Must be super user
3619	 */
3620	error = suser_td(td);
3621	if (error)
3622		return (error);
3623	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, td);
3624	error = namei(&nd);
3625	if (error)
3626		return (error);
3627	NDFREE(&nd, NDF_ONLY_PNBUF);
3628	vp = nd.ni_vp;
3629	bzero(&fh, sizeof(fh));
3630	fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
3631	error = VFS_VPTOFH(vp, &fh.fh_fid);
3632	vput(vp);
3633	if (error)
3634		return (error);
3635	error = copyout(&fh, uap->fhp, sizeof (fh));
3636	return (error);
3637}
3638
3639/*
3640 * syscall for the rpc.lockd to use to translate a NFS file handle into
3641 * an open descriptor.
3642 *
3643 * warning: do not remove the suser() call or this becomes one giant
3644 * security hole.
3645 */
3646#ifndef _SYS_SYSPROTO_H_
3647struct fhopen_args {
3648	const struct fhandle *u_fhp;
3649	int flags;
3650};
3651#endif
3652int
3653fhopen(td, uap)
3654	struct thread *td;
3655	struct fhopen_args /* {
3656		syscallarg(const struct fhandle *) u_fhp;
3657		syscallarg(int) flags;
3658	} */ *uap;
3659{
3660	struct proc *p = td->td_proc;
3661	struct mount *mp;
3662	struct vnode *vp;
3663	struct fhandle fhp;
3664	struct vattr vat;
3665	struct vattr *vap = &vat;
3666	struct flock lf;
3667	struct file *fp;
3668	register struct filedesc *fdp = p->p_fd;
3669	int fmode, mode, error, type;
3670	struct file *nfp;
3671	int indx;
3672
3673	/*
3674	 * Must be super user
3675	 */
3676	error = suser_td(td);
3677	if (error)
3678		return (error);
3679
3680	fmode = FFLAGS(SCARG(uap, flags));
3681	/* why not allow a non-read/write open for our lockd? */
3682	if (((fmode & (FREAD | FWRITE)) == 0) || (fmode & O_CREAT))
3683		return (EINVAL);
3684	error = copyin(SCARG(uap,u_fhp), &fhp, sizeof(fhp));
3685	if (error)
3686		return(error);
3687	/* find the mount point */
3688	mp = vfs_getvfs(&fhp.fh_fsid);
3689	if (mp == NULL)
3690		return (ESTALE);
3691	/* now give me my vnode, it gets returned to me locked */
3692	error = VFS_FHTOVP(mp, &fhp.fh_fid, &vp);
3693	if (error)
3694		return (error);
3695 	/*
3696	 * from now on we have to make sure not
3697	 * to forget about the vnode
3698	 * any error that causes an abort must vput(vp)
3699	 * just set error = err and 'goto bad;'.
3700	 */
3701
3702	/*
3703	 * from vn_open
3704	 */
3705	if (vp->v_type == VLNK) {
3706		error = EMLINK;
3707		goto bad;
3708	}
3709	if (vp->v_type == VSOCK) {
3710		error = EOPNOTSUPP;
3711		goto bad;
3712	}
3713	mode = 0;
3714	if (fmode & (FWRITE | O_TRUNC)) {
3715		if (vp->v_type == VDIR) {
3716			error = EISDIR;
3717			goto bad;
3718		}
3719		error = vn_writechk(vp);
3720		if (error)
3721			goto bad;
3722		mode |= VWRITE;
3723	}
3724	if (fmode & FREAD)
3725		mode |= VREAD;
3726	if (mode) {
3727		error = VOP_ACCESS(vp, mode, td->td_ucred, td);
3728		if (error)
3729			goto bad;
3730	}
3731	if (fmode & O_TRUNC) {
3732		VOP_UNLOCK(vp, 0, td);				/* XXX */
3733		if ((error = vn_start_write(NULL, &mp, V_WAIT | PCATCH)) != 0) {
3734			vrele(vp);
3735			return (error);
3736		}
3737		VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
3738		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);	/* XXX */
3739		VATTR_NULL(vap);
3740		vap->va_size = 0;
3741		error = VOP_SETATTR(vp, vap, td->td_ucred, td);
3742		vn_finished_write(mp);
3743		if (error)
3744			goto bad;
3745	}
3746	error = VOP_OPEN(vp, fmode, td->td_ucred, td);
3747	if (error)
3748		goto bad;
3749	/*
3750	 * Make sure that a VM object is created for VMIO support.
3751	 */
3752	if (vn_canvmio(vp) == TRUE) {
3753		if ((error = vfs_object_create(vp, td, td->td_ucred)) != 0)
3754			goto bad;
3755	}
3756	if (fmode & FWRITE)
3757		vp->v_writecount++;
3758
3759	/*
3760	 * end of vn_open code
3761	 */
3762
3763	if ((error = falloc(td, &nfp, &indx)) != 0) {
3764		if (fmode & FWRITE)
3765			vp->v_writecount--;
3766		goto bad;
3767	}
3768	fp = nfp;
3769
3770	/*
3771	 * Hold an extra reference to avoid having fp ripped out
3772	 * from under us while we block in the lock op
3773	 */
3774	fhold(fp);
3775	nfp->f_data = (caddr_t)vp;
3776	nfp->f_flag = fmode & FMASK;
3777	nfp->f_ops = &vnops;
3778	nfp->f_type = DTYPE_VNODE;
3779	if (fmode & (O_EXLOCK | O_SHLOCK)) {
3780		lf.l_whence = SEEK_SET;
3781		lf.l_start = 0;
3782		lf.l_len = 0;
3783		if (fmode & O_EXLOCK)
3784			lf.l_type = F_WRLCK;
3785		else
3786			lf.l_type = F_RDLCK;
3787		type = F_FLOCK;
3788		if ((fmode & FNONBLOCK) == 0)
3789			type |= F_WAIT;
3790		VOP_UNLOCK(vp, 0, td);
3791		if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) != 0) {
3792			/*
3793			 * The lock request failed.  Normally close the
3794			 * descriptor but handle the case where someone might
3795			 * have dup()d or close()d it when we weren't looking.
3796			 */
3797			FILEDESC_LOCK(fdp);
3798			if (fdp->fd_ofiles[indx] == fp) {
3799				fdp->fd_ofiles[indx] = NULL;
3800				FILEDESC_UNLOCK(fdp);
3801				fdrop(fp, td);
3802			} else
3803				FILEDESC_UNLOCK(fdp);
3804			/*
3805			 * release our private reference
3806			 */
3807			fdrop(fp, td);
3808			return(error);
3809		}
3810		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3811		fp->f_flag |= FHASLOCK;
3812	}
3813	if ((vp->v_type == VREG) && (VOP_GETVOBJECT(vp, NULL) != 0))
3814		vfs_object_create(vp, td, td->td_ucred);
3815
3816	VOP_UNLOCK(vp, 0, td);
3817	fdrop(fp, td);
3818	td->td_retval[0] = indx;
3819	return (0);
3820
3821bad:
3822	vput(vp);
3823	return (error);
3824}
3825
3826/*
3827 * Stat an (NFS) file handle.
3828 */
3829#ifndef _SYS_SYSPROTO_H_
3830struct fhstat_args {
3831	struct fhandle *u_fhp;
3832	struct stat *sb;
3833};
3834#endif
3835int
3836fhstat(td, uap)
3837	struct thread *td;
3838	register struct fhstat_args /* {
3839		syscallarg(struct fhandle *) u_fhp;
3840		syscallarg(struct stat *) sb;
3841	} */ *uap;
3842{
3843	struct stat sb;
3844	fhandle_t fh;
3845	struct mount *mp;
3846	struct vnode *vp;
3847	int error;
3848
3849	/*
3850	 * Must be super user
3851	 */
3852	error = suser_td(td);
3853	if (error)
3854		return (error);
3855
3856	error = copyin(SCARG(uap, u_fhp), &fh, sizeof(fhandle_t));
3857	if (error)
3858		return (error);
3859
3860	if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
3861		return (ESTALE);
3862	if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
3863		return (error);
3864	error = vn_stat(vp, &sb, td);
3865	vput(vp);
3866	if (error)
3867		return (error);
3868	error = copyout(&sb, SCARG(uap, sb), sizeof(sb));
3869	return (error);
3870}
3871
3872/*
3873 * Implement fstatfs() for (NFS) file handles.
3874 */
3875#ifndef _SYS_SYSPROTO_H_
3876struct fhstatfs_args {
3877	struct fhandle *u_fhp;
3878	struct statfs *buf;
3879};
3880#endif
3881int
3882fhstatfs(td, uap)
3883	struct thread *td;
3884	struct fhstatfs_args /* {
3885		syscallarg(struct fhandle) *u_fhp;
3886		syscallarg(struct statfs) *buf;
3887	} */ *uap;
3888{
3889	struct statfs *sp;
3890	struct mount *mp;
3891	struct vnode *vp;
3892	struct statfs sb;
3893	fhandle_t fh;
3894	int error;
3895
3896	/*
3897	 * Must be super user
3898	 */
3899	error = suser_td(td);
3900	if (error)
3901		return (error);
3902
3903	if ((error = copyin(SCARG(uap, u_fhp), &fh, sizeof(fhandle_t))) != 0)
3904		return (error);
3905
3906	if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
3907		return (ESTALE);
3908	if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
3909		return (error);
3910	mp = vp->v_mount;
3911	sp = &mp->mnt_stat;
3912	vput(vp);
3913	if ((error = VFS_STATFS(mp, sp, td)) != 0)
3914		return (error);
3915	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
3916	if (suser_xxx(td->td_ucred, 0, 0)) {
3917		bcopy((caddr_t)sp, (caddr_t)&sb, sizeof(sb));
3918		sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
3919		sp = &sb;
3920	}
3921	return (copyout(sp, SCARG(uap, buf), sizeof(*sp)));
3922}
3923
3924/*
3925 * Syscall to push extended attribute configuration information into the
3926 * VFS.  Accepts a path, which it converts to a mountpoint, as well as
3927 * a command (int cmd), and attribute name and misc data.  For now, the
3928 * attribute name is left in userspace for consumption by the VFS_op.
3929 * It will probably be changed to be copied into sysspace by the
3930 * syscall in the future, once issues with various consumers of the
3931 * attribute code have raised their hands.
3932 *
3933 * Currently this is used only by UFS Extended Attributes.
3934 */
3935int
3936extattrctl(td, uap)
3937	struct thread *td;
3938	struct extattrctl_args *uap;
3939{
3940	struct vnode *filename_vp;
3941	struct nameidata nd;
3942	struct mount *mp, *mp_writable;
3943	char attrname[EXTATTR_MAXNAMELEN];
3944	int error;
3945
3946	/*
3947	 * SCARG(uap, attrname) not always defined.  We check again later
3948	 * when we invoke the VFS call so as to pass in NULL there if needed.
3949	 */
3950	if (SCARG(uap, attrname) != NULL) {
3951		error = copyinstr(SCARG(uap, attrname), attrname,
3952		    EXTATTR_MAXNAMELEN, NULL);
3953		if (error)
3954			return (error);
3955	}
3956
3957	/*
3958	 * SCARG(uap, filename) not always defined.  If it is, grab
3959	 * a vnode lock, which VFS_EXTATTRCTL() will later release.
3960	 */
3961	filename_vp = NULL;
3962	if (SCARG(uap, filename) != NULL) {
3963		NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
3964		    SCARG(uap, filename), td);
3965		if ((error = namei(&nd)) != 0)
3966			return (error);
3967		filename_vp = nd.ni_vp;
3968		NDFREE(&nd, NDF_NO_VP_RELE | NDF_NO_VP_UNLOCK);
3969	}
3970
3971	/* SCARG(uap, path) always defined. */
3972	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
3973	if ((error = namei(&nd)) != 0) {
3974		if (filename_vp != NULL)
3975			vput(filename_vp);
3976		return (error);
3977	}
3978	mp = nd.ni_vp->v_mount;
3979	error = vn_start_write(nd.ni_vp, &mp_writable, V_WAIT | PCATCH);
3980	NDFREE(&nd, 0);
3981	if (error) {
3982		if (filename_vp != NULL)
3983			vput(filename_vp);
3984		return (error);
3985	}
3986
3987	if (SCARG(uap, attrname) != NULL) {
3988		error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp,
3989		    SCARG(uap, attrnamespace), attrname, td);
3990	} else {
3991		error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), filename_vp,
3992		    SCARG(uap, attrnamespace), NULL, td);
3993	}
3994
3995	vn_finished_write(mp_writable);
3996	/*
3997	 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd,
3998	 * filename_vp, so vrele it if it is defined.
3999	 */
4000	if (filename_vp != NULL)
4001		vrele(filename_vp);
4002
4003	return (error);
4004}
4005
4006/*-
4007 * Set a named extended attribute on a file or directory
4008 *
4009 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
4010 *            kernelspace string pointer "attrname", userspace buffer
4011 *            pointer "data", buffer length "nbytes", thread "td".
4012 * Returns: 0 on success, an error number otherwise
4013 * Locks: none
4014 * References: vp must be a valid reference for the duration of the call
4015 */
4016static int
4017extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
4018    void *data, size_t nbytes, struct thread *td)
4019{
4020	struct mount *mp;
4021	struct uio auio;
4022	struct iovec aiov;
4023	ssize_t cnt;
4024	int error;
4025
4026	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
4027		return (error);
4028	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
4029	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
4030
4031	aiov.iov_base = data;
4032	aiov.iov_len = nbytes;
4033	auio.uio_iov = &aiov;
4034	auio.uio_iovcnt = 1;
4035	auio.uio_offset = 0;
4036	if (nbytes > INT_MAX) {
4037		error = EINVAL;
4038		goto done;
4039	}
4040	auio.uio_resid = nbytes;
4041	auio.uio_rw = UIO_WRITE;
4042	auio.uio_segflg = UIO_USERSPACE;
4043	auio.uio_td = td;
4044	cnt = nbytes;
4045
4046	error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
4047	    td->td_ucred, td);
4048	cnt -= auio.uio_resid;
4049	td->td_retval[0] = cnt;
4050
4051done:
4052	VOP_UNLOCK(vp, 0, td);
4053	vn_finished_write(mp);
4054	return (error);
4055}
4056
4057int
4058extattr_set_file(td, uap)
4059	struct thread *td;
4060	struct extattr_set_file_args *uap;
4061{
4062	struct nameidata nd;
4063	char attrname[EXTATTR_MAXNAMELEN];
4064	int error;
4065
4066	error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
4067	    NULL);
4068	if (error)
4069		return (error);
4070
4071	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
4072	if ((error = namei(&nd)) != 0)
4073		return (error);
4074	NDFREE(&nd, NDF_ONLY_PNBUF);
4075
4076	error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
4077	    SCARG(uap, data), SCARG(uap, nbytes), td);
4078
4079	vrele(nd.ni_vp);
4080	return (error);
4081}
4082
4083int
4084extattr_set_fd(td, uap)
4085	struct thread *td;
4086	struct extattr_set_fd_args *uap;
4087{
4088	struct file *fp;
4089	char attrname[EXTATTR_MAXNAMELEN];
4090	int error;
4091
4092	error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
4093	    NULL);
4094	if (error)
4095		return (error);
4096
4097	if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
4098		return (error);
4099
4100	error = extattr_set_vp((struct vnode *)fp->f_data,
4101	    SCARG(uap, attrnamespace), attrname, SCARG(uap, data),
4102	    SCARG(uap, nbytes), td);
4103	fdrop(fp, td);
4104
4105	return (error);
4106}
4107
4108/*-
4109 * Get a named extended attribute on a file or directory
4110 *
4111 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
4112 *            kernelspace string pointer "attrname", userspace buffer
4113 *            pointer "data", buffer length "nbytes", thread "td".
4114 * Returns: 0 on success, an error number otherwise
4115 * Locks: none
4116 * References: vp must be a valid reference for the duration of the call
4117 */
4118static int
4119extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
4120    void *data, size_t nbytes, struct thread *td)
4121{
4122	struct uio auio;
4123	struct iovec aiov;
4124	ssize_t cnt;
4125	size_t size;
4126	int error;
4127
4128	VOP_LEASE(vp, td, td->td_ucred, LEASE_READ);
4129	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
4130
4131	/*
4132	 * Slightly unusual semantics: if the user provides a NULL data
4133	 * pointer, they don't want to receive the data, just the
4134	 * maximum read length.
4135	 */
4136	if (data != NULL) {
4137		aiov.iov_base = data;
4138		aiov.iov_len = nbytes;
4139		auio.uio_iov = &aiov;
4140		auio.uio_offset = 0;
4141		if (nbytes > INT_MAX) {
4142			error = EINVAL;
4143			goto done;
4144		}
4145		auio.uio_resid = nbytes;
4146		auio.uio_rw = UIO_READ;
4147		auio.uio_segflg = UIO_USERSPACE;
4148		auio.uio_td = td;
4149		cnt = nbytes;
4150		error = VOP_GETEXTATTR(vp, attrnamespace, attrname, &auio,
4151		    NULL, td->td_ucred, td);
4152		cnt -= auio.uio_resid;
4153		td->td_retval[0] = cnt;
4154	} else {
4155		error = VOP_GETEXTATTR(vp, attrnamespace, attrname, NULL,
4156		    &size, td->td_ucred, td);
4157		td->td_retval[0] = size;
4158	}
4159done:
4160	VOP_UNLOCK(vp, 0, td);
4161	return (error);
4162}
4163
4164int
4165extattr_get_file(td, uap)
4166	struct thread *td;
4167	struct extattr_get_file_args *uap;
4168{
4169	struct nameidata nd;
4170	char attrname[EXTATTR_MAXNAMELEN];
4171	int error;
4172
4173	error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
4174	    NULL);
4175	if (error)
4176		return (error);
4177
4178	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
4179	if ((error = namei(&nd)) != 0)
4180		return (error);
4181	NDFREE(&nd, NDF_ONLY_PNBUF);
4182
4183	error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
4184	    SCARG(uap, data), SCARG(uap, nbytes), td);
4185
4186	vrele(nd.ni_vp);
4187	return (error);
4188}
4189
4190int
4191extattr_get_fd(td, uap)
4192	struct thread *td;
4193	struct extattr_get_fd_args *uap;
4194{
4195	struct file *fp;
4196	char attrname[EXTATTR_MAXNAMELEN];
4197	int error;
4198
4199	error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
4200	    NULL);
4201	if (error)
4202		return (error);
4203
4204	if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
4205		return (error);
4206
4207	error = extattr_get_vp((struct vnode *)fp->f_data,
4208	    SCARG(uap, attrnamespace), attrname, SCARG(uap, data),
4209	    SCARG(uap, nbytes), td);
4210
4211	fdrop(fp, td);
4212	return (error);
4213}
4214
4215/*
4216 * extattr_delete_vp(): Delete a named extended attribute on a file or
4217 *                      directory
4218 *
4219 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
4220 *            kernelspace string pointer "attrname", proc "p"
4221 * Returns: 0 on success, an error number otherwise
4222 * Locks: none
4223 * References: vp must be a valid reference for the duration of the call
4224 */
4225static int
4226extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
4227    struct thread *td)
4228{
4229	struct mount *mp;
4230	int error;
4231
4232	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
4233		return (error);
4234	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
4235	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
4236
4237	error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL, td->td_ucred,
4238	    td);
4239
4240	VOP_UNLOCK(vp, 0, td);
4241	vn_finished_write(mp);
4242	return (error);
4243}
4244
4245int
4246extattr_delete_file(td, uap)
4247	struct thread *td;
4248	struct extattr_delete_file_args *uap;
4249{
4250	struct nameidata nd;
4251	char attrname[EXTATTR_MAXNAMELEN];
4252	int error;
4253
4254	error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
4255	     NULL);
4256	if (error)
4257		return(error);
4258
4259	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), td);
4260	if ((error = namei(&nd)) != 0)
4261		return(error);
4262	NDFREE(&nd, NDF_ONLY_PNBUF);
4263
4264	error = extattr_delete_vp(nd.ni_vp, SCARG(uap, attrnamespace),
4265	    attrname, td);
4266
4267	vrele(nd.ni_vp);
4268	return(error);
4269}
4270
4271int
4272extattr_delete_fd(td, uap)
4273	struct thread *td;
4274	struct extattr_delete_fd_args *uap;
4275{
4276	struct file *fp;
4277	struct vnode *vp;
4278	char attrname[EXTATTR_MAXNAMELEN];
4279	int error;
4280
4281	error = copyinstr(SCARG(uap, attrname), attrname, EXTATTR_MAXNAMELEN,
4282	    NULL);
4283	if (error)
4284		return (error);
4285
4286	if ((error = getvnode(td->td_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
4287		return (error);
4288	vp = (struct vnode *)fp->f_data;
4289
4290	error = extattr_delete_vp((struct vnode *)fp->f_data,
4291	    SCARG(uap, attrnamespace), attrname, td);
4292
4293	fdrop(fp, td);
4294	return (error);
4295}
4296