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