1 /*
2  * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29 /*
30  * Copyright (c) 1992, 1993
31  *	The Regents of the University of California.  All rights reserved.
32  *
33  * This code is derived from software donated to Berkeley by
34  * Jan-Simon Pendry.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 3. All advertising materials mentioning features or use of this software
45  *    must display the following acknowledgement:
46  *	This product includes software developed by the University of
47  *	California, Berkeley and its contributors.
48  * 4. Neither the name of the University nor the names of its contributors
49  *    may be used to endorse or promote products derived from this software
50  *    without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62  * SUCH DAMAGE.
63  *
64  *	@(#)fdesc_vnops.c	8.17 (Berkeley) 5/22/95
65  *
66  */
67 
68 /*
69  * /dev/fd Filesystem
70  */
71 
72 #include <sys/param.h>
73 #include <sys/systm.h>
74 #include <sys/types.h>
75 #include <sys/time.h>
76 #include <sys/proc_internal.h>
77 #include <sys/kernel.h>	/* boottime */
78 #include <sys/resourcevar.h>
79 #include <sys/filedesc.h>
80 #include <sys/kauth.h>
81 #include <sys/vnode_internal.h>
82 #include <sys/malloc.h>
83 #include <sys/file_internal.h>
84 #include <sys/stat.h>
85 #include <sys/mount_internal.h>
86 #include <sys/namei.h>
87 #include <sys/dirent.h>
88 #include <sys/ubc.h>
89 #include <sys/socketvar.h>
90 #include <sys/pipe.h>
91 #include <sys/uio_internal.h>
92 #include <vfs/vfs_support.h>
93 #include <pexpert/pexpert.h>
94 #include <miscfs/devfs/fdesc.h>
95 #include <miscfs/devfs/devfs.h>
96 #include <miscfs/devfs/devfsdefs.h>
97 
98 /* XXX should be prototyped in header for here, kern_descrip.c */
99 extern int soo_stat(struct socket *so, void *ub, int isstat64);
100 
101 #define FDL_WANT	0x01
102 #define FDL_LOCKED	0x02
103 static int fdcache_lock;
104 
105 
106 #if (FD_STDIN != FD_STDOUT-1) || (FD_STDOUT != FD_STDERR-1)
107 FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2
108 #endif
109 
110 #define	NFDCACHE 3
111 
112 #define FD_NHASH(ix) \
113 	(&fdhashtbl[(ix) & fdhash])
114 LIST_HEAD(fdhashhead, fdescnode) *fdhashtbl;
115 u_long fdhash;
116 
117 static int fdesc_attr(int fd, struct vnode_attr *vap, vfs_context_t a_context);
118 
119 lck_mtx_t fdesc_mtx;
120 lck_grp_t *fdesc_lckgrp;
121 
122 static void
123 fdesc_lock(void)
124 {
125 	lck_mtx_lock(&fdesc_mtx);
126 }
127 
128 static void
129 fdesc_unlock(void)
130 {
131 	lck_mtx_unlock(&fdesc_mtx);
132 }
133 
134 
135 /*
136  * Initialise cache headers, create the devfs node
137  */
138 int
139 devfs_fdesc_init()
140 {
141 	int error = 0;
142 	devnode_t *rootdir = dev_root->de_dnp;
143 	devdirent_t *direntp;
144 
145 	/* XXX Make sure you have the right path... */
146 	fdhashtbl = hashinit(NFDCACHE, M_CACHE, &fdhash);
147 	fdesc_lckgrp = lck_grp_alloc_init("fdesc", NULL);
148 	lck_mtx_init(&fdesc_mtx, fdesc_lckgrp, NULL);
149 
150 	DEVFS_LOCK();
151 	dev_add_entry("fd", rootdir, DEV_DEVFD, NULL, NULL, NULL, &direntp);
152 	devfs_fdesc_makelinks();
153 	DEVFS_UNLOCK();
154 
155 	return(error);
156 }
157 
158 /*
159  * Called during early startup, no need to synchronize
160  */
161 int
162 devfs_fdesc_makelinks()
163 {
164 	int error = 0;
165 	devdirent_t *stdin_ent = NULL, *stdout_ent = NULL, *stderr_ent = NULL;
166 	devnode_t *root_devnode = dev_root->de_dnp;
167 
168 	/* We do this ugliness to get around some "const" warnings */
169 	char in[] = "stdin";
170 	char out[] = "stdout";
171 	char err[] = "stderr";
172 	char zero[] = "fd/0";
173 	char one[] = "fd/1";
174 	char two[] = "fd/2";
175 
176 	if ((error = devfs_make_symlink(root_devnode, in, 0555, zero, &stdin_ent))) {
177 		printf("Couldn't make stdin, err %d.\n", error);
178 		goto bad;
179 	}
180 
181 	if ((error = devfs_make_symlink(root_devnode, out, 0555, one, &stdout_ent))) {
182 		printf("Couldn't make stdout, err %d.\n", error);
183 		goto bad;
184 	}
185 
186 	if ((error = devfs_make_symlink(root_devnode, err, 0555, two, &stderr_ent))) {
187 		printf("Couldn't make stderr, err %d.\n", error);
188 		goto bad;
189 	}
190 
191 	return 0;
192 
193 bad:
194 	if (stdin_ent) {
195 		dev_free_name(stdin_ent);
196 	}
197 	if (stdout_ent) {
198 		dev_free_name(stdout_ent);
199 	}
200 	if (stderr_ent) {
201 		dev_free_name(stderr_ent);
202 	}
203 
204 	return error;
205 }
206 
207 int
208 fdesc_allocvp(fdntype ftype, int ix, struct mount *mp, struct vnode **vpp, enum vtype vtype, int fdno)
209 {
210 	struct fdhashhead *fc;
211 	struct fdescnode *fd;
212 	int error = 0;
213 	int vid = 0;
214 	struct vnode_fsparam vfsp;
215 
216 	fdesc_lock();
217 
218 	fc = FD_NHASH(ix);
219 loop:
220 	for (fd = fc->lh_first; fd != 0; fd = fd->fd_hash.le_next) {
221 		if (fd->fd_ix == ix && vnode_mount(fd->fd_vnode) == mp) {
222 		        vid = vnode_vid(fd->fd_vnode);
223 			fdesc_unlock();
224 
225 			if (vnode_getwithvid(fd->fd_vnode, vid))
226 				goto loop;
227 
228 			*vpp = fd->fd_vnode;
229 			(*vpp)->v_type = vtype;
230 
231 			return (error);
232 		}
233 	}
234 
235 	/* Only one thread can add to the hash at a time */
236 	if (fdcache_lock & FDL_LOCKED) {
237 		fdcache_lock |= FDL_WANT;
238 		msleep((caddr_t) &fdcache_lock, &fdesc_mtx, PINOD, "fdesc_allocvp", NULL);
239 		goto loop;
240 	}
241 
242 	fdcache_lock |= FDL_LOCKED;
243 	fdesc_unlock();
244 
245 	MALLOC(fd, void *, sizeof(struct fdescnode), M_TEMP, M_WAITOK);
246 
247 	vfsp.vnfs_mp = mp;
248 	vfsp.vnfs_vtype = vtype;
249 	vfsp.vnfs_str = "fdesc";
250 	vfsp.vnfs_dvp = NULL;
251 	vfsp.vnfs_fsnode = fd;
252 	vfsp.vnfs_cnp = NULL;
253 	vfsp.vnfs_vops = fdesc_vnodeop_p;
254 	vfsp.vnfs_rdev = 0;
255 	vfsp.vnfs_filesize = 0;
256 	vfsp.vnfs_flags = VNFS_NOCACHE | VNFS_CANTCACHE;
257 	vfsp.vnfs_marksystem = 0;
258 	vfsp.vnfs_markroot = 0;
259 
260 	error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &vfsp, vpp);
261 	if (error) {
262 		FREE(fd, M_TEMP);
263 		fdesc_lock();
264 		goto out;
265 	}
266 
267 	(*vpp)->v_tag = VT_FDESC;
268 	fd->fd_vnode = *vpp;
269 	fd->fd_type = ftype;
270 	fd->fd_fd = -1;
271 	fd->fd_link = NULL;
272 	fd->fd_ix = ix;
273 	fd->fd_fd = fdno;
274 
275 	fdesc_lock();
276 
277 	LIST_INSERT_HEAD(fc, fd, fd_hash);
278 out:
279 	/* Hold the lock when we get here */
280 	fdcache_lock &= ~FDL_LOCKED;
281 
282 	if (fdcache_lock & FDL_WANT) {
283 		fdcache_lock &= ~FDL_WANT;
284 		wakeup((caddr_t) &fdcache_lock);
285 	}
286 
287 	fdesc_unlock();
288 
289 	return (error);
290 }
291 
292 /*
293  * vp is the current namei directory
294  * ndp is the name to locate in that directory...
295  *
296  * This vnop should only be called on the special directory /dev/fd.
297  */
298 int
299 devfs_devfd_lookup(struct vnop_lookup_args *ap)
300 {
301 	struct vnode **vpp = ap->a_vpp;
302 	struct vnode *dvp = ap->a_dvp;
303 	struct componentname *cnp = ap->a_cnp;
304 	char *pname = cnp->cn_nameptr;
305 	struct proc *p = vfs_context_proc(ap->a_context);
306 	int numfiles = p->p_fd->fd_nfiles;
307 	int fd;
308 	int error;
309 	struct vnode *fvp;
310 
311 	if (cnp->cn_namelen == 1 && *pname == '.') {
312 		*vpp = dvp;
313 
314 		if ( (error = vnode_get(dvp)) ) {
315 			return(error);
316 		}
317 		return (0);
318 	}
319 
320 	fd = 0;
321 	while (*pname >= '0' && *pname <= '9') {
322 		fd = 10 * fd + *pname++ - '0';
323 		if (fd >= numfiles)
324 			break;
325 	}
326 
327 	if (*pname != '\0') {
328 		error = ENOENT;
329 		goto bad;
330 	}
331 
332 	if (fd < 0 || fd >= numfiles ||
333 			*fdfile(p, fd) == NULL ||
334 			(*fdflags(p, fd) & UF_RESERVED)) {
335 		error = EBADF;
336 		goto bad;
337 	}
338 
339 	error = fdesc_allocvp(Fdesc, FD_DESC+fd, dvp->v_mount, &fvp, VNON, fd);
340 	if (error)
341 		goto bad;
342 	*vpp = fvp;
343 	return (0);
344 
345 bad:
346 	*vpp = NULL;
347 	return (error);
348 }
349 
350 int
351 fdesc_open(struct vnop_open_args *ap)
352 {
353 	struct vnode *vp = ap->a_vp;
354 	thread_t thr = vfs_context_thread(ap->a_context);
355 	uthread_t uu;
356 	int error = 0;
357 
358 	if (thr == NULL)
359 		return (EINVAL);
360 
361 	uu = get_bsdthread_info(thr);
362 
363 	switch (VTOFDESC(vp)->fd_type) {
364 	case Fdesc:
365 		/*
366 		 * XXX Kludge: set uu->uu_dupfd to contain the value of the
367 		 * the file descriptor being sought for duplication. The error
368 		 * return ensures that the vnode for this device will be
369 		 * released by vn_open. Open will detect this special error and
370 		 * take the actions in dupfdopen.  Other callers of vn_open or
371 		 * vnop_open will simply report the error.
372 		 */
373 		uu->uu_dupfd = VTOFDESC(vp)->fd_fd;	/* XXX */
374 		error = ENODEV;
375 		break;
376 	default:
377 		panic("Invalid type for fdesc node!");
378 		break;
379 	}
380 
381 	return (error);
382 }
383 
384 static int
385 fdesc_attr(int fd, struct vnode_attr *vap, vfs_context_t a_context)
386 {
387 	struct fileproc *fp;
388 	struct proc *p = vfs_context_proc(a_context);
389 	struct stat stb;
390 	int error;
391 
392 	if ((error = fp_lookup(p, fd, &fp, 0)))
393 		return (error);
394 	switch (fp->f_fglob->fg_type) {
395 	case DTYPE_VNODE:
396 		if((error = vnode_getwithref((struct vnode *) fp->f_fglob->fg_data)) != 0) {
397 			break;
398 		}
399 		if ((error = vnode_authorize((struct vnode *)fp->f_fglob->fg_data,
400 			 NULL,
401 			 KAUTH_VNODE_READ_ATTRIBUTES | KAUTH_VNODE_READ_SECURITY,
402 			 a_context)) == 0)
403 			error = vnode_getattr((struct vnode *)fp->f_fglob->fg_data, vap, a_context);
404 		if (error == 0 && vap->va_type == VDIR) {
405 			/*
406 			 * directories can cause loops in the namespace,
407 			 * so turn off the 'x' bits to avoid trouble.
408 			 *
409 			 * XXX ACLs break this, of course
410 			 */
411 			vap->va_mode &= ~((VEXEC)|(VEXEC>>3)|(VEXEC>>6));
412 		}
413 		(void)vnode_put((struct vnode *) fp->f_fglob->fg_data);
414 		break;
415 
416 	case DTYPE_SOCKET:
417 	case DTYPE_PIPE:
418 #if SOCKETS
419 		if (fp->f_fglob->fg_type == DTYPE_SOCKET)
420 			error = soo_stat((struct socket *)fp->f_fglob->fg_data, (void *)&stb, 0);
421 		else
422 #endif /* SOCKETS */
423 			error = pipe_stat((struct pipe *)fp->f_fglob->fg_data, (void *)&stb, 0);
424 
425 		if (error == 0) {
426 			if (fp->f_fglob->fg_type == DTYPE_SOCKET)
427 			        VATTR_RETURN(vap, va_type, VSOCK);
428                         else
429 			        VATTR_RETURN(vap, va_type, VFIFO);
430 
431 			VATTR_RETURN(vap, va_mode, stb.st_mode);
432 			VATTR_RETURN(vap, va_nlink, stb.st_nlink);
433 			VATTR_RETURN(vap, va_uid, stb.st_uid);
434 			VATTR_RETURN(vap, va_gid, stb.st_gid);
435 			VATTR_RETURN(vap, va_fsid, stb.st_dev);
436 			VATTR_RETURN(vap, va_fileid, stb.st_ino);
437 			VATTR_RETURN(vap, va_data_size, stb.st_size);
438 			VATTR_RETURN(vap, va_access_time, stb.st_atimespec);
439 			VATTR_RETURN(vap, va_modify_time, stb.st_mtimespec);
440 			VATTR_RETURN(vap, va_change_time, stb.st_ctimespec);
441 			VATTR_RETURN(vap, va_gen, stb.st_gen);
442 			VATTR_RETURN(vap, va_flags, stb.st_flags);
443 			VATTR_RETURN(vap, va_rdev, stb.st_rdev);
444 			VATTR_RETURN(vap, va_total_alloc, stb.st_blocks * stb.st_blksize);
445 			VATTR_RETURN(vap, va_acl, NULL);
446 		}
447 		break;
448 
449 	default:
450 		error = EBADF;
451 	}
452 
453 	fp_drop(p, fd, fp, 0);
454 	return (error);
455 }
456 
457 int
458 fdesc_getattr(struct vnop_getattr_args *ap)
459 {
460 	struct vnode *vp = ap->a_vp;
461 	struct vnode_attr *vap = ap->a_vap;
462 	unsigned fd;
463 	int error = 0;
464 
465 	switch (VTOFDESC(vp)->fd_type) {
466 	case Fdesc:
467 		fd = VTOFDESC(vp)->fd_fd;
468 		error = fdesc_attr(fd, vap, ap->a_context);
469 		break;
470 
471 	default:
472 		panic("Invalid type for an fdesc node!\n");
473 		break;
474 	}
475 
476 	/*
477 	 * Yes, we do this without locking, but this value is always just
478 	 * a snapshot.
479 	 */
480 	if (error == 0) {
481 		vp->v_type = vap->va_type;
482 
483 		/* We need an inactive to reset type to VNON */
484 		vnode_setneedinactive(vp);
485 	}
486 
487 	return (error);
488 }
489 
490 int
491 fdesc_setattr(struct vnop_setattr_args *ap)
492 {
493 	struct fileproc *fp;
494 	unsigned fd;
495 	int error;
496 	struct proc * p = vfs_context_proc(ap->a_context);
497 
498 	/*
499 	 * Can't mess with the root vnode
500 	 */
501 	switch (VTOFDESC(ap->a_vp)->fd_type) {
502 	case Fdesc:
503 		break;
504 	default:
505 		panic("Invalid type for an fdesc node!\n");
506 		return (EACCES);
507 	}
508 
509 	fd = VTOFDESC(ap->a_vp)->fd_fd;
510 	if ((error = fp_lookup(vfs_context_proc(ap->a_context), fd, &fp, 0)))
511 		return (error);
512 
513 	/*
514 	 * Can setattr the underlying vnode, but not sockets!
515 	 */
516 	switch (fp->f_fglob->fg_type) {
517 	case DTYPE_VNODE:
518 	{
519 		if ((error = vnode_getwithref((struct vnode *) fp->f_fglob->fg_data)) != 0)
520 			break;
521 		error = vnode_setattr((struct vnode *) fp->f_fglob->fg_data, ap->a_vap, ap->a_context);
522 		(void)vnode_put((struct vnode *) fp->f_fglob->fg_data);
523 		break;
524 	}
525 
526 	case DTYPE_SOCKET:
527 	case DTYPE_PIPE:
528 		error = 0;
529 		break;
530 
531 	default:
532 		kprintf("fp->f_fglob->fg_type = %d\n", fp->f_fglob->fg_type);
533         error = EBADF;
534 		break;
535 	}
536 
537 	fp_drop(p, fd, fp, 0);
538 	return (error);
539 }
540 
541 #define UIO_MX 16
542 
543 /*
544 static struct dirtmp {
545 	u_int32_t d_fileno;
546 	u_short d_reclen;
547 	u_short d_namlen;
548 	char d_name[8];
549 } rootent[] = {
550 	{ FD_DEVFD, UIO_MX, 2, "fd" },
551 	{ FD_STDIN, UIO_MX, 5, "stdin" },
552 	{ FD_STDOUT, UIO_MX, 6, "stdout" },
553 	{ FD_STDERR, UIO_MX, 6, "stderr" },
554 	{ 0, 0, 0, "" }
555 };
556 */
557 
558 /* Only called on /dev/fd */
559 int
560 devfs_devfd_readdir(struct vnop_readdir_args *ap)
561 {
562 	struct uio *uio = ap->a_uio;
563 	struct proc *p = current_proc();
564 	int i, error;
565 
566 	/*
567 	 * We don't allow exporting fdesc mounts, and currently local
568 	 * requests do not need cookies.
569 	 */
570 	if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF))
571 		return (EINVAL);
572 
573 	i = uio->uio_offset / UIO_MX;
574 	error = 0;
575 	while (uio_resid(uio) > 0) {
576 		if (i >= p->p_fd->fd_nfiles)
577 			break;
578 
579 		if (*fdfile(p, i) != NULL && !(*fdflags(p, i) & UF_RESERVED)) {
580 			struct dirent d;
581 			struct dirent *dp = &d;
582 
583 			bzero((caddr_t) dp, UIO_MX);
584 
585 			dp->d_namlen = snprintf(dp->d_name, sizeof(dp->d_name),
586 						"%d", i);
587 			dp->d_reclen = UIO_MX;
588 			dp->d_type = DT_UNKNOWN;
589 			dp->d_fileno = i + FD_STDIN;
590 			/*
591 			 * And ship to userland
592 			 */
593 			error = uiomove((caddr_t) dp, UIO_MX, uio);
594 			if (error)
595 				break;
596 		}
597 		i++;
598 	}
599 
600 	uio->uio_offset = i * UIO_MX;
601 	return (error);
602 }
603 
604 int
605 fdesc_read(__unused struct vnop_read_args *ap)
606 {
607 	return (ENOTSUP);
608 }
609 
610 int
611 fdesc_write(__unused struct vnop_write_args *ap)
612 {
613 	return (ENOTSUP);
614 }
615 
616 int
617 fdesc_ioctl(__unused struct vnop_ioctl_args *ap)
618 {
619 	return (ENOTSUP);
620 }
621 
622 int
623 fdesc_select(__unused struct vnop_select_args *ap)
624 {
625 	return (ENOTSUP);
626 }
627 
628 int
629 fdesc_inactive(struct vnop_inactive_args *ap)
630 {
631 	struct vnode *vp = ap->a_vp;
632 
633 	/*
634 	 * Clear out the v_type field to avoid
635 	 * nasty things happening in vgone().
636 	 */
637 	vp->v_type = VNON;
638 
639 	return (0);
640 }
641 
642 int
643 fdesc_reclaim(struct vnop_reclaim_args *ap)
644 {
645 	struct vnode *vp = ap->a_vp;
646 	struct fdescnode *fd = VTOFDESC(vp);
647 
648 	fdesc_lock();
649 
650 	LIST_REMOVE(fd, fd_hash);
651 	FREE(vp->v_data, M_TEMP);
652 	vp->v_data = NULL;
653 
654 	fdesc_unlock();
655 
656 	return (0);
657 }
658 
659 /*
660  * Return POSIX pathconf information applicable to special devices.
661  */
662 int
663 fdesc_pathconf(struct vnop_pathconf_args *ap)
664 {
665 
666 	switch (ap->a_name) {
667 	case _PC_LINK_MAX:
668 		*ap->a_retval = LINK_MAX;
669 		return (0);
670 	case _PC_MAX_CANON:
671 		*ap->a_retval = MAX_CANON;
672 		return (0);
673 	case _PC_MAX_INPUT:
674 		*ap->a_retval = MAX_INPUT;
675 		return (0);
676 	case _PC_PIPE_BUF:
677 		*ap->a_retval = PIPE_BUF;
678 		return (0);
679 	case _PC_CHOWN_RESTRICTED:
680 		*ap->a_retval = 200112;		/* _POSIX_CHOWN_RESTRICTED */
681 		return (0);
682 	case _PC_VDISABLE:
683 		*ap->a_retval = _POSIX_VDISABLE;
684 		return (0);
685 	default:
686 		return (EINVAL);
687 	}
688 	/* NOTREACHED */
689 }
690 
691 /*
692  * /dev/fd "should never get here" operation
693  */
694 int
695 fdesc_badop(void)
696 {
697 
698 	return (ENOTSUP);
699 	/* NOTREACHED */
700 }
701 
702 #define VOPFUNC int (*)(void *)
703 
704 #define fdesc_create (int (*) (struct  vnop_create_args *))eopnotsupp
705 #define fdesc_mknod (int (*) (struct  vnop_mknod_args *))eopnotsupp
706 #define fdesc_close (int (*) (struct  vnop_close_args *))nullop
707 #define fdesc_access (int (*) (struct  vnop_access_args *))nullop
708 #define fdesc_mmap (int (*) (struct  vnop_mmap_args *))eopnotsupp
709 #define	fdesc_revoke nop_revoke
710 #define fdesc_fsync (int (*) (struct  vnop_fsync_args *))nullop
711 #define fdesc_remove (int (*) (struct  vnop_remove_args *))eopnotsupp
712 #define fdesc_link (int (*) (struct  vnop_link_args *))eopnotsupp
713 #define fdesc_rename (int (*) (struct  vnop_rename_args *))eopnotsupp
714 #define fdesc_mkdir (int (*) (struct  vnop_mkdir_args *))eopnotsupp
715 #define fdesc_rmdir (int (*) (struct  vnop_rmdir_args *))eopnotsupp
716 #define fdesc_symlink (int (*) (struct vnop_symlink_args *))eopnotsupp
717 #define fdesc_strategy (int (*) (struct  vnop_strategy_args *))fdesc_badop
718 #define fdesc_advlock (int (*) (struct vnop_advlock_args *))eopnotsupp
719 #define fdesc_bwrite (int (*) (struct  vnop_bwrite_args *))eopnotsupp
720 #define fdesc_blktooff (int (*) (struct  vnop_blktooff_args *))eopnotsupp
721 #define fdesc_offtoblk (int (*) (struct  vnop_offtoblk_args *))eopnotsupp
722 #define fdesc_blockmap (int (*) (struct  vnop_blockmap_args *))eopnotsupp
723 
724 int (**fdesc_vnodeop_p)(void *);
725 struct vnodeopv_entry_desc devfs_fdesc_vnodeop_entries[] = {
726 	{ &vnop_default_desc, (VOPFUNC)vn_default_error },
727 	{ &vnop_lookup_desc, (VOPFUNC)vn_default_error},	/* lookup */
728 	{ &vnop_create_desc, (VOPFUNC)fdesc_create },	/* create */
729 	{ &vnop_mknod_desc, (VOPFUNC)fdesc_mknod },	/* mknod */
730 	{ &vnop_open_desc, (VOPFUNC)fdesc_open },	/* open */
731 	{ &vnop_close_desc, (VOPFUNC)fdesc_close },	/* close */
732 	{ &vnop_access_desc, (VOPFUNC)fdesc_access },	/* access */
733 	{ &vnop_getattr_desc, (VOPFUNC)fdesc_getattr },	/* getattr */
734 	{ &vnop_setattr_desc, (VOPFUNC)fdesc_setattr },	/* setattr */
735 	{ &vnop_read_desc, (VOPFUNC)fdesc_read },	/* read */
736 	{ &vnop_write_desc, (VOPFUNC)fdesc_write },	/* write */
737 	{ &vnop_ioctl_desc, (VOPFUNC)fdesc_ioctl },	/* ioctl */
738 	{ &vnop_select_desc, (VOPFUNC)fdesc_select },	/* select */
739 	{ &vnop_revoke_desc, (VOPFUNC)fdesc_revoke },	/* revoke */
740 	{ &vnop_mmap_desc, (VOPFUNC)fdesc_mmap },	/* mmap */
741 	{ &vnop_fsync_desc, (VOPFUNC)fdesc_fsync },	/* fsync */
742 	{ &vnop_remove_desc, (VOPFUNC)fdesc_remove },	/* remove */
743 	{ &vnop_link_desc, (VOPFUNC)fdesc_link },	/* link */
744 	{ &vnop_rename_desc, (VOPFUNC)fdesc_rename },	/* rename */
745 	{ &vnop_mkdir_desc, (VOPFUNC)fdesc_mkdir },	/* mkdir */
746 	{ &vnop_rmdir_desc, (VOPFUNC)fdesc_rmdir },	/* rmdir */
747 	{ &vnop_symlink_desc, (VOPFUNC)fdesc_symlink },	/* symlink */
748 	{ &vnop_readdir_desc, (VOPFUNC)vn_default_error},/* readdir */
749 	{ &vnop_readlink_desc, (VOPFUNC)err_readlink}, /* readlink */
750 	{ &vnop_inactive_desc, (VOPFUNC)fdesc_inactive },/* inactive */
751 	{ &vnop_reclaim_desc, (VOPFUNC)fdesc_reclaim },	/* reclaim */
752 	{ &vnop_strategy_desc, (VOPFUNC)fdesc_strategy },	/* strategy */
753 	{ &vnop_pathconf_desc, (VOPFUNC)fdesc_pathconf },	/* pathconf */
754 	{ &vnop_advlock_desc, (VOPFUNC)fdesc_advlock },	/* advlock */
755 	{ &vnop_bwrite_desc, (VOPFUNC)fdesc_bwrite },	/* bwrite */
756 	{ &vnop_pagein_desc, (VOPFUNC)err_pagein },	/* pagein */
757 	{ &vnop_pageout_desc, (VOPFUNC)err_pageout },	/* pageout */
758         { &vnop_copyfile_desc, (VOPFUNC)err_copyfile },	/* Copyfile */
759 	{ &vnop_blktooff_desc, (VOPFUNC)fdesc_blktooff },	/* blktooff */
760 	{ &vnop_blktooff_desc, (VOPFUNC)fdesc_offtoblk },	/* offtoblk */
761 	{ &vnop_blockmap_desc, (VOPFUNC)fdesc_blockmap },	/* blockmap */
762 	{ (struct vnodeop_desc*)NULL, (VOPFUNC)NULL }
763 };
764 
765 struct vnodeopv_desc devfs_fdesc_vnodeop_opv_desc =
766 	{ &fdesc_vnodeop_p, devfs_fdesc_vnodeop_entries };
767 
768