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