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