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