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