1 /*- 2 * Copyright (c) 2001 Dag-Erling Coïdan Smørgrav 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include "opt_pseudofs.h" 33 34 #include <sys/param.h> 35 #include <sys/kernel.h> 36 #include <sys/systm.h> 37 #include <sys/ctype.h> 38 #include <sys/dirent.h> 39 #include <sys/fcntl.h> 40 #include <sys/limits.h> 41 #include <sys/lock.h> 42 #include <sys/malloc.h> 43 #include <sys/mount.h> 44 #include <sys/mutex.h> 45 #include <sys/namei.h> 46 #include <sys/proc.h> 47 #include <sys/sbuf.h> 48 #include <sys/sx.h> 49 #include <sys/sysctl.h> 50 #include <sys/vnode.h> 51 52 #include <fs/pseudofs/pseudofs.h> 53 #include <fs/pseudofs/pseudofs_internal.h> 54 55 #define KASSERT_PN_IS_DIR(pn) \ 56 KASSERT((pn)->pn_type == pfstype_root || \ 57 (pn)->pn_type == pfstype_dir || \ 58 (pn)->pn_type == pfstype_procdir, \ 59 ("%s(): VDIR vnode refers to non-directory pfs_node", __func__)) 60 61 #define KASSERT_PN_IS_FILE(pn) \ 62 KASSERT((pn)->pn_type == pfstype_file, \ 63 ("%s(): VREG vnode refers to non-file pfs_node", __func__)) 64 65 #define KASSERT_PN_IS_LINK(pn) \ 66 KASSERT((pn)->pn_type == pfstype_symlink, \ 67 ("%s(): VLNK vnode refers to non-link pfs_node", __func__)) 68 69 /* 70 * Returns the fileno, adjusted for target pid 71 */ 72 static uint32_t 73 pn_fileno(struct pfs_node *pn, pid_t pid) 74 { 75 76 KASSERT(pn->pn_fileno > 0, 77 ("%s(): no fileno allocated", __func__)); 78 if (pid != NO_PID) 79 return (pn->pn_fileno * NO_PID + pid); 80 return (pn->pn_fileno); 81 } 82 83 /* 84 * Returns non-zero if given file is visible to given thread. 85 */ 86 static int 87 pfs_visible_proc(struct thread *td, struct pfs_node *pn, struct proc *proc) 88 { 89 int visible; 90 91 if (proc == NULL) 92 return (0); 93 94 PROC_LOCK_ASSERT(proc, MA_OWNED); 95 96 visible = ((proc->p_flag & P_WEXIT) == 0); 97 if (visible) 98 visible = (p_cansee(td, proc) == 0); 99 if (visible && pn->pn_vis != NULL) 100 visible = pn_vis(td, proc, pn); 101 if (!visible) 102 return (0); 103 return (1); 104 } 105 106 static int 107 pfs_visible(struct thread *td, struct pfs_node *pn, pid_t pid, 108 bool allproc_locked, struct proc **p) 109 { 110 struct proc *proc; 111 112 PFS_TRACE(("%s (pid: %d, req: %d)", 113 pn->pn_name, pid, td->td_proc->p_pid)); 114 115 if (p) 116 *p = NULL; 117 if (pid == NO_PID) 118 PFS_RETURN (1); 119 proc = allproc_locked ? pfind_locked(pid) : pfind(pid); 120 if (proc == NULL) 121 PFS_RETURN (0); 122 if (pfs_visible_proc(td, pn, proc)) { 123 if (p) 124 *p = proc; 125 else 126 PROC_UNLOCK(proc); 127 PFS_RETURN (1); 128 } 129 PROC_UNLOCK(proc); 130 PFS_RETURN (0); 131 } 132 133 /* 134 * Verify permissions 135 */ 136 static int 137 pfs_access(struct vop_access_args *va) 138 { 139 struct vnode *vn = va->a_vp; 140 struct pfs_vdata *pvd = vn->v_data; 141 struct vattr vattr; 142 int error; 143 144 PFS_TRACE(("%s", pvd->pvd_pn->pn_name)); 145 (void)pvd; 146 147 error = VOP_GETATTR(vn, &vattr, va->a_cred); 148 if (error) 149 PFS_RETURN (error); 150 error = vaccess(vn->v_type, vattr.va_mode, vattr.va_uid, 151 vattr.va_gid, va->a_accmode, va->a_cred, NULL); 152 PFS_RETURN (error); 153 } 154 155 /* 156 * Close a file or directory 157 */ 158 static int 159 pfs_close(struct vop_close_args *va) 160 { 161 struct vnode *vn = va->a_vp; 162 struct pfs_vdata *pvd = vn->v_data; 163 struct pfs_node *pn = pvd->pvd_pn; 164 struct proc *proc; 165 int error; 166 167 PFS_TRACE(("%s", pn->pn_name)); 168 pfs_assert_not_owned(pn); 169 170 /* 171 * Do nothing unless this is the last close and the node has a 172 * last-close handler. 173 */ 174 if (vrefcnt(vn) > 1 || pn->pn_close == NULL) 175 PFS_RETURN (0); 176 177 if (pvd->pvd_pid != NO_PID) { 178 proc = pfind(pvd->pvd_pid); 179 } else { 180 proc = NULL; 181 } 182 183 error = pn_close(va->a_td, proc, pn); 184 185 if (proc != NULL) 186 PROC_UNLOCK(proc); 187 188 PFS_RETURN (error); 189 } 190 191 /* 192 * Get file attributes 193 */ 194 static int 195 pfs_getattr(struct vop_getattr_args *va) 196 { 197 struct vnode *vn = va->a_vp; 198 struct pfs_vdata *pvd = vn->v_data; 199 struct pfs_node *pn = pvd->pvd_pn; 200 struct vattr *vap = va->a_vap; 201 struct proc *proc; 202 int error = 0; 203 204 PFS_TRACE(("%s", pn->pn_name)); 205 pfs_assert_not_owned(pn); 206 207 if (!pfs_visible(curthread, pn, pvd->pvd_pid, false, &proc)) 208 PFS_RETURN (ENOENT); 209 210 vap->va_type = vn->v_type; 211 vap->va_fileid = pn_fileno(pn, pvd->pvd_pid); 212 vap->va_flags = 0; 213 vap->va_blocksize = PAGE_SIZE; 214 vap->va_bytes = vap->va_size = 0; 215 vap->va_filerev = 0; 216 vap->va_fsid = vn->v_mount->mnt_stat.f_fsid.val[0]; 217 vap->va_nlink = 1; 218 nanotime(&vap->va_ctime); 219 vap->va_atime = vap->va_mtime = vap->va_ctime; 220 221 switch (pn->pn_type) { 222 case pfstype_procdir: 223 case pfstype_root: 224 case pfstype_dir: 225 #if 0 226 pfs_lock(pn); 227 /* compute link count */ 228 pfs_unlock(pn); 229 #endif 230 vap->va_mode = 0555; 231 break; 232 case pfstype_file: 233 case pfstype_symlink: 234 vap->va_mode = 0444; 235 break; 236 default: 237 printf("shouldn't be here!\n"); 238 vap->va_mode = 0; 239 break; 240 } 241 242 if (proc != NULL) { 243 vap->va_uid = proc->p_ucred->cr_ruid; 244 vap->va_gid = proc->p_ucred->cr_rgid; 245 } else { 246 vap->va_uid = 0; 247 vap->va_gid = 0; 248 } 249 250 if (pn->pn_attr != NULL) 251 error = pn_attr(curthread, proc, pn, vap); 252 253 if(proc != NULL) 254 PROC_UNLOCK(proc); 255 256 PFS_RETURN (error); 257 } 258 259 /* 260 * Perform an ioctl 261 */ 262 static int 263 pfs_ioctl(struct vop_ioctl_args *va) 264 { 265 struct vnode *vn; 266 struct pfs_vdata *pvd; 267 struct pfs_node *pn; 268 struct proc *proc; 269 int error; 270 271 vn = va->a_vp; 272 vn_lock(vn, LK_SHARED | LK_RETRY); 273 if (vn->v_iflag & VI_DOOMED) { 274 VOP_UNLOCK(vn, 0); 275 return (EBADF); 276 } 277 pvd = vn->v_data; 278 pn = pvd->pvd_pn; 279 280 PFS_TRACE(("%s: %lx", pn->pn_name, va->a_command)); 281 pfs_assert_not_owned(pn); 282 283 if (vn->v_type != VREG) { 284 VOP_UNLOCK(vn, 0); 285 PFS_RETURN (EINVAL); 286 } 287 KASSERT_PN_IS_FILE(pn); 288 289 if (pn->pn_ioctl == NULL) { 290 VOP_UNLOCK(vn, 0); 291 PFS_RETURN (ENOTTY); 292 } 293 294 /* 295 * This is necessary because process' privileges may 296 * have changed since the open() call. 297 */ 298 if (!pfs_visible(curthread, pn, pvd->pvd_pid, false, &proc)) { 299 VOP_UNLOCK(vn, 0); 300 PFS_RETURN (EIO); 301 } 302 303 error = pn_ioctl(curthread, proc, pn, va->a_command, va->a_data); 304 305 if (proc != NULL) 306 PROC_UNLOCK(proc); 307 308 VOP_UNLOCK(vn, 0); 309 PFS_RETURN (error); 310 } 311 312 /* 313 * Perform getextattr 314 */ 315 static int 316 pfs_getextattr(struct vop_getextattr_args *va) 317 { 318 struct vnode *vn = va->a_vp; 319 struct pfs_vdata *pvd = vn->v_data; 320 struct pfs_node *pn = pvd->pvd_pn; 321 struct proc *proc; 322 int error; 323 324 PFS_TRACE(("%s", pn->pn_name)); 325 pfs_assert_not_owned(pn); 326 327 /* 328 * This is necessary because either process' privileges may 329 * have changed since the open() call. 330 */ 331 if (!pfs_visible(curthread, pn, pvd->pvd_pid, false, &proc)) 332 PFS_RETURN (EIO); 333 334 if (pn->pn_getextattr == NULL) 335 error = EOPNOTSUPP; 336 else 337 error = pn_getextattr(curthread, proc, pn, 338 va->a_attrnamespace, va->a_name, va->a_uio, 339 va->a_size, va->a_cred); 340 341 if (proc != NULL) 342 PROC_UNLOCK(proc); 343 344 PFS_RETURN (error); 345 } 346 347 /* 348 * Convert a vnode to its component name 349 */ 350 static int 351 pfs_vptocnp(struct vop_vptocnp_args *ap) 352 { 353 struct vnode *vp = ap->a_vp; 354 struct vnode **dvp = ap->a_vpp; 355 struct pfs_vdata *pvd = vp->v_data; 356 struct pfs_node *pd = pvd->pvd_pn; 357 struct pfs_node *pn; 358 struct mount *mp; 359 char *buf = ap->a_buf; 360 int *buflen = ap->a_buflen; 361 char pidbuf[PFS_NAMELEN]; 362 pid_t pid = pvd->pvd_pid; 363 int len, i, error, locked; 364 365 i = *buflen; 366 error = 0; 367 368 pfs_lock(pd); 369 370 if (vp->v_type == VDIR && pd->pn_type == pfstype_root) { 371 *dvp = vp; 372 vhold(*dvp); 373 pfs_unlock(pd); 374 PFS_RETURN (0); 375 } else if (vp->v_type == VDIR && pd->pn_type == pfstype_procdir) { 376 len = snprintf(pidbuf, sizeof(pidbuf), "%d", pid); 377 i -= len; 378 if (i < 0) { 379 error = ENOMEM; 380 goto failed; 381 } 382 bcopy(pidbuf, buf + i, len); 383 } else { 384 len = strlen(pd->pn_name); 385 i -= len; 386 if (i < 0) { 387 error = ENOMEM; 388 goto failed; 389 } 390 bcopy(pd->pn_name, buf + i, len); 391 } 392 393 pn = pd->pn_parent; 394 pfs_unlock(pd); 395 396 mp = vp->v_mount; 397 error = vfs_busy(mp, 0); 398 if (error) 399 return (error); 400 401 /* 402 * vp is held by caller. 403 */ 404 locked = VOP_ISLOCKED(vp); 405 VOP_UNLOCK(vp, 0); 406 407 error = pfs_vncache_alloc(mp, dvp, pn, pid); 408 if (error) { 409 vn_lock(vp, locked | LK_RETRY); 410 vfs_unbusy(mp); 411 PFS_RETURN(error); 412 } 413 414 *buflen = i; 415 VOP_UNLOCK(*dvp, 0); 416 vn_lock(vp, locked | LK_RETRY); 417 vfs_unbusy(mp); 418 419 PFS_RETURN (0); 420 failed: 421 pfs_unlock(pd); 422 PFS_RETURN(error); 423 } 424 425 /* 426 * Look up a file or directory 427 */ 428 static int 429 pfs_lookup(struct vop_cachedlookup_args *va) 430 { 431 struct vnode *vn = va->a_dvp; 432 struct vnode **vpp = va->a_vpp; 433 struct componentname *cnp = va->a_cnp; 434 struct pfs_vdata *pvd = vn->v_data; 435 struct pfs_node *pd = pvd->pvd_pn; 436 struct pfs_node *pn, *pdn = NULL; 437 struct mount *mp; 438 pid_t pid = pvd->pvd_pid; 439 char *pname; 440 int error, i, namelen, visible; 441 442 PFS_TRACE(("%.*s", (int)cnp->cn_namelen, cnp->cn_nameptr)); 443 pfs_assert_not_owned(pd); 444 445 if (vn->v_type != VDIR) 446 PFS_RETURN (ENOTDIR); 447 KASSERT_PN_IS_DIR(pd); 448 449 error = VOP_ACCESS(vn, VEXEC, cnp->cn_cred, cnp->cn_thread); 450 if (error) 451 PFS_RETURN (error); 452 453 /* 454 * Don't support DELETE or RENAME. CREATE is supported so 455 * that O_CREAT will work, but the lookup will still fail if 456 * the file does not exist. 457 */ 458 if ((cnp->cn_flags & ISLASTCN) && 459 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 460 PFS_RETURN (EOPNOTSUPP); 461 462 /* shortcut: check if the name is too long */ 463 if (cnp->cn_namelen >= PFS_NAMELEN) 464 PFS_RETURN (ENOENT); 465 466 /* check that parent directory is visible... */ 467 if (!pfs_visible(curthread, pd, pvd->pvd_pid, false, NULL)) 468 PFS_RETURN (ENOENT); 469 470 /* self */ 471 namelen = cnp->cn_namelen; 472 pname = cnp->cn_nameptr; 473 if (namelen == 1 && pname[0] == '.') { 474 pn = pd; 475 *vpp = vn; 476 VREF(vn); 477 PFS_RETURN (0); 478 } 479 480 mp = vn->v_mount; 481 482 /* parent */ 483 if (cnp->cn_flags & ISDOTDOT) { 484 if (pd->pn_type == pfstype_root) 485 PFS_RETURN (EIO); 486 error = vfs_busy(mp, MBF_NOWAIT); 487 if (error != 0) { 488 vfs_ref(mp); 489 VOP_UNLOCK(vn, 0); 490 error = vfs_busy(mp, 0); 491 vn_lock(vn, LK_EXCLUSIVE | LK_RETRY); 492 vfs_rel(mp); 493 if (error != 0) 494 PFS_RETURN(ENOENT); 495 if (vn->v_iflag & VI_DOOMED) { 496 vfs_unbusy(mp); 497 PFS_RETURN(ENOENT); 498 } 499 } 500 VOP_UNLOCK(vn, 0); 501 KASSERT(pd->pn_parent != NULL, 502 ("%s(): non-root directory has no parent", __func__)); 503 /* 504 * This one is tricky. Descendents of procdir nodes 505 * inherit their parent's process affinity, but 506 * there's no easy reverse mapping. For simplicity, 507 * we assume that if this node is a procdir, its 508 * parent isn't (which is correct as long as 509 * descendents of procdir nodes are never procdir 510 * nodes themselves) 511 */ 512 if (pd->pn_type == pfstype_procdir) 513 pid = NO_PID; 514 pfs_lock(pd); 515 pn = pd->pn_parent; 516 pfs_unlock(pd); 517 goto got_pnode; 518 } 519 520 pfs_lock(pd); 521 522 /* named node */ 523 for (pn = pd->pn_nodes; pn != NULL; pn = pn->pn_next) 524 if (pn->pn_type == pfstype_procdir) 525 pdn = pn; 526 else if (pn->pn_name[namelen] == '\0' && 527 bcmp(pname, pn->pn_name, namelen) == 0) { 528 pfs_unlock(pd); 529 goto got_pnode; 530 } 531 532 /* process dependent node */ 533 if ((pn = pdn) != NULL) { 534 pid = 0; 535 for (pid = 0, i = 0; i < namelen && isdigit(pname[i]); ++i) 536 if ((pid = pid * 10 + pname[i] - '0') > PID_MAX) 537 break; 538 if (i == cnp->cn_namelen) { 539 pfs_unlock(pd); 540 goto got_pnode; 541 } 542 } 543 544 pfs_unlock(pd); 545 546 PFS_RETURN (ENOENT); 547 548 got_pnode: 549 pfs_assert_not_owned(pd); 550 pfs_assert_not_owned(pn); 551 visible = pfs_visible(curthread, pn, pid, false, NULL); 552 if (!visible) { 553 error = ENOENT; 554 goto failed; 555 } 556 557 error = pfs_vncache_alloc(mp, vpp, pn, pid); 558 if (error) 559 goto failed; 560 561 if (cnp->cn_flags & ISDOTDOT) { 562 vfs_unbusy(mp); 563 vn_lock(vn, LK_EXCLUSIVE | LK_RETRY); 564 if (vn->v_iflag & VI_DOOMED) { 565 vput(*vpp); 566 *vpp = NULL; 567 PFS_RETURN(ENOENT); 568 } 569 } 570 if (cnp->cn_flags & MAKEENTRY && !(vn->v_iflag & VI_DOOMED)) 571 cache_enter(vn, *vpp, cnp); 572 PFS_RETURN (0); 573 failed: 574 if (cnp->cn_flags & ISDOTDOT) { 575 vfs_unbusy(mp); 576 vn_lock(vn, LK_EXCLUSIVE | LK_RETRY); 577 *vpp = NULL; 578 } 579 PFS_RETURN(error); 580 } 581 582 /* 583 * Open a file or directory. 584 */ 585 static int 586 pfs_open(struct vop_open_args *va) 587 { 588 struct vnode *vn = va->a_vp; 589 struct pfs_vdata *pvd = vn->v_data; 590 struct pfs_node *pn = pvd->pvd_pn; 591 int mode = va->a_mode; 592 593 PFS_TRACE(("%s (mode 0x%x)", pn->pn_name, mode)); 594 pfs_assert_not_owned(pn); 595 596 /* check if the requested mode is permitted */ 597 if (((mode & FREAD) && !(mode & PFS_RD)) || 598 ((mode & FWRITE) && !(mode & PFS_WR))) 599 PFS_RETURN (EPERM); 600 601 /* we don't support locking */ 602 if ((mode & O_SHLOCK) || (mode & O_EXLOCK)) 603 PFS_RETURN (EOPNOTSUPP); 604 605 PFS_RETURN (0); 606 } 607 608 /* 609 * Read from a file 610 */ 611 static int 612 pfs_read(struct vop_read_args *va) 613 { 614 struct vnode *vn = va->a_vp; 615 struct pfs_vdata *pvd = vn->v_data; 616 struct pfs_node *pn = pvd->pvd_pn; 617 struct uio *uio = va->a_uio; 618 struct proc *proc; 619 struct sbuf *sb = NULL; 620 int error, locked; 621 off_t buflen; 622 623 PFS_TRACE(("%s", pn->pn_name)); 624 pfs_assert_not_owned(pn); 625 626 if (vn->v_type != VREG) 627 PFS_RETURN (EINVAL); 628 KASSERT_PN_IS_FILE(pn); 629 630 if (!(pn->pn_flags & PFS_RD)) 631 PFS_RETURN (EBADF); 632 633 if (pn->pn_fill == NULL) 634 PFS_RETURN (EIO); 635 636 /* 637 * This is necessary because either process' privileges may 638 * have changed since the open() call. 639 */ 640 if (!pfs_visible(curthread, pn, pvd->pvd_pid, false, &proc)) 641 PFS_RETURN (EIO); 642 if (proc != NULL) { 643 _PHOLD(proc); 644 PROC_UNLOCK(proc); 645 } 646 647 vhold(vn); 648 locked = VOP_ISLOCKED(vn); 649 VOP_UNLOCK(vn, 0); 650 651 if (pn->pn_flags & PFS_RAWRD) { 652 PFS_TRACE(("%zd resid", uio->uio_resid)); 653 error = pn_fill(curthread, proc, pn, NULL, uio); 654 PFS_TRACE(("%zd resid", uio->uio_resid)); 655 goto ret; 656 } 657 658 if (uio->uio_resid < 0 || uio->uio_offset < 0 || 659 uio->uio_resid > OFF_MAX - uio->uio_offset) { 660 error = EINVAL; 661 goto ret; 662 } 663 buflen = uio->uio_offset + uio->uio_resid; 664 if (buflen > MAXPHYS) 665 buflen = MAXPHYS; 666 667 sb = sbuf_new(sb, NULL, buflen + 1, 0); 668 if (sb == NULL) { 669 error = EIO; 670 goto ret; 671 } 672 673 error = pn_fill(curthread, proc, pn, sb, uio); 674 675 if (error) { 676 sbuf_delete(sb); 677 goto ret; 678 } 679 680 /* 681 * XXX: If the buffer overflowed, sbuf_len() will not return 682 * the data length. Then just use the full length because an 683 * overflowed sbuf must be full. 684 */ 685 if (sbuf_finish(sb) == 0) 686 buflen = sbuf_len(sb); 687 error = uiomove_frombuf(sbuf_data(sb), buflen, uio); 688 sbuf_delete(sb); 689 ret: 690 vn_lock(vn, locked | LK_RETRY); 691 vdrop(vn); 692 if (proc != NULL) 693 PRELE(proc); 694 PFS_RETURN (error); 695 } 696 697 /* 698 * Iterate through directory entries 699 */ 700 static int 701 pfs_iterate(struct thread *td, struct proc *proc, struct pfs_node *pd, 702 struct pfs_node **pn, struct proc **p) 703 { 704 int visible; 705 706 sx_assert(&allproc_lock, SX_SLOCKED); 707 pfs_assert_owned(pd); 708 again: 709 if (*pn == NULL) { 710 /* first node */ 711 *pn = pd->pn_nodes; 712 } else if ((*pn)->pn_type != pfstype_procdir) { 713 /* next node */ 714 *pn = (*pn)->pn_next; 715 } 716 if (*pn != NULL && (*pn)->pn_type == pfstype_procdir) { 717 /* next process */ 718 if (*p == NULL) 719 *p = LIST_FIRST(&allproc); 720 else 721 *p = LIST_NEXT(*p, p_list); 722 /* out of processes: next node */ 723 if (*p == NULL) 724 *pn = (*pn)->pn_next; 725 else 726 PROC_LOCK(*p); 727 } 728 729 if ((*pn) == NULL) 730 return (-1); 731 732 if (*p != NULL) { 733 visible = pfs_visible_proc(td, *pn, *p); 734 PROC_UNLOCK(*p); 735 } else if (proc != NULL) { 736 visible = pfs_visible_proc(td, *pn, proc); 737 } else { 738 visible = 1; 739 } 740 if (!visible) 741 goto again; 742 743 return (0); 744 } 745 746 /* Directory entry list */ 747 struct pfsentry { 748 STAILQ_ENTRY(pfsentry) link; 749 struct dirent entry; 750 }; 751 STAILQ_HEAD(pfsdirentlist, pfsentry); 752 753 /* 754 * Return directory entries. 755 */ 756 static int 757 pfs_readdir(struct vop_readdir_args *va) 758 { 759 struct vnode *vn = va->a_vp; 760 struct pfs_vdata *pvd = vn->v_data; 761 struct pfs_node *pd = pvd->pvd_pn; 762 pid_t pid = pvd->pvd_pid; 763 struct proc *p, *proc; 764 struct pfs_node *pn; 765 struct uio *uio; 766 struct pfsentry *pfsent, *pfsent2; 767 struct pfsdirentlist lst; 768 off_t offset; 769 int error, i, resid; 770 771 STAILQ_INIT(&lst); 772 error = 0; 773 KASSERT(pd->pn_info == vn->v_mount->mnt_data, 774 ("%s(): pn_info does not match mountpoint", __func__)); 775 PFS_TRACE(("%s pid %lu", pd->pn_name, (unsigned long)pid)); 776 pfs_assert_not_owned(pd); 777 778 if (vn->v_type != VDIR) 779 PFS_RETURN (ENOTDIR); 780 KASSERT_PN_IS_DIR(pd); 781 uio = va->a_uio; 782 783 /* only allow reading entire entries */ 784 offset = uio->uio_offset; 785 resid = uio->uio_resid; 786 if (offset < 0 || offset % PFS_DELEN != 0 || 787 (resid && resid < PFS_DELEN)) 788 PFS_RETURN (EINVAL); 789 if (resid == 0) 790 PFS_RETURN (0); 791 792 sx_slock(&allproc_lock); 793 pfs_lock(pd); 794 795 /* check if the directory is visible to the caller */ 796 if (!pfs_visible(curthread, pd, pid, true, &proc)) { 797 sx_sunlock(&allproc_lock); 798 pfs_unlock(pd); 799 PFS_RETURN (ENOENT); 800 } 801 KASSERT(pid == NO_PID || proc != NULL, 802 ("%s(): no process for pid %lu", __func__, (unsigned long)pid)); 803 804 /* skip unwanted entries */ 805 for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN) { 806 if (pfs_iterate(curthread, proc, pd, &pn, &p) == -1) { 807 /* nothing left... */ 808 if (proc != NULL) 809 PROC_UNLOCK(proc); 810 pfs_unlock(pd); 811 sx_sunlock(&allproc_lock); 812 PFS_RETURN (0); 813 } 814 } 815 816 /* fill in entries */ 817 while (pfs_iterate(curthread, proc, pd, &pn, &p) != -1 && 818 resid >= PFS_DELEN) { 819 if ((pfsent = malloc(sizeof(struct pfsentry), M_IOV, 820 M_NOWAIT | M_ZERO)) == NULL) { 821 error = ENOMEM; 822 break; 823 } 824 pfsent->entry.d_reclen = PFS_DELEN; 825 pfsent->entry.d_fileno = pn_fileno(pn, pid); 826 /* PFS_DELEN was picked to fit PFS_NAMLEN */ 827 for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i) 828 pfsent->entry.d_name[i] = pn->pn_name[i]; 829 pfsent->entry.d_name[i] = 0; 830 pfsent->entry.d_namlen = i; 831 switch (pn->pn_type) { 832 case pfstype_procdir: 833 KASSERT(p != NULL, 834 ("reached procdir node with p == NULL")); 835 pfsent->entry.d_namlen = snprintf(pfsent->entry.d_name, 836 PFS_NAMELEN, "%d", p->p_pid); 837 /* fall through */ 838 case pfstype_root: 839 case pfstype_dir: 840 case pfstype_this: 841 case pfstype_parent: 842 pfsent->entry.d_type = DT_DIR; 843 break; 844 case pfstype_file: 845 pfsent->entry.d_type = DT_REG; 846 break; 847 case pfstype_symlink: 848 pfsent->entry.d_type = DT_LNK; 849 break; 850 default: 851 panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type); 852 } 853 PFS_TRACE(("%s", pfsent->entry.d_name)); 854 STAILQ_INSERT_TAIL(&lst, pfsent, link); 855 offset += PFS_DELEN; 856 resid -= PFS_DELEN; 857 } 858 if (proc != NULL) 859 PROC_UNLOCK(proc); 860 pfs_unlock(pd); 861 sx_sunlock(&allproc_lock); 862 i = 0; 863 STAILQ_FOREACH_SAFE(pfsent, &lst, link, pfsent2) { 864 if (error == 0) 865 error = uiomove(&pfsent->entry, PFS_DELEN, uio); 866 free(pfsent, M_IOV); 867 i++; 868 } 869 PFS_TRACE(("%d bytes", i * PFS_DELEN)); 870 PFS_RETURN (error); 871 } 872 873 /* 874 * Read a symbolic link 875 */ 876 static int 877 pfs_readlink(struct vop_readlink_args *va) 878 { 879 struct vnode *vn = va->a_vp; 880 struct pfs_vdata *pvd = vn->v_data; 881 struct pfs_node *pn = pvd->pvd_pn; 882 struct uio *uio = va->a_uio; 883 struct proc *proc = NULL; 884 char buf[PATH_MAX]; 885 struct sbuf sb; 886 int error, locked; 887 888 PFS_TRACE(("%s", pn->pn_name)); 889 pfs_assert_not_owned(pn); 890 891 if (vn->v_type != VLNK) 892 PFS_RETURN (EINVAL); 893 KASSERT_PN_IS_LINK(pn); 894 895 if (pn->pn_fill == NULL) 896 PFS_RETURN (EIO); 897 898 if (pvd->pvd_pid != NO_PID) { 899 if ((proc = pfind(pvd->pvd_pid)) == NULL) 900 PFS_RETURN (EIO); 901 if (proc->p_flag & P_WEXIT) { 902 PROC_UNLOCK(proc); 903 PFS_RETURN (EIO); 904 } 905 _PHOLD(proc); 906 PROC_UNLOCK(proc); 907 } 908 vhold(vn); 909 locked = VOP_ISLOCKED(vn); 910 VOP_UNLOCK(vn, 0); 911 912 /* sbuf_new() can't fail with a static buffer */ 913 sbuf_new(&sb, buf, sizeof buf, 0); 914 915 error = pn_fill(curthread, proc, pn, &sb, NULL); 916 917 if (proc != NULL) 918 PRELE(proc); 919 vn_lock(vn, locked | LK_RETRY); 920 vdrop(vn); 921 922 if (error) { 923 sbuf_delete(&sb); 924 PFS_RETURN (error); 925 } 926 927 if (sbuf_finish(&sb) != 0) { 928 sbuf_delete(&sb); 929 PFS_RETURN (ENAMETOOLONG); 930 } 931 932 error = uiomove_frombuf(sbuf_data(&sb), sbuf_len(&sb), uio); 933 sbuf_delete(&sb); 934 PFS_RETURN (error); 935 } 936 937 /* 938 * Reclaim a vnode 939 */ 940 static int 941 pfs_reclaim(struct vop_reclaim_args *va) 942 { 943 struct vnode *vn = va->a_vp; 944 struct pfs_vdata *pvd = vn->v_data; 945 struct pfs_node *pn = pvd->pvd_pn; 946 947 PFS_TRACE(("%s", pn->pn_name)); 948 pfs_assert_not_owned(pn); 949 950 return (pfs_vncache_free(va->a_vp)); 951 } 952 953 /* 954 * Set attributes 955 */ 956 static int 957 pfs_setattr(struct vop_setattr_args *va) 958 { 959 struct vnode *vn = va->a_vp; 960 struct pfs_vdata *pvd = vn->v_data; 961 struct pfs_node *pn = pvd->pvd_pn; 962 963 PFS_TRACE(("%s", pn->pn_name)); 964 pfs_assert_not_owned(pn); 965 966 PFS_RETURN (EOPNOTSUPP); 967 } 968 969 /* 970 * Write to a file 971 */ 972 static int 973 pfs_write(struct vop_write_args *va) 974 { 975 struct vnode *vn = va->a_vp; 976 struct pfs_vdata *pvd = vn->v_data; 977 struct pfs_node *pn = pvd->pvd_pn; 978 struct uio *uio = va->a_uio; 979 struct proc *proc; 980 struct sbuf sb; 981 int error; 982 983 PFS_TRACE(("%s", pn->pn_name)); 984 pfs_assert_not_owned(pn); 985 986 if (vn->v_type != VREG) 987 PFS_RETURN (EINVAL); 988 KASSERT_PN_IS_FILE(pn); 989 990 if (!(pn->pn_flags & PFS_WR)) 991 PFS_RETURN (EBADF); 992 993 if (pn->pn_fill == NULL) 994 PFS_RETURN (EIO); 995 996 /* 997 * This is necessary because either process' privileges may 998 * have changed since the open() call. 999 */ 1000 if (!pfs_visible(curthread, pn, pvd->pvd_pid, false, &proc)) 1001 PFS_RETURN (EIO); 1002 if (proc != NULL) { 1003 _PHOLD(proc); 1004 PROC_UNLOCK(proc); 1005 } 1006 1007 if (pn->pn_flags & PFS_RAWWR) { 1008 error = pn_fill(curthread, proc, pn, NULL, uio); 1009 if (proc != NULL) 1010 PRELE(proc); 1011 PFS_RETURN (error); 1012 } 1013 1014 sbuf_uionew(&sb, uio, &error); 1015 if (error) { 1016 if (proc != NULL) 1017 PRELE(proc); 1018 PFS_RETURN (error); 1019 } 1020 1021 error = pn_fill(curthread, proc, pn, &sb, uio); 1022 1023 sbuf_delete(&sb); 1024 if (proc != NULL) 1025 PRELE(proc); 1026 PFS_RETURN (error); 1027 } 1028 1029 /* 1030 * Vnode operations 1031 */ 1032 struct vop_vector pfs_vnodeops = { 1033 .vop_default = &default_vnodeops, 1034 1035 .vop_access = pfs_access, 1036 .vop_cachedlookup = pfs_lookup, 1037 .vop_close = pfs_close, 1038 .vop_create = VOP_EOPNOTSUPP, 1039 .vop_getattr = pfs_getattr, 1040 .vop_getextattr = pfs_getextattr, 1041 .vop_ioctl = pfs_ioctl, 1042 .vop_link = VOP_EOPNOTSUPP, 1043 .vop_lookup = vfs_cache_lookup, 1044 .vop_mkdir = VOP_EOPNOTSUPP, 1045 .vop_mknod = VOP_EOPNOTSUPP, 1046 .vop_open = pfs_open, 1047 .vop_read = pfs_read, 1048 .vop_readdir = pfs_readdir, 1049 .vop_readlink = pfs_readlink, 1050 .vop_reclaim = pfs_reclaim, 1051 .vop_remove = VOP_EOPNOTSUPP, 1052 .vop_rename = VOP_EOPNOTSUPP, 1053 .vop_rmdir = VOP_EOPNOTSUPP, 1054 .vop_setattr = pfs_setattr, 1055 .vop_symlink = VOP_EOPNOTSUPP, 1056 .vop_vptocnp = pfs_vptocnp, 1057 .vop_write = pfs_write, 1058 /* XXX I've probably forgotten a few that need VOP_EOPNOTSUPP */ 1059 }; 1060