xref: /original-bsd/sys/miscfs/fdesc/fdesc_vnops.c (revision 609cdd5c)
1 /*
2  * Copyright (c) 1992 The Regents of the University of California
3  * Copyright (c) 1990, 1992, 1993 Jan-Simon Pendry
4  * All rights reserved.
5  *
6  * This code is derived from software donated to Berkeley by
7  * Jan-Simon Pendry.
8  *
9  * %sccs.include.redist.c%
10  *
11  *	@(#)fdesc_vnops.c	7.6 (Berkeley) 04/28/93
12  *
13  * $Id: fdesc_vnops.c,v 1.12 1993/04/06 16:17:17 jsp Exp $
14  */
15 
16 /*
17  * /dev/fd Filesystem
18  */
19 
20 #include <sys/param.h>
21 #include <sys/systm.h>
22 #include <sys/types.h>
23 #include <sys/time.h>
24 #include <sys/proc.h>
25 #include <sys/kernel.h>	/* boottime */
26 #include <sys/resourcevar.h>
27 #include <sys/filedesc.h>
28 #include <sys/vnode.h>
29 #include <sys/malloc.h>
30 #include <sys/file.h>
31 #include <sys/stat.h>
32 #include <sys/mount.h>
33 #include <sys/namei.h>
34 #include <sys/buf.h>
35 #include <sys/dirent.h>
36 #include <miscfs/fdesc/fdesc.h>
37 
38 #define cttyvp(p) ((p)->p_flag&SCTTY ? (p)->p_session->s_ttyvp : NULL)
39 
40 #define FDL_WANT	0x01
41 #define FDL_LOCKED	0x02
42 static int fdescvplock;
43 static struct vnode *fdescvp[FD_MAX];
44 
45 #if (FD_STDIN != FD_STDOUT-1) || (FD_STDOUT != FD_STDERR-1)
46 FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2
47 #endif
48 
49 fdesc_allocvp(ftype, ix, mp, vpp)
50 	fdntype ftype;
51 	int ix;
52 	struct mount *mp;
53 	struct vnode **vpp;
54 {
55 	struct vnode **nvpp = 0;
56 	int error = 0;
57 
58 loop:
59 	/* get stashed copy of the vnode */
60 	if (ix >= 0 && ix < FD_MAX) {
61 		nvpp = &fdescvp[ix];
62 		if (*nvpp) {
63 			if (vget(*nvpp))
64 				goto loop;
65 			VOP_UNLOCK(*nvpp);
66 			*vpp = *nvpp;
67 			return (error);
68 		}
69 	}
70 
71 	/*
72 	 * otherwise lock the array while we call getnewvnode
73 	 * since that can block.
74 	 */
75 	if (fdescvplock & FDL_LOCKED) {
76 		fdescvplock |= FDL_WANT;
77 		sleep((caddr_t) &fdescvplock, PINOD);
78 		goto loop;
79 	}
80 	fdescvplock |= FDL_LOCKED;
81 
82 	error = getnewvnode(VT_UFS, mp, fdesc_vnodeop_p, vpp);
83 	if (error)
84 		goto out;
85 	MALLOC((*vpp)->v_data, void *, sizeof(struct fdescnode), M_TEMP, M_WAITOK);
86 	if (nvpp)
87 		*nvpp = *vpp;
88 	VTOFDESC(*vpp)->fd_type = ftype;
89 	VTOFDESC(*vpp)->fd_fd = -1;
90 	VTOFDESC(*vpp)->fd_link = 0;
91 	VTOFDESC(*vpp)->fd_ix = ix;
92 
93 out:;
94 	fdescvplock &= ~FDL_LOCKED;
95 
96 	if (fdescvplock & FDL_WANT) {
97 		fdescvplock &= ~FDL_WANT;
98 		wakeup((caddr_t) &fdescvplock);
99 	}
100 
101 	return (error);
102 }
103 
104 /*
105  * vp is the current namei directory
106  * ndp is the name to locate in that directory...
107  */
108 fdesc_lookup(ap)
109 	struct vop_lookup_args /* {
110 		struct vnode * a_dvp;
111 		struct vnode ** a_vpp;
112 		struct componentname * a_cnp;
113 	} */ *ap;
114 {
115 	struct vnode **vpp = ap->a_vpp;
116 	struct vnode *dvp = ap->a_dvp;
117 	char *pname;
118 	struct proc *p;
119 	int nfiles;
120 	unsigned fd;
121 	int error;
122 	struct vnode *fvp;
123 	char *ln;
124 
125 #ifdef FDESC_DIAGNOSTIC
126 	printf("fdesc_lookup(%x)\n", ap);
127 	printf("fdesc_lookup(dp = %x, vpp = %x, cnp = %x)\n", dvp, vpp, ap->a_cnp);
128 #endif
129 	pname = ap->a_cnp->cn_nameptr;
130 #ifdef FDESC_DIAGNOSTIC
131 	printf("fdesc_lookup(%s)\n", pname);
132 #endif
133 	if (ap->a_cnp->cn_namelen == 1 && *pname == '.') {
134 		*vpp = dvp;
135 		VREF(dvp);
136 		VOP_LOCK(dvp);
137 		return (0);
138 	}
139 
140 	p = ap->a_cnp->cn_proc;
141 	nfiles = p->p_fd->fd_nfiles;
142 
143 	switch (VTOFDESC(dvp)->fd_type) {
144 	default:
145 	case Flink:
146 	case Fdesc:
147 	case Fctty:
148 		error = ENOTDIR;
149 		goto bad;
150 
151 	case Froot:
152 		if (ap->a_cnp->cn_namelen == 2 && bcmp(pname, "fd", 2) == 0) {
153 			error = fdesc_allocvp(Fdevfd, FD_DEVFD, dvp->v_mount, &fvp);
154 			if (error)
155 				goto bad;
156 			*vpp = fvp;
157 			fvp->v_type = VDIR;
158 			VOP_LOCK(fvp);
159 #ifdef FDESC_DIAGNOSTIC
160 			printf("fdesc_lookup: newvp = %x\n", fvp);
161 #endif
162 			return (0);
163 		}
164 
165 		if (ap->a_cnp->cn_namelen == 3 && bcmp(pname, "tty", 3) == 0) {
166 			struct vnode *ttyvp = cttyvp(p);
167 			if (ttyvp == NULL) {
168 				error = ENXIO;
169 				goto bad;
170 			}
171 			error = fdesc_allocvp(Fctty, FD_CTTY, dvp->v_mount, &fvp);
172 			if (error)
173 				goto bad;
174 			*vpp = fvp;
175 			fvp->v_type = VFIFO;
176 			VOP_LOCK(fvp);
177 #ifdef FDESC_DIAGNOSTIC
178 			printf("fdesc_lookup: ttyvp = %x\n", fvp);
179 #endif
180 			return (0);
181 		}
182 
183 		ln = 0;
184 		switch (ap->a_cnp->cn_namelen) {
185 		case 5:
186 			if (bcmp(pname, "stdin", 5) == 0) {
187 				ln = "fd/0";
188 				fd = FD_STDIN;
189 			}
190 			break;
191 		case 6:
192 			if (bcmp(pname, "stdout", 6) == 0) {
193 				ln = "fd/1";
194 				fd = FD_STDOUT;
195 			} else
196 			if (bcmp(pname, "stderr", 6) == 0) {
197 				ln = "fd/2";
198 				fd = FD_STDERR;
199 			}
200 			break;
201 		}
202 
203 		if (ln) {
204 #ifdef FDESC_DIAGNOSTIC
205 			printf("fdesc_lookup: link -> %s\n", ln);
206 #endif
207 			error = fdesc_allocvp(Flink, fd, dvp->v_mount, &fvp);
208 			if (error)
209 				goto bad;
210 			VTOFDESC(fvp)->fd_link = ln;
211 			*vpp = fvp;
212 			fvp->v_type = VLNK;
213 			VOP_LOCK(fvp);
214 #ifdef FDESC_DIAGNOSTIC
215 			printf("fdesc_lookup: newvp = %x\n", fvp);
216 #endif
217 			return (0);
218 		} else {
219 			error = ENOENT;
220 			goto bad;
221 		}
222 
223 		/* fall through */
224 
225 	case Fdevfd:
226 		if (ap->a_cnp->cn_namelen == 2 && bcmp(pname, "..", 2) == 0) {
227 			error = fdesc_root(dvp->v_mount, vpp);
228 			return (error);
229 		}
230 
231 		fd = 0;
232 		while (*pname >= '0' && *pname <= '9') {
233 			fd = 10 * fd + *pname++ - '0';
234 			if (fd >= nfiles)
235 				break;
236 		}
237 
238 #ifdef FDESC_DIAGNOSTIC
239 		printf("fdesc_lookup: fd = %d, *pname = %x\n", fd, *pname);
240 #endif
241 		if (*pname != '\0') {
242 			error = ENOENT;
243 			goto bad;
244 		}
245 
246 		if (fd >= nfiles || p->p_fd->fd_ofiles[fd] == NULL) {
247 			error = EBADF;
248 			goto bad;
249 		}
250 
251 #ifdef FDESC_DIAGNOSTIC
252 		printf("fdesc_lookup: allocate new vnode\n");
253 #endif
254 		error = fdesc_allocvp(Fdesc, FD_DESC+fd, dvp->v_mount, &fvp);
255 		if (error)
256 			goto bad;
257 		VTOFDESC(fvp)->fd_fd = fd;
258 		*vpp = fvp;
259 #ifdef FDESC_DIAGNOSTIC
260 		printf("fdesc_lookup: newvp = %x\n", fvp);
261 #endif
262 		return (0);
263 	}
264 
265 bad:;
266 	*vpp = NULL;
267 #ifdef FDESC_DIAGNOSTIC
268 	printf("fdesc_lookup: error = %d\n", error);
269 #endif
270 	return (error);
271 }
272 
273 fdesc_open(ap)
274 	struct vop_open_args /* {
275 		struct vnode *a_vp;
276 		int  a_mode;
277 		struct ucred *a_cred;
278 		struct proc *a_p;
279 	} */ *ap;
280 {
281 	struct vnode *vp = ap->a_vp;
282 	int error = 0;
283 
284 	switch (VTOFDESC(vp)->fd_type) {
285 	case Fdesc:
286 		/*
287 		 * XXX Kludge: set p->p_dupfd to contain the value of the
288 		 * the file descriptor being sought for duplication. The error
289 		 * return ensures that the vnode for this device will be
290 		 * released by vn_open. Open will detect this special error and
291 		 * take the actions in dupfdopen.  Other callers of vn_open or
292 		 * VOP_OPEN will simply report the error.
293 		 */
294 		ap->a_p->p_dupfd = VTOFDESC(vp)->fd_fd;	/* XXX */
295 		error = ENODEV;
296 		break;
297 
298 	case Fctty:
299 		error = cttyopen(devctty, ap->a_mode, 0, ap->a_p);
300 		break;
301 	}
302 
303 	return (error);
304 }
305 
306 static int
307 fdesc_attr(fd, vap, cred, p)
308 	int fd;
309 	struct vattr *vap;
310 	struct ucred *cred;
311 	struct proc *p;
312 {
313 	struct filedesc *fdp = p->p_fd;
314 	struct file *fp;
315 	int error;
316 
317 #ifdef FDESC_DIAGNOSTIC
318 	printf("fdesc_attr: fd = %d, nfiles = %d\n", fd, fdp->fd_nfiles);
319 #endif
320 	if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) {
321 #ifdef FDESC_DIAGNOSTIC
322 		printf("fdesc_attr: fp = %x (EBADF)\n", fp);
323 #endif
324 		return (EBADF);
325 	}
326 
327 	/*
328 	 * Can stat the underlying vnode, but not sockets because
329 	 * they don't use struct vattrs.  Well, we could convert from
330 	 * a struct stat back to a struct vattr, later...
331 	 */
332 	switch (fp->f_type) {
333 	case DTYPE_VNODE:
334 		error = VOP_GETATTR((struct vnode *) fp->f_data, vap, cred, p);
335 		break;
336 
337 	case DTYPE_SOCKET:
338 		error = EOPNOTSUPP;
339 		break;
340 
341 	default:
342 		panic("fdesc attr");
343 		break;
344 	}
345 
346 #ifdef FDESC_DIAGNOSTIC
347 	printf("fdesc_attr: returns error %d\n", error);
348 #endif
349 	return (error);
350 }
351 
352 fdesc_getattr(ap)
353 	struct vop_getattr_args /* {
354 		struct vnode *a_vp;
355 		struct vattr *a_vap;
356 		struct ucred *a_cred;
357 		struct proc *a_p;
358 	} */ *ap;
359 {
360 	struct vnode *vp = ap->a_vp;
361 	struct vattr *vap = ap->a_vap;
362 	unsigned fd;
363 	int error;
364 
365 #ifdef FDESC_DIAGNOSTIC
366 	printf("fdesc_getattr: stat type = %d\n", VTOFDESC(vp)->fd_type);
367 #endif
368 
369 	switch (VTOFDESC(vp)->fd_type) {
370 	case Froot:
371 	case Fdevfd:
372 	case Flink:
373 	case Fctty:
374 		bzero((caddr_t) vap, sizeof(*vap));
375 		vattr_null(vap);
376 		vap->va_fileid = VTOFDESC(vp)->fd_ix;
377 
378 		switch (VTOFDESC(vp)->fd_type) {
379 		case Flink:
380 			vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
381 			vap->va_type = VLNK;
382 			vap->va_nlink = 1;
383 			/* vap->va_qsize = strlen(VTOFDESC(vp)->fd_link); */
384 			vap->va_size = strlen(VTOFDESC(vp)->fd_link);
385 			break;
386 
387 		case Fctty:
388 			vap->va_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
389 			vap->va_type = VFIFO;
390 			vap->va_nlink = 1;
391 			/* vap->va_qsize = 0; */
392 			vap->va_size = 0;
393 			break;
394 
395 		default:
396 			vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
397 			vap->va_type = VDIR;
398 			vap->va_nlink = 2;
399 			/* vap->va_qsize = 0; */
400 			vap->va_size = DEV_BSIZE;
401 			break;
402 		}
403 		vap->va_uid = 0;
404 		vap->va_gid = 0;
405 		vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
406 		vap->va_blocksize = DEV_BSIZE;
407 		vap->va_atime.ts_sec = boottime.tv_sec;
408 		vap->va_atime.ts_nsec = 0;
409 		vap->va_mtime = vap->va_atime;
410 		vap->va_ctime = vap->va_ctime;
411 		vap->va_gen = 0;
412 		vap->va_flags = 0;
413 		vap->va_rdev = 0;
414 		/* vap->va_qbytes = 0; */
415 		vap->va_bytes = 0;
416 		break;
417 
418 	case Fdesc:
419 #ifdef FDESC_DIAGNOSTIC
420 		printf("fdesc_getattr: stat desc #%d\n", VTOFDESC(vp)->fd_fd);
421 #endif
422 		fd = VTOFDESC(vp)->fd_fd;
423 		error = fdesc_attr(fd, vap, ap->a_cred, ap->a_p);
424 		break;
425 
426 	default:
427 		panic("fdesc_getattr");
428 		break;
429 	}
430 
431 	if (error == 0)
432 		vp->v_type = vap->va_type;
433 
434 #ifdef FDESC_DIAGNOSTIC
435 	printf("fdesc_getattr: stat returns 0\n");
436 #endif
437 	return (error);
438 }
439 
440 fdesc_setattr(ap)
441 	struct vop_setattr_args /* {
442 		struct vnode *a_vp;
443 		struct vattr *a_vap;
444 		struct ucred *a_cred;
445 		struct proc *a_p;
446 	} */ *ap;
447 {
448 	struct filedesc *fdp = ap->a_p->p_fd;
449 	struct file *fp;
450 	unsigned fd;
451 	int error;
452 
453 	/*
454 	 * Can't mess with the root vnode
455 	 */
456 	switch (VTOFDESC(ap->a_vp)->fd_type) {
457 	case Fdesc:
458 		break;
459 
460 	case Fctty:
461 		return (0);
462 
463 	default:
464 		return (EACCES);
465 	}
466 
467 	fd = VTOFDESC(ap->a_vp)->fd_fd;
468 #ifdef FDESC_DIAGNOSTIC
469 	printf("fdesc_setattr: fd = %d, nfiles = %d\n", fd, fdp->fd_nfiles);
470 #endif
471 	if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) {
472 #ifdef FDESC_DIAGNOSTIC
473 		printf("fdesc_setattr: fp = %x (EBADF)\n", fp);
474 #endif
475 		return (EBADF);
476 	}
477 
478 	/*
479 	 * Can setattr the underlying vnode, but not sockets!
480 	 */
481 	switch (fp->f_type) {
482 	case DTYPE_VNODE:
483 		error = VOP_SETATTR((struct vnode *) fp->f_data, ap->a_vap, ap->a_cred, ap->a_p);
484 		break;
485 
486 	case DTYPE_SOCKET:
487 		error = 0;
488 		break;
489 
490 	default:
491 		panic("fdesc setattr");
492 		break;
493 	}
494 
495 #ifdef FDESC_DIAGNOSTIC
496 	printf("fdesc_setattr: returns error %d\n", error);
497 #endif
498 	return (error);
499 }
500 
501 #define UIO_MX 16
502 
503 static struct dirtmp {
504 	u_long d_fileno;
505 	u_short d_reclen;
506 	u_short d_namlen;
507 	char d_name[8];
508 } rootent[] = {
509 	{ FD_DEVFD, UIO_MX, 2, "fd" },
510 	{ FD_STDIN, UIO_MX, 5, "stdin" },
511 	{ FD_STDOUT, UIO_MX, 6, "stdout" },
512 	{ FD_STDERR, UIO_MX, 6, "stderr" },
513 	{ FD_CTTY, UIO_MX, 3, "tty" },
514 	{ 0 }
515 };
516 
517 fdesc_readdir(ap)
518 	struct vop_readdir_args /* {
519 		struct vnode *a_vp;
520 		struct uio *a_uio;
521 		struct ucred *a_cred;
522 	} */ *ap;
523 {
524 	struct uio *uio = ap->a_uio;
525 	struct filedesc *fdp;
526 	int i;
527 	int error;
528 
529 	switch (VTOFDESC(ap->a_vp)->fd_type) {
530 	case Fctty:
531 		return (0);
532 
533 	case Fdesc:
534 		return (ENOTDIR);
535 
536 	default:
537 		break;
538 	}
539 
540 	fdp = uio->uio_procp->p_fd;
541 
542 	if (VTOFDESC(ap->a_vp)->fd_type == Froot) {
543 		struct dirent d;
544 		struct dirent *dp = &d;
545 		struct dirtmp *dt;
546 
547 		i = uio->uio_offset / UIO_MX;
548 		error = 0;
549 
550 		while (uio->uio_resid > 0) {
551 			dt = &rootent[i];
552 			if (dt->d_fileno == 0) {
553 				/**eofflagp = 1;*/
554 				break;
555 			}
556 			i++;
557 
558 			switch (dt->d_fileno) {
559 			case FD_CTTY:
560 				if (cttyvp(uio->uio_procp) == NULL)
561 					continue;
562 				break;
563 
564 			case FD_STDIN:
565 			case FD_STDOUT:
566 			case FD_STDERR:
567 				if ((i-FD_STDIN) >= fdp->fd_nfiles)
568 					continue;
569 				if (fdp->fd_ofiles[i-FD_STDIN] == NULL)
570 					continue;
571 				break;
572 			}
573 			bzero(dp, UIO_MX);
574 			dp->d_fileno = dt->d_fileno;
575 			dp->d_namlen = dt->d_namlen;
576 			dp->d_type = DT_UNKNOWN;
577 			dp->d_reclen = dt->d_reclen;
578 			bcopy(dt->d_name, dp->d_name, dp->d_namlen+1);
579 			error = uiomove((caddr_t) dp, UIO_MX, uio);
580 			if (error)
581 				break;
582 		}
583 		uio->uio_offset = i * UIO_MX;
584 		return (error);
585 	}
586 
587 	i = uio->uio_offset / UIO_MX;
588 	error = 0;
589 	while (uio->uio_resid > 0) {
590 		if (i >= fdp->fd_nfiles) {
591 			/* *ap->a_eofflagp = 1; */
592 			break;
593 		}
594 		if (fdp->fd_ofiles[i] != NULL) {
595 			struct dirent d;
596 			struct dirent *dp = &d;
597 			char *cp = dp->d_name;
598 			bzero((caddr_t) dp, UIO_MX);
599 
600 			dp->d_namlen = sprintf(dp->d_name, "%d", i);
601 			/*
602 			 * Fill in the remaining fields
603 			 */
604 			dp->d_reclen = UIO_MX;
605 			dp->d_type = DT_UNKNOWN;
606 			dp->d_fileno = i + FD_STDIN;
607 			/*
608 			 * And ship to userland
609 			 */
610 			error = uiomove((caddr_t) dp, UIO_MX, uio);
611 			if (error)
612 				break;
613 		}
614 		i++;
615 	}
616 
617 	uio->uio_offset = i * UIO_MX;
618 	return (error);
619 }
620 
621 int
622 fdesc_readlink(ap)
623 	struct vop_readlink_args /* {
624 		struct vnode *a_vp;
625 		struct uio *a_uio;
626 		struct ucred *a_cred;
627 	} */ *ap;
628 {
629 	register struct vnode *vp = ap->a_vp;
630 	int error;
631 
632 	if (vp->v_type != VLNK)
633 		return (EPERM);
634 
635 	if (VTOFDESC(vp)->fd_type == Flink) {
636 		char *ln = VTOFDESC(vp)->fd_link;
637 		error = uiomove(ln, strlen(ln), ap->a_uio);
638 	} else {
639 		error = EOPNOTSUPP;
640 	}
641 
642 	return (error);
643 }
644 
645 fdesc_read(ap)
646 	struct vop_read_args /* {
647 		struct vnode *a_vp;
648 		struct uio *a_uio;
649 		int  a_ioflag;
650 		struct ucred *a_cred;
651 	} */ *ap;
652 {
653 	int error = EOPNOTSUPP;
654 
655 	switch (VTOFDESC(ap->a_vp)->fd_type) {
656 	case Fctty:
657 		error = cttyread(devctty, ap->a_uio, ap->a_ioflag);
658 		break;
659 
660 	default:
661 		error = EOPNOTSUPP;
662 		break;
663 	}
664 
665 	return (error);
666 }
667 
668 fdesc_write(ap)
669 	struct vop_write_args /* {
670 		struct vnode *a_vp;
671 		struct uio *a_uio;
672 		int  a_ioflag;
673 		struct ucred *a_cred;
674 	} */ *ap;
675 {
676 	int error = EOPNOTSUPP;
677 
678 	switch (VTOFDESC(ap->a_vp)->fd_type) {
679 	case Fctty:
680 		error = cttywrite(devctty, ap->a_uio, ap->a_ioflag);
681 		break;
682 
683 	default:
684 		error = EOPNOTSUPP;
685 		break;
686 	}
687 
688 	return (error);
689 }
690 
691 fdesc_ioctl(ap)
692 	struct vop_ioctl_args /* {
693 		struct vnode *a_vp;
694 		int  a_command;
695 		caddr_t  a_data;
696 		int  a_fflag;
697 		struct ucred *a_cred;
698 		struct proc *a_p;
699 	} */ *ap;
700 {
701 	int error = EOPNOTSUPP;
702 
703 #ifdef FDESC_DIAGNOSTIC
704 	printf("fdesc_ioctl: type = %d, command = %x\n",
705 			VTOFDESC(ap->a_vp)->fd_type, ap->a_command);
706 #endif
707 	switch (VTOFDESC(ap->a_vp)->fd_type) {
708 	case Fctty:
709 		error = cttyioctl(devctty, ap->a_command, ap->a_data,
710 					ap->a_fflag, ap->a_p);
711 		break;
712 
713 	default:
714 		error = EOPNOTSUPP;
715 		break;
716 	}
717 
718 	return (error);
719 }
720 
721 fdesc_select(ap)
722 	struct vop_select_args /* {
723 		struct vnode *a_vp;
724 		int  a_which;
725 		int  a_fflags;
726 		struct ucred *a_cred;
727 		struct proc *a_p;
728 	} */ *ap;
729 {
730 	int error = EOPNOTSUPP;
731 
732 	switch (VTOFDESC(ap->a_vp)->fd_type) {
733 	case Fctty:
734 		error = cttyselect(devctty, ap->a_fflags, ap->a_p);
735 		break;
736 
737 	default:
738 		error = EOPNOTSUPP;
739 		break;
740 	}
741 
742 	return (error);
743 }
744 
745 fdesc_inactive(ap)
746 	struct vop_inactive_args /* {
747 		struct vnode *a_vp;
748 	} */ *ap;
749 {
750 	struct vnode *vp = ap->a_vp;
751 
752 	/*
753 	 * Clear out the v_type field to avoid
754 	 * nasty things happening in vgone().
755 	 */
756 	vp->v_type = VNON;
757 #ifdef FDESC_DIAGNOSTIC
758 	printf("fdesc_inactive(%x)\n", vp);
759 #endif
760 	return (0);
761 }
762 
763 fdesc_reclaim(ap)
764 	struct vop_reclaim_args /* {
765 		struct vnode *a_vp;
766 	} */ *ap;
767 {
768 	struct vnode *vp = ap->a_vp;
769 	int ix;
770 
771 #ifdef FDESC_DIAGNOSTIC
772 	printf("fdesc_reclaim(%x)\n", vp);
773 #endif
774 	ix = VTOFDESC(vp)->fd_ix;
775 	if (ix >= 0 && ix < FD_MAX) {
776 		if (fdescvp[ix] != vp)
777 			panic("fdesc_reclaim");
778 		fdescvp[ix] = 0;
779 	}
780 	if (vp->v_data) {
781 		FREE(vp->v_data, M_TEMP);
782 		vp->v_data = 0;
783 	}
784 	return (0);
785 }
786 
787 /*
788  * Print out the contents of a /dev/fd vnode.
789  */
790 /* ARGSUSED */
791 fdesc_print(ap)
792 	struct vop_print_args /* {
793 		struct vnode *a_vp;
794 	} */ *ap;
795 {
796 
797 	printf("tag VT_NON, fdesc vnode\n");
798 	return (0);
799 }
800 
801 /*void*/
802 fdesc_vfree(ap)
803 	struct vop_vfree_args /* {
804 		struct vnode *a_pvp;
805 		ino_t a_ino;
806 		int a_mode;
807 	} */ *ap;
808 {
809 
810 	return (0);
811 }
812 
813 /*
814  * /dev/fd vnode unsupported operation
815  */
816 fdesc_enotsupp()
817 {
818 
819 	return (EOPNOTSUPP);
820 }
821 
822 /*
823  * /dev/fd "should never get here" operation
824  */
825 fdesc_badop()
826 {
827 
828 	panic("fdesc: bad op");
829 	/* NOTREACHED */
830 }
831 
832 /*
833  * /dev/fd vnode null operation
834  */
835 fdesc_nullop()
836 {
837 
838 	return (0);
839 }
840 
841 #define fdesc_create ((int (*) __P((struct  vop_create_args *)))fdesc_enotsupp)
842 #define fdesc_mknod ((int (*) __P((struct  vop_mknod_args *)))fdesc_enotsupp)
843 #define fdesc_close ((int (*) __P((struct  vop_close_args *)))nullop)
844 #define fdesc_access ((int (*) __P((struct  vop_access_args *)))nullop)
845 #define fdesc_mmap ((int (*) __P((struct  vop_mmap_args *)))fdesc_enotsupp)
846 #define fdesc_fsync ((int (*) __P((struct  vop_fsync_args *)))nullop)
847 #define fdesc_seek ((int (*) __P((struct  vop_seek_args *)))nullop)
848 #define fdesc_remove ((int (*) __P((struct  vop_remove_args *)))fdesc_enotsupp)
849 #define fdesc_link ((int (*) __P((struct  vop_link_args *)))fdesc_enotsupp)
850 #define fdesc_rename ((int (*) __P((struct  vop_rename_args *)))fdesc_enotsupp)
851 #define fdesc_mkdir ((int (*) __P((struct  vop_mkdir_args *)))fdesc_enotsupp)
852 #define fdesc_rmdir ((int (*) __P((struct  vop_rmdir_args *)))fdesc_enotsupp)
853 #define fdesc_symlink ((int (*) __P((struct vop_symlink_args *)))fdesc_enotsupp)
854 #define fdesc_abortop ((int (*) __P((struct  vop_abortop_args *)))nullop)
855 #define fdesc_lock ((int (*) __P((struct  vop_lock_args *)))nullop)
856 #define fdesc_unlock ((int (*) __P((struct  vop_unlock_args *)))nullop)
857 #define fdesc_bmap ((int (*) __P((struct  vop_bmap_args *)))fdesc_badop)
858 #define fdesc_strategy ((int (*) __P((struct  vop_strategy_args *)))fdesc_badop)
859 #define fdesc_islocked ((int (*) __P((struct  vop_islocked_args *)))nullop)
860 #define fdesc_advlock ((int (*) __P((struct vop_advlock_args *)))fdesc_enotsupp)
861 #define fdesc_blkatoff \
862 	((int (*) __P((struct  vop_blkatoff_args *)))fdesc_enotsupp)
863 #define fdesc_vget ((int (*) __P((struct  vop_vget_args *)))fdesc_enotsupp)
864 #define fdesc_valloc ((int(*) __P(( \
865 		struct vnode *pvp, \
866 		int mode, \
867 		struct ucred *cred, \
868 		struct vnode **vpp))) fdesc_enotsupp)
869 #define fdesc_truncate \
870 	((int (*) __P((struct  vop_truncate_args *)))fdesc_enotsupp)
871 #define fdesc_update ((int (*) __P((struct  vop_update_args *)))fdesc_enotsupp)
872 #define fdesc_bwrite ((int (*) __P((struct  vop_bwrite_args *)))fdesc_enotsupp)
873 
874 int (**fdesc_vnodeop_p)();
875 struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = {
876 	{ &vop_default_desc, vn_default_error },
877 	{ &vop_lookup_desc, fdesc_lookup },	/* lookup */
878 	{ &vop_create_desc, fdesc_create },	/* create */
879 	{ &vop_mknod_desc, fdesc_mknod },	/* mknod */
880 	{ &vop_open_desc, fdesc_open },		/* open */
881 	{ &vop_close_desc, fdesc_close },	/* close */
882 	{ &vop_access_desc, fdesc_access },	/* access */
883 	{ &vop_getattr_desc, fdesc_getattr },	/* getattr */
884 	{ &vop_setattr_desc, fdesc_setattr },	/* setattr */
885 	{ &vop_read_desc, fdesc_read },		/* read */
886 	{ &vop_write_desc, fdesc_write },	/* write */
887 	{ &vop_ioctl_desc, fdesc_ioctl },	/* ioctl */
888 	{ &vop_select_desc, fdesc_select },	/* select */
889 	{ &vop_mmap_desc, fdesc_mmap },		/* mmap */
890 	{ &vop_fsync_desc, fdesc_fsync },	/* fsync */
891 	{ &vop_seek_desc, fdesc_seek },		/* seek */
892 	{ &vop_remove_desc, fdesc_remove },	/* remove */
893 	{ &vop_link_desc, fdesc_link },		/* link */
894 	{ &vop_rename_desc, fdesc_rename },	/* rename */
895 	{ &vop_mkdir_desc, fdesc_mkdir },	/* mkdir */
896 	{ &vop_rmdir_desc, fdesc_rmdir },	/* rmdir */
897 	{ &vop_symlink_desc, fdesc_symlink },	/* symlink */
898 	{ &vop_readdir_desc, fdesc_readdir },	/* readdir */
899 	{ &vop_readlink_desc, fdesc_readlink },	/* readlink */
900 	{ &vop_abortop_desc, fdesc_abortop },	/* abortop */
901 	{ &vop_inactive_desc, fdesc_inactive },	/* inactive */
902 	{ &vop_reclaim_desc, fdesc_reclaim },	/* reclaim */
903 	{ &vop_lock_desc, fdesc_lock },		/* lock */
904 	{ &vop_unlock_desc, fdesc_unlock },	/* unlock */
905 	{ &vop_bmap_desc, fdesc_bmap },		/* bmap */
906 	{ &vop_strategy_desc, fdesc_strategy },	/* strategy */
907 	{ &vop_print_desc, fdesc_print },	/* print */
908 	{ &vop_islocked_desc, fdesc_islocked },	/* islocked */
909 	{ &vop_advlock_desc, fdesc_advlock },	/* advlock */
910 	{ &vop_blkatoff_desc, fdesc_blkatoff },	/* blkatoff */
911 	{ &vop_valloc_desc, fdesc_valloc },	/* valloc */
912 	{ &vop_vfree_desc, fdesc_vfree },	/* vfree */
913 	{ &vop_truncate_desc, fdesc_truncate },	/* truncate */
914 	{ &vop_update_desc, fdesc_update },	/* update */
915 	{ &vop_bwrite_desc, fdesc_bwrite },	/* bwrite */
916 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
917 };
918 struct vnodeopv_desc fdesc_vnodeop_opv_desc =
919 	{ &fdesc_vnodeop_p, fdesc_vnodeop_entries };
920