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