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