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