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