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.18 1996/09/03 14:22:12 bde Exp $ 39 */ 40 41 /* 42 * /dev/fd Filesystem 43 */ 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/proc.h> 48 #include <sys/kernel.h> /* boottime */ 49 #include <sys/resourcevar.h> 50 #include <sys/filedesc.h> 51 #include <sys/unistd.h> 52 #include <sys/vnode.h> 53 #include <sys/malloc.h> 54 #include <sys/file.h> 55 #include <sys/stat.h> 56 #include <sys/mount.h> 57 #include <sys/namei.h> 58 #include <sys/buf.h> 59 #include <sys/dirent.h> 60 #include <sys/socketvar.h> 61 #include <sys/tty.h> 62 #include <sys/conf.h> 63 #include <miscfs/fdesc/fdesc.h> 64 65 extern struct cdevsw ctty_cdevsw; 66 67 #define cttyvp(p) ((p)->p_flag & P_CONTROLT ? (p)->p_session->s_ttyvp : NULL) 68 69 #define FDL_WANT 0x01 70 #define FDL_LOCKED 0x02 71 static int fdcache_lock; 72 73 dev_t devctty; 74 75 #if (FD_STDIN != FD_STDOUT-1) || (FD_STDOUT != FD_STDERR-1) 76 FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2 77 #endif 78 79 #define NFDCACHE 4 80 #define FD_NHASH(ix) ((ix) & NFDCACHE-1) 81 82 /* 83 * Cache head 84 */ 85 struct fdcache { 86 struct fdescnode *fc_forw; 87 struct fdescnode *fc_back; 88 }; 89 90 static struct fdcache fdcache[NFDCACHE]; 91 92 static int fdesc_attr __P((int fd, struct vattr *vap, struct ucred *cred, 93 struct proc *p)); 94 static int fdesc_badop __P((void)); 95 static int fdesc_enotsupp __P((void)); 96 static int fdesc_getattr __P((struct vop_getattr_args *ap)); 97 static struct fdcache * 98 fdesc_hash __P((int ix)); 99 static int fdesc_inactive __P((struct vop_inactive_args *ap)); 100 static int fdesc_ioctl __P((struct vop_ioctl_args *ap)); 101 static int fdesc_lookup __P((struct vop_lookup_args *ap)); 102 static int fdesc_open __P((struct vop_open_args *ap)); 103 static int fdesc_pathconf __P((struct vop_pathconf_args *ap)); 104 static int fdesc_print __P((struct vop_print_args *ap)); 105 static int fdesc_read __P((struct vop_read_args *ap)); 106 static int fdesc_readdir __P((struct vop_readdir_args *ap)); 107 static int fdesc_readlink __P((struct vop_readlink_args *ap)); 108 static int fdesc_reclaim __P((struct vop_reclaim_args *ap)); 109 static int fdesc_select __P((struct vop_select_args *ap)); 110 static int fdesc_setattr __P((struct vop_setattr_args *ap)); 111 static int fdesc_vfree __P((struct vop_vfree_args *ap)); 112 static int fdesc_write __P((struct vop_write_args *ap)); 113 114 /* 115 * Initialise cache headers 116 */ 117 int 118 fdesc_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 */ 132 static struct fdcache * 133 fdesc_hash(ix) 134 int ix; 135 { 136 137 return (&fdcache[FD_NHASH(ix)]); 138 } 139 140 int 141 fdesc_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 151 loop: 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 194 out:; 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 */ 209 static int 210 fdesc_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 345 bad:; 346 *vpp = NULL; 347 return (error); 348 } 349 350 static int 351 fdesc_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 384 static int 385 fdesc_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 442 static int 443 fdesc_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.tv_sec = boottime.tv_sec; 492 vap->va_atime.tv_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 517 static int 518 fdesc_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 572 static 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 586 static int 587 fdesc_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 687 static int 688 fdesc_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 711 static int 712 fdesc_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 735 static int 736 fdesc_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 759 static int 760 fdesc_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 786 static int 787 fdesc_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 811 static int 812 fdesc_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 827 static int 828 fdesc_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 */ 845 static int 846 fdesc_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 */ 883 static int 884 fdesc_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*/ 895 static int 896 fdesc_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 */ 910 static int 911 fdesc_enotsupp() 912 { 913 914 return (EOPNOTSUPP); 915 } 916 917 /* 918 * /dev/fd "should never get here" operation 919 */ 920 static int 921 fdesc_badop() 922 { 923 924 panic("fdesc: bad op"); 925 /* NOTREACHED */ 926 } 927 928 #define fdesc_create ((int (*) __P((struct vop_create_args *)))fdesc_enotsupp) 929 #define fdesc_mknod ((int (*) __P((struct vop_mknod_args *)))fdesc_enotsupp) 930 #define fdesc_close ((int (*) __P((struct vop_close_args *)))nullop) 931 #define fdesc_access ((int (*) __P((struct vop_access_args *)))nullop) 932 #define fdesc_mmap ((int (*) __P((struct vop_mmap_args *)))fdesc_enotsupp) 933 #define fdesc_fsync ((int (*) __P((struct vop_fsync_args *)))nullop) 934 #define fdesc_seek ((int (*) __P((struct vop_seek_args *)))nullop) 935 #define fdesc_remove ((int (*) __P((struct vop_remove_args *)))fdesc_enotsupp) 936 #define fdesc_link ((int (*) __P((struct vop_link_args *)))fdesc_enotsupp) 937 #define fdesc_rename ((int (*) __P((struct vop_rename_args *)))fdesc_enotsupp) 938 #define fdesc_mkdir ((int (*) __P((struct vop_mkdir_args *)))fdesc_enotsupp) 939 #define fdesc_rmdir ((int (*) __P((struct vop_rmdir_args *)))fdesc_enotsupp) 940 #define fdesc_symlink ((int (*) __P((struct vop_symlink_args *)))fdesc_enotsupp) 941 #define fdesc_abortop ((int (*) __P((struct vop_abortop_args *)))nullop) 942 #define fdesc_lock ((int (*) __P((struct vop_lock_args *)))nullop) 943 #define fdesc_unlock ((int (*) __P((struct vop_unlock_args *)))nullop) 944 #define fdesc_bmap ((int (*) __P((struct vop_bmap_args *)))fdesc_badop) 945 #define fdesc_strategy ((int (*) __P((struct vop_strategy_args *)))fdesc_badop) 946 #define fdesc_islocked ((int (*) __P((struct vop_islocked_args *)))nullop) 947 #define fdesc_advlock ((int (*) __P((struct vop_advlock_args *)))fdesc_enotsupp) 948 #define fdesc_blkatoff \ 949 ((int (*) __P((struct vop_blkatoff_args *)))fdesc_enotsupp) 950 #define fdesc_vget ((int (*) __P((struct vop_vget_args *)))fdesc_enotsupp) 951 #define fdesc_valloc ((int(*) __P(( \ 952 struct vnode *pvp, \ 953 int mode, \ 954 struct ucred *cred, \ 955 struct vnode **vpp))) fdesc_enotsupp) 956 #define fdesc_truncate \ 957 ((int (*) __P((struct vop_truncate_args *)))fdesc_enotsupp) 958 #define fdesc_update ((int (*) __P((struct vop_update_args *)))fdesc_enotsupp) 959 #define fdesc_bwrite ((int (*) __P((struct vop_bwrite_args *)))fdesc_enotsupp) 960 961 static vop_t **fdesc_vnodeop_p; 962 static struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = { 963 { &vop_default_desc, (vop_t *)vn_default_error }, 964 { &vop_lookup_desc, (vop_t *)fdesc_lookup }, /* lookup */ 965 { &vop_create_desc, (vop_t *)fdesc_create }, /* create */ 966 { &vop_mknod_desc, (vop_t *)fdesc_mknod }, /* mknod */ 967 { &vop_open_desc, (vop_t *)fdesc_open }, /* open */ 968 { &vop_close_desc, (vop_t *)fdesc_close }, /* close */ 969 { &vop_access_desc, (vop_t *)fdesc_access }, /* access */ 970 { &vop_getattr_desc, (vop_t *)fdesc_getattr }, /* getattr */ 971 { &vop_setattr_desc, (vop_t *)fdesc_setattr }, /* setattr */ 972 { &vop_read_desc, (vop_t *)fdesc_read }, /* read */ 973 { &vop_write_desc, (vop_t *)fdesc_write }, /* write */ 974 { &vop_ioctl_desc, (vop_t *)fdesc_ioctl }, /* ioctl */ 975 { &vop_select_desc, (vop_t *)fdesc_select }, /* select */ 976 { &vop_mmap_desc, (vop_t *)fdesc_mmap }, /* mmap */ 977 { &vop_fsync_desc, (vop_t *)fdesc_fsync }, /* fsync */ 978 { &vop_seek_desc, (vop_t *)fdesc_seek }, /* seek */ 979 { &vop_remove_desc, (vop_t *)fdesc_remove }, /* remove */ 980 { &vop_link_desc, (vop_t *)fdesc_link }, /* link */ 981 { &vop_rename_desc, (vop_t *)fdesc_rename }, /* rename */ 982 { &vop_mkdir_desc, (vop_t *)fdesc_mkdir }, /* mkdir */ 983 { &vop_rmdir_desc, (vop_t *)fdesc_rmdir }, /* rmdir */ 984 { &vop_symlink_desc, (vop_t *)fdesc_symlink }, /* symlink */ 985 { &vop_readdir_desc, (vop_t *)fdesc_readdir }, /* readdir */ 986 { &vop_readlink_desc, (vop_t *)fdesc_readlink }, /* readlink */ 987 { &vop_abortop_desc, (vop_t *)fdesc_abortop }, /* abortop */ 988 { &vop_inactive_desc, (vop_t *)fdesc_inactive }, /* inactive */ 989 { &vop_reclaim_desc, (vop_t *)fdesc_reclaim }, /* reclaim */ 990 { &vop_lock_desc, (vop_t *)fdesc_lock }, /* lock */ 991 { &vop_unlock_desc, (vop_t *)fdesc_unlock }, /* unlock */ 992 { &vop_bmap_desc, (vop_t *)fdesc_bmap }, /* bmap */ 993 { &vop_strategy_desc, (vop_t *)fdesc_strategy }, /* strategy */ 994 { &vop_print_desc, (vop_t *)fdesc_print }, /* print */ 995 { &vop_islocked_desc, (vop_t *)fdesc_islocked }, /* islocked */ 996 { &vop_pathconf_desc, (vop_t *)fdesc_pathconf }, /* pathconf */ 997 { &vop_advlock_desc, (vop_t *)fdesc_advlock }, /* advlock */ 998 { &vop_blkatoff_desc, (vop_t *)fdesc_blkatoff }, /* blkatoff */ 999 { &vop_valloc_desc, (vop_t *)fdesc_valloc }, /* valloc */ 1000 { &vop_vfree_desc, (vop_t *)fdesc_vfree }, /* vfree */ 1001 { &vop_truncate_desc, (vop_t *)fdesc_truncate }, /* truncate */ 1002 { &vop_update_desc, (vop_t *)fdesc_update }, /* update */ 1003 { &vop_bwrite_desc, (vop_t *)fdesc_bwrite }, /* bwrite */ 1004 { NULL, NULL } 1005 }; 1006 static struct vnodeopv_desc fdesc_vnodeop_opv_desc = 1007 { &fdesc_vnodeop_p, fdesc_vnodeop_entries }; 1008 1009 VNODEOP_SET(fdesc_vnodeop_opv_desc); 1010