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