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 /* 56 * Returns the fileno, adjusted for target pid 57 */ 58 static uint32_t 59 pn_fileno(struct pfs_node *pn, pid_t pid) 60 { 61 62 KASSERT(pn->pn_fileno > 0, 63 ("%s(): no fileno allocated", __func__)); 64 if (pid != NO_PID) 65 return (pn->pn_fileno * NO_PID + pid); 66 return (pn->pn_fileno); 67 } 68 69 /* 70 * Returns non-zero if given file is visible to given thread. 71 */ 72 static int 73 pfs_visible_proc(struct thread *td, struct pfs_node *pn, struct proc *proc) 74 { 75 int visible; 76 77 if (proc == NULL) 78 return (0); 79 80 PROC_LOCK_ASSERT(proc, MA_OWNED); 81 82 visible = ((proc->p_flag & P_WEXIT) == 0); 83 if (visible) 84 visible = (p_cansee(td, proc) == 0); 85 if (visible && pn->pn_vis != NULL) 86 visible = pn_vis(td, proc, pn); 87 if (!visible) 88 return (0); 89 return (1); 90 } 91 92 static int 93 pfs_visible(struct thread *td, struct pfs_node *pn, pid_t pid, struct proc **p) 94 { 95 struct proc *proc; 96 97 PFS_TRACE(("%s (pid: %d, req: %d)", 98 pn->pn_name, pid, td->td_proc->p_pid)); 99 100 if (p) 101 *p = NULL; 102 if (pid == NO_PID) 103 PFS_RETURN (1); 104 if ((proc = pfind(pid)) == NULL) 105 PFS_RETURN (0); 106 if (pfs_visible_proc(td, pn, proc)) { 107 if (p) 108 *p = proc; 109 else 110 PROC_UNLOCK(proc); 111 PFS_RETURN (1); 112 } 113 PROC_UNLOCK(proc); 114 PFS_RETURN (0); 115 } 116 117 /* 118 * Verify permissions 119 */ 120 static int 121 pfs_access(struct vop_access_args *va) 122 { 123 struct vnode *vn = va->a_vp; 124 struct pfs_vdata *pvd = vn->v_data; 125 struct vattr vattr; 126 int error; 127 128 PFS_TRACE(("%s", pvd->pvd_pn->pn_name)); 129 (void)pvd; 130 131 error = VOP_GETATTR(vn, &vattr, va->a_cred, va->a_td); 132 if (error) 133 PFS_RETURN (error); 134 error = vaccess(vn->v_type, vattr.va_mode, vattr.va_uid, 135 vattr.va_gid, va->a_mode, va->a_cred, NULL); 136 PFS_RETURN (error); 137 } 138 139 /* 140 * Close a file or directory 141 */ 142 static int 143 pfs_close(struct vop_close_args *va) 144 { 145 struct vnode *vn = va->a_vp; 146 struct pfs_vdata *pvd = vn->v_data; 147 struct pfs_node *pn = pvd->pvd_pn; 148 struct proc *proc; 149 int error; 150 151 PFS_TRACE(("%s", pn->pn_name)); 152 pfs_assert_not_owned(pn); 153 154 /* 155 * Do nothing unless this is the last close and the node has a 156 * last-close handler. 157 */ 158 if (vrefcnt(vn) > 1 || pn->pn_close == NULL) 159 PFS_RETURN (0); 160 161 if (pvd->pvd_pid != NO_PID) { 162 proc = pfind(pvd->pvd_pid); 163 } else { 164 proc = NULL; 165 } 166 167 error = pn_close(va->a_td, proc, pn); 168 169 if (proc != NULL) 170 PROC_UNLOCK(proc); 171 172 PFS_RETURN (error); 173 } 174 175 /* 176 * Get file attributes 177 */ 178 static int 179 pfs_getattr(struct vop_getattr_args *va) 180 { 181 struct vnode *vn = va->a_vp; 182 struct pfs_vdata *pvd = vn->v_data; 183 struct pfs_node *pn = pvd->pvd_pn; 184 struct vattr *vap = va->a_vap; 185 struct proc *proc; 186 int error = 0; 187 188 PFS_TRACE(("%s", pn->pn_name)); 189 pfs_assert_not_owned(pn); 190 191 if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) 192 PFS_RETURN (ENOENT); 193 194 VATTR_NULL(vap); 195 vap->va_type = vn->v_type; 196 vap->va_fileid = pn_fileno(pn, pvd->pvd_pid); 197 vap->va_flags = 0; 198 vap->va_blocksize = PAGE_SIZE; 199 vap->va_bytes = vap->va_size = 0; 200 vap->va_fsid = vn->v_mount->mnt_stat.f_fsid.val[0]; 201 vap->va_nlink = 1; 202 nanotime(&vap->va_ctime); 203 vap->va_atime = vap->va_mtime = vap->va_ctime; 204 205 switch (pn->pn_type) { 206 case pfstype_procdir: 207 case pfstype_root: 208 case pfstype_dir: 209 #if 0 210 pfs_lock(pn); 211 /* compute link count */ 212 pfs_unlock(pn); 213 #endif 214 vap->va_mode = 0555; 215 break; 216 case pfstype_file: 217 case pfstype_symlink: 218 vap->va_mode = 0444; 219 break; 220 default: 221 printf("shouldn't be here!\n"); 222 vap->va_mode = 0; 223 break; 224 } 225 226 if (proc != NULL) { 227 vap->va_uid = proc->p_ucred->cr_ruid; 228 vap->va_gid = proc->p_ucred->cr_rgid; 229 if (pn->pn_attr != NULL) 230 error = pn_attr(va->a_td, proc, pn, vap); 231 PROC_UNLOCK(proc); 232 } else { 233 vap->va_uid = 0; 234 vap->va_gid = 0; 235 } 236 237 PFS_RETURN (error); 238 } 239 240 /* 241 * Perform an ioctl 242 */ 243 static int 244 pfs_ioctl(struct vop_ioctl_args *va) 245 { 246 struct vnode *vn = va->a_vp; 247 struct pfs_vdata *pvd = vn->v_data; 248 struct pfs_node *pn = pvd->pvd_pn; 249 struct proc *proc; 250 int error; 251 252 PFS_TRACE(("%s: %lx", pn->pn_name, va->a_command)); 253 pfs_assert_not_owned(pn); 254 255 if (vn->v_type != VREG) 256 PFS_RETURN (EINVAL); 257 258 if (pn->pn_ioctl == NULL) 259 PFS_RETURN (ENOTTY); 260 261 /* 262 * This is necessary because process' privileges may 263 * have changed since the open() call. 264 */ 265 if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) 266 PFS_RETURN (EIO); 267 268 error = pn_ioctl(curthread, proc, pn, va->a_command, va->a_data); 269 270 if (proc != NULL) 271 PROC_UNLOCK(proc); 272 273 PFS_RETURN (error); 274 } 275 276 /* 277 * Perform getextattr 278 */ 279 static int 280 pfs_getextattr(struct vop_getextattr_args *va) 281 { 282 struct vnode *vn = va->a_vp; 283 struct pfs_vdata *pvd = vn->v_data; 284 struct pfs_node *pn = pvd->pvd_pn; 285 struct proc *proc; 286 int error; 287 288 PFS_TRACE(("%s", pn->pn_name)); 289 pfs_assert_not_owned(pn); 290 291 /* 292 * This is necessary because either process' privileges may 293 * have changed since the open() call. 294 */ 295 if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) 296 PFS_RETURN (EIO); 297 298 if (pn->pn_getextattr == NULL) 299 error = EOPNOTSUPP; 300 else 301 error = pn_getextattr(curthread, proc, pn, 302 va->a_attrnamespace, va->a_name, va->a_uio, 303 va->a_size, va->a_cred); 304 305 if (proc != NULL) 306 PROC_UNLOCK(proc); 307 308 pfs_unlock(pn); 309 PFS_RETURN (error); 310 } 311 312 /* 313 * Look up a file or directory 314 */ 315 static int 316 pfs_lookup(struct vop_cachedlookup_args *va) 317 { 318 struct vnode *vn = va->a_dvp; 319 struct vnode **vpp = va->a_vpp; 320 struct componentname *cnp = va->a_cnp; 321 struct pfs_vdata *pvd = vn->v_data; 322 struct pfs_node *pd = pvd->pvd_pn; 323 struct pfs_node *pn, *pdn = NULL; 324 pid_t pid = pvd->pvd_pid; 325 char *pname; 326 int error, i, namelen, visible; 327 328 PFS_TRACE(("%.*s", (int)cnp->cn_namelen, cnp->cn_nameptr)); 329 pfs_assert_not_owned(pd); 330 331 if (vn->v_type != VDIR) 332 PFS_RETURN (ENOTDIR); 333 334 error = VOP_ACCESS(vn, VEXEC, cnp->cn_cred, cnp->cn_thread); 335 if (error) 336 PFS_RETURN (error); 337 338 /* 339 * Don't support DELETE or RENAME. CREATE is supported so 340 * that O_CREAT will work, but the lookup will still fail if 341 * the file does not exist. 342 */ 343 if ((cnp->cn_flags & ISLASTCN) && 344 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 345 PFS_RETURN (EOPNOTSUPP); 346 347 /* shortcut: check if the name is too long */ 348 if (cnp->cn_namelen >= PFS_NAMELEN) 349 PFS_RETURN (ENOENT); 350 351 /* check that parent directory is visible... */ 352 if (!pfs_visible(curthread, pd, pvd->pvd_pid, NULL)) 353 PFS_RETURN (ENOENT); 354 355 /* self */ 356 namelen = cnp->cn_namelen; 357 pname = cnp->cn_nameptr; 358 if (namelen == 1 && pname[0] == '.') { 359 pn = pd; 360 *vpp = vn; 361 VREF(vn); 362 PFS_RETURN (0); 363 } 364 365 /* parent */ 366 if (cnp->cn_flags & ISDOTDOT) { 367 if (pd->pn_type == pfstype_root) 368 PFS_RETURN (EIO); 369 VOP_UNLOCK(vn, 0); 370 KASSERT(pd->pn_parent != NULL, 371 ("%s(): non-root directory has no parent", __func__)); 372 /* 373 * This one is tricky. Descendents of procdir nodes 374 * inherit their parent's process affinity, but 375 * there's no easy reverse mapping. For simplicity, 376 * we assume that if this node is a procdir, its 377 * parent isn't (which is correct as long as 378 * descendents of procdir nodes are never procdir 379 * nodes themselves) 380 */ 381 if (pd->pn_type == pfstype_procdir) 382 pid = NO_PID; 383 pfs_lock(pd); 384 pn = pd->pn_parent; 385 pfs_unlock(pd); 386 goto got_pnode; 387 } 388 389 pfs_lock(pd); 390 391 /* named node */ 392 for (pn = pd->pn_nodes; pn != NULL; pn = pn->pn_next) 393 if (pn->pn_type == pfstype_procdir) 394 pdn = pn; 395 else if (pn->pn_name[namelen] == '\0' && 396 bcmp(pname, pn->pn_name, namelen) == 0) { 397 pfs_unlock(pd); 398 goto got_pnode; 399 } 400 401 /* process dependent node */ 402 if ((pn = pdn) != NULL) { 403 pid = 0; 404 for (pid = 0, i = 0; i < namelen && isdigit(pname[i]); ++i) 405 if ((pid = pid * 10 + pname[i] - '0') > PID_MAX) 406 break; 407 if (i == cnp->cn_namelen) { 408 pfs_unlock(pd); 409 goto got_pnode; 410 } 411 } 412 413 pfs_unlock(pd); 414 415 PFS_RETURN (ENOENT); 416 417 got_pnode: 418 pfs_assert_not_owned(pd); 419 pfs_assert_not_owned(pn); 420 visible = pfs_visible(curthread, pn, pid, NULL); 421 if (!visible) { 422 error = ENOENT; 423 goto failed; 424 } 425 426 error = pfs_vncache_alloc(vn->v_mount, vpp, pn, pid); 427 if (error) 428 goto failed; 429 430 if (cnp->cn_flags & ISDOTDOT) 431 vn_lock(vn, LK_EXCLUSIVE|LK_RETRY); 432 if (cnp->cn_flags & MAKEENTRY) 433 cache_enter(vn, *vpp, cnp); 434 PFS_RETURN (0); 435 failed: 436 if (cnp->cn_flags & ISDOTDOT) 437 vn_lock(vn, LK_EXCLUSIVE|LK_RETRY); 438 PFS_RETURN(error); 439 } 440 441 /* 442 * Open a file or directory. 443 */ 444 static int 445 pfs_open(struct vop_open_args *va) 446 { 447 struct vnode *vn = va->a_vp; 448 struct pfs_vdata *pvd = vn->v_data; 449 struct pfs_node *pn = pvd->pvd_pn; 450 int mode = va->a_mode; 451 452 PFS_TRACE(("%s (mode 0x%x)", pn->pn_name, mode)); 453 pfs_assert_not_owned(pn); 454 455 /* check if the requested mode is permitted */ 456 if (((mode & FREAD) && !(mode & PFS_RD)) || 457 ((mode & FWRITE) && !(mode & PFS_WR))) 458 PFS_RETURN (EPERM); 459 460 /* we don't support locking */ 461 if ((mode & O_SHLOCK) || (mode & O_EXLOCK)) 462 PFS_RETURN (EOPNOTSUPP); 463 464 PFS_RETURN (0); 465 } 466 467 /* 468 * Read from a file 469 */ 470 static int 471 pfs_read(struct vop_read_args *va) 472 { 473 struct vnode *vn = va->a_vp; 474 struct pfs_vdata *pvd = vn->v_data; 475 struct pfs_node *pn = pvd->pvd_pn; 476 struct uio *uio = va->a_uio; 477 struct proc *proc; 478 struct sbuf *sb = NULL; 479 int error; 480 unsigned int buflen, offset, resid; 481 482 PFS_TRACE(("%s", pn->pn_name)); 483 pfs_assert_not_owned(pn); 484 485 if (vn->v_type != VREG) 486 PFS_RETURN (EINVAL); 487 488 if (!(pn->pn_flags & PFS_RD)) 489 PFS_RETURN (EBADF); 490 491 if (pn->pn_fill == NULL) 492 PFS_RETURN (EIO); 493 494 /* 495 * This is necessary because either process' privileges may 496 * have changed since the open() call. 497 */ 498 if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) 499 PFS_RETURN (EIO); 500 if (proc != NULL) { 501 _PHOLD(proc); 502 PROC_UNLOCK(proc); 503 } 504 505 if (pn->pn_flags & PFS_RAWRD) { 506 PFS_TRACE(("%lu resid", (unsigned long)uio->uio_resid)); 507 error = pn_fill(curthread, proc, pn, NULL, uio); 508 PFS_TRACE(("%lu resid", (unsigned long)uio->uio_resid)); 509 if (proc != NULL) 510 PRELE(proc); 511 PFS_RETURN (error); 512 } 513 514 /* beaucoup sanity checks so we don't ask for bogus allocation */ 515 if (uio->uio_offset < 0 || uio->uio_resid < 0 || 516 (offset = uio->uio_offset) != uio->uio_offset || 517 (resid = uio->uio_resid) != uio->uio_resid || 518 (buflen = offset + resid + 1) < offset || buflen > INT_MAX) { 519 if (proc != NULL) 520 PRELE(proc); 521 PFS_RETURN (EINVAL); 522 } 523 if (buflen > MAXPHYS + 1) { 524 if (proc != NULL) 525 PRELE(proc); 526 PFS_RETURN (EIO); 527 } 528 529 sb = sbuf_new(sb, NULL, buflen, 0); 530 if (sb == NULL) { 531 if (proc != NULL) 532 PRELE(proc); 533 PFS_RETURN (EIO); 534 } 535 536 error = pn_fill(curthread, proc, pn, sb, uio); 537 538 if (proc != NULL) 539 PRELE(proc); 540 541 if (error) { 542 sbuf_delete(sb); 543 PFS_RETURN (error); 544 } 545 546 sbuf_finish(sb); 547 error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio); 548 sbuf_delete(sb); 549 PFS_RETURN (error); 550 } 551 552 /* 553 * Iterate through directory entries 554 */ 555 static int 556 pfs_iterate(struct thread *td, struct proc *proc, struct pfs_node *pd, 557 struct pfs_node **pn, struct proc **p) 558 { 559 int visible; 560 561 sx_assert(&allproc_lock, SX_SLOCKED); 562 pfs_assert_owned(pd); 563 again: 564 if (*pn == NULL) { 565 /* first node */ 566 *pn = pd->pn_nodes; 567 } else if ((*pn)->pn_type != pfstype_procdir) { 568 /* next node */ 569 *pn = (*pn)->pn_next; 570 } 571 if (*pn != NULL && (*pn)->pn_type == pfstype_procdir) { 572 /* next process */ 573 if (*p == NULL) 574 *p = LIST_FIRST(&allproc); 575 else 576 *p = LIST_NEXT(*p, p_list); 577 /* out of processes: next node */ 578 if (*p == NULL) 579 *pn = (*pn)->pn_next; 580 else 581 PROC_LOCK(*p); 582 } 583 584 if ((*pn) == NULL) 585 return (-1); 586 587 if (*p != NULL) { 588 visible = pfs_visible_proc(td, *pn, *p); 589 PROC_UNLOCK(*p); 590 } else if (proc != NULL) { 591 visible = pfs_visible_proc(td, *pn, proc); 592 } else { 593 visible = 1; 594 } 595 if (!visible) 596 goto again; 597 598 return (0); 599 } 600 601 /* 602 * Return directory entries. 603 */ 604 static int 605 pfs_readdir(struct vop_readdir_args *va) 606 { 607 struct vnode *vn = va->a_vp; 608 struct pfs_vdata *pvd = vn->v_data; 609 struct pfs_node *pd = pvd->pvd_pn; 610 pid_t pid = pvd->pvd_pid; 611 struct proc *p, *proc; 612 struct pfs_node *pn; 613 struct dirent *entry; 614 struct uio *uio; 615 off_t offset; 616 int error, i, resid; 617 char *buf, *ent; 618 619 KASSERT(pd->pn_info == vn->v_mount->mnt_data, 620 ("%s(): pn_info does not match mountpoint", __func__)); 621 PFS_TRACE(("%s pid %lu", pd->pn_name, (unsigned long)pid)); 622 pfs_assert_not_owned(pd); 623 624 if (vn->v_type != VDIR) 625 PFS_RETURN (ENOTDIR); 626 uio = va->a_uio; 627 628 /* only allow reading entire entries */ 629 offset = uio->uio_offset; 630 resid = uio->uio_resid; 631 if (offset < 0 || offset % PFS_DELEN != 0 || 632 (resid && resid < PFS_DELEN)) 633 PFS_RETURN (EINVAL); 634 if (resid == 0) 635 PFS_RETURN (0); 636 637 /* can't do this while holding the proc lock... */ 638 buf = malloc(resid, M_IOV, M_WAITOK | M_ZERO); 639 sx_slock(&allproc_lock); 640 pfs_lock(pd); 641 642 /* check if the directory is visible to the caller */ 643 if (!pfs_visible(curthread, pd, pid, &proc)) { 644 sx_sunlock(&allproc_lock); 645 pfs_unlock(pd); 646 free(buf, M_IOV); 647 PFS_RETURN (ENOENT); 648 } 649 KASSERT(pid == NO_PID || proc != NULL, 650 ("%s(): no process for pid %lu", __func__, (unsigned long)pid)); 651 652 /* skip unwanted entries */ 653 for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN) { 654 if (pfs_iterate(curthread, proc, pd, &pn, &p) == -1) { 655 /* nothing left... */ 656 if (proc != NULL) 657 PROC_UNLOCK(proc); 658 pfs_unlock(pd); 659 sx_sunlock(&allproc_lock); 660 free(buf, M_IOV); 661 PFS_RETURN (0); 662 } 663 } 664 665 /* fill in entries */ 666 ent = buf; 667 while (pfs_iterate(curthread, proc, pd, &pn, &p) != -1 && 668 resid >= PFS_DELEN) { 669 entry = (struct dirent *)ent; 670 entry->d_reclen = PFS_DELEN; 671 entry->d_fileno = pn_fileno(pn, pid); 672 /* PFS_DELEN was picked to fit PFS_NAMLEN */ 673 for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i) 674 entry->d_name[i] = pn->pn_name[i]; 675 entry->d_name[i] = 0; 676 entry->d_namlen = i; 677 switch (pn->pn_type) { 678 case pfstype_procdir: 679 KASSERT(p != NULL, 680 ("reached procdir node with p == NULL")); 681 entry->d_namlen = snprintf(entry->d_name, 682 PFS_NAMELEN, "%d", p->p_pid); 683 /* fall through */ 684 case pfstype_root: 685 case pfstype_dir: 686 case pfstype_this: 687 case pfstype_parent: 688 entry->d_type = DT_DIR; 689 break; 690 case pfstype_file: 691 entry->d_type = DT_REG; 692 break; 693 case pfstype_symlink: 694 entry->d_type = DT_LNK; 695 break; 696 default: 697 panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type); 698 } 699 PFS_TRACE(("%s", entry->d_name)); 700 offset += PFS_DELEN; 701 resid -= PFS_DELEN; 702 ent += PFS_DELEN; 703 } 704 if (proc != NULL) 705 PROC_UNLOCK(proc); 706 pfs_unlock(pd); 707 sx_sunlock(&allproc_lock); 708 PFS_TRACE(("%zd bytes", ent - buf)); 709 error = uiomove(buf, ent - buf, uio); 710 free(buf, M_IOV); 711 PFS_RETURN (error); 712 } 713 714 /* 715 * Read a symbolic link 716 */ 717 static int 718 pfs_readlink(struct vop_readlink_args *va) 719 { 720 struct vnode *vn = va->a_vp; 721 struct pfs_vdata *pvd = vn->v_data; 722 struct pfs_node *pn = pvd->pvd_pn; 723 struct uio *uio = va->a_uio; 724 struct proc *proc = NULL; 725 char buf[PATH_MAX]; 726 struct sbuf sb; 727 int error; 728 729 PFS_TRACE(("%s", pn->pn_name)); 730 pfs_assert_not_owned(pn); 731 732 if (vn->v_type != VLNK) 733 PFS_RETURN (EINVAL); 734 735 if (pn->pn_fill == NULL) 736 PFS_RETURN (EIO); 737 738 if (pvd->pvd_pid != NO_PID) { 739 if ((proc = pfind(pvd->pvd_pid)) == NULL) 740 PFS_RETURN (EIO); 741 if (proc->p_flag & P_WEXIT) { 742 PROC_UNLOCK(proc); 743 PFS_RETURN (EIO); 744 } 745 _PHOLD(proc); 746 PROC_UNLOCK(proc); 747 } 748 749 /* sbuf_new() can't fail with a static buffer */ 750 sbuf_new(&sb, buf, sizeof buf, 0); 751 752 error = pn_fill(curthread, proc, pn, &sb, NULL); 753 754 if (proc != NULL) 755 PRELE(proc); 756 757 if (error) { 758 sbuf_delete(&sb); 759 PFS_RETURN (error); 760 } 761 762 sbuf_finish(&sb); 763 error = uiomove_frombuf(sbuf_data(&sb), sbuf_len(&sb), uio); 764 sbuf_delete(&sb); 765 PFS_RETURN (error); 766 } 767 768 /* 769 * Reclaim a vnode 770 */ 771 static int 772 pfs_reclaim(struct vop_reclaim_args *va) 773 { 774 struct vnode *vn = va->a_vp; 775 struct pfs_vdata *pvd = vn->v_data; 776 struct pfs_node *pn = pvd->pvd_pn; 777 778 PFS_TRACE(("%s", pn->pn_name)); 779 pfs_assert_not_owned(pn); 780 781 return (pfs_vncache_free(va->a_vp)); 782 } 783 784 /* 785 * Set attributes 786 */ 787 static int 788 pfs_setattr(struct vop_setattr_args *va) 789 { 790 struct vnode *vn = va->a_vp; 791 struct pfs_vdata *pvd = vn->v_data; 792 struct pfs_node *pn = pvd->pvd_pn; 793 794 PFS_TRACE(("%s", pn->pn_name)); 795 pfs_assert_not_owned(pn); 796 797 PFS_RETURN (EOPNOTSUPP); 798 } 799 800 /* 801 * Write to a file 802 */ 803 static int 804 pfs_write(struct vop_write_args *va) 805 { 806 struct vnode *vn = va->a_vp; 807 struct pfs_vdata *pvd = vn->v_data; 808 struct pfs_node *pn = pvd->pvd_pn; 809 struct uio *uio = va->a_uio; 810 struct proc *proc; 811 struct sbuf sb; 812 int error; 813 814 PFS_TRACE(("%s", pn->pn_name)); 815 pfs_assert_not_owned(pn); 816 817 if (vn->v_type != VREG) 818 PFS_RETURN (EINVAL); 819 KASSERT(pn->pn_type != pfstype_file, 820 ("%s(): VREG vnode refers to non-file pfs_node", __func__)); 821 822 if (!(pn->pn_flags & PFS_WR)) 823 PFS_RETURN (EBADF); 824 825 if (pn->pn_fill == NULL) 826 PFS_RETURN (EIO); 827 828 /* 829 * This is necessary because either process' privileges may 830 * have changed since the open() call. 831 */ 832 if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) 833 PFS_RETURN (EIO); 834 if (proc != NULL) { 835 _PHOLD(proc); 836 PROC_UNLOCK(proc); 837 } 838 839 if (pn->pn_flags & PFS_RAWWR) { 840 pfs_lock(pn); 841 error = pn_fill(curthread, proc, pn, NULL, uio); 842 pfs_unlock(pn); 843 if (proc != NULL) 844 PRELE(proc); 845 PFS_RETURN (error); 846 } 847 848 sbuf_uionew(&sb, uio, &error); 849 if (error) { 850 if (proc != NULL) 851 PRELE(proc); 852 PFS_RETURN (error); 853 } 854 855 error = pn_fill(curthread, proc, pn, &sb, uio); 856 857 sbuf_delete(&sb); 858 if (proc != NULL) 859 PRELE(proc); 860 PFS_RETURN (error); 861 } 862 863 /* 864 * Vnode operations 865 */ 866 struct vop_vector pfs_vnodeops = { 867 .vop_default = &default_vnodeops, 868 869 .vop_access = pfs_access, 870 .vop_cachedlookup = pfs_lookup, 871 .vop_close = pfs_close, 872 .vop_create = VOP_EOPNOTSUPP, 873 .vop_getattr = pfs_getattr, 874 .vop_getextattr = pfs_getextattr, 875 .vop_ioctl = pfs_ioctl, 876 .vop_link = VOP_EOPNOTSUPP, 877 .vop_lookup = vfs_cache_lookup, 878 .vop_mkdir = VOP_EOPNOTSUPP, 879 .vop_mknod = VOP_EOPNOTSUPP, 880 .vop_open = pfs_open, 881 .vop_read = pfs_read, 882 .vop_readdir = pfs_readdir, 883 .vop_readlink = pfs_readlink, 884 .vop_reclaim = pfs_reclaim, 885 .vop_remove = VOP_EOPNOTSUPP, 886 .vop_rename = VOP_EOPNOTSUPP, 887 .vop_rmdir = VOP_EOPNOTSUPP, 888 .vop_setattr = pfs_setattr, 889 .vop_symlink = VOP_EOPNOTSUPP, 890 .vop_write = pfs_write, 891 /* XXX I've probably forgotten a few that need VOP_EOPNOTSUPP */ 892 }; 893