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