1 /* $NetBSD: fdesc_vnops.c,v 1.129 2017/05/26 14:21:01 riastradh 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.129 2017/05/26 14:21:01 riastradh Exp $"); 45 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/time.h> 49 #include <sys/proc.h> 50 #include <sys/kernel.h> /* boottime */ 51 #include <sys/resourcevar.h> 52 #include <sys/socketvar.h> 53 #include <sys/filedesc.h> 54 #include <sys/vnode.h> 55 #include <sys/malloc.h> 56 #include <sys/conf.h> 57 #include <sys/file.h> 58 #include <sys/stat.h> 59 #include <sys/mount.h> 60 #include <sys/namei.h> 61 #include <sys/buf.h> 62 #include <sys/dirent.h> 63 #include <sys/tty.h> 64 #include <sys/kauth.h> 65 #include <sys/atomic.h> 66 67 #include <miscfs/fdesc/fdesc.h> 68 #include <miscfs/genfs/genfs.h> 69 70 #define cttyvp(p) ((p)->p_lflag & PL_CONTROLT ? (p)->p_session->s_ttyvp : NULL) 71 72 dev_t devctty; 73 74 #if (FD_STDIN != FD_STDOUT-1) || (FD_STDOUT != FD_STDERR-1) 75 FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2 76 #endif 77 78 int fdesc_lookup(void *); 79 #define fdesc_create genfs_eopnotsupp 80 #define fdesc_mknod genfs_eopnotsupp 81 int fdesc_open(void *); 82 #define fdesc_close genfs_nullop 83 #define fdesc_access genfs_nullop 84 int fdesc_getattr(void *); 85 int fdesc_setattr(void *); 86 int fdesc_read(void *); 87 int fdesc_write(void *); 88 int fdesc_ioctl(void *); 89 int fdesc_poll(void *); 90 int fdesc_kqfilter(void *); 91 #define fdesc_mmap genfs_eopnotsupp 92 #define fdesc_fcntl genfs_fcntl 93 #define fdesc_fsync genfs_nullop 94 #define fdesc_seek genfs_seek 95 #define fdesc_remove genfs_eopnotsupp 96 int fdesc_link(void *); 97 #define fdesc_rename genfs_eopnotsupp 98 #define fdesc_mkdir genfs_eopnotsupp 99 #define fdesc_rmdir genfs_eopnotsupp 100 int fdesc_symlink(void *); 101 int fdesc_readdir(void *); 102 int fdesc_readlink(void *); 103 #define fdesc_abortop genfs_abortop 104 int fdesc_inactive(void *); 105 int fdesc_reclaim(void *); 106 #define fdesc_lock genfs_lock 107 #define fdesc_unlock genfs_unlock 108 #define fdesc_bmap genfs_badop 109 #define fdesc_strategy genfs_badop 110 int fdesc_print(void *); 111 int fdesc_pathconf(void *); 112 #define fdesc_islocked genfs_islocked 113 #define fdesc_advlock genfs_einval 114 #define fdesc_bwrite genfs_eopnotsupp 115 #define fdesc_revoke genfs_revoke 116 #define fdesc_putpages genfs_null_putpages 117 118 static int fdesc_attr(int, struct vattr *, kauth_cred_t); 119 120 int (**fdesc_vnodeop_p)(void *); 121 const struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = { 122 { &vop_default_desc, vn_default_error }, 123 { &vop_lookup_desc, fdesc_lookup }, /* lookup */ 124 { &vop_create_desc, fdesc_create }, /* create */ 125 { &vop_mknod_desc, fdesc_mknod }, /* mknod */ 126 { &vop_open_desc, fdesc_open }, /* open */ 127 { &vop_close_desc, fdesc_close }, /* close */ 128 { &vop_access_desc, fdesc_access }, /* access */ 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 = 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 416 switch (VTOFDESC(vp)->fd_type) { 417 case Froot: 418 case Fdevfd: 419 case Flink: 420 case Fctty: 421 vattr_null(vap); 422 vap->va_fileid = VTOFDESC(vp)->fd_ix; 423 424 #define R_ALL (S_IRUSR|S_IRGRP|S_IROTH) 425 #define W_ALL (S_IWUSR|S_IWGRP|S_IWOTH) 426 #define X_ALL (S_IXUSR|S_IXGRP|S_IXOTH) 427 428 switch (VTOFDESC(vp)->fd_type) { 429 case Flink: 430 vap->va_mode = R_ALL|X_ALL; 431 vap->va_type = VLNK; 432 vap->va_rdev = 0; 433 vap->va_nlink = 1; 434 vap->va_size = strlen(VTOFDESC(vp)->fd_link); 435 break; 436 437 case Fctty: 438 vap->va_mode = R_ALL|W_ALL; 439 vap->va_type = VCHR; 440 vap->va_rdev = devctty; 441 vap->va_nlink = 1; 442 vap->va_size = 0; 443 break; 444 445 default: 446 vap->va_mode = R_ALL|X_ALL; 447 vap->va_type = VDIR; 448 vap->va_rdev = 0; 449 vap->va_nlink = 2; 450 vap->va_size = DEV_BSIZE; 451 break; 452 } 453 vap->va_uid = 0; 454 vap->va_gid = 0; 455 vap->va_fsid = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0]; 456 vap->va_blocksize = DEV_BSIZE; 457 vap->va_atime.tv_sec = boottime.tv_sec; 458 vap->va_atime.tv_nsec = 0; 459 vap->va_mtime = vap->va_atime; 460 vap->va_ctime = vap->va_mtime; 461 vap->va_gen = 0; 462 vap->va_flags = 0; 463 vap->va_bytes = 0; 464 break; 465 466 case Fdesc: 467 fd = VTOFDESC(vp)->fd_fd; 468 error = fdesc_attr(fd, vap, ap->a_cred); 469 break; 470 471 default: 472 panic("fdesc_getattr"); 473 break; 474 } 475 476 if (error == 0) 477 vp->v_type = vap->va_type; 478 479 return (error); 480 } 481 482 int 483 fdesc_setattr(void *v) 484 { 485 struct vop_setattr_args /* { 486 struct vnode *a_vp; 487 struct vattr *a_vap; 488 kauth_cred_t a_cred; 489 } */ *ap = v; 490 file_t *fp; 491 unsigned fd; 492 493 /* 494 * Can't mess with the root vnode 495 */ 496 switch (VTOFDESC(ap->a_vp)->fd_type) { 497 case Fdesc: 498 break; 499 500 case Fctty: 501 return (0); 502 503 default: 504 return (EACCES); 505 } 506 507 fd = VTOFDESC(ap->a_vp)->fd_fd; 508 if ((fp = fd_getfile(fd)) == NULL) 509 return (EBADF); 510 511 /* 512 * XXX: Can't reasonably set the attr's on any types currently. 513 * On vnode's this will cause truncation and socket/pipes make 514 * no sense. 515 */ 516 fd_putfile(fd); 517 return (0); 518 } 519 520 521 struct fdesc_target { 522 ino_t ft_fileno; 523 u_char ft_type; 524 u_char ft_namlen; 525 const char *ft_name; 526 } fdesc_targets[] = { 527 #define N(s) sizeof(s)-1, s 528 { FD_DEVFD, DT_DIR, N("fd") }, 529 { FD_STDIN, DT_LNK, N("stdin") }, 530 { FD_STDOUT, DT_LNK, N("stdout") }, 531 { FD_STDERR, DT_LNK, N("stderr") }, 532 { FD_CTTY, DT_UNKNOWN, N("tty") }, 533 #undef N 534 #define UIO_MX _DIRENT_RECLEN((struct dirent *)NULL, sizeof("stderr") - 1) 535 }; 536 static int nfdesc_targets = sizeof(fdesc_targets) / sizeof(fdesc_targets[0]); 537 538 int 539 fdesc_readdir(void *v) 540 { 541 struct vop_readdir_args /* { 542 struct vnode *a_vp; 543 struct uio *a_uio; 544 kauth_cred_t a_cred; 545 int *a_eofflag; 546 off_t **a_cookies; 547 int *a_ncookies; 548 } */ *ap = v; 549 struct uio *uio = ap->a_uio; 550 struct dirent d; 551 off_t i; 552 int j; 553 int error; 554 off_t *cookies = NULL; 555 int ncookies; 556 fdtab_t *dt; 557 558 switch (VTOFDESC(ap->a_vp)->fd_type) { 559 case Fctty: 560 return 0; 561 562 case Fdesc: 563 return ENOTDIR; 564 565 default: 566 break; 567 } 568 569 dt = curlwp->l_fd->fd_dt; 570 571 if (uio->uio_resid < UIO_MX) 572 return EINVAL; 573 if (uio->uio_offset < 0) 574 return EINVAL; 575 576 error = 0; 577 i = uio->uio_offset; 578 (void)memset(&d, 0, UIO_MX); 579 d.d_reclen = UIO_MX; 580 if (ap->a_ncookies) 581 ncookies = uio->uio_resid / UIO_MX; 582 else 583 ncookies = 0; 584 585 if (VTOFDESC(ap->a_vp)->fd_type == Froot) { 586 struct fdesc_target *ft; 587 588 if (i >= nfdesc_targets) 589 return 0; 590 591 if (ap->a_ncookies) { 592 ncookies = min(ncookies, (nfdesc_targets - i)); 593 cookies = malloc(ncookies * sizeof(off_t), 594 M_TEMP, M_WAITOK); 595 *ap->a_cookies = cookies; 596 *ap->a_ncookies = ncookies; 597 } 598 599 for (ft = &fdesc_targets[i]; uio->uio_resid >= UIO_MX && 600 i < nfdesc_targets; ft++, i++) { 601 switch (ft->ft_fileno) { 602 case FD_CTTY: 603 if (cttyvp(curproc) == NULL) 604 continue; 605 break; 606 607 case FD_STDIN: 608 case FD_STDOUT: 609 case FD_STDERR: 610 if ((ft->ft_fileno - FD_STDIN) >= 611 dt->dt_nfiles) 612 continue; 613 if (dt->dt_ff[ft->ft_fileno - FD_STDIN] 614 == NULL || dt->dt_ff[ft->ft_fileno - 615 FD_STDIN]->ff_file == NULL) 616 continue; 617 break; 618 } 619 620 d.d_fileno = ft->ft_fileno; 621 d.d_namlen = ft->ft_namlen; 622 (void)memcpy(d.d_name, ft->ft_name, ft->ft_namlen + 1); 623 d.d_type = ft->ft_type; 624 625 if ((error = uiomove(&d, UIO_MX, uio)) != 0) 626 break; 627 if (cookies) 628 *cookies++ = i + 1; 629 } 630 } else { 631 membar_consumer(); 632 if (ap->a_ncookies) { 633 ncookies = min(ncookies, dt->dt_nfiles + 2); 634 cookies = malloc(ncookies * sizeof(off_t), 635 M_TEMP, M_WAITOK); 636 *ap->a_cookies = cookies; 637 *ap->a_ncookies = ncookies; 638 } 639 for (; i - 2 < dt->dt_nfiles && uio->uio_resid >= UIO_MX; i++) { 640 switch (i) { 641 case 0: 642 case 1: 643 d.d_fileno = FD_ROOT; /* XXX */ 644 d.d_namlen = i + 1; 645 (void)memcpy(d.d_name, "..", d.d_namlen); 646 d.d_name[i + 1] = '\0'; 647 d.d_type = DT_DIR; 648 break; 649 650 default: 651 j = (int)i - 2; 652 if (dt->dt_ff[j] == NULL || 653 dt->dt_ff[j]->ff_file == NULL) 654 continue; 655 d.d_fileno = j + FD_STDIN; 656 d.d_namlen = snprintf(d.d_name, 657 sizeof(d.d_name), "%d", j); 658 d.d_type = DT_UNKNOWN; 659 break; 660 } 661 662 if ((error = uiomove(&d, UIO_MX, uio)) != 0) 663 break; 664 if (cookies) 665 *cookies++ = i + 1; 666 } 667 } 668 669 if (ap->a_ncookies && error) { 670 free(*ap->a_cookies, M_TEMP); 671 *ap->a_ncookies = 0; 672 *ap->a_cookies = NULL; 673 } 674 675 uio->uio_offset = i; 676 return error; 677 } 678 679 int 680 fdesc_readlink(void *v) 681 { 682 struct vop_readlink_args /* { 683 struct vnode *a_vp; 684 struct uio *a_uio; 685 kauth_cred_t a_cred; 686 } */ *ap = v; 687 struct vnode *vp = ap->a_vp; 688 int error; 689 690 if (vp->v_type != VLNK) 691 return (EPERM); 692 693 if (VTOFDESC(vp)->fd_type == Flink) { 694 const char *ln = VTOFDESC(vp)->fd_link; 695 error = uiomove(__UNCONST(ln), strlen(ln), ap->a_uio); 696 } else { 697 error = EOPNOTSUPP; 698 } 699 700 return (error); 701 } 702 703 int 704 fdesc_read(void *v) 705 { 706 struct vop_read_args /* { 707 struct vnode *a_vp; 708 struct uio *a_uio; 709 int a_ioflag; 710 kauth_cred_t a_cred; 711 } */ *ap = v; 712 int error = EOPNOTSUPP; 713 struct vnode *vp = ap->a_vp; 714 715 switch (VTOFDESC(vp)->fd_type) { 716 case Fctty: 717 VOP_UNLOCK(vp); 718 error = cdev_read(devctty, ap->a_uio, ap->a_ioflag); 719 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 720 break; 721 722 default: 723 error = EOPNOTSUPP; 724 break; 725 } 726 727 return (error); 728 } 729 730 int 731 fdesc_write(void *v) 732 { 733 struct vop_write_args /* { 734 struct vnode *a_vp; 735 struct uio *a_uio; 736 int a_ioflag; 737 kauth_cred_t a_cred; 738 } */ *ap = v; 739 int error = EOPNOTSUPP; 740 struct vnode *vp = ap->a_vp; 741 742 switch (VTOFDESC(vp)->fd_type) { 743 case Fctty: 744 VOP_UNLOCK(vp); 745 error = cdev_write(devctty, ap->a_uio, ap->a_ioflag); 746 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 747 break; 748 749 default: 750 error = EOPNOTSUPP; 751 break; 752 } 753 754 return (error); 755 } 756 757 int 758 fdesc_ioctl(void *v) 759 { 760 struct vop_ioctl_args /* { 761 struct vnode *a_vp; 762 u_long a_command; 763 void *a_data; 764 int a_fflag; 765 kauth_cred_t a_cred; 766 } */ *ap = v; 767 int error = EOPNOTSUPP; 768 769 switch (VTOFDESC(ap->a_vp)->fd_type) { 770 case Fctty: 771 error = cdev_ioctl(devctty, ap->a_command, ap->a_data, 772 ap->a_fflag, curlwp); 773 break; 774 775 default: 776 error = EOPNOTSUPP; 777 break; 778 } 779 780 return (error); 781 } 782 783 int 784 fdesc_poll(void *v) 785 { 786 struct vop_poll_args /* { 787 struct vnode *a_vp; 788 int a_events; 789 } */ *ap = v; 790 int revents; 791 792 switch (VTOFDESC(ap->a_vp)->fd_type) { 793 case Fctty: 794 revents = cdev_poll(devctty, ap->a_events, curlwp); 795 break; 796 797 default: 798 revents = genfs_poll(v); 799 break; 800 } 801 802 return (revents); 803 } 804 805 int 806 fdesc_kqfilter(void *v) 807 { 808 struct vop_kqfilter_args /* { 809 struct vnode *a_vp; 810 struct knote *a_kn; 811 } */ *ap = v; 812 int error, fd; 813 file_t *fp; 814 815 switch (VTOFDESC(ap->a_vp)->fd_type) { 816 case Fctty: 817 error = cdev_kqfilter(devctty, ap->a_kn); 818 break; 819 820 case Fdesc: 821 /* just invoke kqfilter for the underlying descriptor */ 822 fd = VTOFDESC(ap->a_vp)->fd_fd; 823 if ((fp = fd_getfile(fd)) == NULL) 824 return (1); 825 error = (*fp->f_ops->fo_kqfilter)(fp, ap->a_kn); 826 fd_putfile(fd); 827 break; 828 829 default: 830 return (genfs_kqfilter(v)); 831 } 832 833 return (error); 834 } 835 836 int 837 fdesc_inactive(void *v) 838 { 839 struct vop_inactive_v2_args /* { 840 struct vnode *a_vp; 841 } */ *ap = v; 842 struct vnode *vp = ap->a_vp; 843 struct fdescnode *fd = VTOFDESC(vp); 844 845 /* 846 * Clear out the v_type field to avoid 847 * nasty things happening on reclaim. 848 */ 849 if (fd->fd_type == Fctty || fd->fd_type == Fdesc) 850 vp->v_type = VNON; 851 852 return (0); 853 } 854 855 int 856 fdesc_reclaim(void *v) 857 { 858 struct vop_reclaim_v2_args /* { 859 struct vnode *a_vp; 860 } */ *ap = v; 861 struct vnode *vp = ap->a_vp; 862 struct fdescnode *fd = VTOFDESC(vp); 863 864 VOP_UNLOCK(vp); 865 866 vp->v_data = NULL; 867 kmem_free(fd, sizeof(struct fdescnode)); 868 869 return (0); 870 } 871 872 /* 873 * Return POSIX pathconf information applicable to special devices. 874 */ 875 int 876 fdesc_pathconf(void *v) 877 { 878 struct vop_pathconf_args /* { 879 struct vnode *a_vp; 880 int a_name; 881 register_t *a_retval; 882 } */ *ap = v; 883 884 switch (ap->a_name) { 885 case _PC_LINK_MAX: 886 *ap->a_retval = LINK_MAX; 887 return (0); 888 case _PC_MAX_CANON: 889 *ap->a_retval = MAX_CANON; 890 return (0); 891 case _PC_MAX_INPUT: 892 *ap->a_retval = MAX_INPUT; 893 return (0); 894 case _PC_PIPE_BUF: 895 *ap->a_retval = PIPE_BUF; 896 return (0); 897 case _PC_CHOWN_RESTRICTED: 898 *ap->a_retval = 1; 899 return (0); 900 case _PC_VDISABLE: 901 *ap->a_retval = _POSIX_VDISABLE; 902 return (0); 903 case _PC_SYNC_IO: 904 *ap->a_retval = 1; 905 return (0); 906 default: 907 return (EINVAL); 908 } 909 /* NOTREACHED */ 910 } 911 912 /* 913 * Print out the contents of a /dev/fd vnode. 914 */ 915 /* ARGSUSED */ 916 int 917 fdesc_print(void *v) 918 { 919 printf("tag VT_NON, fdesc vnode\n"); 920 return (0); 921 } 922 923 int 924 fdesc_link(void *v) 925 { 926 struct vop_link_v2_args /* { 927 struct vnode *a_dvp; 928 struct vnode *a_vp; 929 struct componentname *a_cnp; 930 } */ *ap = v; 931 932 VOP_ABORTOP(ap->a_dvp, ap->a_cnp); 933 return (EROFS); 934 } 935 936 int 937 fdesc_symlink(void *v) 938 { 939 struct vop_symlink_v3_args /* { 940 struct vnode *a_dvp; 941 struct vnode **a_vpp; 942 struct componentname *a_cnp; 943 struct vattr *a_vap; 944 char *a_target; 945 } */ *ap = v; 946 947 VOP_ABORTOP(ap->a_dvp, ap->a_cnp); 948 return (EROFS); 949 } 950