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