1 /* $NetBSD: fdesc_vnops.c,v 1.134 2020/06/27 17:29:19 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.134 2020/06/27 17:29:19 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/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 == 0 && ix == FD_CTTY) 299 (*vpp)->v_type = VCHR; 300 return error; 301 } 302 303 int 304 fdesc_open(void *v) 305 { 306 struct vop_open_args /* { 307 struct vnode *a_vp; 308 int a_mode; 309 kauth_cred_t a_cred; 310 } */ *ap = v; 311 struct vnode *vp = ap->a_vp; 312 313 switch (VTOFDESC(vp)->fd_type) { 314 case Fdesc: 315 /* 316 * XXX Kludge: set dupfd to contain the value of the 317 * the file descriptor being sought for duplication. The error 318 * return ensures that the vnode for this device will be 319 * released by vn_open. Open will detect this special error and 320 * take the actions in dupfdopen. Other callers of vn_open or 321 * VOP_OPEN will simply report the error. 322 */ 323 curlwp->l_dupfd = VTOFDESC(vp)->fd_fd; /* XXX */ 324 return EDUPFD; 325 326 case Fctty: 327 return cdev_open(devctty, ap->a_mode, 0, curlwp); 328 case Froot: 329 case Fdevfd: 330 case Flink: 331 break; 332 } 333 334 return (0); 335 } 336 337 static int 338 fdesc_attr(int fd, struct vattr *vap, kauth_cred_t cred) 339 { 340 file_t *fp; 341 struct stat stb; 342 int error; 343 344 if ((fp = fd_getfile(fd)) == NULL) 345 return (EBADF); 346 347 switch (fp->f_type) { 348 case DTYPE_VNODE: 349 vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY); 350 error = VOP_GETATTR(fp->f_vnode, vap, cred); 351 VOP_UNLOCK(fp->f_vnode); 352 if (error == 0 && vap->va_type == VDIR) { 353 /* 354 * directories can cause loops in the namespace, 355 * so turn off the 'x' bits to avoid trouble. 356 */ 357 vap->va_mode &= ~(S_IXUSR|S_IXGRP|S_IXOTH); 358 } 359 break; 360 361 default: 362 memset(&stb, 0, sizeof(stb)); 363 error = (*fp->f_ops->fo_stat)(fp, &stb); 364 if (error) 365 break; 366 367 vattr_null(vap); 368 switch(fp->f_type) { 369 case DTYPE_SOCKET: 370 vap->va_type = VSOCK; 371 break; 372 case DTYPE_PIPE: 373 vap->va_type = VFIFO; 374 break; 375 default: 376 /* use VNON perhaps? */ 377 vap->va_type = VBAD; 378 break; 379 } 380 vap->va_mode = stb.st_mode; 381 vap->va_nlink = stb.st_nlink; 382 vap->va_uid = stb.st_uid; 383 vap->va_gid = stb.st_gid; 384 vap->va_fsid = stb.st_dev; 385 vap->va_fileid = stb.st_ino; 386 vap->va_size = stb.st_size; 387 vap->va_blocksize = stb.st_blksize; 388 vap->va_atime = stb.st_atimespec; 389 vap->va_mtime = stb.st_mtimespec; 390 vap->va_ctime = stb.st_ctimespec; 391 vap->va_gen = stb.st_gen; 392 vap->va_flags = stb.st_flags; 393 vap->va_rdev = stb.st_rdev; 394 vap->va_bytes = stb.st_blocks * stb.st_blksize; 395 break; 396 } 397 398 fd_putfile(fd); 399 return (error); 400 } 401 402 int 403 fdesc_getattr(void *v) 404 { 405 struct vop_getattr_args /* { 406 struct vnode *a_vp; 407 struct vattr *a_vap; 408 kauth_cred_t a_cred; 409 struct lwp *a_l; 410 } */ *ap = v; 411 struct vnode *vp = ap->a_vp; 412 struct vattr *vap = ap->a_vap; 413 unsigned fd; 414 int error = 0; 415 struct timeval tv; 416 417 switch (VTOFDESC(vp)->fd_type) { 418 case Froot: 419 case Fdevfd: 420 case Flink: 421 case Fctty: 422 vattr_null(vap); 423 vap->va_fileid = VTOFDESC(vp)->fd_ix; 424 425 #define R_ALL (S_IRUSR|S_IRGRP|S_IROTH) 426 #define W_ALL (S_IWUSR|S_IWGRP|S_IWOTH) 427 #define X_ALL (S_IXUSR|S_IXGRP|S_IXOTH) 428 429 switch (VTOFDESC(vp)->fd_type) { 430 case Flink: 431 vap->va_mode = R_ALL|X_ALL; 432 vap->va_type = VLNK; 433 vap->va_rdev = 0; 434 vap->va_nlink = 1; 435 vap->va_size = strlen(VTOFDESC(vp)->fd_link); 436 break; 437 438 case Fctty: 439 vap->va_mode = R_ALL|W_ALL; 440 vap->va_type = VCHR; 441 vap->va_rdev = devctty; 442 vap->va_nlink = 1; 443 vap->va_size = 0; 444 break; 445 446 default: 447 vap->va_mode = R_ALL|X_ALL; 448 vap->va_type = VDIR; 449 vap->va_rdev = 0; 450 vap->va_nlink = 2; 451 vap->va_size = DEV_BSIZE; 452 break; 453 } 454 vap->va_uid = 0; 455 vap->va_gid = 0; 456 vap->va_fsid = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0]; 457 vap->va_blocksize = DEV_BSIZE; 458 getmicroboottime(&tv); 459 vap->va_atime.tv_sec = tv.tv_sec; 460 vap->va_atime.tv_nsec = 0; 461 vap->va_mtime = vap->va_atime; 462 vap->va_ctime = vap->va_mtime; 463 vap->va_gen = 0; 464 vap->va_flags = 0; 465 vap->va_bytes = 0; 466 break; 467 468 case Fdesc: 469 fd = VTOFDESC(vp)->fd_fd; 470 error = fdesc_attr(fd, vap, ap->a_cred); 471 break; 472 473 default: 474 panic("fdesc_getattr"); 475 break; 476 } 477 478 if (error == 0) 479 vp->v_type = vap->va_type; 480 481 return (error); 482 } 483 484 int 485 fdesc_setattr(void *v) 486 { 487 struct vop_setattr_args /* { 488 struct vnode *a_vp; 489 struct vattr *a_vap; 490 kauth_cred_t a_cred; 491 } */ *ap = v; 492 file_t *fp; 493 unsigned fd; 494 495 /* 496 * Can't mess with the root vnode 497 */ 498 switch (VTOFDESC(ap->a_vp)->fd_type) { 499 case Fdesc: 500 break; 501 502 case Fctty: 503 return (0); 504 505 default: 506 return (EACCES); 507 } 508 509 fd = VTOFDESC(ap->a_vp)->fd_fd; 510 if ((fp = fd_getfile(fd)) == NULL) 511 return (EBADF); 512 513 /* 514 * XXX: Can't reasonably set the attr's on any types currently. 515 * On vnode's this will cause truncation and socket/pipes make 516 * no sense. 517 */ 518 fd_putfile(fd); 519 return (0); 520 } 521 522 523 struct fdesc_target { 524 ino_t ft_fileno; 525 u_char ft_type; 526 u_char ft_namlen; 527 const char *ft_name; 528 } fdesc_targets[] = { 529 #define N(s) sizeof(s)-1, s 530 { FD_DEVFD, DT_DIR, N("fd") }, 531 { FD_STDIN, DT_LNK, N("stdin") }, 532 { FD_STDOUT, DT_LNK, N("stdout") }, 533 { FD_STDERR, DT_LNK, N("stderr") }, 534 { FD_CTTY, DT_UNKNOWN, N("tty") }, 535 #undef N 536 #define UIO_MX _DIRENT_RECLEN((struct dirent *)NULL, sizeof("stderr") - 1) 537 }; 538 static int nfdesc_targets = sizeof(fdesc_targets) / sizeof(fdesc_targets[0]); 539 540 int 541 fdesc_readdir(void *v) 542 { 543 struct vop_readdir_args /* { 544 struct vnode *a_vp; 545 struct uio *a_uio; 546 kauth_cred_t a_cred; 547 int *a_eofflag; 548 off_t **a_cookies; 549 int *a_ncookies; 550 } */ *ap = v; 551 struct uio *uio = ap->a_uio; 552 struct dirent d; 553 off_t i; 554 int j; 555 int error; 556 off_t *cookies = NULL; 557 int ncookies; 558 fdtab_t *dt; 559 560 switch (VTOFDESC(ap->a_vp)->fd_type) { 561 case Fctty: 562 return 0; 563 564 case Fdesc: 565 return ENOTDIR; 566 567 default: 568 break; 569 } 570 571 dt = atomic_load_consume(&curlwp->l_fd->fd_dt); 572 573 if (uio->uio_resid < UIO_MX) 574 return EINVAL; 575 if (uio->uio_offset < 0) 576 return EINVAL; 577 578 error = 0; 579 i = uio->uio_offset; 580 (void)memset(&d, 0, UIO_MX); 581 d.d_reclen = UIO_MX; 582 if (ap->a_ncookies) 583 ncookies = uio->uio_resid / UIO_MX; 584 else 585 ncookies = 0; 586 587 if (VTOFDESC(ap->a_vp)->fd_type == Froot) { 588 struct fdesc_target *ft; 589 590 if (i >= nfdesc_targets) 591 return 0; 592 593 if (ap->a_ncookies) { 594 ncookies = uimin(ncookies, (nfdesc_targets - i)); 595 cookies = malloc(ncookies * sizeof(off_t), 596 M_TEMP, M_WAITOK); 597 *ap->a_cookies = cookies; 598 *ap->a_ncookies = ncookies; 599 } 600 601 for (ft = &fdesc_targets[i]; uio->uio_resid >= UIO_MX && 602 i < nfdesc_targets; ft++, i++) { 603 switch (ft->ft_fileno) { 604 case FD_CTTY: 605 if (cttyvp(curproc) == NULL) 606 continue; 607 break; 608 609 case FD_STDIN: 610 case FD_STDOUT: 611 case FD_STDERR: 612 if ((ft->ft_fileno - FD_STDIN) >= 613 dt->dt_nfiles) 614 continue; 615 if (dt->dt_ff[ft->ft_fileno - FD_STDIN] 616 == NULL || dt->dt_ff[ft->ft_fileno - 617 FD_STDIN]->ff_file == NULL) 618 continue; 619 break; 620 } 621 622 d.d_fileno = ft->ft_fileno; 623 d.d_namlen = ft->ft_namlen; 624 (void)memcpy(d.d_name, ft->ft_name, ft->ft_namlen + 1); 625 d.d_type = ft->ft_type; 626 627 if ((error = uiomove(&d, UIO_MX, uio)) != 0) 628 break; 629 if (cookies) 630 *cookies++ = i + 1; 631 } 632 } else { 633 if (ap->a_ncookies) { 634 ncookies = uimin(ncookies, dt->dt_nfiles + 2); 635 cookies = malloc(ncookies * sizeof(off_t), 636 M_TEMP, M_WAITOK); 637 *ap->a_cookies = cookies; 638 *ap->a_ncookies = ncookies; 639 } 640 for (; i - 2 < dt->dt_nfiles && uio->uio_resid >= UIO_MX; i++) { 641 switch (i) { 642 case 0: 643 case 1: 644 d.d_fileno = FD_ROOT; /* XXX */ 645 d.d_namlen = i + 1; 646 (void)memcpy(d.d_name, "..", d.d_namlen); 647 d.d_name[i + 1] = '\0'; 648 d.d_type = DT_DIR; 649 break; 650 651 default: 652 j = (int)i - 2; 653 if (dt->dt_ff[j] == NULL || 654 dt->dt_ff[j]->ff_file == NULL) 655 continue; 656 d.d_fileno = j + FD_STDIN; 657 d.d_namlen = snprintf(d.d_name, 658 sizeof(d.d_name), "%d", j); 659 d.d_type = DT_UNKNOWN; 660 break; 661 } 662 663 if ((error = uiomove(&d, UIO_MX, uio)) != 0) 664 break; 665 if (cookies) 666 *cookies++ = i + 1; 667 } 668 } 669 670 if (ap->a_ncookies && error) { 671 free(*ap->a_cookies, M_TEMP); 672 *ap->a_ncookies = 0; 673 *ap->a_cookies = NULL; 674 } 675 676 uio->uio_offset = i; 677 return error; 678 } 679 680 int 681 fdesc_readlink(void *v) 682 { 683 struct vop_readlink_args /* { 684 struct vnode *a_vp; 685 struct uio *a_uio; 686 kauth_cred_t a_cred; 687 } */ *ap = v; 688 struct vnode *vp = ap->a_vp; 689 int error; 690 691 if (vp->v_type != VLNK) 692 return (EPERM); 693 694 if (VTOFDESC(vp)->fd_type == Flink) { 695 const char *ln = VTOFDESC(vp)->fd_link; 696 error = uiomove(__UNCONST(ln), strlen(ln), ap->a_uio); 697 } else { 698 error = EOPNOTSUPP; 699 } 700 701 return (error); 702 } 703 704 int 705 fdesc_read(void *v) 706 { 707 struct vop_read_args /* { 708 struct vnode *a_vp; 709 struct uio *a_uio; 710 int a_ioflag; 711 kauth_cred_t a_cred; 712 } */ *ap = v; 713 int error = EOPNOTSUPP; 714 struct vnode *vp = ap->a_vp; 715 716 switch (VTOFDESC(vp)->fd_type) { 717 case Fctty: 718 VOP_UNLOCK(vp); 719 error = cdev_read(devctty, ap->a_uio, ap->a_ioflag); 720 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 721 break; 722 723 default: 724 error = EOPNOTSUPP; 725 break; 726 } 727 728 return (error); 729 } 730 731 int 732 fdesc_write(void *v) 733 { 734 struct vop_write_args /* { 735 struct vnode *a_vp; 736 struct uio *a_uio; 737 int a_ioflag; 738 kauth_cred_t a_cred; 739 } */ *ap = v; 740 int error = EOPNOTSUPP; 741 struct vnode *vp = ap->a_vp; 742 743 switch (VTOFDESC(vp)->fd_type) { 744 case Fctty: 745 VOP_UNLOCK(vp); 746 error = cdev_write(devctty, ap->a_uio, ap->a_ioflag); 747 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 748 break; 749 750 default: 751 error = EOPNOTSUPP; 752 break; 753 } 754 755 return (error); 756 } 757 758 int 759 fdesc_ioctl(void *v) 760 { 761 struct vop_ioctl_args /* { 762 struct vnode *a_vp; 763 u_long a_command; 764 void *a_data; 765 int a_fflag; 766 kauth_cred_t a_cred; 767 } */ *ap = v; 768 int error = EOPNOTSUPP; 769 770 switch (VTOFDESC(ap->a_vp)->fd_type) { 771 case Fctty: 772 error = cdev_ioctl(devctty, ap->a_command, ap->a_data, 773 ap->a_fflag, curlwp); 774 break; 775 776 default: 777 error = EOPNOTSUPP; 778 break; 779 } 780 781 return (error); 782 } 783 784 int 785 fdesc_poll(void *v) 786 { 787 struct vop_poll_args /* { 788 struct vnode *a_vp; 789 int a_events; 790 } */ *ap = v; 791 int revents; 792 793 switch (VTOFDESC(ap->a_vp)->fd_type) { 794 case Fctty: 795 revents = cdev_poll(devctty, ap->a_events, curlwp); 796 break; 797 798 default: 799 revents = genfs_poll(v); 800 break; 801 } 802 803 return (revents); 804 } 805 806 int 807 fdesc_kqfilter(void *v) 808 { 809 struct vop_kqfilter_args /* { 810 struct vnode *a_vp; 811 struct knote *a_kn; 812 } */ *ap = v; 813 int error, fd; 814 file_t *fp; 815 816 switch (VTOFDESC(ap->a_vp)->fd_type) { 817 case Fctty: 818 error = cdev_kqfilter(devctty, ap->a_kn); 819 break; 820 821 case Fdesc: 822 /* just invoke kqfilter for the underlying descriptor */ 823 fd = VTOFDESC(ap->a_vp)->fd_fd; 824 if ((fp = fd_getfile(fd)) == NULL) 825 return (1); 826 error = (*fp->f_ops->fo_kqfilter)(fp, ap->a_kn); 827 fd_putfile(fd); 828 break; 829 830 default: 831 return (genfs_kqfilter(v)); 832 } 833 834 return (error); 835 } 836 837 int 838 fdesc_inactive(void *v) 839 { 840 struct vop_inactive_v2_args /* { 841 struct vnode *a_vp; 842 } */ *ap = v; 843 struct vnode *vp = ap->a_vp; 844 struct fdescnode *fd = VTOFDESC(vp); 845 846 /* 847 * Clear out the v_type field to avoid 848 * nasty things happening on reclaim. 849 */ 850 if (fd->fd_type == Fctty || fd->fd_type == Fdesc) 851 vp->v_type = VNON; 852 853 return (0); 854 } 855 856 int 857 fdesc_reclaim(void *v) 858 { 859 struct vop_reclaim_v2_args /* { 860 struct vnode *a_vp; 861 } */ *ap = v; 862 struct vnode *vp = ap->a_vp; 863 struct fdescnode *fd = VTOFDESC(vp); 864 865 VOP_UNLOCK(vp); 866 867 vp->v_data = NULL; 868 kmem_free(fd, sizeof(struct fdescnode)); 869 870 return (0); 871 } 872 873 /* 874 * Return POSIX pathconf information applicable to special devices. 875 */ 876 int 877 fdesc_pathconf(void *v) 878 { 879 struct vop_pathconf_args /* { 880 struct vnode *a_vp; 881 int a_name; 882 register_t *a_retval; 883 } */ *ap = v; 884 885 switch (ap->a_name) { 886 case _PC_LINK_MAX: 887 *ap->a_retval = LINK_MAX; 888 return (0); 889 case _PC_MAX_CANON: 890 *ap->a_retval = MAX_CANON; 891 return (0); 892 case _PC_MAX_INPUT: 893 *ap->a_retval = MAX_INPUT; 894 return (0); 895 case _PC_PIPE_BUF: 896 *ap->a_retval = PIPE_BUF; 897 return (0); 898 case _PC_CHOWN_RESTRICTED: 899 *ap->a_retval = 1; 900 return (0); 901 case _PC_VDISABLE: 902 *ap->a_retval = _POSIX_VDISABLE; 903 return (0); 904 case _PC_SYNC_IO: 905 *ap->a_retval = 1; 906 return (0); 907 default: 908 return genfs_pathconf(ap); 909 } 910 /* NOTREACHED */ 911 } 912 913 /* 914 * Print out the contents of a /dev/fd vnode. 915 */ 916 /* ARGSUSED */ 917 int 918 fdesc_print(void *v) 919 { 920 printf("tag VT_NON, fdesc vnode\n"); 921 return (0); 922 } 923 924 int 925 fdesc_link(void *v) 926 { 927 struct vop_link_v2_args /* { 928 struct vnode *a_dvp; 929 struct vnode *a_vp; 930 struct componentname *a_cnp; 931 } */ *ap = v; 932 933 VOP_ABORTOP(ap->a_dvp, ap->a_cnp); 934 return (EROFS); 935 } 936 937 int 938 fdesc_symlink(void *v) 939 { 940 struct vop_symlink_v3_args /* { 941 struct vnode *a_dvp; 942 struct vnode **a_vpp; 943 struct componentname *a_cnp; 944 struct vattr *a_vap; 945 char *a_target; 946 } */ *ap = v; 947 948 VOP_ABORTOP(ap->a_dvp, ap->a_cnp); 949 return (EROFS); 950 } 951