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