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