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