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