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