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