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