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 * $FreeBSD$ 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/vnode.h> 51 #include <sys/malloc.h> 52 #include <sys/file.h> 53 #include <sys/stat.h> 54 #include <sys/mount.h> 55 #include <sys/namei.h> 56 #include <sys/dirent.h> 57 #include <sys/socketvar.h> 58 #include <sys/conf.h> 59 #include <miscfs/fdesc/fdesc.h> 60 61 extern struct cdevsw ctty_cdevsw; 62 63 #define cttyvp(p) ((p)->p_flag & P_CONTROLT ? (p)->p_session->s_ttyvp : NULL) 64 65 #define FDL_WANT 0x01 66 #define FDL_LOCKED 0x02 67 static int fdcache_lock; 68 69 static vop_t **fdesc_vnodeop_p; 70 71 dev_t devctty; 72 73 #if (FD_STDIN != FD_STDOUT-1) || (FD_STDOUT != FD_STDERR-1) 74 FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2 75 #endif 76 77 #define NFDCACHE 4 78 #define FD_NHASH(ix) \ 79 (&fdhashtbl[(ix) & fdhash]) 80 static LIST_HEAD(fdhashhead, fdescnode) *fdhashtbl; 81 static u_long fdhash; 82 83 static int fdesc_attr __P((int fd, struct vattr *vap, struct ucred *cred, 84 struct proc *p)); 85 static int fdesc_badop __P((void)); 86 static int fdesc_getattr __P((struct vop_getattr_args *ap)); 87 static int fdesc_inactive __P((struct vop_inactive_args *ap)); 88 static int fdesc_ioctl __P((struct vop_ioctl_args *ap)); 89 static int fdesc_lookup __P((struct vop_lookup_args *ap)); 90 static int fdesc_open __P((struct vop_open_args *ap)); 91 static int fdesc_print __P((struct vop_print_args *ap)); 92 static int fdesc_read __P((struct vop_read_args *ap)); 93 static int fdesc_readdir __P((struct vop_readdir_args *ap)); 94 static int fdesc_readlink __P((struct vop_readlink_args *ap)); 95 static int fdesc_reclaim __P((struct vop_reclaim_args *ap)); 96 static int fdesc_poll __P((struct vop_poll_args *ap)); 97 static int fdesc_setattr __P((struct vop_setattr_args *ap)); 98 static int fdesc_write __P((struct vop_write_args *ap)); 99 100 /* 101 * Initialise cache headers 102 */ 103 int 104 fdesc_init(vfsp) 105 struct vfsconf *vfsp; 106 { 107 108 devctty = NODEV; 109 fdhashtbl = hashinit(NFDCACHE, M_CACHE, &fdhash); 110 return (0); 111 } 112 113 int 114 fdesc_allocvp(ftype, ix, mp, vpp) 115 fdntype ftype; 116 int ix; 117 struct mount *mp; 118 struct vnode **vpp; 119 { 120 struct proc *p = curproc; /* XXX */ 121 struct fdhashhead *fc; 122 struct fdescnode *fd; 123 int error = 0; 124 125 fc = FD_NHASH(ix); 126 loop: 127 for (fd = fc->lh_first; fd != 0; fd = fd->fd_hash.le_next) { 128 if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) { 129 if (vget(fd->fd_vnode, 0, p)) 130 goto loop; 131 *vpp = fd->fd_vnode; 132 return (error); 133 } 134 } 135 136 /* 137 * otherwise lock the array while we call getnewvnode 138 * since that can block. 139 */ 140 if (fdcache_lock & FDL_LOCKED) { 141 fdcache_lock |= FDL_WANT; 142 (void) tsleep((caddr_t) &fdcache_lock, PINOD, "fdalvp", 0); 143 goto loop; 144 } 145 fdcache_lock |= FDL_LOCKED; 146 147 /* 148 * Do the MALLOC before the getnewvnode since doing so afterward 149 * might cause a bogus v_data pointer to get dereferenced 150 * elsewhere if MALLOC should block. 151 */ 152 MALLOC(fd, struct fdescnode *, sizeof(struct fdescnode), M_TEMP, M_WAITOK); 153 154 error = getnewvnode(VT_FDESC, mp, fdesc_vnodeop_p, vpp); 155 if (error) { 156 FREE(fd, M_TEMP); 157 goto out; 158 } 159 (*vpp)->v_data = fd; 160 fd->fd_vnode = *vpp; 161 fd->fd_type = ftype; 162 fd->fd_fd = -1; 163 fd->fd_link = 0; 164 fd->fd_ix = ix; 165 LIST_INSERT_HEAD(fc, fd, fd_hash); 166 167 out:; 168 fdcache_lock &= ~FDL_LOCKED; 169 170 if (fdcache_lock & FDL_WANT) { 171 fdcache_lock &= ~FDL_WANT; 172 wakeup((caddr_t) &fdcache_lock); 173 } 174 175 return (error); 176 } 177 178 /* 179 * vp is the current namei directory 180 * ndp is the name to locate in that directory... 181 */ 182 static int 183 fdesc_lookup(ap) 184 struct vop_lookup_args /* { 185 struct vnode * a_dvp; 186 struct vnode ** a_vpp; 187 struct componentname * a_cnp; 188 } */ *ap; 189 { 190 struct vnode **vpp = ap->a_vpp; 191 struct vnode *dvp = ap->a_dvp; 192 struct componentname *cnp = ap->a_cnp; 193 char *pname = cnp->cn_nameptr; 194 struct proc *p = cnp->cn_proc; 195 int nfiles = p->p_fd->fd_nfiles; 196 unsigned fd = -1; 197 int error; 198 struct vnode *fvp; 199 char *ln; 200 201 if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) { 202 error = EROFS; 203 goto bad; 204 } 205 206 VOP_UNLOCK(dvp, 0, p); 207 if (cnp->cn_namelen == 1 && *pname == '.') { 208 *vpp = dvp; 209 VREF(dvp); 210 vn_lock(dvp, LK_SHARED | LK_RETRY, p); 211 return (0); 212 } 213 214 switch (VTOFDESC(dvp)->fd_type) { 215 default: 216 case Flink: 217 case Fdesc: 218 case Fctty: 219 error = ENOTDIR; 220 goto bad; 221 222 case Froot: 223 if (cnp->cn_namelen == 2 && bcmp(pname, "fd", 2) == 0) { 224 error = fdesc_allocvp(Fdevfd, FD_DEVFD, dvp->v_mount, &fvp); 225 if (error) 226 goto bad; 227 *vpp = fvp; 228 fvp->v_type = VDIR; 229 vn_lock(fvp, LK_SHARED | LK_RETRY, p); 230 return (0); 231 } 232 233 if (cnp->cn_namelen == 3 && bcmp(pname, "tty", 3) == 0) { 234 struct vnode *ttyvp = cttyvp(p); 235 if (ttyvp == NULL) { 236 error = ENXIO; 237 goto bad; 238 } 239 error = fdesc_allocvp(Fctty, FD_CTTY, dvp->v_mount, &fvp); 240 if (error) 241 goto bad; 242 *vpp = fvp; 243 fvp->v_type = VFIFO; 244 vn_lock(fvp, LK_SHARED | LK_RETRY, p); 245 return (0); 246 } 247 248 ln = 0; 249 switch (cnp->cn_namelen) { 250 case 5: 251 if (bcmp(pname, "stdin", 5) == 0) { 252 ln = "fd/0"; 253 fd = FD_STDIN; 254 } 255 break; 256 case 6: 257 if (bcmp(pname, "stdout", 6) == 0) { 258 ln = "fd/1"; 259 fd = FD_STDOUT; 260 } else 261 if (bcmp(pname, "stderr", 6) == 0) { 262 ln = "fd/2"; 263 fd = FD_STDERR; 264 } 265 break; 266 } 267 268 if (ln) { 269 error = fdesc_allocvp(Flink, fd, dvp->v_mount, &fvp); 270 if (error) 271 goto bad; 272 VTOFDESC(fvp)->fd_link = ln; 273 *vpp = fvp; 274 fvp->v_type = VLNK; 275 vn_lock(fvp, LK_SHARED | LK_RETRY, p); 276 return (0); 277 } else { 278 error = ENOENT; 279 goto bad; 280 } 281 282 /* FALL THROUGH */ 283 284 case Fdevfd: 285 if (cnp->cn_namelen == 2 && bcmp(pname, "..", 2) == 0) { 286 if ((error = fdesc_root(dvp->v_mount, vpp)) != 0) 287 goto bad; 288 return (0); 289 } 290 291 fd = 0; 292 while (*pname >= '0' && *pname <= '9') { 293 fd = 10 * fd + *pname++ - '0'; 294 if (fd >= nfiles) 295 break; 296 } 297 298 if (*pname != '\0') { 299 error = ENOENT; 300 goto bad; 301 } 302 303 if (fd >= nfiles || p->p_fd->fd_ofiles[fd] == NULL) { 304 error = EBADF; 305 goto bad; 306 } 307 308 error = fdesc_allocvp(Fdesc, FD_DESC+fd, dvp->v_mount, &fvp); 309 if (error) 310 goto bad; 311 VTOFDESC(fvp)->fd_fd = fd; 312 vn_lock(fvp, LK_SHARED | LK_RETRY, p); 313 *vpp = fvp; 314 return (0); 315 } 316 317 bad:; 318 vn_lock(dvp, LK_SHARED | LK_RETRY, p); 319 *vpp = NULL; 320 return (error); 321 } 322 323 static int 324 fdesc_open(ap) 325 struct vop_open_args /* { 326 struct vnode *a_vp; 327 int a_mode; 328 struct ucred *a_cred; 329 struct proc *a_p; 330 } */ *ap; 331 { 332 struct vnode *vp = ap->a_vp; 333 int error = 0; 334 335 switch (VTOFDESC(vp)->fd_type) { 336 case Fdesc: 337 /* 338 * XXX Kludge: set p->p_dupfd to contain the value of the 339 * the file descriptor being sought for duplication. The error 340 * return ensures that the vnode for this device will be 341 * released by vn_open. Open will detect this special error and 342 * take the actions in dupfdopen. Other callers of vn_open or 343 * VOP_OPEN will simply report the error. 344 */ 345 ap->a_p->p_dupfd = VTOFDESC(vp)->fd_fd; /* XXX */ 346 error = ENODEV; 347 break; 348 349 case Fctty: 350 error = (*ctty_cdevsw.d_open)(devctty, ap->a_mode, 0, ap->a_p); 351 break; 352 } 353 354 return (error); 355 } 356 357 static int 358 fdesc_attr(fd, vap, cred, p) 359 int fd; 360 struct vattr *vap; 361 struct ucred *cred; 362 struct proc *p; 363 { 364 struct filedesc *fdp = p->p_fd; 365 struct file *fp; 366 struct stat stb; 367 int error; 368 369 if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) 370 return (EBADF); 371 372 switch (fp->f_type) { 373 case DTYPE_FIFO: 374 case DTYPE_VNODE: 375 error = VOP_GETATTR((struct vnode *) fp->f_data, vap, cred, p); 376 if (error == 0 && vap->va_type == VDIR) { 377 /* 378 * directories can cause loops in the namespace, 379 * so turn off the 'x' bits to avoid trouble. 380 */ 381 vap->va_mode &= ~((VEXEC)|(VEXEC>>3)|(VEXEC>>6)); 382 } 383 break; 384 385 case DTYPE_SOCKET: 386 error = soo_stat((struct socket *)fp->f_data, &stb); 387 if (error == 0) { 388 vattr_null(vap); 389 vap->va_type = VSOCK; 390 vap->va_mode = stb.st_mode; 391 vap->va_nlink = stb.st_nlink; 392 vap->va_uid = stb.st_uid; 393 vap->va_gid = stb.st_gid; 394 vap->va_fsid = stb.st_dev; 395 vap->va_fileid = stb.st_ino; 396 vap->va_size = stb.st_size; 397 vap->va_blocksize = stb.st_blksize; 398 vap->va_atime = stb.st_atimespec; 399 vap->va_mtime = stb.st_mtimespec; 400 vap->va_ctime = stb.st_ctimespec; 401 vap->va_gen = stb.st_gen; 402 vap->va_flags = stb.st_flags; 403 vap->va_rdev = stb.st_rdev; 404 vap->va_bytes = stb.st_blocks * stb.st_blksize; 405 } 406 break; 407 408 default: 409 panic("fdesc attr"); 410 break; 411 } 412 413 return (error); 414 } 415 416 static int 417 fdesc_getattr(ap) 418 struct vop_getattr_args /* { 419 struct vnode *a_vp; 420 struct vattr *a_vap; 421 struct ucred *a_cred; 422 struct proc *a_p; 423 } */ *ap; 424 { 425 struct vnode *vp = ap->a_vp; 426 struct vattr *vap = ap->a_vap; 427 unsigned fd; 428 int error = 0; 429 430 switch (VTOFDESC(vp)->fd_type) { 431 case Froot: 432 case Fdevfd: 433 case Flink: 434 case Fctty: 435 bzero((caddr_t) vap, sizeof(*vap)); 436 vattr_null(vap); 437 vap->va_fileid = VTOFDESC(vp)->fd_ix; 438 439 switch (VTOFDESC(vp)->fd_type) { 440 case Flink: 441 vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; 442 vap->va_type = VLNK; 443 vap->va_nlink = 1; 444 vap->va_size = strlen(VTOFDESC(vp)->fd_link); 445 break; 446 447 case Fctty: 448 vap->va_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; 449 vap->va_type = VFIFO; 450 vap->va_nlink = 1; 451 vap->va_size = 0; 452 break; 453 454 default: 455 vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; 456 vap->va_type = VDIR; 457 vap->va_nlink = 2; 458 vap->va_size = DEV_BSIZE; 459 break; 460 } 461 vap->va_uid = 0; 462 vap->va_gid = 0; 463 vap->va_blocksize = DEV_BSIZE; 464 vap->va_atime.tv_sec = boottime.tv_sec; 465 vap->va_atime.tv_nsec = 0; 466 vap->va_mtime = vap->va_atime; 467 vap->va_ctime = vap->va_mtime; 468 vap->va_gen = 0; 469 vap->va_flags = 0; 470 vap->va_rdev = 0; 471 vap->va_bytes = 0; 472 break; 473 474 case Fdesc: 475 fd = VTOFDESC(vp)->fd_fd; 476 error = fdesc_attr(fd, vap, ap->a_cred, ap->a_p); 477 break; 478 479 default: 480 panic("fdesc_getattr"); 481 break; 482 } 483 484 if (error == 0) 485 vp->v_type = vap->va_type; 486 487 return (error); 488 } 489 490 static int 491 fdesc_setattr(ap) 492 struct vop_setattr_args /* { 493 struct vnode *a_vp; 494 struct vattr *a_vap; 495 struct ucred *a_cred; 496 struct proc *a_p; 497 } */ *ap; 498 { 499 struct filedesc *fdp = ap->a_p->p_fd; 500 struct vattr *vap = ap->a_vap; 501 struct file *fp; 502 unsigned fd; 503 int error; 504 505 /* 506 * Can't mess with the root vnode 507 */ 508 switch (VTOFDESC(ap->a_vp)->fd_type) { 509 case Fdesc: 510 break; 511 512 case Fctty: 513 if (vap->va_flags != VNOVAL) 514 return (EOPNOTSUPP); 515 return (0); 516 517 default: 518 return (EACCES); 519 } 520 521 fd = VTOFDESC(ap->a_vp)->fd_fd; 522 if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) { 523 return (EBADF); 524 } 525 526 /* 527 * Can setattr the underlying vnode, but not sockets! 528 */ 529 switch (fp->f_type) { 530 case DTYPE_FIFO: 531 case DTYPE_PIPE: 532 case DTYPE_VNODE: 533 error = VOP_SETATTR((struct vnode *) fp->f_data, ap->a_vap, ap->a_cred, ap->a_p); 534 break; 535 536 case DTYPE_SOCKET: 537 if (vap->va_flags != VNOVAL) 538 error = EOPNOTSUPP; 539 else 540 error = 0; 541 break; 542 543 default: 544 error = EBADF; 545 break; 546 } 547 548 return (error); 549 } 550 551 #define UIO_MX 16 552 553 static struct dirtmp { 554 u_long d_fileno; 555 u_short d_reclen; 556 u_short d_namlen; 557 char d_name[8]; 558 } rootent[] = { 559 { FD_DEVFD, UIO_MX, 2, "fd" }, 560 { FD_STDIN, UIO_MX, 5, "stdin" }, 561 { FD_STDOUT, UIO_MX, 6, "stdout" }, 562 { FD_STDERR, UIO_MX, 6, "stderr" }, 563 { FD_CTTY, UIO_MX, 3, "tty" }, 564 }; 565 566 static int 567 fdesc_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 error, i, off; 580 581 /* 582 * We don't allow exporting fdesc mounts, and currently local 583 * requests do not need cookies. 584 */ 585 if (ap->a_ncookies) 586 panic("fdesc_readdir: not hungry"); 587 588 if (VTOFDESC(ap->a_vp)->fd_type != Froot && 589 VTOFDESC(ap->a_vp)->fd_type != Fdevfd) 590 panic("fdesc_readdir: not dir"); 591 592 off = (int)uio->uio_offset; 593 if (off != uio->uio_offset || off < 0 || (u_int)off % UIO_MX != 0 || 594 uio->uio_resid < UIO_MX) 595 return (EINVAL); 596 i = (u_int)off / UIO_MX; 597 fdp = uio->uio_procp->p_fd; 598 599 if (VTOFDESC(ap->a_vp)->fd_type == Froot) { 600 struct dirent d; 601 struct dirent *dp = &d; 602 struct dirtmp *dt; 603 604 error = 0; 605 606 while (i < sizeof(rootent) / sizeof(rootent[0]) && 607 uio->uio_resid >= UIO_MX) { 608 dt = &rootent[i]; 609 switch (dt->d_fileno) { 610 case FD_CTTY: 611 if (cttyvp(uio->uio_procp) == NULL) 612 continue; 613 break; 614 615 case FD_STDIN: 616 case FD_STDOUT: 617 case FD_STDERR: 618 if ((dt->d_fileno-FD_STDIN) >= fdp->fd_nfiles) 619 continue; 620 if (fdp->fd_ofiles[dt->d_fileno-FD_STDIN] == NULL) 621 continue; 622 break; 623 } 624 bzero((caddr_t) dp, UIO_MX); 625 dp->d_fileno = dt->d_fileno; 626 dp->d_namlen = dt->d_namlen; 627 dp->d_type = DT_UNKNOWN; 628 dp->d_reclen = dt->d_reclen; 629 bcopy(dt->d_name, dp->d_name, dp->d_namlen+1); 630 error = uiomove((caddr_t) dp, UIO_MX, uio); 631 if (error) 632 break; 633 i++; 634 } 635 uio->uio_offset = i * UIO_MX; 636 return (error); 637 } 638 639 error = 0; 640 while (i < fdp->fd_nfiles && uio->uio_resid >= UIO_MX) { 641 if (fdp->fd_ofiles[i] != NULL) { 642 struct dirent d; 643 struct dirent *dp = &d; 644 645 bzero((caddr_t) dp, UIO_MX); 646 647 dp->d_namlen = sprintf(dp->d_name, "%d", i); 648 dp->d_reclen = UIO_MX; 649 dp->d_type = DT_UNKNOWN; 650 dp->d_fileno = i + FD_STDIN; 651 /* 652 * And ship to userland 653 */ 654 error = uiomove((caddr_t) dp, UIO_MX, uio); 655 if (error) 656 break; 657 } 658 i++; 659 } 660 661 uio->uio_offset = i * UIO_MX; 662 return (error); 663 } 664 665 static int 666 fdesc_readlink(ap) 667 struct vop_readlink_args /* { 668 struct vnode *a_vp; 669 struct uio *a_uio; 670 struct ucred *a_cred; 671 } */ *ap; 672 { 673 struct vnode *vp = ap->a_vp; 674 int error; 675 676 if (vp->v_type != VLNK) 677 return (EPERM); 678 679 if (VTOFDESC(vp)->fd_type == Flink) { 680 char *ln = VTOFDESC(vp)->fd_link; 681 error = uiomove(ln, strlen(ln), ap->a_uio); 682 } else { 683 error = EOPNOTSUPP; 684 } 685 686 return (error); 687 } 688 689 static int 690 fdesc_read(ap) 691 struct vop_read_args /* { 692 struct vnode *a_vp; 693 struct uio *a_uio; 694 int a_ioflag; 695 struct ucred *a_cred; 696 } */ *ap; 697 { 698 int error = EOPNOTSUPP; 699 700 switch (VTOFDESC(ap->a_vp)->fd_type) { 701 case Fctty: 702 error = (*ctty_cdevsw.d_read)(devctty, ap->a_uio, ap->a_ioflag); 703 break; 704 705 default: 706 error = EOPNOTSUPP; 707 break; 708 } 709 710 return (error); 711 } 712 713 static int 714 fdesc_write(ap) 715 struct vop_write_args /* { 716 struct vnode *a_vp; 717 struct uio *a_uio; 718 int a_ioflag; 719 struct ucred *a_cred; 720 } */ *ap; 721 { 722 int error = EOPNOTSUPP; 723 724 switch (VTOFDESC(ap->a_vp)->fd_type) { 725 case Fctty: 726 error = (*ctty_cdevsw.d_write)(devctty, ap->a_uio, ap->a_ioflag); 727 break; 728 729 default: 730 error = EOPNOTSUPP; 731 break; 732 } 733 734 return (error); 735 } 736 737 static int 738 fdesc_ioctl(ap) 739 struct vop_ioctl_args /* { 740 struct vnode *a_vp; 741 int a_command; 742 caddr_t a_data; 743 int a_fflag; 744 struct ucred *a_cred; 745 struct proc *a_p; 746 } */ *ap; 747 { 748 int error = EOPNOTSUPP; 749 750 switch (VTOFDESC(ap->a_vp)->fd_type) { 751 case Fctty: 752 error = (*ctty_cdevsw.d_ioctl)(devctty, ap->a_command, 753 ap->a_data, ap->a_fflag, ap->a_p); 754 break; 755 756 default: 757 error = EOPNOTSUPP; 758 break; 759 } 760 761 return (error); 762 } 763 764 static int 765 fdesc_poll(ap) 766 struct vop_poll_args /* { 767 struct vnode *a_vp; 768 int a_events; 769 struct ucred *a_cred; 770 struct proc *a_p; 771 } */ *ap; 772 { 773 int revents; 774 775 switch (VTOFDESC(ap->a_vp)->fd_type) { 776 case Fctty: 777 revents = (*ctty_cdevsw.d_poll)(devctty, ap->a_events, ap->a_p); 778 break; 779 780 default: 781 revents = seltrue(0, ap->a_events, ap->a_p); 782 break; 783 } 784 785 return (revents); 786 } 787 788 static int 789 fdesc_inactive(ap) 790 struct vop_inactive_args /* { 791 struct vnode *a_vp; 792 struct proc *a_p; 793 } */ *ap; 794 { 795 struct vnode *vp = ap->a_vp; 796 797 /* 798 * Clear out the v_type field to avoid 799 * nasty things happening in vgone(). 800 */ 801 VOP_UNLOCK(vp, 0, ap->a_p); 802 vp->v_type = VNON; 803 return (0); 804 } 805 806 static int 807 fdesc_reclaim(ap) 808 struct vop_reclaim_args /* { 809 struct vnode *a_vp; 810 } */ *ap; 811 { 812 struct vnode *vp = ap->a_vp; 813 struct fdescnode *fd = VTOFDESC(vp); 814 815 LIST_REMOVE(fd, fd_hash); 816 FREE(vp->v_data, M_TEMP); 817 vp->v_data = 0; 818 819 return (0); 820 } 821 822 /* 823 * Print out the contents of a /dev/fd vnode. 824 */ 825 /* ARGSUSED */ 826 static int 827 fdesc_print(ap) 828 struct vop_print_args /* { 829 struct vnode *a_vp; 830 } */ *ap; 831 { 832 833 printf("tag VT_NON, fdesc vnode\n"); 834 return (0); 835 } 836 837 /* 838 * /dev/fd "should never get here" operation 839 */ 840 static int 841 fdesc_badop() 842 { 843 844 panic("fdesc: bad op"); 845 /* NOTREACHED */ 846 } 847 848 static struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = { 849 { &vop_default_desc, (vop_t *) vop_defaultop }, 850 { &vop_access_desc, (vop_t *) vop_null }, 851 { &vop_bmap_desc, (vop_t *) fdesc_badop }, 852 { &vop_getattr_desc, (vop_t *) fdesc_getattr }, 853 { &vop_inactive_desc, (vop_t *) fdesc_inactive }, 854 { &vop_ioctl_desc, (vop_t *) fdesc_ioctl }, 855 { &vop_lookup_desc, (vop_t *) fdesc_lookup }, 856 { &vop_open_desc, (vop_t *) fdesc_open }, 857 { &vop_pathconf_desc, (vop_t *) vop_stdpathconf }, 858 { &vop_poll_desc, (vop_t *) fdesc_poll }, 859 { &vop_print_desc, (vop_t *) fdesc_print }, 860 { &vop_read_desc, (vop_t *) fdesc_read }, 861 { &vop_readdir_desc, (vop_t *) fdesc_readdir }, 862 { &vop_readlink_desc, (vop_t *) fdesc_readlink }, 863 { &vop_reclaim_desc, (vop_t *) fdesc_reclaim }, 864 { &vop_setattr_desc, (vop_t *) fdesc_setattr }, 865 { &vop_write_desc, (vop_t *) fdesc_write }, 866 { NULL, NULL } 867 }; 868 static struct vnodeopv_desc fdesc_vnodeop_opv_desc = 869 { &fdesc_vnodeop_p, fdesc_vnodeop_entries }; 870 871 VNODEOP_SET(fdesc_vnodeop_opv_desc); 872