xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 39632)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)vfs_syscalls.c	7.31 (Berkeley) 11/25/89
18  */
19 
20 #include "param.h"
21 #include "systm.h"
22 #include "syscontext.h"
23 #include "kernel.h"
24 #include "file.h"
25 #include "stat.h"
26 #include "vnode.h"
27 #include "../ufs/inode.h"
28 #include "mount.h"
29 #include "proc.h"
30 #include "uio.h"
31 #include "malloc.h"
32 
33 /*
34  * Virtual File System System Calls
35  */
36 
37 /*
38  * mount system call
39  */
40 mount(scp)
41 	register struct syscontext *scp;
42 {
43 	register struct a {
44 		int	type;
45 		char	*dir;
46 		int	flags;
47 		caddr_t	data;
48 	} *uap = (struct a *)scp->sc_ap;
49 	register struct nameidata *ndp = &scp->sc_nd;
50 	register struct vnode *vp;
51 	register struct mount *mp;
52 	int error;
53 
54 	/*
55 	 * Must be super user
56 	 */
57 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
58 		RETURN (error);
59 	/*
60 	 * Get vnode to be covered
61 	 */
62 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
63 	ndp->ni_segflg = UIO_USERSPACE;
64 	ndp->ni_dirp = uap->dir;
65 	if (error = namei(ndp))
66 		RETURN (error);
67 	vp = ndp->ni_vp;
68 	if (uap->flags & M_UPDATE) {
69 		if ((vp->v_flag & VROOT) == 0) {
70 			vput(vp);
71 			RETURN (EINVAL);
72 		}
73 		mp = vp->v_mount;
74 		/*
75 		 * We allow going from read-only to read-write,
76 		 * but not from read-write to read-only.
77 		 */
78 		if ((mp->m_flag & M_RDONLY) == 0 &&
79 		    (uap->flags & M_RDONLY) != 0) {
80 			vput(vp);
81 			RETURN (EOPNOTSUPP);	/* Needs translation */
82 		}
83 		mp->m_flag |= M_UPDATE;
84 		VOP_UNLOCK(vp);
85 		goto update;
86 	}
87 	if (vp->v_count != 1) {
88 		vput(vp);
89 		RETURN (EBUSY);
90 	}
91 	if (vp->v_type != VDIR) {
92 		vput(vp);
93 		RETURN (ENOTDIR);
94 	}
95 	if (uap->type > MOUNT_MAXTYPE ||
96 	    vfssw[uap->type] == (struct vfsops *)0) {
97 		vput(vp);
98 		RETURN (ENODEV);
99 	}
100 
101 	/*
102 	 * Allocate and initialize the file system.
103 	 */
104 	mp = (struct mount *)malloc((u_long)sizeof(struct mount),
105 		M_MOUNT, M_WAITOK);
106 	mp->m_op = vfssw[uap->type];
107 	mp->m_flag = 0;
108 	mp->m_exroot = 0;
109 	mp->m_mounth = (struct vnode *)0;
110 	if (error = vfs_lock(mp)) {
111 		free((caddr_t)mp, M_MOUNT);
112 		vput(vp);
113 		RETURN (error);
114 	}
115 	if (vp->v_mountedhere != (struct mount *)0) {
116 		vfs_unlock(mp);
117 		free((caddr_t)mp, M_MOUNT);
118 		vput(vp);
119 		RETURN (EBUSY);
120 	}
121 	/*
122 	 * Put the new filesystem on the mount list after root.
123 	 */
124 	mp->m_next = rootfs->m_next;
125 	mp->m_prev = rootfs;
126 	rootfs->m_next = mp;
127 	mp->m_next->m_prev = mp;
128 	vp->v_mountedhere = mp;
129 	mp->m_vnodecovered = vp;
130 update:
131 	/*
132 	 * Set the mount level flags.
133 	 */
134 	if (uap->flags & M_RDONLY)
135 		mp->m_flag |= M_RDONLY;
136 	else
137 		mp->m_flag &= ~M_RDONLY;
138 	if (uap->flags & M_NOSUID)
139 		mp->m_flag |= M_NOSUID;
140 	else
141 		mp->m_flag &= ~M_NOSUID;
142 	if (uap->flags & M_NOEXEC)
143 		mp->m_flag |= M_NOEXEC;
144 	else
145 		mp->m_flag &= ~M_NOEXEC;
146 	if (uap->flags & M_NODEV)
147 		mp->m_flag |= M_NODEV;
148 	else
149 		mp->m_flag &= ~M_NODEV;
150 	if (uap->flags & M_SYNCHRONOUS)
151 		mp->m_flag |= M_SYNCHRONOUS;
152 	else
153 		mp->m_flag &= ~M_SYNCHRONOUS;
154 	/*
155 	 * Mount the filesystem.
156 	 */
157 	error = VFS_MOUNT(mp, uap->dir, uap->data, ndp);
158 	if (mp->m_flag & M_UPDATE) {
159 		mp->m_flag &= ~M_UPDATE;
160 		vrele(vp);
161 		RETURN (error);
162 	}
163 	cache_purge(vp);
164 	if (!error) {
165 		VOP_UNLOCK(vp);
166 		vfs_unlock(mp);
167 		error = VFS_START(mp, 0);
168 	} else {
169 		vfs_remove(mp);
170 		free((caddr_t)mp, M_MOUNT);
171 		vput(vp);
172 	}
173 	RETURN (error);
174 }
175 
176 /*
177  * Unmount system call.
178  *
179  * Note: unmount takes a path to the vnode mounted on as argument,
180  * not special file (as before).
181  */
182 unmount(scp)
183 	register struct syscontext *scp;
184 {
185 	struct a {
186 		char	*pathp;
187 		int	flags;
188 	} *uap = (struct a *)scp->sc_ap;
189 	register struct vnode *vp;
190 	register struct nameidata *ndp = &scp->sc_nd;
191 	struct mount *mp;
192 	int error;
193 
194 	/*
195 	 * Must be super user
196 	 */
197 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
198 		RETURN (error);
199 
200 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
201 	ndp->ni_segflg = UIO_USERSPACE;
202 	ndp->ni_dirp = uap->pathp;
203 	if (error = namei(ndp))
204 		RETURN (error);
205 	vp = ndp->ni_vp;
206 	/*
207 	 * Must be the root of the filesystem
208 	 */
209 	if ((vp->v_flag & VROOT) == 0) {
210 		vput(vp);
211 		RETURN (EINVAL);
212 	}
213 	mp = vp->v_mount;
214 	vput(vp);
215 	RETURN (dounmount(mp, uap->flags));
216 }
217 
218 /*
219  * Do an unmount.
220  */
221 dounmount(mp, flags)
222 	register struct mount *mp;
223 	int flags;
224 {
225 	struct vnode *coveredvp;
226 	int error;
227 
228 	coveredvp = mp->m_vnodecovered;
229 	if (error = vfs_lock(mp))
230 		return (error);
231 
232 	xumount(mp);		/* remove unused sticky files from text table */
233 	cache_purgevfs(mp);	/* remove cache entries for this file sys */
234 	VFS_SYNC(mp, MNT_WAIT);
235 
236 	error = VFS_UNMOUNT(mp, flags);
237 	if (error) {
238 		vfs_unlock(mp);
239 	} else {
240 		vrele(coveredvp);
241 		vfs_remove(mp);
242 		free((caddr_t)mp, M_MOUNT);
243 	}
244 	return (error);
245 }
246 
247 /*
248  * Sync system call.
249  * Sync each mounted filesystem.
250  */
251 /* ARGSUSED */
252 sync(scp)
253 	struct syscontext *scp;
254 {
255 	register struct mount *mp;
256 
257 	mp = rootfs;
258 	do {
259 		if ((mp->m_flag & M_RDONLY) == 0)
260 			VFS_SYNC(mp, MNT_NOWAIT);
261 		mp = mp->m_next;
262 	} while (mp != rootfs);
263 }
264 
265 /*
266  * get filesystem statistics
267  */
268 statfs(scp)
269 	register struct syscontext *scp;
270 {
271 	struct a {
272 		char *path;
273 		struct statfs *buf;
274 	} *uap = (struct a *)scp->sc_ap;
275 	register struct mount *mp;
276 	register struct nameidata *ndp = &scp->sc_nd;
277 	struct statfs sb;
278 	int error;
279 
280 	ndp->ni_nameiop = LOOKUP | FOLLOW;
281 	ndp->ni_segflg = UIO_USERSPACE;
282 	ndp->ni_dirp = uap->path;
283 	if (error = namei(ndp))
284 		RETURN (error);
285 	mp = ndp->ni_vp->v_mount;
286 	vrele(ndp->ni_vp);
287 	if (error = VFS_STATFS(mp, &sb))
288 		RETURN (error);
289 	sb.f_flags = mp->m_flag & M_VISFLAGMASK;
290 	sb.f_fsid = mp->m_fsid;
291 	RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)));
292 }
293 
294 fstatfs(scp)
295 	register struct syscontext *scp;
296 {
297 	struct a {
298 		int fd;
299 		struct statfs *buf;
300 	} *uap = (struct a *)scp->sc_ap;
301 	struct file *fp;
302 	struct mount *mp;
303 	struct statfs sb;
304 	int error;
305 
306 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
307 		RETURN (error);
308 	mp = ((struct vnode *)fp->f_data)->v_mount;
309 	if (error = VFS_STATFS(mp, &sb))
310 		RETURN (error);
311 	sb.f_flags = mp->m_flag & M_VISFLAGMASK;
312 	sb.f_fsid = mp->m_fsid;
313 	RETURN (copyout((caddr_t)&sb, (caddr_t)uap->buf, sizeof(sb)));
314 }
315 
316 /*
317  * get statistics on all filesystems
318  */
319 getfsstat(scp)
320 	register struct syscontext *scp;
321 {
322 	struct a {
323 		struct statfs *buf;
324 		long bufsize;
325 	} *uap = (struct a *)scp->sc_ap;
326 	register struct mount *mp;
327 	caddr_t sfsp;
328 	long count, maxcount, error;
329 	struct statfs sb;
330 
331 	maxcount = uap->bufsize / sizeof(struct statfs);
332 	sfsp = (caddr_t)uap->buf;
333 	mp = rootfs;
334 	count = 0;
335 	do {
336 		if (sfsp && count < maxcount && ((mp->m_flag & M_MLOCK) == 0)) {
337 			if (error = VFS_STATFS(mp, &sb)) {
338 				mp = mp->m_prev;
339 				continue;
340 			}
341 			sb.f_flags = mp->m_flag & M_VISFLAGMASK;
342 			sb.f_fsid = mp->m_fsid;
343 			if (error = copyout((caddr_t)&sb, sfsp, sizeof(sb)))
344 				RETURN (error);
345 			sfsp += sizeof(sb);
346 		}
347 		count++;
348 		mp = mp->m_prev;
349 	} while (mp != rootfs);
350 	if (sfsp && count > maxcount)
351 		scp->sc_retval1 = maxcount;
352 	else
353 		scp->sc_retval1 = count;
354 	RETURN (0);
355 }
356 
357 /*
358  * Change current working directory to a given file descriptor.
359  */
360 fchdir(scp)
361 	register struct syscontext *scp;
362 {
363 	struct a {
364 		int	fd;
365 	} *uap = (struct a *)scp->sc_ap;
366 	register struct vnode *vp;
367 	struct file *fp;
368 	int error;
369 
370 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
371 		RETURN (error);
372 	vp = (struct vnode *)fp->f_data;
373 	VOP_LOCK(vp);
374 	if (vp->v_type != VDIR)
375 		error = ENOTDIR;
376 	else
377 		error = VOP_ACCESS(vp, VEXEC, scp->sc_cred);
378 	VOP_UNLOCK(vp);
379 	vrele(scp->sc_cdir);
380 	scp->sc_cdir = vp;
381 	RETURN (error);
382 }
383 
384 /*
385  * Change current working directory (``.'').
386  */
387 chdir(scp)
388 	register struct syscontext *scp;
389 {
390 	struct a {
391 		char	*fname;
392 	} *uap = (struct a *)scp->sc_ap;
393 	register struct nameidata *ndp = &scp->sc_nd;
394 	int error;
395 
396 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
397 	ndp->ni_segflg = UIO_USERSPACE;
398 	ndp->ni_dirp = uap->fname;
399 	if (error = chdirec(ndp))
400 		RETURN (error);
401 	vrele(scp->sc_cdir);
402 	scp->sc_cdir = ndp->ni_vp;
403 	RETURN (0);
404 }
405 
406 /*
407  * Change notion of root (``/'') directory.
408  */
409 chroot(scp)
410 	register struct syscontext *scp;
411 {
412 	struct a {
413 		char	*fname;
414 	} *uap = (struct a *)scp->sc_ap;
415 	register struct nameidata *ndp = &scp->sc_nd;
416 	int error;
417 
418 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
419 		RETURN (error);
420 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
421 	ndp->ni_segflg = UIO_USERSPACE;
422 	ndp->ni_dirp = uap->fname;
423 	if (error = chdirec(ndp))
424 		RETURN (error);
425 	if (scp->sc_rdir != NULL)
426 		vrele(scp->sc_rdir);
427 	scp->sc_rdir = ndp->ni_vp;
428 	RETURN (0);
429 }
430 
431 /*
432  * Common routine for chroot and chdir.
433  */
434 chdirec(ndp)
435 	register struct nameidata *ndp;
436 {
437 	struct vnode *vp;
438 	int error;
439 
440 	if (error = namei(ndp))
441 		return (error);
442 	vp = ndp->ni_vp;
443 	if (vp->v_type != VDIR)
444 		error = ENOTDIR;
445 	else
446 		error = VOP_ACCESS(vp, VEXEC, ndp->ni_cred);
447 	VOP_UNLOCK(vp);
448 	if (error)
449 		vrele(vp);
450 	return (error);
451 }
452 
453 /*
454  * Open system call.
455  */
456 open(scp)
457 	register struct syscontext *scp;
458 {
459 	struct a {
460 		char	*fname;
461 		int	mode;
462 		int	crtmode;
463 	} *uap = (struct a *) scp->sc_ap;
464 	struct nameidata *ndp = &scp->sc_nd;
465 
466 	ndp->ni_segflg = UIO_USERSPACE;
467 	ndp->ni_dirp = uap->fname;
468 	RETURN (copen(scp, uap->mode-FOPEN, uap->crtmode &~ scp->sc_cmask, ndp,
469 		&scp->sc_retval1));
470 }
471 
472 /*
473  * Creat system call.
474  */
475 creat(scp)
476 	register struct syscontext *scp;
477 {
478 	struct a {
479 		char	*fname;
480 		int	fmode;
481 	} *uap = (struct a *)scp->sc_ap;
482 	struct nameidata *ndp = &scp->sc_nd;
483 
484 	ndp->ni_segflg = UIO_USERSPACE;
485 	ndp->ni_dirp = uap->fname;
486 	RETURN (copen(scp, FWRITE|FCREAT|FTRUNC, uap->fmode &~ scp->sc_cmask,
487 		ndp, &scp->sc_retval1));
488 }
489 
490 /*
491  * Common code for open and creat.
492  * Check permissions, allocate an open file structure,
493  * and call the device open routine if any.
494  */
495 copen(scp, fmode, cmode, ndp, resultfd)
496 	register struct syscontext *scp;
497 	int fmode, cmode;
498 	struct nameidata *ndp;
499 	int *resultfd;
500 {
501 	register struct file *fp;
502 	struct file *nfp;
503 	int indx, error;
504 	extern struct fileops vnops;
505 
506 	if (error = falloc(&nfp, &indx))
507 		return (error);
508 	fp = nfp;
509 	scp->sc_retval1 = indx;	/* XXX for fdopen() */
510 	if (error = vn_open(ndp, fmode, (cmode & 07777) &~ ISVTX)) {
511 		crfree(fp->f_cred);
512 		fp->f_count--;
513 		if (error == -1)	/* XXX from fdopen */
514 			return (0);	/* XXX from fdopen */
515 		scp->sc_ofile[indx] = NULL;
516 		return (error);
517 	}
518 	fp->f_flag = fmode & FMASK;
519 	fp->f_type = DTYPE_VNODE;
520 	fp->f_ops = &vnops;
521 	fp->f_data = (caddr_t)ndp->ni_vp;
522 	if (resultfd)
523 		*resultfd = indx;
524 	return (0);
525 }
526 
527 /*
528  * Mknod system call
529  */
530 mknod(scp)
531 	register struct syscontext *scp;
532 {
533 	register struct a {
534 		char	*fname;
535 		int	fmode;
536 		int	dev;
537 	} *uap = (struct a *)scp->sc_ap;
538 	register struct nameidata *ndp = &scp->sc_nd;
539 	register struct vnode *vp;
540 	struct vattr vattr;
541 	int error;
542 
543 	if (error = suser(scp->sc_cred, &scp->sc_acflag))
544 		RETURN (error);
545 	ndp->ni_nameiop = CREATE | LOCKPARENT;
546 	ndp->ni_segflg = UIO_USERSPACE;
547 	ndp->ni_dirp = uap->fname;
548 	if (error = namei(ndp))
549 		RETURN (error);
550 	vp = ndp->ni_vp;
551 	if (vp != NULL) {
552 		error = EEXIST;
553 		goto out;
554 	}
555 	vattr_null(&vattr);
556 	switch (uap->fmode & IFMT) {
557 
558 	case IFMT:	/* used by badsect to flag bad sectors */
559 		vattr.va_type = VBAD;
560 		break;
561 	case IFCHR:
562 		vattr.va_type = VCHR;
563 		break;
564 	case IFBLK:
565 		vattr.va_type = VBLK;
566 		break;
567 	default:
568 		error = EINVAL;
569 		goto out;
570 	}
571 	vattr.va_mode = (uap->fmode & 07777) &~ scp->sc_cmask;
572 	vattr.va_rdev = uap->dev;
573 out:
574 	if (error)
575 		VOP_ABORTOP(ndp);
576 	else
577 		error = VOP_MKNOD(ndp, &vattr, ndp->ni_cred);
578 	RETURN (error);
579 }
580 
581 /*
582  * link system call
583  */
584 link(scp)
585 	register struct syscontext *scp;
586 {
587 	register struct a {
588 		char	*target;
589 		char	*linkname;
590 	} *uap = (struct a *)scp->sc_ap;
591 	register struct nameidata *ndp = &scp->sc_nd;
592 	register struct vnode *vp, *xp;
593 	int error;
594 
595 	ndp->ni_nameiop = LOOKUP | FOLLOW;
596 	ndp->ni_segflg = UIO_USERSPACE;
597 	ndp->ni_dirp = uap->target;
598 	if (error = namei(ndp))
599 		RETURN (error);
600 	vp = ndp->ni_vp;
601 	if (vp->v_type == VDIR &&
602 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
603 		goto out1;
604 	ndp->ni_nameiop = CREATE | LOCKPARENT;
605 	ndp->ni_dirp = (caddr_t)uap->linkname;
606 	if (error = namei(ndp))
607 		goto out1;
608 	xp = ndp->ni_vp;
609 	if (xp != NULL) {
610 		error = EEXIST;
611 		goto out;
612 	}
613 	xp = ndp->ni_dvp;
614 	if (vp->v_mount != xp->v_mount)
615 		error = EXDEV;
616 out:
617 	if (error)
618 		VOP_ABORTOP(ndp);
619 	else
620 		error = VOP_LINK(vp, ndp);
621 out1:
622 	vrele(vp);
623 	RETURN (error);
624 }
625 
626 /*
627  * symlink -- make a symbolic link
628  */
629 symlink(scp)
630 	register struct syscontext *scp;
631 {
632 	struct a {
633 		char	*target;
634 		char	*linkname;
635 	} *uap = (struct a *)scp->sc_ap;
636 	register struct nameidata *ndp = &scp->sc_nd;
637 	register struct vnode *vp;
638 	struct vattr vattr;
639 	char *target;
640 	int error;
641 
642 	ndp->ni_segflg = UIO_USERSPACE;
643 	ndp->ni_dirp = uap->linkname;
644 	MALLOC(target, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
645 	if (error = copyinstr(uap->target, target, MAXPATHLEN, (u_int *)0))
646 		goto out1;
647 	ndp->ni_nameiop = CREATE | LOCKPARENT;
648 	if (error = namei(ndp))
649 		goto out1;
650 	vp = ndp->ni_vp;
651 	if (vp) {
652 		error = EEXIST;
653 		goto out;
654 	}
655 	vp = ndp->ni_dvp;
656 	vattr_null(&vattr);
657 	vattr.va_mode = 0777 &~ scp->sc_cmask;
658 out:
659 	if (error)
660 		VOP_ABORTOP(ndp);
661 	else
662 		error = VOP_SYMLINK(ndp, &vattr, target);
663 out1:
664 	FREE(target, M_NAMEI);
665 	RETURN (error);
666 }
667 
668 /*
669  * Unlink system call.
670  * Hard to avoid races here, especially
671  * in unlinking directories.
672  */
673 unlink(scp)
674 	register struct syscontext *scp;
675 {
676 	struct a {
677 		char	*fname;
678 	} *uap = (struct a *)scp->sc_ap;
679 	register struct nameidata *ndp = &scp->sc_nd;
680 	register struct vnode *vp;
681 	int error;
682 
683 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
684 	ndp->ni_segflg = UIO_USERSPACE;
685 	ndp->ni_dirp = uap->fname;
686 	if (error = namei(ndp))
687 		RETURN (error);
688 	vp = ndp->ni_vp;
689 	if (vp->v_type == VDIR &&
690 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
691 		goto out;
692 	/*
693 	 * Don't unlink a mounted file.
694 	 */
695 	if (vp->v_flag & VROOT) {
696 		error = EBUSY;
697 		goto out;
698 	}
699 	if (vp->v_flag & VTEXT)
700 		xrele(vp);	/* try once to free text */
701 out:
702 	if (error)
703 		VOP_ABORTOP(ndp);
704 	else
705 		error = VOP_REMOVE(ndp);
706 	RETURN (error);
707 }
708 
709 /*
710  * Seek system call
711  */
712 lseek(scp)
713 	register struct syscontext *scp;
714 {
715 	register struct file *fp;
716 	register struct a {
717 		int	fdes;
718 		off_t	off;
719 		int	sbase;
720 	} *uap = (struct a *)scp->sc_ap;
721 	struct vattr vattr;
722 	int error;
723 
724 	if ((unsigned)uap->fdes >= NOFILE ||
725 	    (fp = scp->sc_ofile[uap->fdes]) == NULL)
726 		RETURN (EBADF);
727 	if (fp->f_type != DTYPE_VNODE)
728 		RETURN (ESPIPE);
729 	switch (uap->sbase) {
730 
731 	case L_INCR:
732 		fp->f_offset += uap->off;
733 		break;
734 
735 	case L_XTND:
736 		if (error = VOP_GETATTR((struct vnode *)fp->f_data,
737 		    &vattr, scp->sc_cred))
738 			RETURN (error);
739 		fp->f_offset = uap->off + vattr.va_size;
740 		break;
741 
742 	case L_SET:
743 		fp->f_offset = uap->off;
744 		break;
745 
746 	default:
747 		RETURN (EINVAL);
748 	}
749 	scp->sc_offset = fp->f_offset;
750 	RETURN (0);
751 }
752 
753 /*
754  * Access system call
755  */
756 saccess(scp)
757 	register struct syscontext *scp;
758 {
759 	register struct a {
760 		char	*fname;
761 		int	fmode;
762 	} *uap = (struct a *)scp->sc_ap;
763 	register struct nameidata *ndp = &scp->sc_nd;
764 	register struct vnode *vp;
765 	int error, mode, svuid, svgid;
766 
767 	svuid = scp->sc_uid;
768 	svgid = scp->sc_gid;
769 	scp->sc_uid = scp->sc_ruid;
770 	scp->sc_gid = scp->sc_rgid;
771 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
772 	ndp->ni_segflg = UIO_USERSPACE;
773 	ndp->ni_dirp = uap->fname;
774 	if (error = namei(ndp))
775 		goto out1;
776 	vp = ndp->ni_vp;
777 	/*
778 	 * fmode == 0 means only check for exist
779 	 */
780 	if (uap->fmode) {
781 		mode = 0;
782 		if (uap->fmode & R_OK)
783 			mode |= VREAD;
784 		if (uap->fmode & W_OK)
785 			mode |= VWRITE;
786 		if (uap->fmode & X_OK)
787 			mode |= VEXEC;
788 		if ((mode & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
789 			error = VOP_ACCESS(vp, mode, ndp->ni_cred);
790 	}
791 	vput(vp);
792 out1:
793 	scp->sc_uid = svuid;
794 	scp->sc_gid = svgid;
795 	RETURN (error);
796 }
797 
798 /*
799  * Stat system call.  This version follows links.
800  */
801 stat(scp)
802 	struct syscontext *scp;
803 {
804 
805 	stat1(scp, FOLLOW);
806 }
807 
808 /*
809  * Lstat system call.  This version does not follow links.
810  */
811 lstat(scp)
812 	struct syscontext *scp;
813 {
814 
815 	stat1(scp, NOFOLLOW);
816 }
817 
818 stat1(scp, follow)
819 	register struct syscontext *scp;
820 	int follow;
821 {
822 	register struct a {
823 		char	*fname;
824 		struct stat *ub;
825 	} *uap = (struct a *)scp->sc_ap;
826 	register struct nameidata *ndp = &scp->sc_nd;
827 	struct stat sb;
828 	int error;
829 
830 	ndp->ni_nameiop = LOOKUP | LOCKLEAF | follow;
831 	ndp->ni_segflg = UIO_USERSPACE;
832 	ndp->ni_dirp = uap->fname;
833 	if (error = namei(ndp))
834 		RETURN (error);
835 	error = vn_stat(ndp->ni_vp, &sb);
836 	vput(ndp->ni_vp);
837 	if (error)
838 		RETURN (error);
839 	error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
840 	RETURN (error);
841 }
842 
843 /*
844  * Return target name of a symbolic link
845  */
846 readlink(scp)
847 	register struct syscontext *scp;
848 {
849 	register struct a {
850 		char	*name;
851 		char	*buf;
852 		int	count;
853 	} *uap = (struct a *)scp->sc_ap;
854 	register struct nameidata *ndp = &scp->sc_nd;
855 	register struct vnode *vp;
856 	struct iovec aiov;
857 	struct uio auio;
858 	int error;
859 
860 	ndp->ni_nameiop = LOOKUP | LOCKLEAF;
861 	ndp->ni_segflg = UIO_USERSPACE;
862 	ndp->ni_dirp = uap->name;
863 	if (error = namei(ndp))
864 		RETURN (error);
865 	vp = ndp->ni_vp;
866 	if (vp->v_type != VLNK) {
867 		error = EINVAL;
868 		goto out;
869 	}
870 	aiov.iov_base = uap->buf;
871 	aiov.iov_len = uap->count;
872 	auio.uio_iov = &aiov;
873 	auio.uio_iovcnt = 1;
874 	auio.uio_offset = 0;
875 	auio.uio_rw = UIO_READ;
876 	auio.uio_segflg = UIO_USERSPACE;
877 	auio.uio_resid = uap->count;
878 	error = VOP_READLINK(vp, &auio, ndp->ni_cred);
879 out:
880 	vput(vp);
881 	scp->sc_retval1 = uap->count - auio.uio_resid;
882 	RETURN (error);
883 }
884 
885 /*
886  * Change flags of a file given path name.
887  */
888 chflags(scp)
889 	register struct syscontext *scp;
890 {
891 	struct a {
892 		char	*fname;
893 		int	flags;
894 	} *uap = (struct a *)scp->sc_ap;
895 	register struct nameidata *ndp = &scp->sc_nd;
896 	register struct vnode *vp;
897 	struct vattr vattr;
898 	int error;
899 
900 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
901 	ndp->ni_segflg = UIO_USERSPACE;
902 	ndp->ni_dirp = uap->fname;
903 	vattr_null(&vattr);
904 	vattr.va_flags = uap->flags;
905 	if (error = namei(ndp))
906 		RETURN (error);
907 	vp = ndp->ni_vp;
908 	if (vp->v_mount->m_flag & M_RDONLY) {
909 		error = EROFS;
910 		goto out;
911 	}
912 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
913 out:
914 	vput(vp);
915 	RETURN (error);
916 }
917 
918 /*
919  * Change flags of a file given a file descriptor.
920  */
921 fchflags(scp)
922 	register struct syscontext *scp;
923 {
924 	struct a {
925 		int	fd;
926 		int	flags;
927 	} *uap = (struct a *)scp->sc_ap;
928 	struct vattr vattr;
929 	struct vnode *vp;
930 	struct file *fp;
931 	int error;
932 
933 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
934 		RETURN (error);
935 	vattr_null(&vattr);
936 	vattr.va_flags = uap->flags;
937 	vp = (struct vnode *)fp->f_data;
938 	VOP_LOCK(vp);
939 	if (vp->v_mount->m_flag & M_RDONLY) {
940 		error = EROFS;
941 		goto out;
942 	}
943 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
944 out:
945 	VOP_UNLOCK(vp);
946 	RETURN (error);
947 }
948 
949 /*
950  * Change mode of a file given path name.
951  */
952 chmod(scp)
953 	register struct syscontext *scp;
954 {
955 	struct a {
956 		char	*fname;
957 		int	fmode;
958 	} *uap = (struct a *)scp->sc_ap;
959 	register struct nameidata *ndp = &scp->sc_nd;
960 	register struct vnode *vp;
961 	struct vattr vattr;
962 	int error;
963 
964 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
965 	ndp->ni_segflg = UIO_USERSPACE;
966 	ndp->ni_dirp = uap->fname;
967 	vattr_null(&vattr);
968 	vattr.va_mode = uap->fmode & 07777;
969 	if (error = namei(ndp))
970 		RETURN (error);
971 	vp = ndp->ni_vp;
972 	if (vp->v_mount->m_flag & M_RDONLY) {
973 		error = EROFS;
974 		goto out;
975 	}
976 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
977 out:
978 	vput(vp);
979 	RETURN (error);
980 }
981 
982 /*
983  * Change mode of a file given a file descriptor.
984  */
985 fchmod(scp)
986 	register struct syscontext *scp;
987 {
988 	struct a {
989 		int	fd;
990 		int	fmode;
991 	} *uap = (struct a *)scp->sc_ap;
992 	struct vattr vattr;
993 	struct vnode *vp;
994 	struct file *fp;
995 	int error;
996 
997 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
998 		RETURN (error);
999 	vattr_null(&vattr);
1000 	vattr.va_mode = uap->fmode & 07777;
1001 	vp = (struct vnode *)fp->f_data;
1002 	VOP_LOCK(vp);
1003 	if (vp->v_mount->m_flag & M_RDONLY) {
1004 		error = EROFS;
1005 		goto out;
1006 	}
1007 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
1008 out:
1009 	VOP_UNLOCK(vp);
1010 	RETURN (error);
1011 }
1012 
1013 /*
1014  * Set ownership given a path name.
1015  */
1016 chown(scp)
1017 	register struct syscontext *scp;
1018 {
1019 	struct a {
1020 		char	*fname;
1021 		int	uid;
1022 		int	gid;
1023 	} *uap = (struct a *)scp->sc_ap;
1024 	register struct nameidata *ndp = &scp->sc_nd;
1025 	register struct vnode *vp;
1026 	struct vattr vattr;
1027 	int error;
1028 
1029 	ndp->ni_nameiop = LOOKUP | NOFOLLOW | LOCKLEAF;
1030 	ndp->ni_segflg = UIO_USERSPACE;
1031 	ndp->ni_dirp = uap->fname;
1032 	vattr_null(&vattr);
1033 	vattr.va_uid = uap->uid;
1034 	vattr.va_gid = uap->gid;
1035 	if (error = namei(ndp))
1036 		RETURN (error);
1037 	vp = ndp->ni_vp;
1038 	if (vp->v_mount->m_flag & M_RDONLY) {
1039 		error = EROFS;
1040 		goto out;
1041 	}
1042 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
1043 out:
1044 	vput(vp);
1045 	RETURN (error);
1046 }
1047 
1048 /*
1049  * Set ownership given a file descriptor.
1050  */
1051 fchown(scp)
1052 	register struct syscontext *scp;
1053 {
1054 	struct a {
1055 		int	fd;
1056 		int	uid;
1057 		int	gid;
1058 	} *uap = (struct a *)scp->sc_ap;
1059 	struct vattr vattr;
1060 	struct vnode *vp;
1061 	struct file *fp;
1062 	int error;
1063 
1064 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
1065 		RETURN (error);
1066 	vattr_null(&vattr);
1067 	vattr.va_uid = uap->uid;
1068 	vattr.va_gid = uap->gid;
1069 	vp = (struct vnode *)fp->f_data;
1070 	VOP_LOCK(vp);
1071 	if (vp->v_mount->m_flag & M_RDONLY) {
1072 		error = EROFS;
1073 		goto out;
1074 	}
1075 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
1076 out:
1077 	VOP_UNLOCK(vp);
1078 	RETURN (error);
1079 }
1080 
1081 utimes(scp)
1082 	register struct syscontext *scp;
1083 {
1084 	register struct a {
1085 		char	*fname;
1086 		struct	timeval *tptr;
1087 	} *uap = (struct a *)scp->sc_ap;
1088 	register struct nameidata *ndp = &scp->sc_nd;
1089 	register struct vnode *vp;
1090 	struct timeval tv[2];
1091 	struct vattr vattr;
1092 	int error;
1093 
1094 	if (error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv)))
1095 		RETURN (error);
1096 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
1097 	ndp->ni_segflg = UIO_USERSPACE;
1098 	ndp->ni_dirp = uap->fname;
1099 	vattr_null(&vattr);
1100 	vattr.va_atime = tv[0];
1101 	vattr.va_mtime = tv[1];
1102 	if (error = namei(ndp))
1103 		RETURN (error);
1104 	vp = ndp->ni_vp;
1105 	if (vp->v_mount->m_flag & M_RDONLY) {
1106 		error = EROFS;
1107 		goto out;
1108 	}
1109 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
1110 out:
1111 	vput(vp);
1112 	RETURN (error);
1113 }
1114 
1115 /*
1116  * Truncate a file given its path name.
1117  */
1118 truncate(scp)
1119 	register struct syscontext *scp;
1120 {
1121 	struct a {
1122 		char	*fname;
1123 		off_t	length;
1124 	} *uap = (struct a *)scp->sc_ap;
1125 	register struct nameidata *ndp = &scp->sc_nd;
1126 	register struct vnode *vp;
1127 	struct vattr vattr;
1128 	int error;
1129 
1130 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
1131 	ndp->ni_segflg = UIO_USERSPACE;
1132 	ndp->ni_dirp = uap->fname;
1133 	vattr_null(&vattr);
1134 	vattr.va_size = uap->length;
1135 	if (error = namei(ndp))
1136 		RETURN (error);
1137 	vp = ndp->ni_vp;
1138 	if (vp->v_type == VDIR) {
1139 		error = EISDIR;
1140 		goto out;
1141 	}
1142 	if ((error = vn_writechk(vp)) ||
1143 	    (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)))
1144 		goto out;
1145 	error = VOP_SETATTR(vp, &vattr, ndp->ni_cred);
1146 out:
1147 	vput(vp);
1148 	RETURN (error);
1149 }
1150 
1151 /*
1152  * Truncate a file given a file descriptor.
1153  */
1154 ftruncate(scp)
1155 	register struct syscontext *scp;
1156 {
1157 	struct a {
1158 		int	fd;
1159 		off_t	length;
1160 	} *uap = (struct a *)scp->sc_ap;
1161 	struct vattr vattr;
1162 	struct vnode *vp;
1163 	struct file *fp;
1164 	int error;
1165 
1166 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
1167 		RETURN (error);
1168 	if ((fp->f_flag & FWRITE) == 0)
1169 		RETURN (EINVAL);
1170 	vattr_null(&vattr);
1171 	vattr.va_size = uap->length;
1172 	vp = (struct vnode *)fp->f_data;
1173 	VOP_LOCK(vp);
1174 	if (vp->v_type == VDIR) {
1175 		error = EISDIR;
1176 		goto out;
1177 	}
1178 	if (error = vn_writechk(vp))
1179 		goto out;
1180 	error = VOP_SETATTR(vp, &vattr, fp->f_cred);
1181 out:
1182 	VOP_UNLOCK(vp);
1183 	RETURN (error);
1184 }
1185 
1186 /*
1187  * Synch an open file.
1188  */
1189 fsync(scp)
1190 	register struct syscontext *scp;
1191 {
1192 	struct a {
1193 		int	fd;
1194 	} *uap = (struct a *)scp->sc_ap;
1195 	register struct vnode *vp;
1196 	struct file *fp;
1197 	int error;
1198 
1199 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
1200 		RETURN (error);
1201 	vp = (struct vnode *)fp->f_data;
1202 	VOP_LOCK(vp);
1203 	error = VOP_FSYNC(vp, fp->f_flag, fp->f_cred, MNT_WAIT);
1204 	VOP_UNLOCK(vp);
1205 	RETURN (error);
1206 }
1207 
1208 /*
1209  * Rename system call.
1210  *
1211  * Source and destination must either both be directories, or both
1212  * not be directories.  If target is a directory, it must be empty.
1213  */
1214 rename(scp)
1215 	register struct syscontext *scp;
1216 {
1217 	struct a {
1218 		char	*from;
1219 		char	*to;
1220 	} *uap = (struct a *)scp->sc_ap;
1221 	register struct vnode *tvp, *fvp, *tdvp;
1222 	register struct nameidata *ndp = &scp->sc_nd;
1223 	struct nameidata tond;
1224 	int error;
1225 
1226 	ndp->ni_nameiop = DELETE | WANTPARENT;
1227 	ndp->ni_segflg = UIO_USERSPACE;
1228 	ndp->ni_dirp = uap->from;
1229 	if (error = namei(ndp))
1230 		RETURN (error);
1231 	fvp = ndp->ni_vp;
1232 	nddup(ndp, &tond);
1233 	tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
1234 	tond.ni_segflg = UIO_USERSPACE;
1235 	tond.ni_dirp = uap->to;
1236 	error = namei(&tond);
1237 	tdvp = tond.ni_dvp;
1238 	tvp = tond.ni_vp;
1239 	if (tvp != NULL) {
1240 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
1241 			error = ENOTDIR;
1242 			goto out;
1243 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
1244 			error = EISDIR;
1245 			goto out;
1246 		}
1247 	}
1248 	if (error) {
1249 		VOP_ABORTOP(ndp);
1250 		goto out1;
1251 	}
1252 	if (fvp->v_mount != tdvp->v_mount) {
1253 		error = EXDEV;
1254 		goto out;
1255 	}
1256 	if (fvp == tdvp)
1257 		error = EINVAL;
1258 	/*
1259 	 * If source is the same as the destination,
1260 	 * then there is nothing to do.
1261 	 */
1262 	if (fvp == tvp)
1263 		error = -1;
1264 out:
1265 	if (error) {
1266 		VOP_ABORTOP(&tond);
1267 		VOP_ABORTOP(ndp);
1268 	} else {
1269 		error = VOP_RENAME(ndp, &tond);
1270 	}
1271 out1:
1272 	ndrele(&tond);
1273 	if (error == -1)
1274 		RETURN (0);
1275 	RETURN (error);
1276 }
1277 
1278 /*
1279  * Mkdir system call
1280  */
1281 mkdir(scp)
1282 	register struct syscontext *scp;
1283 {
1284 	struct a {
1285 		char	*name;
1286 		int	dmode;
1287 	} *uap = (struct a *)scp->sc_ap;
1288 	register struct nameidata *ndp = &scp->sc_nd;
1289 	register struct vnode *vp;
1290 	struct vattr vattr;
1291 	int error;
1292 
1293 	ndp->ni_nameiop = CREATE | LOCKPARENT;
1294 	ndp->ni_segflg = UIO_USERSPACE;
1295 	ndp->ni_dirp = uap->name;
1296 	if (error = namei(ndp))
1297 		RETURN (error);
1298 	vp = ndp->ni_vp;
1299 	if (vp != NULL) {
1300 		VOP_ABORTOP(ndp);
1301 		RETURN (EEXIST);
1302 	}
1303 	vattr_null(&vattr);
1304 	vattr.va_type = VDIR;
1305 	vattr.va_mode = (uap->dmode & 0777) &~ scp->sc_cmask;
1306 	error = VOP_MKDIR(ndp, &vattr);
1307 	if (!error)
1308 		vput(ndp->ni_vp);
1309 	RETURN (error);
1310 }
1311 
1312 /*
1313  * Rmdir system call.
1314  */
1315 rmdir(scp)
1316 	register struct syscontext *scp;
1317 {
1318 	struct a {
1319 		char	*name;
1320 	} *uap = (struct a *)scp->sc_ap;
1321 	register struct nameidata *ndp = &scp->sc_nd;
1322 	register struct vnode *vp;
1323 	int error;
1324 
1325 	ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
1326 	ndp->ni_segflg = UIO_USERSPACE;
1327 	ndp->ni_dirp = uap->name;
1328 	if (error = namei(ndp))
1329 		RETURN (error);
1330 	vp = ndp->ni_vp;
1331 	if (vp->v_type != VDIR) {
1332 		error = ENOTDIR;
1333 		goto out;
1334 	}
1335 	/*
1336 	 * No rmdir "." please.
1337 	 */
1338 	if (ndp->ni_dvp == vp) {
1339 		error = EINVAL;
1340 		goto out;
1341 	}
1342 	/*
1343 	 * Don't unlink a mounted file.
1344 	 */
1345 	if (vp->v_flag & VROOT)
1346 		error = EBUSY;
1347 out:
1348 	if (error)
1349 		VOP_ABORTOP(ndp);
1350 	else
1351 		error = VOP_RMDIR(ndp);
1352 	RETURN (error);
1353 }
1354 
1355 /*
1356  * Read a block of directory entries in a file system independent format
1357  */
1358 getdirentries(scp)
1359 	register struct syscontext *scp;
1360 {
1361 	register struct a {
1362 		int	fd;
1363 		char	*buf;
1364 		unsigned count;
1365 		long	*basep;
1366 	} *uap = (struct a *)scp->sc_ap;
1367 	register struct vnode *vp;
1368 	struct file *fp;
1369 	struct uio auio;
1370 	struct iovec aiov;
1371 	off_t off;
1372 	int error;
1373 
1374 	if (error = getvnode(scp->sc_ofile, uap->fd, &fp))
1375 		RETURN (error);
1376 	if ((fp->f_flag & FREAD) == 0)
1377 		RETURN (EBADF);
1378 	vp = (struct vnode *)fp->f_data;
1379 	if (vp->v_type != VDIR)
1380 		RETURN (EINVAL);
1381 	aiov.iov_base = uap->buf;
1382 	aiov.iov_len = uap->count;
1383 	auio.uio_iov = &aiov;
1384 	auio.uio_iovcnt = 1;
1385 	auio.uio_rw = UIO_READ;
1386 	auio.uio_segflg = UIO_USERSPACE;
1387 	auio.uio_resid = uap->count;
1388 	VOP_LOCK(vp);
1389 	auio.uio_offset = off = fp->f_offset;
1390 	error = VOP_READDIR(vp, &auio, fp->f_cred);
1391 	fp->f_offset = auio.uio_offset;
1392 	VOP_UNLOCK(vp);
1393 	if (error)
1394 		RETURN (error);
1395 	error = copyout((caddr_t)&off, (caddr_t)uap->basep, sizeof(long));
1396 	scp->sc_retval1 = uap->count - auio.uio_resid;
1397 	RETURN (error);
1398 }
1399 
1400 /*
1401  * mode mask for creation of files
1402  */
1403 umask(scp)
1404 	register struct syscontext *scp;
1405 {
1406 	register struct a {
1407 		int	mask;
1408 	} *uap = (struct a *)scp->sc_ap;
1409 
1410 	scp->sc_retval1 = scp->sc_cmask;
1411 	scp->sc_cmask = uap->mask & 07777;
1412 	RETURN (0);
1413 }
1414 
1415 /*
1416  * Void all references to file by ripping underlying filesystem
1417  * away from vnode.
1418  */
1419 revoke(scp)
1420 	register struct syscontext *scp;
1421 {
1422 	struct a {
1423 		char	*fname;
1424 	} *uap = (struct a *)scp->sc_ap;
1425 	register struct nameidata *ndp = &scp->sc_nd;
1426 	register struct vnode *vp;
1427 	struct vattr vattr;
1428 	int error;
1429 
1430 	ndp->ni_nameiop = LOOKUP | FOLLOW;
1431 	ndp->ni_segflg = UIO_USERSPACE;
1432 	ndp->ni_dirp = uap->fname;
1433 	if (error = namei(ndp))
1434 		RETURN (error);
1435 	vp = ndp->ni_vp;
1436 	if (vp->v_type != VCHR && vp->v_type != VBLK) {
1437 		error = EINVAL;
1438 		goto out;
1439 	}
1440 	if (error = VOP_GETATTR(vp, &vattr, scp->sc_cred))
1441 		goto out;
1442 	if (scp->sc_uid != vattr.va_uid ||
1443 	    (error = suser(scp->sc_cred, &scp->sc_acflag)))
1444 		goto out;
1445 	if (vp->v_count > 1 || (vp->v_flag & VALIASED))
1446 		vgoneall(vp);
1447 out:
1448 	vrele(vp);
1449 	RETURN (error);
1450 }
1451 
1452 getvnode(ofile, fdes, fpp)
1453 	struct file *ofile[];
1454 	struct file **fpp;
1455 	int fdes;
1456 {
1457 	struct file *fp;
1458 
1459 	if ((unsigned)fdes >= NOFILE || (fp = ofile[fdes]) == NULL)
1460 		return (EBADF);
1461 	if (fp->f_type != DTYPE_VNODE)
1462 		return (EINVAL);
1463 	*fpp = fp;
1464 	return (0);
1465 }
1466