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