]> git.saurik.com Git - apple/xnu.git/blob - bsd/miscfs/fdesc/fdesc_vnops.c
xnu-792.22.5.tar.gz
[apple/xnu.git] / bsd / miscfs / fdesc / fdesc_vnops.c
1 /*
2 * Copyright (c) 2000-2004 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 <miscfs/fdesc/fdesc.h>
93 #include <vfs/vfs_support.h>
94 #include <pexpert/pexpert.h>
95
96 #define FDL_WANT 0x01
97 #define FDL_LOCKED 0x02
98 static int fdcache_lock;
99
100
101 #if (FD_STDIN != FD_STDOUT-1) || (FD_STDOUT != FD_STDERR-1)
102 FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2
103 #endif
104
105 #define NFDCACHE 3
106
107 #define FD_NHASH(ix) \
108 (&fdhashtbl[(ix) & fdhash])
109 LIST_HEAD(fdhashhead, fdescnode) *fdhashtbl;
110 u_long fdhash;
111
112 static int fdesc_attr(int fd, struct vnode_attr *vap, vfs_context_t a_context);
113
114
115 /*
116 * Initialise cache headers
117 */
118 int
119 fdesc_init(__unused struct vfsconf *vfsp)
120 {
121
122 fdhashtbl = hashinit(NFDCACHE, M_CACHE, &fdhash);
123
124 return( 0 );
125 }
126
127 int
128 fdesc_allocvp(ftype, ix, mp, vpp, vtype)
129 fdntype ftype;
130 int ix;
131 struct mount *mp;
132 struct vnode **vpp;
133 enum vtype vtype;
134 {
135 struct fdhashhead *fc;
136 struct fdescnode *fd;
137 int error = 0;
138 int vid = 0;
139 struct vnode_fsparam vfsp;
140
141 fc = FD_NHASH(ix);
142 loop:
143 for (fd = fc->lh_first; fd != 0; fd = fd->fd_hash.le_next) {
144 if (fd->fd_ix == ix && vnode_mount(fd->fd_vnode) == mp) {
145 /*
146 * doing a vnode_getwithvid isn't technically
147 * necessary since fdesc is an unsafe filesystem
148 * and we're running behind a funnel at this point
149 * however, vnode_get always succeeds, which isn't
150 * what we want if this vnode is in the process of
151 * being terminated
152 */
153 vid = vnode_vid(fd->fd_vnode);
154
155 if (vnode_getwithvid(fd->fd_vnode, vid))
156 goto loop;
157 *vpp = fd->fd_vnode;
158 (*vpp)->v_type = vtype;
159
160 return (error);
161 }
162 }
163
164 /*
165 * otherwise lock the array while we call getnewvnode
166 * since that can block.
167 */
168 if (fdcache_lock & FDL_LOCKED) {
169 fdcache_lock |= FDL_WANT;
170 sleep((caddr_t) &fdcache_lock, PINOD);
171 goto loop;
172 }
173 fdcache_lock |= FDL_LOCKED;
174
175 MALLOC(fd, void *, sizeof(struct fdescnode), M_TEMP, M_WAITOK);
176
177 vfsp.vnfs_mp = mp;
178 vfsp.vnfs_vtype = vtype;
179 vfsp.vnfs_str = "fdesc";
180 vfsp.vnfs_dvp = 0;
181 vfsp.vnfs_fsnode = fd;
182 vfsp.vnfs_cnp = 0;
183 vfsp.vnfs_vops = fdesc_vnodeop_p;
184 vfsp.vnfs_rdev = 0;
185 vfsp.vnfs_filesize = 0;
186 vfsp.vnfs_flags = VNFS_NOCACHE | VNFS_CANTCACHE;
187 vfsp.vnfs_marksystem = 0;
188 if (ftype == Froot)
189 vfsp.vnfs_markroot = 1;
190 else
191 vfsp.vnfs_markroot = 0;
192
193 error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &vfsp, vpp);
194 if (error) {
195 FREE(fd, M_TEMP);
196 goto out;
197 }
198 (*vpp)->v_tag = VT_FDESC;
199 fd->fd_vnode = *vpp;
200 fd->fd_type = ftype;
201 fd->fd_fd = -1;
202 fd->fd_link = 0;
203 fd->fd_ix = ix;
204 LIST_INSERT_HEAD(fc, fd, fd_hash);
205
206 out:
207 fdcache_lock &= ~FDL_LOCKED;
208
209 if (fdcache_lock & FDL_WANT) {
210 fdcache_lock &= ~FDL_WANT;
211 wakeup((caddr_t) &fdcache_lock);
212 }
213
214 return (error);
215 }
216
217 /*
218 * vp is the current namei directory
219 * ndp is the name to locate in that directory...
220 */
221 int
222 fdesc_lookup(ap)
223 struct vnop_lookup_args /* {
224 struct vnode * a_dvp;
225 struct vnode ** a_vpp;
226 struct componentname * a_cnp;
227 vfs_context_t a_context;
228 } */ *ap;
229 {
230 struct vnode **vpp = ap->a_vpp;
231 struct vnode *dvp = ap->a_dvp;
232 struct componentname *cnp = ap->a_cnp;
233 char *pname = cnp->cn_nameptr;
234 struct proc *p = vfs_context_proc(ap->a_context);
235 int numfiles = p->p_fd->fd_nfiles;
236 int fd;
237 int error;
238 struct vnode *fvp;
239 char *ln;
240
241 if (cnp->cn_namelen == 1 && *pname == '.') {
242 *vpp = dvp;
243
244 if ( (error = vnode_get(dvp)) ) {
245 return(error);
246 }
247 return (0);
248 }
249
250 switch (VTOFDESC(dvp)->fd_type) {
251 default:
252 case Flink:
253 case Fdesc:
254 /* should never happen */
255 error = ENOTDIR;
256 goto bad;
257
258 case Froot:
259 if (cnp->cn_namelen == 2 && bcmp(pname, "fd", 2) == 0) {
260 error = fdesc_allocvp(Fdevfd, FD_DEVFD, dvp->v_mount, &fvp, VDIR);
261 if (error)
262 goto bad;
263 *vpp = fvp;
264 return (0);
265 }
266
267 ln = NULL;
268 switch (cnp->cn_namelen) {
269 case 5:
270 if (bcmp(pname, "stdin", 5) == 0) {
271 ln = "fd/0";
272 fd = FD_STDIN;
273 }
274 break;
275 case 6:
276 if (bcmp(pname, "stdout", 6) == 0) {
277 ln = "fd/1";
278 fd = FD_STDOUT;
279 } else
280 if (bcmp(pname, "stderr", 6) == 0) {
281 ln = "fd/2";
282 fd = FD_STDERR;
283 }
284 break;
285 }
286
287 if (ln) {
288 error = fdesc_allocvp(Flink, fd, dvp->v_mount, &fvp, VLNK);
289 if (error)
290 goto bad;
291 VTOFDESC(fvp)->fd_link = ln;
292 *vpp = fvp;
293 return (0);
294 } else {
295 error = ENOENT;
296 goto bad;
297 }
298
299 /* FALL THROUGH */
300
301 case Fdevfd:
302 if (cnp->cn_namelen == 2 && bcmp(pname, "..", 2) == 0) {
303 if ((error = fdesc_root(dvp->v_mount, vpp, ap->a_context)))
304 goto bad;
305 return (0);
306 }
307
308 fd = 0;
309 while (*pname >= '0' && *pname <= '9') {
310 fd = 10 * fd + *pname++ - '0';
311 if (fd >= numfiles)
312 break;
313 }
314
315 if (*pname != '\0') {
316 error = ENOENT;
317 goto bad;
318 }
319
320 if (fd < 0 || fd >= numfiles ||
321 *fdfile(p, fd) == NULL ||
322 (*fdflags(p, fd) & UF_RESERVED)) {
323 error = EBADF;
324 goto bad;
325 }
326
327 error = fdesc_allocvp(Fdesc, FD_DESC+fd, dvp->v_mount, &fvp, VNON);
328 if (error)
329 goto bad;
330 VTOFDESC(fvp)->fd_fd = fd;
331 *vpp = fvp;
332 return (0);
333 }
334
335 bad:;
336 *vpp = NULL;
337 return (error);
338 }
339
340 int
341 fdesc_open(ap)
342 struct vnop_open_args /* {
343 struct vnode *a_vp;
344 int a_mode;
345 vfs_context_t a_context;
346 } */ *ap;
347 {
348 struct vnode *vp = ap->a_vp;
349 struct proc *p = vfs_context_proc(ap->a_context);
350 int error = 0;
351
352 switch (VTOFDESC(vp)->fd_type) {
353 case Fdesc:
354 /*
355 * XXX Kludge: set p->p_dupfd to contain the value of the
356 * the file descriptor being sought for duplication. The error
357 * return ensures that the vnode for this device will be
358 * released by vn_open. Open will detect this special error and
359 * take the actions in dupfdopen. Other callers of vn_open or
360 * vnop_open will simply report the error.
361 */
362 p->p_dupfd = VTOFDESC(vp)->fd_fd; /* XXX */
363 error = ENODEV;
364 break;
365
366 }
367
368 return (error);
369 }
370
371 static int
372 fdesc_attr(int fd, struct vnode_attr *vap, vfs_context_t a_context)
373 {
374 struct fileproc *fp;
375 struct proc *p = vfs_context_proc(a_context);
376 struct stat stb;
377 int error;
378
379 if ((error = fp_lookup(p, fd, &fp, 0)))
380 return (error);
381 switch (fp->f_fglob->fg_type) {
382 case DTYPE_VNODE:
383 if(error = vnode_getwithref((struct vnode *) fp->f_fglob->fg_data)) {
384 break;
385 }
386 if ((error = vnode_authorize((struct vnode *)fp->f_fglob->fg_data,
387 NULL,
388 KAUTH_VNODE_READ_ATTRIBUTES | KAUTH_VNODE_READ_SECURITY,
389 a_context)) == 0)
390 error = vnode_getattr((struct vnode *)fp->f_fglob->fg_data, vap, a_context);
391 if (error == 0 && vap->va_type == VDIR) {
392 /*
393 * directories can cause loops in the namespace,
394 * so turn off the 'x' bits to avoid trouble.
395 *
396 * XXX ACLs break this, of course
397 */
398 vap->va_mode &= ~((VEXEC)|(VEXEC>>3)|(VEXEC>>6));
399 }
400 (void)vnode_put((struct vnode *) fp->f_fglob->fg_data);
401 break;
402
403 case DTYPE_SOCKET:
404 case DTYPE_PIPE:
405 if (fp->f_fglob->fg_type == DTYPE_SOCKET)
406 error = soo_stat((struct socket *)fp->f_fglob->fg_data, &stb);
407 else
408 error = pipe_stat((struct socket *)fp->f_fglob->fg_data, &stb);
409
410 if (error == 0) {
411 if (fp->f_fglob->fg_type == DTYPE_SOCKET)
412 VATTR_RETURN(vap, va_type, VSOCK);
413 else
414 VATTR_RETURN(vap, va_type, VFIFO);
415
416 VATTR_RETURN(vap, va_mode, stb.st_mode);
417 VATTR_RETURN(vap, va_nlink, stb.st_nlink);
418 VATTR_RETURN(vap, va_uid, stb.st_uid);
419 VATTR_RETURN(vap, va_gid, stb.st_gid);
420 VATTR_RETURN(vap, va_fsid, stb.st_dev);
421 VATTR_RETURN(vap, va_fileid, stb.st_ino);
422 VATTR_RETURN(vap, va_data_size, stb.st_size);
423 VATTR_RETURN(vap, va_access_time, stb.st_atimespec);
424 VATTR_RETURN(vap, va_modify_time, stb.st_mtimespec);
425 VATTR_RETURN(vap, va_change_time, stb.st_ctimespec);
426 VATTR_RETURN(vap, va_gen, stb.st_gen);
427 VATTR_RETURN(vap, va_flags, stb.st_flags);
428 VATTR_RETURN(vap, va_rdev, stb.st_rdev);
429 VATTR_RETURN(vap, va_total_alloc, stb.st_blocks * stb.st_blksize);
430 VATTR_RETURN(vap, va_acl, NULL);
431 }
432 break;
433
434 default:
435 error = EBADF;
436 }
437
438 fp_drop(p, fd, fp, 0);
439 return (error);
440 }
441
442 int
443 fdesc_getattr(ap)
444 struct vnop_getattr_args /* {
445 struct vnode *a_vp;
446 struct vnode_attr *a_vap;
447 vfs_context_t a_context;
448 } */ *ap;
449 {
450 struct vnode *vp = ap->a_vp;
451 struct vnode_attr *vap = ap->a_vap;
452 unsigned fd;
453 int error = 0;
454 struct timespec ts;
455
456 switch (VTOFDESC(vp)->fd_type) {
457 case Froot:
458 case Fdevfd:
459 case Flink:
460 VATTR_RETURN(vap, va_fileid, VTOFDESC(vp)->fd_ix);
461 VATTR_RETURN(vap, va_uid, 0);
462 VATTR_RETURN(vap, va_gid, 0);
463 VATTR_RETURN(vap, va_fsid, vp->v_mount->mnt_vfsstat.f_fsid.val[0]);
464 VATTR_RETURN(vap, va_iosize, DEV_BSIZE);
465 ts.tv_sec = boottime_sec();
466 ts.tv_nsec = 0;
467 VATTR_RETURN(vap, va_access_time, ts);
468 VATTR_RETURN(vap, va_modify_time, ts);
469 VATTR_RETURN(vap, va_change_time, ts);
470 VATTR_RETURN(vap, va_gen, 0);
471 VATTR_RETURN(vap, va_flags, 0);
472 VATTR_RETURN(vap, va_rdev, 0);
473 VATTR_RETURN(vap, va_acl, NULL);
474
475 switch (VTOFDESC(vp)->fd_type) {
476 case Flink:
477 VATTR_RETURN(vap, va_mode, S_IRUSR|S_IRGRP|S_IROTH);
478 VATTR_RETURN(vap, va_type, VLNK); /* not strictly required */
479 VATTR_RETURN(vap, va_nlink, 1);
480 VATTR_RETURN(vap, va_data_size, strlen(VTOFDESC(vp)->fd_link));
481 break;
482
483 default:
484 VATTR_RETURN(vap, va_mode, S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
485 VATTR_RETURN(vap, va_type, VDIR);
486 VATTR_RETURN(vap, va_nlink, 2);
487 VATTR_RETURN(vap, va_data_size, DEV_BSIZE);
488 break;
489 }
490 break;
491
492 case Fdesc:
493 fd = VTOFDESC(vp)->fd_fd;
494 error = fdesc_attr(fd, vap, ap->a_context);
495 break;
496
497 default:
498 return (EBADF);
499 break;
500 }
501
502 if (error == 0) {
503 vp->v_type = vap->va_type;
504 }
505
506 return (error);
507 }
508
509 int
510 fdesc_setattr(ap)
511 struct vnop_setattr_args /* {
512 struct vnode *a_vp;
513 struct vnode_attr *a_vap;
514 vfs_context_t a_context;
515 } */ *ap;
516 {
517 struct fileproc *fp;
518 unsigned fd;
519 int error;
520 struct proc * p = vfs_context_proc(ap->a_context);
521
522 /*
523 * Can't mess with the root vnode
524 */
525 switch (VTOFDESC(ap->a_vp)->fd_type) {
526 case Fdesc:
527 break;
528
529 default:
530 return (EACCES);
531 }
532
533 fd = VTOFDESC(ap->a_vp)->fd_fd;
534 if ((error = fp_lookup(vfs_context_proc(ap->a_context), fd, &fp, 0)))
535 return (error);
536
537 /*
538 * Can setattr the underlying vnode, but not sockets!
539 */
540 switch (fp->f_fglob->fg_type) {
541 case DTYPE_VNODE:
542 {
543 if ((error = vnode_getwithref((struct vnode *) fp->f_fglob->fg_data)) != 0)
544 break;
545 error = vnode_setattr((struct vnode *) fp->f_fglob->fg_data, ap->a_vap, ap->a_context);
546 (void)vnode_put((struct vnode *) fp->f_fglob->fg_data);
547 break;
548 }
549
550 case DTYPE_SOCKET:
551 case DTYPE_PIPE:
552 error = 0;
553 break;
554
555 default:
556 kprintf("fp->f_fglob->fg_type = %d\n", fp->f_fglob->fg_type);
557 error = EBADF;
558 break;
559 }
560
561 fp_drop(p, fd, fp, 0);
562 return (error);
563 }
564
565 #define UIO_MX 16
566
567 static struct dirtmp {
568 u_long d_fileno;
569 u_short d_reclen;
570 u_short d_namlen;
571 char d_name[8];
572 } rootent[] = {
573 { FD_DEVFD, UIO_MX, 2, "fd" },
574 { FD_STDIN, UIO_MX, 5, "stdin" },
575 { FD_STDOUT, UIO_MX, 6, "stdout" },
576 { FD_STDERR, UIO_MX, 6, "stderr" },
577 { 0, 0, 0, "" }
578 };
579
580 int
581 fdesc_readdir(ap)
582 struct vnop_readdir_args /* {
583 struct vnode *a_vp;
584 struct uio *a_uio;
585 int a_flags;
586 int *a_eofflag;
587 int *a_numdirent;
588 vfs_context_t a_context;
589 } */ *ap;
590 {
591 struct uio *uio = ap->a_uio;
592 struct proc *p = current_proc();
593 int i, error;
594
595 /*
596 * We don't allow exporting fdesc mounts, and currently local
597 * requests do not need cookies.
598 */
599 if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF))
600 return (EINVAL);
601
602 switch (VTOFDESC(ap->a_vp)->fd_type) {
603 case Fdesc:
604 return (ENOTDIR);
605
606 default:
607 break;
608 }
609
610 if (VTOFDESC(ap->a_vp)->fd_type == Froot) {
611 struct dirent d;
612 struct dirent *dp = &d;
613 struct dirtmp *dt;
614 int fd;
615
616 i = uio->uio_offset / UIO_MX;
617 error = 0;
618
619 while (uio_resid(uio) > 0) {
620 dt = &rootent[i];
621 if (dt->d_fileno == 0) {
622 /**eofflagp = 1;*/
623 break;
624 }
625 i++;
626
627 switch (dt->d_fileno) {
628 case FD_STDIN:
629 case FD_STDOUT:
630 case FD_STDERR:
631 fd = dt->d_fileno - FD_STDIN;
632 if (fd >= p->p_fd->fd_nfiles)
633 continue;
634 if (*fdfile(p, fd) == NULL &&
635 !(*fdflags(p, fd) &
636 UF_RESERVED))
637 continue;
638 break;
639 }
640 bzero((caddr_t) dp, UIO_MX);
641 dp->d_fileno = dt->d_fileno;
642 dp->d_namlen = dt->d_namlen;
643 dp->d_type = DT_UNKNOWN;
644 dp->d_reclen = dt->d_reclen;
645 bcopy(dt->d_name, dp->d_name, dp->d_namlen+1);
646 error = uiomove((caddr_t) dp, UIO_MX, uio);
647 if (error)
648 break;
649 }
650 uio->uio_offset = i * UIO_MX;
651 return (error);
652 }
653
654 i = uio->uio_offset / UIO_MX;
655 error = 0;
656 while (uio_resid(uio) > 0) {
657 if (i >= p->p_fd->fd_nfiles)
658 break;
659
660 if (*fdfile(p, i) != NULL && !(*fdflags(p, i) & UF_RESERVED)) {
661 struct dirent d;
662 struct dirent *dp = &d;
663
664 bzero((caddr_t) dp, UIO_MX);
665
666 dp->d_namlen = sprintf(dp->d_name, "%d", i);
667 dp->d_reclen = UIO_MX;
668 dp->d_type = DT_UNKNOWN;
669 dp->d_fileno = i + FD_STDIN;
670 /*
671 * And ship to userland
672 */
673 error = uiomove((caddr_t) dp, UIO_MX, uio);
674 if (error)
675 break;
676 }
677 i++;
678 }
679
680 uio->uio_offset = i * UIO_MX;
681 return (error);
682 }
683
684 int
685 fdesc_readlink(ap)
686 struct vnop_readlink_args /* {
687 struct vnode *a_vp;
688 struct uio *a_uio;
689 vfs_context_t a_context;
690 } */ *ap;
691 {
692 struct vnode *vp = ap->a_vp;
693 int error;
694
695 if (vp->v_type != VLNK)
696 return (EPERM);
697
698 if (VTOFDESC(vp)->fd_type == Flink) {
699 char *ln = VTOFDESC(vp)->fd_link;
700 error = uiomove(ln, strlen(ln), ap->a_uio);
701 } else {
702 error = ENOTSUP;
703 }
704
705 return (error);
706 }
707
708 int
709 fdesc_read(__unused struct vnop_read_args *ap)
710 {
711
712 return (ENOTSUP);
713 }
714
715 int
716 fdesc_write(__unused struct vnop_write_args *ap)
717 {
718 return (ENOTSUP);
719 }
720
721 int
722 fdesc_ioctl(__unused struct vnop_ioctl_args *ap)
723 {
724 return (ENOTSUP);
725 }
726
727 int
728 fdesc_select(__unused struct vnop_select_args *ap)
729 {
730 return (ENOTSUP);
731 }
732
733 int
734 fdesc_inactive(ap)
735 struct vnop_inactive_args /* {
736 struct vnode *a_vp;
737 vfs_context_t a_context;
738 } */ *ap;
739 {
740 struct vnode *vp = ap->a_vp;
741
742 /*
743 * Clear out the v_type field to avoid
744 * nasty things happening in vgone().
745 */
746 vp->v_type = VNON;
747 return (0);
748 }
749
750 int
751 fdesc_reclaim(ap)
752 struct vnop_reclaim_args /* {
753 struct vnode *a_vp;
754 vfs_context_t a_context;
755 } */ *ap;
756 {
757 struct vnode *vp = ap->a_vp;
758 struct fdescnode *fd = VTOFDESC(vp);
759
760 LIST_REMOVE(fd, fd_hash);
761 FREE(vp->v_data, M_TEMP);
762 vp->v_data = 0;
763
764 return (0);
765 }
766
767 /*
768 * Return POSIX pathconf information applicable to special devices.
769 */
770 int
771 fdesc_pathconf(ap)
772 struct vnop_pathconf_args /* {
773 struct vnode *a_vp;
774 int a_name;
775 int *a_retval;
776 vfs_context_t a_context;
777 } */ *ap;
778 {
779
780 switch (ap->a_name) {
781 case _PC_LINK_MAX:
782 *ap->a_retval = LINK_MAX;
783 return (0);
784 case _PC_MAX_CANON:
785 *ap->a_retval = MAX_CANON;
786 return (0);
787 case _PC_MAX_INPUT:
788 *ap->a_retval = MAX_INPUT;
789 return (0);
790 case _PC_PIPE_BUF:
791 *ap->a_retval = PIPE_BUF;
792 return (0);
793 case _PC_CHOWN_RESTRICTED:
794 *ap->a_retval = 1;
795 return (0);
796 case _PC_VDISABLE:
797 *ap->a_retval = _POSIX_VDISABLE;
798 return (0);
799 default:
800 return (EINVAL);
801 }
802 /* NOTREACHED */
803 }
804
805
806 /*void*/
807 int
808 fdesc_vfree(__unused struct vnop_vfree_args *ap)
809 {
810
811 return (0);
812 }
813
814 /*
815 * /dev/fd "should never get here" operation
816 */
817 int
818 fdesc_badop(void)
819 {
820
821 return (ENOTSUP);
822 /* NOTREACHED */
823 }
824
825 #define VOPFUNC int (*)(void *)
826
827 #define fdesc_create (int (*) (struct vnop_create_args *))eopnotsupp
828 #define fdesc_mknod (int (*) (struct vnop_mknod_args *))eopnotsupp
829 #define fdesc_close (int (*) (struct vnop_close_args *))nullop
830 #define fdesc_access (int (*) (struct vnop_access_args *))nullop
831 #define fdesc_mmap (int (*) (struct vnop_mmap_args *))eopnotsupp
832 #define fdesc_revoke nop_revoke
833 #define fdesc_fsync (int (*) (struct vnop_fsync_args *))nullop
834 #define fdesc_remove (int (*) (struct vnop_remove_args *))eopnotsupp
835 #define fdesc_link (int (*) (struct vnop_link_args *))eopnotsupp
836 #define fdesc_rename (int (*) (struct vnop_rename_args *))eopnotsupp
837 #define fdesc_mkdir (int (*) (struct vnop_mkdir_args *))eopnotsupp
838 #define fdesc_rmdir (int (*) (struct vnop_rmdir_args *))eopnotsupp
839 #define fdesc_symlink (int (*) (struct vnop_symlink_args *))eopnotsupp
840 #define fdesc_strategy (int (*) (struct vnop_strategy_args *))fdesc_badop
841 #define fdesc_advlock (int (*) (struct vnop_advlock_args *))eopnotsupp
842 #define fdesc_bwrite (int (*) (struct vnop_bwrite_args *))eopnotsupp
843 #define fdesc_blktooff (int (*) (struct vnop_blktooff_args *))eopnotsupp
844 #define fdesc_offtoblk (int (*) (struct vnop_offtoblk_args *))eopnotsupp
845 #define fdesc_blockmap (int (*) (struct vnop_blockmap_args *))eopnotsupp
846
847 int (**fdesc_vnodeop_p)(void *);
848 struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = {
849 { &vnop_default_desc, (VOPFUNC)vn_default_error },
850 { &vnop_lookup_desc, (VOPFUNC)fdesc_lookup }, /* lookup */
851 { &vnop_create_desc, (VOPFUNC)fdesc_create }, /* create */
852 { &vnop_mknod_desc, (VOPFUNC)fdesc_mknod }, /* mknod */
853 { &vnop_open_desc, (VOPFUNC)fdesc_open }, /* open */
854 { &vnop_close_desc, (VOPFUNC)fdesc_close }, /* close */
855 { &vnop_access_desc, (VOPFUNC)fdesc_access }, /* access */
856 { &vnop_getattr_desc, (VOPFUNC)fdesc_getattr }, /* getattr */
857 { &vnop_setattr_desc, (VOPFUNC)fdesc_setattr }, /* setattr */
858 { &vnop_read_desc, (VOPFUNC)fdesc_read }, /* read */
859 { &vnop_write_desc, (VOPFUNC)fdesc_write }, /* write */
860 { &vnop_ioctl_desc, (VOPFUNC)fdesc_ioctl }, /* ioctl */
861 { &vnop_select_desc, (VOPFUNC)fdesc_select }, /* select */
862 { &vnop_revoke_desc, (VOPFUNC)fdesc_revoke }, /* revoke */
863 { &vnop_mmap_desc, (VOPFUNC)fdesc_mmap }, /* mmap */
864 { &vnop_fsync_desc, (VOPFUNC)fdesc_fsync }, /* fsync */
865 { &vnop_remove_desc, (VOPFUNC)fdesc_remove }, /* remove */
866 { &vnop_link_desc, (VOPFUNC)fdesc_link }, /* link */
867 { &vnop_rename_desc, (VOPFUNC)fdesc_rename }, /* rename */
868 { &vnop_mkdir_desc, (VOPFUNC)fdesc_mkdir }, /* mkdir */
869 { &vnop_rmdir_desc, (VOPFUNC)fdesc_rmdir }, /* rmdir */
870 { &vnop_symlink_desc, (VOPFUNC)fdesc_symlink }, /* symlink */
871 { &vnop_readdir_desc, (VOPFUNC)fdesc_readdir }, /* readdir */
872 { &vnop_readlink_desc, (VOPFUNC)fdesc_readlink },/* readlink */
873 { &vnop_inactive_desc, (VOPFUNC)fdesc_inactive },/* inactive */
874 { &vnop_reclaim_desc, (VOPFUNC)fdesc_reclaim }, /* reclaim */
875 { &vnop_strategy_desc, (VOPFUNC)fdesc_strategy }, /* strategy */
876 { &vnop_pathconf_desc, (VOPFUNC)fdesc_pathconf }, /* pathconf */
877 { &vnop_advlock_desc, (VOPFUNC)fdesc_advlock }, /* advlock */
878 { &vnop_bwrite_desc, (VOPFUNC)fdesc_bwrite }, /* bwrite */
879 { &vnop_pagein_desc, (VOPFUNC)err_pagein }, /* pagein */
880 { &vnop_pageout_desc, (VOPFUNC)err_pageout }, /* pageout */
881 { &vnop_copyfile_desc, (VOPFUNC)err_copyfile }, /* Copyfile */
882 { &vnop_blktooff_desc, (VOPFUNC)fdesc_blktooff }, /* blktooff */
883 { &vnop_blktooff_desc, (VOPFUNC)fdesc_offtoblk }, /* offtoblk */
884 { &vnop_blockmap_desc, (VOPFUNC)fdesc_blockmap }, /* blockmap */
885 { (struct vnodeop_desc*)NULL, (VOPFUNC)NULL }
886 };
887 struct vnodeopv_desc fdesc_vnodeop_opv_desc =
888 { &fdesc_vnodeop_p, fdesc_vnodeop_entries };