fdesc_vnops.c revision 1.31 1 /* $NetBSD: fdesc_vnops.c,v 1.31 1996/02/13 13:12:52 mycroft Exp $ */
2
3 /*
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software donated to Berkeley by
8 * Jan-Simon Pendry.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)fdesc_vnops.c 8.12 (Berkeley) 8/20/94
39 *
40 * #Id: fdesc_vnops.c,v 1.12 1993/04/06 16:17:17 jsp Exp #
41 */
42
43 /*
44 * /dev/fd Filesystem
45 */
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/types.h>
50 #include <sys/time.h>
51 #include <sys/proc.h>
52 #include <sys/kernel.h> /* boottime */
53 #include <sys/resourcevar.h>
54 #include <sys/socketvar.h>
55 #include <sys/filedesc.h>
56 #include <sys/vnode.h>
57 #include <sys/malloc.h>
58 #include <sys/file.h>
59 #include <sys/stat.h>
60 #include <sys/mount.h>
61 #include <sys/namei.h>
62 #include <sys/buf.h>
63 #include <sys/dirent.h>
64 #include <sys/tty.h>
65 #include <miscfs/fdesc/fdesc.h>
66
67 #define cttyvp(p) ((p)->p_flag & P_CONTROLT ? (p)->p_session->s_ttyvp : NULL)
68
69 #define FDL_WANT 0x01
70 #define FDL_LOCKED 0x02
71 static int fdcache_lock;
72
73 dev_t devctty;
74
75 #if (FD_STDIN != FD_STDOUT-1) || (FD_STDOUT != FD_STDERR-1)
76 FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2
77 #endif
78
79 #define NFDCACHE 4
80
81 #define FD_NHASH(ix) \
82 (&fdhashtbl[(ix) & fdhash])
83 LIST_HEAD(fdhashhead, fdescnode) *fdhashtbl;
84 u_long fdhash;
85
86 int fdesc_badop __P((void *));
87 int fdesc_enotsupp __P((void *));
88
89 int fdesc_lookup __P((void *));
90 #define fdesc_create fdesc_enotsupp
91 #define fdesc_mknod fdesc_enotsupp
92 int fdesc_open __P((void *));
93 #define fdesc_close nullop
94 #define fdesc_access nullop
95 int fdesc_getattr __P((void *));
96 int fdesc_setattr __P((void *));
97 int fdesc_read __P((void *));
98 int fdesc_write __P((void *));
99 int fdesc_ioctl __P((void *));
100 int fdesc_select __P((void *));
101 #define fdesc_mmap fdesc_enotsupp
102 #define fdesc_fsync nullop
103 #define fdesc_seek nullop
104 #define fdesc_remove fdesc_enotsupp
105 int fdesc_link __P((void *));
106 #define fdesc_rename fdesc_enotsupp
107 #define fdesc_mkdir fdesc_enotsupp
108 #define fdesc_rmdir fdesc_enotsupp
109 int fdesc_symlink __P((void *));
110 int fdesc_readdir __P((void *));
111 int fdesc_readlink __P((void *));
112 int fdesc_abortop __P((void *));
113 int fdesc_inactive __P((void *));
114 int fdesc_reclaim __P((void *));
115 #define fdesc_lock nullop
116 #define fdesc_unlock nullop
117 #define fdesc_bmap fdesc_badop
118 #define fdesc_strategy fdesc_badop
119 int fdesc_print __P((void *));
120 int fdesc_pathconf __P((void *));
121 #define fdesc_islocked nullop
122 #define fdesc_advlock fdesc_enotsupp
123 #define fdesc_blkatoff fdesc_enotsupp
124 #define fdesc_valloc fdesc_enotsupp
125 int fdesc_vfree __P((void *));
126 #define fdesc_truncate fdesc_enotsupp
127 #define fdesc_update fdesc_enotsupp
128 #define fdesc_bwrite fdesc_enotsupp
129
130 static int fdesc_attr __P((int, struct vattr *, struct ucred *, struct proc *));
131
132 int (**fdesc_vnodeop_p) __P((void *));
133 struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = {
134 { &vop_default_desc, vn_default_error },
135 { &vop_lookup_desc, fdesc_lookup }, /* lookup */
136 { &vop_create_desc, fdesc_create }, /* create */
137 { &vop_mknod_desc, fdesc_mknod }, /* mknod */
138 { &vop_open_desc, fdesc_open }, /* open */
139 { &vop_close_desc, fdesc_close }, /* close */
140 { &vop_access_desc, fdesc_access }, /* access */
141 { &vop_getattr_desc, fdesc_getattr }, /* getattr */
142 { &vop_setattr_desc, fdesc_setattr }, /* setattr */
143 { &vop_read_desc, fdesc_read }, /* read */
144 { &vop_write_desc, fdesc_write }, /* write */
145 { &vop_ioctl_desc, fdesc_ioctl }, /* ioctl */
146 { &vop_select_desc, fdesc_select }, /* select */
147 { &vop_mmap_desc, fdesc_mmap }, /* mmap */
148 { &vop_fsync_desc, fdesc_fsync }, /* fsync */
149 { &vop_seek_desc, fdesc_seek }, /* seek */
150 { &vop_remove_desc, fdesc_remove }, /* remove */
151 { &vop_link_desc, fdesc_link }, /* link */
152 { &vop_rename_desc, fdesc_rename }, /* rename */
153 { &vop_mkdir_desc, fdesc_mkdir }, /* mkdir */
154 { &vop_rmdir_desc, fdesc_rmdir }, /* rmdir */
155 { &vop_symlink_desc, fdesc_symlink }, /* symlink */
156 { &vop_readdir_desc, fdesc_readdir }, /* readdir */
157 { &vop_readlink_desc, fdesc_readlink }, /* readlink */
158 { &vop_abortop_desc, fdesc_abortop }, /* abortop */
159 { &vop_inactive_desc, fdesc_inactive }, /* inactive */
160 { &vop_reclaim_desc, fdesc_reclaim }, /* reclaim */
161 { &vop_lock_desc, fdesc_lock }, /* lock */
162 { &vop_unlock_desc, fdesc_unlock }, /* unlock */
163 { &vop_bmap_desc, fdesc_bmap }, /* bmap */
164 { &vop_strategy_desc, fdesc_strategy }, /* strategy */
165 { &vop_print_desc, fdesc_print }, /* print */
166 { &vop_islocked_desc, fdesc_islocked }, /* islocked */
167 { &vop_pathconf_desc, fdesc_pathconf }, /* pathconf */
168 { &vop_advlock_desc, fdesc_advlock }, /* advlock */
169 { &vop_blkatoff_desc, fdesc_blkatoff }, /* blkatoff */
170 { &vop_valloc_desc, fdesc_valloc }, /* valloc */
171 { &vop_vfree_desc, fdesc_vfree }, /* vfree */
172 { &vop_truncate_desc, fdesc_truncate }, /* truncate */
173 { &vop_update_desc, fdesc_update }, /* update */
174 { &vop_bwrite_desc, fdesc_bwrite }, /* bwrite */
175 { (struct vnodeop_desc*)NULL, (int(*) __P((void *)))NULL }
176 };
177
178 struct vnodeopv_desc fdesc_vnodeop_opv_desc =
179 { &fdesc_vnodeop_p, fdesc_vnodeop_entries };
180
181 /*
182 * Initialise cache headers
183 */
184 void
185 fdesc_init()
186 {
187
188 devctty = makedev(nchrdev, 0);
189 fdhashtbl = hashinit(NFDCACHE, M_CACHE, &fdhash);
190 }
191
192 int
193 fdesc_allocvp(ftype, ix, mp, vpp)
194 fdntype ftype;
195 int ix;
196 struct mount *mp;
197 struct vnode **vpp;
198 {
199 struct fdhashhead *fc;
200 struct fdescnode *fd;
201 int error = 0;
202
203 fc = FD_NHASH(ix);
204 loop:
205 for (fd = fc->lh_first; fd != 0; fd = fd->fd_hash.le_next) {
206 if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) {
207 if (vget(fd->fd_vnode, 0))
208 goto loop;
209 *vpp = fd->fd_vnode;
210 return (error);
211 }
212 }
213
214 /*
215 * otherwise lock the array while we call getnewvnode
216 * since that can block.
217 */
218 if (fdcache_lock & FDL_LOCKED) {
219 fdcache_lock |= FDL_WANT;
220 sleep((caddr_t) &fdcache_lock, PINOD);
221 goto loop;
222 }
223 fdcache_lock |= FDL_LOCKED;
224
225 error = getnewvnode(VT_FDESC, mp, fdesc_vnodeop_p, vpp);
226 if (error)
227 goto out;
228 MALLOC(fd, void *, sizeof(struct fdescnode), M_TEMP, M_WAITOK);
229 (*vpp)->v_data = fd;
230 fd->fd_vnode = *vpp;
231 fd->fd_type = ftype;
232 fd->fd_fd = -1;
233 fd->fd_link = 0;
234 fd->fd_ix = ix;
235 LIST_INSERT_HEAD(fc, fd, fd_hash);
236
237 out:;
238 fdcache_lock &= ~FDL_LOCKED;
239
240 if (fdcache_lock & FDL_WANT) {
241 fdcache_lock &= ~FDL_WANT;
242 wakeup((caddr_t) &fdcache_lock);
243 }
244
245 return (error);
246 }
247
248 /*
249 * vp is the current namei directory
250 * ndp is the name to locate in that directory...
251 */
252 int
253 fdesc_lookup(v)
254 void *v;
255 {
256 struct vop_lookup_args /* {
257 struct vnode * a_dvp;
258 struct vnode ** a_vpp;
259 struct componentname * a_cnp;
260 } */ *ap = v;
261 struct vnode **vpp = ap->a_vpp;
262 struct vnode *dvp = ap->a_dvp;
263 char *pname;
264 struct proc *p;
265 int nfiles;
266 unsigned fd = 0;
267 int error;
268 struct vnode *fvp;
269 char *ln;
270
271 pname = ap->a_cnp->cn_nameptr;
272 if (ap->a_cnp->cn_namelen == 1 && *pname == '.') {
273 *vpp = dvp;
274 VREF(dvp);
275 VOP_LOCK(dvp);
276 return (0);
277 }
278
279 p = ap->a_cnp->cn_proc;
280 nfiles = p->p_fd->fd_nfiles;
281
282 switch (VTOFDESC(dvp)->fd_type) {
283 default:
284 case Flink:
285 case Fdesc:
286 case Fctty:
287 error = ENOTDIR;
288 goto bad;
289
290 case Froot:
291 if (ap->a_cnp->cn_namelen == 2 && bcmp(pname, "fd", 2) == 0) {
292 error = fdesc_allocvp(Fdevfd, FD_DEVFD, dvp->v_mount, &fvp);
293 if (error)
294 goto bad;
295 *vpp = fvp;
296 fvp->v_type = VDIR;
297 VOP_LOCK(fvp);
298 return (0);
299 }
300
301 if (ap->a_cnp->cn_namelen == 3 && bcmp(pname, "tty", 3) == 0) {
302 struct vnode *ttyvp = cttyvp(p);
303 if (ttyvp == NULL) {
304 error = ENXIO;
305 goto bad;
306 }
307 error = fdesc_allocvp(Fctty, FD_CTTY, dvp->v_mount, &fvp);
308 if (error)
309 goto bad;
310 *vpp = fvp;
311 fvp->v_type = VFIFO;
312 VOP_LOCK(fvp);
313 return (0);
314 }
315
316 ln = 0;
317 switch (ap->a_cnp->cn_namelen) {
318 case 5:
319 if (bcmp(pname, "stdin", 5) == 0) {
320 ln = "fd/0";
321 fd = FD_STDIN;
322 }
323 break;
324 case 6:
325 if (bcmp(pname, "stdout", 6) == 0) {
326 ln = "fd/1";
327 fd = FD_STDOUT;
328 } else
329 if (bcmp(pname, "stderr", 6) == 0) {
330 ln = "fd/2";
331 fd = FD_STDERR;
332 }
333 break;
334 }
335
336 if (ln) {
337 error = fdesc_allocvp(Flink, fd, dvp->v_mount, &fvp);
338 if (error)
339 goto bad;
340 VTOFDESC(fvp)->fd_link = ln;
341 *vpp = fvp;
342 fvp->v_type = VLNK;
343 VOP_LOCK(fvp);
344 return (0);
345 } else {
346 error = ENOENT;
347 goto bad;
348 }
349
350 /* FALL THROUGH */
351
352 case Fdevfd:
353 if (ap->a_cnp->cn_namelen == 2 && bcmp(pname, "..", 2) == 0) {
354 error = fdesc_root(dvp->v_mount, vpp);
355 return (error);
356 }
357
358 fd = 0;
359 while (*pname >= '0' && *pname <= '9') {
360 fd = 10 * fd + *pname++ - '0';
361 if (fd >= nfiles)
362 break;
363 }
364
365 if (*pname != '\0') {
366 error = ENOENT;
367 goto bad;
368 }
369
370 if (fd >= nfiles || p->p_fd->fd_ofiles[fd] == NULL) {
371 error = EBADF;
372 goto bad;
373 }
374
375 error = fdesc_allocvp(Fdesc, FD_DESC+fd, dvp->v_mount, &fvp);
376 if (error)
377 goto bad;
378 VTOFDESC(fvp)->fd_fd = fd;
379 *vpp = fvp;
380 return (0);
381 }
382
383 bad:;
384 *vpp = NULL;
385 return (error);
386 }
387
388 int
389 fdesc_open(v)
390 void *v;
391 {
392 struct vop_open_args /* {
393 struct vnode *a_vp;
394 int a_mode;
395 struct ucred *a_cred;
396 struct proc *a_p;
397 } */ *ap = v;
398 struct vnode *vp = ap->a_vp;
399
400 switch (VTOFDESC(vp)->fd_type) {
401 case Fdesc:
402 /*
403 * XXX Kludge: set p->p_dupfd to contain the value of the
404 * the file descriptor being sought for duplication. The error
405 * return ensures that the vnode for this device will be
406 * released by vn_open. Open will detect this special error and
407 * take the actions in dupfdopen. Other callers of vn_open or
408 * VOP_OPEN will simply report the error.
409 */
410 ap->a_p->p_dupfd = VTOFDESC(vp)->fd_fd; /* XXX */
411 return (ENODEV);
412
413 case Fctty:
414 return (cttyopen(devctty, ap->a_mode, 0, ap->a_p));
415 case Froot:
416 case Fdevfd:
417 case Flink:
418 break;
419 }
420
421 return (0);
422 }
423
424 static int
425 fdesc_attr(fd, vap, cred, p)
426 int fd;
427 struct vattr *vap;
428 struct ucred *cred;
429 struct proc *p;
430 {
431 struct filedesc *fdp = p->p_fd;
432 struct file *fp;
433 struct stat stb;
434 int error;
435
436 if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL)
437 return (EBADF);
438
439 switch (fp->f_type) {
440 case DTYPE_VNODE:
441 error = VOP_GETATTR((struct vnode *) fp->f_data, vap, cred, p);
442 if (error == 0 && vap->va_type == VDIR) {
443 /*
444 * directories can cause loops in the namespace,
445 * so turn off the 'x' bits to avoid trouble.
446 */
447 vap->va_mode &= ~((VEXEC)|(VEXEC>>3)|(VEXEC>>6));
448 }
449 break;
450
451 case DTYPE_SOCKET:
452 error = soo_stat((struct socket *)fp->f_data, &stb);
453 if (error == 0) {
454 vattr_null(vap);
455 vap->va_type = VSOCK;
456 vap->va_mode = stb.st_mode;
457 vap->va_nlink = stb.st_nlink;
458 vap->va_uid = stb.st_uid;
459 vap->va_gid = stb.st_gid;
460 vap->va_fsid = stb.st_dev;
461 vap->va_fileid = stb.st_ino;
462 vap->va_size = stb.st_size;
463 vap->va_blocksize = stb.st_blksize;
464 vap->va_atime = stb.st_atimespec;
465 vap->va_mtime = stb.st_mtimespec;
466 vap->va_ctime = stb.st_ctimespec;
467 vap->va_gen = stb.st_gen;
468 vap->va_flags = stb.st_flags;
469 vap->va_rdev = stb.st_rdev;
470 vap->va_bytes = stb.st_blocks * stb.st_blksize;
471 }
472 break;
473
474 default:
475 panic("fdesc attr");
476 break;
477 }
478
479 return (error);
480 }
481
482 int
483 fdesc_getattr(v)
484 void *v;
485 {
486 struct vop_getattr_args /* {
487 struct vnode *a_vp;
488 struct vattr *a_vap;
489 struct ucred *a_cred;
490 struct proc *a_p;
491 } */ *ap = v;
492 struct vnode *vp = ap->a_vp;
493 struct vattr *vap = ap->a_vap;
494 unsigned fd;
495 int error = 0;
496
497 switch (VTOFDESC(vp)->fd_type) {
498 case Froot:
499 case Fdevfd:
500 case Flink:
501 case Fctty:
502 bzero((caddr_t) vap, sizeof(*vap));
503 vattr_null(vap);
504 vap->va_fileid = VTOFDESC(vp)->fd_ix;
505
506 #define R_ALL (S_IRUSR|S_IRGRP|S_IROTH)
507 #define W_ALL (S_IWUSR|S_IWGRP|S_IWOTH)
508 #define X_ALL (S_IXUSR|S_IXGRP|S_IXOTH)
509
510 switch (VTOFDESC(vp)->fd_type) {
511 case Flink:
512 vap->va_mode = R_ALL|X_ALL;
513 vap->va_type = VLNK;
514 vap->va_nlink = 1;
515 vap->va_size = strlen(VTOFDESC(vp)->fd_link);
516 break;
517
518 case Fctty:
519 vap->va_mode = R_ALL|W_ALL;
520 vap->va_type = VFIFO;
521 vap->va_nlink = 1;
522 vap->va_size = 0;
523 break;
524
525 default:
526 vap->va_mode = R_ALL|X_ALL;
527 vap->va_type = VDIR;
528 vap->va_nlink = 2;
529 vap->va_size = DEV_BSIZE;
530 break;
531 }
532 vap->va_uid = 0;
533 vap->va_gid = 0;
534 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
535 vap->va_blocksize = DEV_BSIZE;
536 vap->va_atime.tv_sec = boottime.tv_sec;
537 vap->va_atime.tv_nsec = 0;
538 vap->va_mtime = vap->va_atime;
539 vap->va_ctime = vap->va_mtime;
540 vap->va_gen = 0;
541 vap->va_flags = 0;
542 vap->va_rdev = 0;
543 vap->va_bytes = 0;
544 break;
545
546 case Fdesc:
547 fd = VTOFDESC(vp)->fd_fd;
548 error = fdesc_attr(fd, vap, ap->a_cred, ap->a_p);
549 break;
550
551 default:
552 panic("fdesc_getattr");
553 break;
554 }
555
556 if (error == 0)
557 vp->v_type = vap->va_type;
558
559 return (error);
560 }
561
562 int
563 fdesc_setattr(v)
564 void *v;
565 {
566 struct vop_setattr_args /* {
567 struct vnode *a_vp;
568 struct vattr *a_vap;
569 struct ucred *a_cred;
570 struct proc *a_p;
571 } */ *ap = v;
572 struct filedesc *fdp = ap->a_p->p_fd;
573 struct file *fp;
574 unsigned fd;
575 int error;
576
577 /*
578 * Can't mess with the root vnode
579 */
580 switch (VTOFDESC(ap->a_vp)->fd_type) {
581 case Fdesc:
582 break;
583
584 case Fctty:
585 return (0);
586
587 default:
588 return (EACCES);
589 }
590
591 fd = VTOFDESC(ap->a_vp)->fd_fd;
592 if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) {
593 return (EBADF);
594 }
595
596 /*
597 * Can setattr the underlying vnode, but not sockets!
598 */
599 switch (fp->f_type) {
600 case DTYPE_VNODE:
601 error = VOP_SETATTR((struct vnode *) fp->f_data, ap->a_vap, ap->a_cred, ap->a_p);
602 break;
603
604 case DTYPE_SOCKET:
605 error = 0;
606 break;
607
608 default:
609 panic("fdesc setattr");
610 break;
611 }
612
613 return (error);
614 }
615
616 #define UIO_MX 32
617
618 struct fdesc_target {
619 ino_t ft_fileno;
620 u_char ft_type;
621 u_char ft_namlen;
622 char *ft_name;
623 } fdesc_targets[] = {
624 /* NOTE: The name must be less than UIO_MX-16 chars in length */
625 #define N(s) sizeof(s)-1, s
626 { FD_DEVFD, DT_DIR, N("fd") },
627 { FD_STDIN, DT_LNK, N("stdin") },
628 { FD_STDOUT, DT_LNK, N("stdout") },
629 { FD_STDERR, DT_LNK, N("stderr") },
630 { FD_CTTY, DT_UNKNOWN, N("tty") },
631 #undef N
632 };
633 static int nfdesc_targets = sizeof(fdesc_targets) / sizeof(fdesc_targets[0]);
634
635 int
636 fdesc_readdir(v)
637 void *v;
638 {
639 struct vop_readdir_args /* {
640 struct vnode *a_vp;
641 struct uio *a_uio;
642 struct ucred *a_cred;
643 int *a_eofflag;
644 u_long *a_cookies;
645 int a_ncookies;
646 } */ *ap = v;
647 struct uio *uio = ap->a_uio;
648 struct dirent d;
649 struct filedesc *fdp;
650 int i;
651 int error;
652 u_long *cookies = ap->a_cookies;
653 int ncookies = ap->a_ncookies;
654
655 switch (VTOFDESC(ap->a_vp)->fd_type) {
656 case Fctty:
657 return (0);
658
659 case Fdesc:
660 return (ENOTDIR);
661
662 default:
663 break;
664 }
665
666 fdp = uio->uio_procp->p_fd;
667
668 if (uio->uio_resid < UIO_MX)
669 return (EINVAL);
670 if (uio->uio_offset < 0)
671 return (EINVAL);
672
673 error = 0;
674 i = uio->uio_offset;
675 bzero((caddr_t)&d, UIO_MX);
676 d.d_reclen = UIO_MX;
677
678 if (VTOFDESC(ap->a_vp)->fd_type == Froot) {
679 struct fdesc_target *ft;
680
681 for (ft = &fdesc_targets[i];
682 uio->uio_resid >= UIO_MX && i < nfdesc_targets; ft++, i++) {
683 switch (ft->ft_fileno) {
684 case FD_CTTY:
685 if (cttyvp(uio->uio_procp) == NULL)
686 continue;
687 break;
688
689 case FD_STDIN:
690 case FD_STDOUT:
691 case FD_STDERR:
692 if ((ft->ft_fileno - FD_STDIN) >= fdp->fd_nfiles)
693 continue;
694 if (fdp->fd_ofiles[ft->ft_fileno - FD_STDIN] == NULL)
695 continue;
696 break;
697 }
698
699 d.d_fileno = ft->ft_fileno;
700 d.d_namlen = ft->ft_namlen;
701 bcopy(ft->ft_name, d.d_name, ft->ft_namlen + 1);
702 d.d_type = ft->ft_type;
703
704 if ((error = uiomove((caddr_t)&d, UIO_MX, uio)) != 0)
705 break;
706 if (ncookies-- > 0)
707 *cookies++ = i + 1;
708 }
709 } else {
710 for (; i - 2 < fdp->fd_nfiles && uio->uio_resid >= UIO_MX;
711 i++) {
712 switch (i) {
713 case 0:
714 case 1:
715 d.d_fileno = FD_ROOT; /* XXX */
716 d.d_namlen = i + 1;
717 bcopy("..", d.d_name, d.d_namlen);
718 d.d_name[i + 1] = '\0';
719 d.d_type = DT_DIR;
720 break;
721
722 default:
723 if (fdp->fd_ofiles[i - 2] == NULL)
724 continue;
725 d.d_fileno = i - 2 + FD_STDIN;
726 d.d_namlen = sprintf(d.d_name, "%d", i - 2);
727 d.d_type = DT_UNKNOWN;
728 break;
729 }
730
731 if ((error = uiomove((caddr_t)&d, UIO_MX, uio)) != 0)
732 break;
733 if (ncookies-- > 0)
734 *cookies++ = i + 1;
735 }
736 }
737
738 uio->uio_offset = i;
739 return (error);
740 }
741
742 int
743 fdesc_readlink(v)
744 void *v;
745 {
746 struct vop_readlink_args /* {
747 struct vnode *a_vp;
748 struct uio *a_uio;
749 struct ucred *a_cred;
750 } */ *ap = v;
751 struct vnode *vp = ap->a_vp;
752 int error;
753
754 if (vp->v_type != VLNK)
755 return (EPERM);
756
757 if (VTOFDESC(vp)->fd_type == Flink) {
758 char *ln = VTOFDESC(vp)->fd_link;
759 error = uiomove(ln, strlen(ln), ap->a_uio);
760 } else {
761 error = EOPNOTSUPP;
762 }
763
764 return (error);
765 }
766
767 int
768 fdesc_read(v)
769 void *v;
770 {
771 struct vop_read_args /* {
772 struct vnode *a_vp;
773 struct uio *a_uio;
774 int a_ioflag;
775 struct ucred *a_cred;
776 } */ *ap = v;
777 int error = EOPNOTSUPP;
778
779 switch (VTOFDESC(ap->a_vp)->fd_type) {
780 case Fctty:
781 error = cttyread(devctty, ap->a_uio, ap->a_ioflag);
782 break;
783
784 default:
785 error = EOPNOTSUPP;
786 break;
787 }
788
789 return (error);
790 }
791
792 int
793 fdesc_write(v)
794 void *v;
795 {
796 struct vop_write_args /* {
797 struct vnode *a_vp;
798 struct uio *a_uio;
799 int a_ioflag;
800 struct ucred *a_cred;
801 } */ *ap = v;
802 int error = EOPNOTSUPP;
803
804 switch (VTOFDESC(ap->a_vp)->fd_type) {
805 case Fctty:
806 error = cttywrite(devctty, ap->a_uio, ap->a_ioflag);
807 break;
808
809 default:
810 error = EOPNOTSUPP;
811 break;
812 }
813
814 return (error);
815 }
816
817 int
818 fdesc_ioctl(v)
819 void *v;
820 {
821 struct vop_ioctl_args /* {
822 struct vnode *a_vp;
823 u_long a_command;
824 caddr_t a_data;
825 int a_fflag;
826 struct ucred *a_cred;
827 struct proc *a_p;
828 } */ *ap = v;
829 int error = EOPNOTSUPP;
830
831 switch (VTOFDESC(ap->a_vp)->fd_type) {
832 case Fctty:
833 error = cttyioctl(devctty, ap->a_command, ap->a_data,
834 ap->a_fflag, ap->a_p);
835 break;
836
837 default:
838 error = EOPNOTSUPP;
839 break;
840 }
841
842 return (error);
843 }
844
845 int
846 fdesc_select(v)
847 void *v;
848 {
849 struct vop_select_args /* {
850 struct vnode *a_vp;
851 int a_which;
852 int a_fflags;
853 struct ucred *a_cred;
854 struct proc *a_p;
855 } */ *ap = v;
856 int error = EOPNOTSUPP;
857
858 switch (VTOFDESC(ap->a_vp)->fd_type) {
859 case Fctty:
860 error = cttyselect(devctty, ap->a_fflags, ap->a_p);
861 break;
862
863 default:
864 error = EOPNOTSUPP;
865 break;
866 }
867
868 return (error);
869 }
870
871 int
872 fdesc_inactive(v)
873 void *v;
874 {
875 struct vop_inactive_args /* {
876 struct vnode *a_vp;
877 } */ *ap = v;
878 struct vnode *vp = ap->a_vp;
879
880 /*
881 * Clear out the v_type field to avoid
882 * nasty things happening in vgone().
883 */
884 vp->v_type = VNON;
885 return (0);
886 }
887
888 int
889 fdesc_reclaim(v)
890 void *v;
891 {
892 struct vop_reclaim_args /* {
893 struct vnode *a_vp;
894 } */ *ap = v;
895 struct vnode *vp = ap->a_vp;
896 struct fdescnode *fd = VTOFDESC(vp);
897
898 LIST_REMOVE(fd, fd_hash);
899 FREE(vp->v_data, M_TEMP);
900 vp->v_data = 0;
901
902 return (0);
903 }
904
905 /*
906 * Return POSIX pathconf information applicable to special devices.
907 */
908 int
909 fdesc_pathconf(v)
910 void *v;
911 {
912 struct vop_pathconf_args /* {
913 struct vnode *a_vp;
914 int a_name;
915 register_t *a_retval;
916 } */ *ap = v;
917
918 switch (ap->a_name) {
919 case _PC_LINK_MAX:
920 *ap->a_retval = LINK_MAX;
921 return (0);
922 case _PC_MAX_CANON:
923 *ap->a_retval = MAX_CANON;
924 return (0);
925 case _PC_MAX_INPUT:
926 *ap->a_retval = MAX_INPUT;
927 return (0);
928 case _PC_PIPE_BUF:
929 *ap->a_retval = PIPE_BUF;
930 return (0);
931 case _PC_CHOWN_RESTRICTED:
932 *ap->a_retval = 1;
933 return (0);
934 case _PC_VDISABLE:
935 *ap->a_retval = _POSIX_VDISABLE;
936 return (0);
937 default:
938 return (EINVAL);
939 }
940 /* NOTREACHED */
941 }
942
943 /*
944 * Print out the contents of a /dev/fd vnode.
945 */
946 /* ARGSUSED */
947 int
948 fdesc_print(v)
949 void *v;
950 {
951 printf("tag VT_NON, fdesc vnode\n");
952 return (0);
953 }
954
955 int
956 fdesc_vfree(v)
957 void *v;
958 {
959 return (0);
960 }
961
962 int
963 fdesc_link(v)
964 void *v;
965 {
966 struct vop_link_args /* {
967 struct vnode *a_dvp;
968 struct vnode *a_vp;
969 struct componentname *a_cnp;
970 } */ *ap = v;
971
972 VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
973 vput(ap->a_dvp);
974 return (EROFS);
975 }
976
977 int
978 fdesc_symlink(v)
979 void *v;
980 {
981 struct vop_symlink_args /* {
982 struct vnode *a_dvp;
983 struct vnode **a_vpp;
984 struct componentname *a_cnp;
985 struct vattr *a_vap;
986 char *a_target;
987 } */ *ap = v;
988
989 VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
990 vput(ap->a_dvp);
991 return (EROFS);
992 }
993
994 int
995 fdesc_abortop(v)
996 void *v;
997 {
998 struct vop_abortop_args /* {
999 struct vnode *a_dvp;
1000 struct componentname *a_cnp;
1001 } */ *ap = v;
1002
1003 if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
1004 FREE(ap->a_cnp->cn_pnbuf, M_NAMEI);
1005 return (0);
1006 }
1007
1008 /*
1009 * /dev/fd vnode unsupported operation
1010 */
1011 /*ARGSUSED*/
1012 int
1013 fdesc_enotsupp(v)
1014 void *v;
1015 {
1016
1017 return (EOPNOTSUPP);
1018 }
1019
1020 /*
1021 * /dev/fd "should never get here" operation
1022 */
1023 /*ARGSUSED*/
1024 int
1025 fdesc_badop(v)
1026 void *v;
1027 {
1028
1029 panic("fdesc: bad op");
1030 /* NOTREACHED */
1031 }
1032