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