xref: /original-bsd/sys/miscfs/fdesc/fdesc_vnops.c (revision 95ecee29)
1 /*
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
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	8.3 (Berkeley) 09/23/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 & P_CONTROLT ? (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 	struct stat stb;
316 	int error;
317 
318 #ifdef FDESC_DIAGNOSTIC
319 	printf("fdesc_attr: fd = %d, nfiles = %d\n", fd, fdp->fd_nfiles);
320 #endif
321 	if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) {
322 #ifdef FDESC_DIAGNOSTIC
323 		printf("fdesc_attr: fp = %x (EBADF)\n", fp);
324 #endif
325 		return (EBADF);
326 	}
327 
328 	switch (fp->f_type) {
329 	case DTYPE_VNODE:
330 		error = VOP_GETATTR((struct vnode *) fp->f_data, vap, cred, p);
331 		if (error == 0 && vap->va_type == VDIR) {
332 			/*
333 			 * don't allow directories to show up because
334 			 * that causes loops in the namespace.
335 			 */
336 			vap->va_type = VFIFO;
337 		}
338 		break;
339 
340 	case DTYPE_SOCKET:
341 		error = soo_stat((struct socket *)fp->f_data, &stb);
342 		if (error == 0) {
343 			vattr_null(vap);
344 			vap->va_type = VSOCK;
345 			vap->va_mode = stb.st_mode;
346 			vap->va_nlink = stb.st_nlink;
347 			vap->va_uid = stb.st_uid;
348 			vap->va_gid = stb.st_gid;
349 			vap->va_fsid = stb.st_dev;
350 			vap->va_fileid = stb.st_ino;
351 			vap->va_size = stb.st_size;
352 			vap->va_blocksize = stb.st_blksize;
353 			vap->va_atime = stb.st_atimespec;
354 			vap->va_mtime = stb.st_mtimespec;
355 			vap->va_ctime = stb.st_ctimespec;
356 			vap->va_gen = stb.st_gen;
357 			vap->va_flags = stb.st_flags;
358 			vap->va_rdev = stb.st_rdev;
359 			vap->va_bytes = stb.st_blocks * stb.st_blksize;
360 		}
361 		break;
362 
363 	default:
364 		panic("fdesc attr");
365 		break;
366 	}
367 
368 #ifdef FDESC_DIAGNOSTIC
369 	printf("fdesc_attr: returns error %d\n", error);
370 #endif
371 	return (error);
372 }
373 
374 fdesc_getattr(ap)
375 	struct vop_getattr_args /* {
376 		struct vnode *a_vp;
377 		struct vattr *a_vap;
378 		struct ucred *a_cred;
379 		struct proc *a_p;
380 	} */ *ap;
381 {
382 	struct vnode *vp = ap->a_vp;
383 	struct vattr *vap = ap->a_vap;
384 	unsigned fd;
385 	int error = 0;
386 
387 #ifdef FDESC_DIAGNOSTIC
388 	printf("fdesc_getattr: stat type = %d\n", VTOFDESC(vp)->fd_type);
389 #endif
390 
391 	switch (VTOFDESC(vp)->fd_type) {
392 	case Froot:
393 	case Fdevfd:
394 	case Flink:
395 	case Fctty:
396 		bzero((caddr_t) vap, sizeof(*vap));
397 		vattr_null(vap);
398 		vap->va_fileid = VTOFDESC(vp)->fd_ix;
399 
400 		switch (VTOFDESC(vp)->fd_type) {
401 		case Flink:
402 			vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
403 			vap->va_type = VLNK;
404 			vap->va_nlink = 1;
405 			/* vap->va_qsize = strlen(VTOFDESC(vp)->fd_link); */
406 			vap->va_size = strlen(VTOFDESC(vp)->fd_link);
407 			break;
408 
409 		case Fctty:
410 			vap->va_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
411 			vap->va_type = VFIFO;
412 			vap->va_nlink = 1;
413 			/* vap->va_qsize = 0; */
414 			vap->va_size = 0;
415 			break;
416 
417 		default:
418 			vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
419 			vap->va_type = VDIR;
420 			vap->va_nlink = 2;
421 			/* vap->va_qsize = 0; */
422 			vap->va_size = DEV_BSIZE;
423 			break;
424 		}
425 		vap->va_uid = 0;
426 		vap->va_gid = 0;
427 		vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
428 		vap->va_blocksize = DEV_BSIZE;
429 		vap->va_atime.ts_sec = boottime.tv_sec;
430 		vap->va_atime.ts_nsec = 0;
431 		vap->va_mtime = vap->va_atime;
432 		vap->va_ctime = vap->va_mtime;
433 		vap->va_gen = 0;
434 		vap->va_flags = 0;
435 		vap->va_rdev = 0;
436 		/* vap->va_qbytes = 0; */
437 		vap->va_bytes = 0;
438 		break;
439 
440 	case Fdesc:
441 #ifdef FDESC_DIAGNOSTIC
442 		printf("fdesc_getattr: stat desc #%d\n", VTOFDESC(vp)->fd_fd);
443 #endif
444 		fd = VTOFDESC(vp)->fd_fd;
445 		error = fdesc_attr(fd, vap, ap->a_cred, ap->a_p);
446 		break;
447 
448 	default:
449 		panic("fdesc_getattr");
450 		break;
451 	}
452 
453 	if (error == 0)
454 		vp->v_type = vap->va_type;
455 
456 #ifdef FDESC_DIAGNOSTIC
457 	printf("fdesc_getattr: stat returns 0\n");
458 #endif
459 	return (error);
460 }
461 
462 fdesc_setattr(ap)
463 	struct vop_setattr_args /* {
464 		struct vnode *a_vp;
465 		struct vattr *a_vap;
466 		struct ucred *a_cred;
467 		struct proc *a_p;
468 	} */ *ap;
469 {
470 	struct filedesc *fdp = ap->a_p->p_fd;
471 	struct file *fp;
472 	unsigned fd;
473 	int error;
474 
475 	/*
476 	 * Can't mess with the root vnode
477 	 */
478 	switch (VTOFDESC(ap->a_vp)->fd_type) {
479 	case Fdesc:
480 		break;
481 
482 	case Fctty:
483 		return (0);
484 
485 	default:
486 		return (EACCES);
487 	}
488 
489 	fd = VTOFDESC(ap->a_vp)->fd_fd;
490 #ifdef FDESC_DIAGNOSTIC
491 	printf("fdesc_setattr: fd = %d, nfiles = %d\n", fd, fdp->fd_nfiles);
492 #endif
493 	if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) {
494 #ifdef FDESC_DIAGNOSTIC
495 		printf("fdesc_setattr: fp = %x (EBADF)\n", fp);
496 #endif
497 		return (EBADF);
498 	}
499 
500 	/*
501 	 * Can setattr the underlying vnode, but not sockets!
502 	 */
503 	switch (fp->f_type) {
504 	case DTYPE_VNODE:
505 		error = VOP_SETATTR((struct vnode *) fp->f_data, ap->a_vap, ap->a_cred, ap->a_p);
506 		break;
507 
508 	case DTYPE_SOCKET:
509 		error = 0;
510 		break;
511 
512 	default:
513 		panic("fdesc setattr");
514 		break;
515 	}
516 
517 #ifdef FDESC_DIAGNOSTIC
518 	printf("fdesc_setattr: returns error %d\n", error);
519 #endif
520 	return (error);
521 }
522 
523 #define UIO_MX 16
524 
525 static struct dirtmp {
526 	u_long d_fileno;
527 	u_short d_reclen;
528 	u_short d_namlen;
529 	char d_name[8];
530 } rootent[] = {
531 	{ FD_DEVFD, UIO_MX, 2, "fd" },
532 	{ FD_STDIN, UIO_MX, 5, "stdin" },
533 	{ FD_STDOUT, UIO_MX, 6, "stdout" },
534 	{ FD_STDERR, UIO_MX, 6, "stderr" },
535 	{ FD_CTTY, UIO_MX, 3, "tty" },
536 	{ 0 }
537 };
538 
539 fdesc_readdir(ap)
540 	struct vop_readdir_args /* {
541 		struct vnode *a_vp;
542 		struct uio *a_uio;
543 		struct ucred *a_cred;
544 	} */ *ap;
545 {
546 	struct uio *uio = ap->a_uio;
547 	struct filedesc *fdp;
548 	int i;
549 	int error;
550 
551 	switch (VTOFDESC(ap->a_vp)->fd_type) {
552 	case Fctty:
553 		return (0);
554 
555 	case Fdesc:
556 		return (ENOTDIR);
557 
558 	default:
559 		break;
560 	}
561 
562 	fdp = uio->uio_procp->p_fd;
563 
564 	if (VTOFDESC(ap->a_vp)->fd_type == Froot) {
565 		struct dirent d;
566 		struct dirent *dp = &d;
567 		struct dirtmp *dt;
568 
569 		i = uio->uio_offset / UIO_MX;
570 		error = 0;
571 
572 		while (uio->uio_resid > 0) {
573 			dt = &rootent[i];
574 			if (dt->d_fileno == 0) {
575 				/**eofflagp = 1;*/
576 				break;
577 			}
578 			i++;
579 
580 			switch (dt->d_fileno) {
581 			case FD_CTTY:
582 				if (cttyvp(uio->uio_procp) == NULL)
583 					continue;
584 				break;
585 
586 			case FD_STDIN:
587 			case FD_STDOUT:
588 			case FD_STDERR:
589 				if ((dt->d_fileno-FD_STDIN) >= fdp->fd_nfiles)
590 					continue;
591 				if (fdp->fd_ofiles[dt->d_fileno-FD_STDIN] == NULL)
592 					continue;
593 				break;
594 			}
595 			bzero((caddr_t) dp, UIO_MX);
596 			dp->d_fileno = dt->d_fileno;
597 			dp->d_namlen = dt->d_namlen;
598 			dp->d_type = DT_UNKNOWN;
599 			dp->d_reclen = dt->d_reclen;
600 			bcopy(dt->d_name, dp->d_name, dp->d_namlen+1);
601 			error = uiomove((caddr_t) dp, UIO_MX, uio);
602 			if (error)
603 				break;
604 		}
605 		uio->uio_offset = i * UIO_MX;
606 		return (error);
607 	}
608 
609 	i = uio->uio_offset / UIO_MX;
610 	error = 0;
611 	while (uio->uio_resid > 0) {
612 		if (i >= fdp->fd_nfiles) {
613 			/* *ap->a_eofflagp = 1; */
614 			break;
615 		}
616 		if (fdp->fd_ofiles[i] != NULL) {
617 			struct dirent d;
618 			struct dirent *dp = &d;
619 			char *cp = dp->d_name;
620 			bzero((caddr_t) dp, UIO_MX);
621 
622 			dp->d_namlen = sprintf(dp->d_name, "%d", i);
623 			/*
624 			 * Fill in the remaining fields
625 			 */
626 			dp->d_reclen = UIO_MX;
627 			dp->d_type = DT_UNKNOWN;
628 			dp->d_fileno = i + FD_STDIN;
629 			/*
630 			 * And ship to userland
631 			 */
632 			error = uiomove((caddr_t) dp, UIO_MX, uio);
633 			if (error)
634 				break;
635 		}
636 		i++;
637 	}
638 
639 	uio->uio_offset = i * UIO_MX;
640 	return (error);
641 }
642 
643 int
644 fdesc_readlink(ap)
645 	struct vop_readlink_args /* {
646 		struct vnode *a_vp;
647 		struct uio *a_uio;
648 		struct ucred *a_cred;
649 	} */ *ap;
650 {
651 	register struct vnode *vp = ap->a_vp;
652 	int error;
653 
654 	if (vp->v_type != VLNK)
655 		return (EPERM);
656 
657 	if (VTOFDESC(vp)->fd_type == Flink) {
658 		char *ln = VTOFDESC(vp)->fd_link;
659 		error = uiomove(ln, strlen(ln), ap->a_uio);
660 	} else {
661 		error = EOPNOTSUPP;
662 	}
663 
664 	return (error);
665 }
666 
667 fdesc_read(ap)
668 	struct vop_read_args /* {
669 		struct vnode *a_vp;
670 		struct uio *a_uio;
671 		int  a_ioflag;
672 		struct ucred *a_cred;
673 	} */ *ap;
674 {
675 	int error = EOPNOTSUPP;
676 
677 	switch (VTOFDESC(ap->a_vp)->fd_type) {
678 	case Fctty:
679 		error = cttyread(devctty, ap->a_uio, ap->a_ioflag);
680 		break;
681 
682 	default:
683 		error = EOPNOTSUPP;
684 		break;
685 	}
686 
687 	return (error);
688 }
689 
690 fdesc_write(ap)
691 	struct vop_write_args /* {
692 		struct vnode *a_vp;
693 		struct uio *a_uio;
694 		int  a_ioflag;
695 		struct ucred *a_cred;
696 	} */ *ap;
697 {
698 	int error = EOPNOTSUPP;
699 
700 	switch (VTOFDESC(ap->a_vp)->fd_type) {
701 	case Fctty:
702 		error = cttywrite(devctty, ap->a_uio, ap->a_ioflag);
703 		break;
704 
705 	default:
706 		error = EOPNOTSUPP;
707 		break;
708 	}
709 
710 	return (error);
711 }
712 
713 fdesc_ioctl(ap)
714 	struct vop_ioctl_args /* {
715 		struct vnode *a_vp;
716 		int  a_command;
717 		caddr_t  a_data;
718 		int  a_fflag;
719 		struct ucred *a_cred;
720 		struct proc *a_p;
721 	} */ *ap;
722 {
723 	int error = EOPNOTSUPP;
724 
725 #ifdef FDESC_DIAGNOSTIC
726 	printf("fdesc_ioctl: type = %d, command = %x\n",
727 			VTOFDESC(ap->a_vp)->fd_type, ap->a_command);
728 #endif
729 	switch (VTOFDESC(ap->a_vp)->fd_type) {
730 	case Fctty:
731 		error = cttyioctl(devctty, ap->a_command, ap->a_data,
732 					ap->a_fflag, ap->a_p);
733 		break;
734 
735 	default:
736 		error = EOPNOTSUPP;
737 		break;
738 	}
739 
740 	return (error);
741 }
742 
743 fdesc_select(ap)
744 	struct vop_select_args /* {
745 		struct vnode *a_vp;
746 		int  a_which;
747 		int  a_fflags;
748 		struct ucred *a_cred;
749 		struct proc *a_p;
750 	} */ *ap;
751 {
752 	int error = EOPNOTSUPP;
753 
754 	switch (VTOFDESC(ap->a_vp)->fd_type) {
755 	case Fctty:
756 		error = cttyselect(devctty, ap->a_fflags, ap->a_p);
757 		break;
758 
759 	default:
760 		error = EOPNOTSUPP;
761 		break;
762 	}
763 
764 	return (error);
765 }
766 
767 fdesc_inactive(ap)
768 	struct vop_inactive_args /* {
769 		struct vnode *a_vp;
770 	} */ *ap;
771 {
772 	struct vnode *vp = ap->a_vp;
773 
774 	/*
775 	 * Clear out the v_type field to avoid
776 	 * nasty things happening in vgone().
777 	 */
778 	vp->v_type = VNON;
779 #ifdef FDESC_DIAGNOSTIC
780 	printf("fdesc_inactive(%x)\n", vp);
781 #endif
782 	return (0);
783 }
784 
785 fdesc_reclaim(ap)
786 	struct vop_reclaim_args /* {
787 		struct vnode *a_vp;
788 	} */ *ap;
789 {
790 	struct vnode *vp = ap->a_vp;
791 	int ix;
792 
793 #ifdef FDESC_DIAGNOSTIC
794 	printf("fdesc_reclaim(%x)\n", vp);
795 #endif
796 	ix = VTOFDESC(vp)->fd_ix;
797 	if (ix >= 0 && ix < FD_MAX) {
798 		if (fdescvp[ix] != vp)
799 			panic("fdesc_reclaim");
800 		fdescvp[ix] = 0;
801 	}
802 	if (vp->v_data) {
803 		FREE(vp->v_data, M_TEMP);
804 		vp->v_data = 0;
805 	}
806 	return (0);
807 }
808 
809 /*
810  * Print out the contents of a /dev/fd vnode.
811  */
812 /* ARGSUSED */
813 fdesc_print(ap)
814 	struct vop_print_args /* {
815 		struct vnode *a_vp;
816 	} */ *ap;
817 {
818 
819 	printf("tag VT_NON, fdesc vnode\n");
820 	return (0);
821 }
822 
823 /*void*/
824 fdesc_vfree(ap)
825 	struct vop_vfree_args /* {
826 		struct vnode *a_pvp;
827 		ino_t a_ino;
828 		int a_mode;
829 	} */ *ap;
830 {
831 
832 	return (0);
833 }
834 
835 /*
836  * /dev/fd vnode unsupported operation
837  */
838 fdesc_enotsupp()
839 {
840 
841 	return (EOPNOTSUPP);
842 }
843 
844 /*
845  * /dev/fd "should never get here" operation
846  */
847 fdesc_badop()
848 {
849 
850 	panic("fdesc: bad op");
851 	/* NOTREACHED */
852 }
853 
854 /*
855  * /dev/fd vnode null operation
856  */
857 fdesc_nullop()
858 {
859 
860 	return (0);
861 }
862 
863 #define fdesc_create ((int (*) __P((struct  vop_create_args *)))fdesc_enotsupp)
864 #define fdesc_mknod ((int (*) __P((struct  vop_mknod_args *)))fdesc_enotsupp)
865 #define fdesc_close ((int (*) __P((struct  vop_close_args *)))nullop)
866 #define fdesc_access ((int (*) __P((struct  vop_access_args *)))nullop)
867 #define fdesc_mmap ((int (*) __P((struct  vop_mmap_args *)))fdesc_enotsupp)
868 #define fdesc_fsync ((int (*) __P((struct  vop_fsync_args *)))nullop)
869 #define fdesc_seek ((int (*) __P((struct  vop_seek_args *)))nullop)
870 #define fdesc_remove ((int (*) __P((struct  vop_remove_args *)))fdesc_enotsupp)
871 #define fdesc_link ((int (*) __P((struct  vop_link_args *)))fdesc_enotsupp)
872 #define fdesc_rename ((int (*) __P((struct  vop_rename_args *)))fdesc_enotsupp)
873 #define fdesc_mkdir ((int (*) __P((struct  vop_mkdir_args *)))fdesc_enotsupp)
874 #define fdesc_rmdir ((int (*) __P((struct  vop_rmdir_args *)))fdesc_enotsupp)
875 #define fdesc_symlink ((int (*) __P((struct vop_symlink_args *)))fdesc_enotsupp)
876 #define fdesc_abortop ((int (*) __P((struct  vop_abortop_args *)))nullop)
877 #define fdesc_lock ((int (*) __P((struct  vop_lock_args *)))nullop)
878 #define fdesc_unlock ((int (*) __P((struct  vop_unlock_args *)))nullop)
879 #define fdesc_bmap ((int (*) __P((struct  vop_bmap_args *)))fdesc_badop)
880 #define fdesc_strategy ((int (*) __P((struct  vop_strategy_args *)))fdesc_badop)
881 #define fdesc_islocked ((int (*) __P((struct  vop_islocked_args *)))nullop)
882 #define fdesc_advlock ((int (*) __P((struct vop_advlock_args *)))fdesc_enotsupp)
883 #define fdesc_blkatoff \
884 	((int (*) __P((struct  vop_blkatoff_args *)))fdesc_enotsupp)
885 #define fdesc_vget ((int (*) __P((struct  vop_vget_args *)))fdesc_enotsupp)
886 #define fdesc_valloc ((int(*) __P(( \
887 		struct vnode *pvp, \
888 		int mode, \
889 		struct ucred *cred, \
890 		struct vnode **vpp))) fdesc_enotsupp)
891 #define fdesc_truncate \
892 	((int (*) __P((struct  vop_truncate_args *)))fdesc_enotsupp)
893 #define fdesc_update ((int (*) __P((struct  vop_update_args *)))fdesc_enotsupp)
894 #define fdesc_bwrite ((int (*) __P((struct  vop_bwrite_args *)))fdesc_enotsupp)
895 
896 int (**fdesc_vnodeop_p)();
897 struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = {
898 	{ &vop_default_desc, vn_default_error },
899 	{ &vop_lookup_desc, fdesc_lookup },	/* lookup */
900 	{ &vop_create_desc, fdesc_create },	/* create */
901 	{ &vop_mknod_desc, fdesc_mknod },	/* mknod */
902 	{ &vop_open_desc, fdesc_open },		/* open */
903 	{ &vop_close_desc, fdesc_close },	/* close */
904 	{ &vop_access_desc, fdesc_access },	/* access */
905 	{ &vop_getattr_desc, fdesc_getattr },	/* getattr */
906 	{ &vop_setattr_desc, fdesc_setattr },	/* setattr */
907 	{ &vop_read_desc, fdesc_read },		/* read */
908 	{ &vop_write_desc, fdesc_write },	/* write */
909 	{ &vop_ioctl_desc, fdesc_ioctl },	/* ioctl */
910 	{ &vop_select_desc, fdesc_select },	/* select */
911 	{ &vop_mmap_desc, fdesc_mmap },		/* mmap */
912 	{ &vop_fsync_desc, fdesc_fsync },	/* fsync */
913 	{ &vop_seek_desc, fdesc_seek },		/* seek */
914 	{ &vop_remove_desc, fdesc_remove },	/* remove */
915 	{ &vop_link_desc, fdesc_link },		/* link */
916 	{ &vop_rename_desc, fdesc_rename },	/* rename */
917 	{ &vop_mkdir_desc, fdesc_mkdir },	/* mkdir */
918 	{ &vop_rmdir_desc, fdesc_rmdir },	/* rmdir */
919 	{ &vop_symlink_desc, fdesc_symlink },	/* symlink */
920 	{ &vop_readdir_desc, fdesc_readdir },	/* readdir */
921 	{ &vop_readlink_desc, fdesc_readlink },	/* readlink */
922 	{ &vop_abortop_desc, fdesc_abortop },	/* abortop */
923 	{ &vop_inactive_desc, fdesc_inactive },	/* inactive */
924 	{ &vop_reclaim_desc, fdesc_reclaim },	/* reclaim */
925 	{ &vop_lock_desc, fdesc_lock },		/* lock */
926 	{ &vop_unlock_desc, fdesc_unlock },	/* unlock */
927 	{ &vop_bmap_desc, fdesc_bmap },		/* bmap */
928 	{ &vop_strategy_desc, fdesc_strategy },	/* strategy */
929 	{ &vop_print_desc, fdesc_print },	/* print */
930 	{ &vop_islocked_desc, fdesc_islocked },	/* islocked */
931 	{ &vop_advlock_desc, fdesc_advlock },	/* advlock */
932 	{ &vop_blkatoff_desc, fdesc_blkatoff },	/* blkatoff */
933 	{ &vop_valloc_desc, fdesc_valloc },	/* valloc */
934 	{ &vop_vfree_desc, fdesc_vfree },	/* vfree */
935 	{ &vop_truncate_desc, fdesc_truncate },	/* truncate */
936 	{ &vop_update_desc, fdesc_update },	/* update */
937 	{ &vop_bwrite_desc, fdesc_bwrite },	/* bwrite */
938 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
939 };
940 struct vnodeopv_desc fdesc_vnodeop_opv_desc =
941 	{ &fdesc_vnodeop_p, fdesc_vnodeop_entries };
942