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