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