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