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 * $FreeBSD$ 29 */ 30 31 #include <sys/param.h> 32 #include <sys/kernel.h> 33 #include <sys/systm.h> 34 #include <sys/ctype.h> 35 #include <sys/dirent.h> 36 #include <sys/fcntl.h> 37 #include <sys/lock.h> 38 #include <sys/mount.h> 39 #include <sys/mutex.h> 40 #include <sys/namei.h> 41 #include <sys/proc.h> 42 #include <sys/sbuf.h> 43 #include <sys/sx.h> 44 #include <sys/sysctl.h> 45 #include <sys/vnode.h> 46 47 #include <fs/pseudofs/pseudofs.h> 48 #include <fs/pseudofs/pseudofs_internal.h> 49 50 #if 0 51 #define PFS_TRACE(foo) \ 52 do { \ 53 printf("pseudofs: %s(): line %d: ", __func__, __LINE__); \ 54 printf foo ; \ 55 printf("\n"); \ 56 } while (0) 57 #define PFS_RETURN(err) \ 58 do { \ 59 printf("pseudofs: %s(): line %d: returning %d\n", \ 60 __func__, __LINE__, err); \ 61 return (err); \ 62 } while (0) 63 #else 64 #define PFS_TRACE(foo) \ 65 do { /* nothing */ } while (0) 66 #define PFS_RETURN(err) \ 67 return (err) 68 #endif 69 70 /* 71 * Returns non-zero if given file is visible to given process 72 */ 73 static int 74 pfs_visible(struct thread *td, struct pfs_node *pn, pid_t pid) 75 { 76 struct proc *proc; 77 int r; 78 79 PFS_TRACE(("%s (pid: %d, req: %d)", 80 pn->pn_name, pid, td->td_proc->p_pid)); 81 82 if (pn->pn_flags & PFS_DISABLED) 83 PFS_RETURN (0); 84 85 r = 1; 86 if (pid != NO_PID) { 87 if ((proc = pfind(pid)) == NULL) 88 PFS_RETURN (0); 89 if (p_cansee(td->td_proc, proc) != 0 || 90 (pn->pn_vis != NULL && !(pn->pn_vis)(td, proc, pn))) 91 r = 0; 92 PROC_UNLOCK(proc); 93 } 94 PFS_RETURN (r); 95 } 96 97 /* 98 * Verify permissions 99 */ 100 static int 101 pfs_access(struct vop_access_args *va) 102 { 103 struct vnode *vn = va->a_vp; 104 struct vattr vattr; 105 int error; 106 107 PFS_TRACE((((struct pfs_vdata *)vn->v_data)->pvd_pn->pn_name)); 108 109 error = VOP_GETATTR(vn, &vattr, va->a_cred, va->a_td); 110 if (error) 111 PFS_RETURN (error); 112 error = vaccess(vn->v_type, vattr.va_mode, vattr.va_uid, 113 vattr.va_gid, va->a_mode, va->a_cred, NULL); 114 PFS_RETURN (error); 115 } 116 117 /* 118 * Close a file or directory 119 */ 120 static int 121 pfs_close(struct vop_close_args *va) 122 { 123 struct vnode *vn = va->a_vp; 124 struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data; 125 struct pfs_node *pn = pvd->pvd_pn; 126 struct proc *proc; 127 int error; 128 129 PFS_TRACE((pn->pn_name)); 130 131 /* 132 * Do nothing unless this is the last close and the node has a 133 * last-close handler. 134 */ 135 if (vn->v_usecount > 1 || pn->pn_close == NULL) 136 PFS_RETURN (0); 137 138 if (pvd->pvd_pid != NO_PID) 139 proc = pfind(pvd->pvd_pid); 140 else 141 proc = NULL; 142 143 error = (pn->pn_close)(va->a_td, proc, pn); 144 145 if (proc != NULL) 146 PROC_UNLOCK(proc); 147 148 PFS_RETURN (error); 149 } 150 151 /* 152 * Get file attributes 153 */ 154 static int 155 pfs_getattr(struct vop_getattr_args *va) 156 { 157 struct vnode *vn = va->a_vp; 158 struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data; 159 struct pfs_node *pn = pvd->pvd_pn; 160 struct vattr *vap = va->a_vap; 161 struct proc *proc; 162 int error = 0; 163 164 PFS_TRACE((pn->pn_name)); 165 166 VATTR_NULL(vap); 167 vap->va_type = vn->v_type; 168 vap->va_fileid = pn->pn_fileno; 169 vap->va_flags = 0; 170 vap->va_blocksize = PAGE_SIZE; 171 vap->va_bytes = vap->va_size = 0; 172 vap->va_fsid = vn->v_mount->mnt_stat.f_fsid.val[0]; 173 vap->va_nlink = 1; 174 nanotime(&vap->va_ctime); 175 vap->va_atime = vap->va_mtime = vap->va_ctime; 176 177 switch (pn->pn_type) { 178 case pfstype_procdir: 179 case pfstype_root: 180 case pfstype_dir: 181 vap->va_mode = 0555; 182 break; 183 case pfstype_file: 184 case pfstype_symlink: 185 vap->va_mode = 0444; 186 break; 187 default: 188 printf("shouldn't be here!\n"); 189 vap->va_mode = 0; 190 break; 191 } 192 193 if (pvd->pvd_pid != NO_PID) { 194 if ((proc = pfind(pvd->pvd_pid)) == NULL) 195 PFS_RETURN (ENOENT); 196 vap->va_uid = proc->p_ucred->cr_ruid; 197 vap->va_gid = proc->p_ucred->cr_rgid; 198 if (pn->pn_attr != NULL) 199 error = (pn->pn_attr)(va->a_td, proc, pn, vap); 200 PROC_UNLOCK(proc); 201 } else { 202 vap->va_uid = 0; 203 vap->va_gid = 0; 204 } 205 206 PFS_RETURN (error); 207 } 208 209 /* 210 * Perform an ioctl 211 */ 212 static int 213 pfs_ioctl(struct vop_ioctl_args *va) 214 { 215 struct vnode *vn = va->a_vp; 216 struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data; 217 struct pfs_node *pn = pvd->pvd_pn; 218 struct proc *proc = NULL; 219 int error; 220 221 PFS_TRACE(("%s: %lx", pn->pn_name, va->a_command)); 222 223 if (vn->v_type != VREG) 224 PFS_RETURN (EINVAL); 225 226 if (pn->pn_ioctl == NULL) 227 PFS_RETURN (ENOTTY); 228 229 /* 230 * This is necessary because either process' privileges may 231 * have changed since the open() call. 232 */ 233 if (!pfs_visible(curthread, pn, pvd->pvd_pid)) 234 PFS_RETURN (EIO); 235 236 /* XXX duplicates bits of pfs_visible() */ 237 if (pvd->pvd_pid != NO_PID) { 238 if ((proc = pfind(pvd->pvd_pid)) == NULL) 239 PFS_RETURN (EIO); 240 _PHOLD(proc); 241 PROC_UNLOCK(proc); 242 } 243 244 error = (pn->pn_ioctl)(curthread, proc, pn, va->a_command, va->a_data); 245 246 if (proc != NULL) 247 PRELE(proc); 248 249 PFS_RETURN (error); 250 } 251 252 /* 253 * Perform getextattr 254 */ 255 static int 256 pfs_getextattr(struct vop_getextattr_args *va) 257 { 258 struct vnode *vn = va->a_vp; 259 struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data; 260 struct pfs_node *pn = pvd->pvd_pn; 261 struct proc *proc = NULL; 262 int error; 263 264 PFS_TRACE((pd->pn_name)); 265 266 if (pn->pn_getextattr == NULL) 267 PFS_RETURN (EOPNOTSUPP); 268 269 /* 270 * This is necessary because either process' privileges may 271 * have changed since the open() call. 272 */ 273 if (!pfs_visible(curthread, pn, pvd->pvd_pid)) 274 PFS_RETURN (EIO); 275 276 /* XXX duplicates bits of pfs_visible() */ 277 if (pvd->pvd_pid != NO_PID) { 278 if ((proc = pfind(pvd->pvd_pid)) == NULL) 279 PFS_RETURN (EIO); 280 _PHOLD(proc); 281 PROC_UNLOCK(proc); 282 } 283 284 error = (pn->pn_getextattr)(curthread, proc, pn, va->a_attrnamespace, 285 va->a_name, va->a_uio, va->a_size, va->a_cred); 286 287 if (proc != NULL) 288 PRELE(proc); 289 290 PFS_RETURN (error); 291 } 292 293 /* 294 * Look up a file or directory 295 * 296 * XXX NOTE! pfs_lookup() has been hooked into vop_lookup_desc! This 297 * will result in a lookup operation for a vnode which may already be 298 * cached, therefore we have to be careful to purge the VFS cache when 299 * reusing a vnode. 300 * 301 * This code will work, but is not really correct. Normally we would hook 302 * vfs_cache_lookup() into vop_lookup_desc and hook pfs_lookup() into 303 * vop_cachedlookup_desc. 304 */ 305 static int 306 pfs_lookup(struct vop_lookup_args *va) 307 { 308 struct vnode *vn = va->a_dvp; 309 struct vnode **vpp = va->a_vpp; 310 struct componentname *cnp = va->a_cnp; 311 struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data; 312 struct pfs_node *pd = pvd->pvd_pn; 313 struct pfs_node *pn, *pdn = NULL; 314 pid_t pid = pvd->pvd_pid; 315 char *pname; 316 int error, i, namelen; 317 318 PFS_TRACE(("%.*s", (int)cnp->cn_namelen, cnp->cn_nameptr)); 319 320 if (vn->v_type != VDIR) 321 PFS_RETURN (ENOTDIR); 322 323 /* 324 * Don't support DELETE or RENAME. CREATE is supported so 325 * that O_CREAT will work, but the lookup will still fail if 326 * the file does not exist. 327 */ 328 if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) 329 PFS_RETURN (EOPNOTSUPP); 330 331 /* shortcut: check if the name is too long */ 332 if (cnp->cn_namelen >= PFS_NAMELEN) 333 PFS_RETURN (ENOENT); 334 335 /* check that parent directory is visisble... */ 336 if (!pfs_visible(curthread, pd, pvd->pvd_pid)) 337 PFS_RETURN (ENOENT); 338 339 /* self */ 340 namelen = cnp->cn_namelen; 341 pname = cnp->cn_nameptr; 342 if (namelen == 1 && *pname == '.') { 343 pn = pd; 344 *vpp = vn; 345 VREF(vn); 346 PFS_RETURN (0); 347 } 348 349 /* parent */ 350 if (cnp->cn_flags & ISDOTDOT) { 351 if (pd->pn_type == pfstype_root) 352 PFS_RETURN (EIO); 353 KASSERT(pd->pn_parent, ("non-root directory has no parent")); 354 /* 355 * This one is tricky. Descendents of procdir nodes 356 * inherit their parent's process affinity, but 357 * there's no easy reverse mapping. For simplicity, 358 * we assume that if this node is a procdir, its 359 * parent isn't (which is correct as long as 360 * descendents of procdir nodes are never procdir 361 * nodes themselves) 362 */ 363 if (pd->pn_type == pfstype_procdir) 364 pid = NO_PID; 365 pn = pd->pn_parent; 366 goto got_pnode; 367 } 368 369 /* named node */ 370 for (pn = pd->pn_nodes; pn != NULL; pn = pn->pn_next) 371 if (pn->pn_type == pfstype_procdir) 372 pdn = pn; 373 else if (pn->pn_name[namelen] == '\0' 374 && bcmp(pname, pn->pn_name, namelen) == 0) 375 goto got_pnode; 376 377 /* process dependent node */ 378 if ((pn = pdn) != NULL) { 379 pid = 0; 380 for (pid = 0, i = 0; i < namelen && isdigit(pname[i]); ++i) 381 if ((pid = pid * 10 + pname[i] - '0') > PID_MAX) 382 break; 383 if (i == cnp->cn_namelen) 384 goto got_pnode; 385 } 386 387 PFS_RETURN (ENOENT); 388 got_pnode: 389 if (pn != pd->pn_parent && !pn->pn_parent) 390 pn->pn_parent = pd; 391 if (!pfs_visible(curthread, pn, pvd->pvd_pid)) 392 PFS_RETURN (ENOENT); 393 error = pfs_vncache_alloc(vn->v_mount, vpp, pn, pid); 394 if (error) 395 PFS_RETURN (error); 396 /* 397 * XXX See comment at top of the routine. 398 */ 399 if (cnp->cn_flags & MAKEENTRY) 400 cache_enter(vn, *vpp, cnp); 401 PFS_RETURN (0); 402 } 403 404 /* 405 * Open a file or directory. 406 */ 407 static int 408 pfs_open(struct vop_open_args *va) 409 { 410 struct vnode *vn = va->a_vp; 411 struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data; 412 struct pfs_node *pn = pvd->pvd_pn; 413 int mode = va->a_mode; 414 415 PFS_TRACE(("%s (mode 0x%x)", pn->pn_name, mode)); 416 417 /* 418 * check if the file is visible to the caller 419 * 420 * XXX Not sure if this is necessary, as the VFS system calls 421 * XXX pfs_lookup() and pfs_access() first, and pfs_lookup() 422 * XXX calls pfs_visible(). There's a race condition here, but 423 * XXX calling pfs_visible() from here doesn't really close it, 424 * XXX and the only consequence of that race is an EIO further 425 * XXX down the line. 426 */ 427 if (!pfs_visible(va->a_td, pn, pvd->pvd_pid)) 428 PFS_RETURN (ENOENT); 429 430 /* check if the requested mode is permitted */ 431 if (((mode & FREAD) && !(mode & PFS_RD)) || 432 ((mode & FWRITE) && !(mode & PFS_WR))) 433 PFS_RETURN (EPERM); 434 435 /* we don't support locking */ 436 if ((mode & O_SHLOCK) || (mode & O_EXLOCK)) 437 PFS_RETURN (EOPNOTSUPP); 438 439 PFS_RETURN (0); 440 } 441 442 /* 443 * Read from a file 444 */ 445 static int 446 pfs_read(struct vop_read_args *va) 447 { 448 struct vnode *vn = va->a_vp; 449 struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data; 450 struct pfs_node *pn = pvd->pvd_pn; 451 struct uio *uio = va->a_uio; 452 struct proc *proc = NULL; 453 struct sbuf *sb = NULL; 454 char *ps; 455 int error, xlen; 456 457 PFS_TRACE((pn->pn_name)); 458 459 if (vn->v_type != VREG) 460 PFS_RETURN (EINVAL); 461 462 if (!(pn->pn_flags & PFS_RD)) 463 PFS_RETURN (EBADF); 464 465 if (pn->pn_func == NULL) 466 PFS_RETURN (EIO); 467 468 /* 469 * This is necessary because either process' privileges may 470 * have changed since the open() call. 471 */ 472 if (!pfs_visible(curthread, pn, pvd->pvd_pid)) 473 PFS_RETURN (EIO); 474 475 /* XXX duplicates bits of pfs_visible() */ 476 if (pvd->pvd_pid != NO_PID) { 477 if ((proc = pfind(pvd->pvd_pid)) == NULL) 478 PFS_RETURN (EIO); 479 _PHOLD(proc); 480 PROC_UNLOCK(proc); 481 } 482 483 if (pn->pn_flags & PFS_RAWRD) { 484 error = (pn->pn_func)(curthread, proc, pn, NULL, uio); 485 if (proc != NULL) 486 PRELE(proc); 487 PFS_RETURN (error); 488 } 489 490 sb = sbuf_new(sb, NULL, uio->uio_offset + uio->uio_resid, 0); 491 if (sb == NULL) { 492 if (proc != NULL) 493 PRELE(proc); 494 PFS_RETURN (EIO); 495 } 496 497 error = (pn->pn_func)(curthread, proc, pn, sb, uio); 498 499 if (proc != NULL) 500 PRELE(proc); 501 502 if (error) { 503 sbuf_delete(sb); 504 PFS_RETURN (error); 505 } 506 507 /* XXX we should possibly detect and handle overflows */ 508 sbuf_finish(sb); 509 ps = sbuf_data(sb) + uio->uio_offset; 510 xlen = sbuf_len(sb) - uio->uio_offset; 511 xlen = imin(xlen, uio->uio_resid); 512 error = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); 513 sbuf_delete(sb); 514 PFS_RETURN (error); 515 } 516 517 /* 518 * Iterate through directory entries 519 */ 520 static int 521 pfs_iterate(struct thread *td, pid_t pid, struct pfs_node *pd, 522 struct pfs_node **pn, struct proc **p) 523 { 524 if ((*pn) == NULL) 525 *pn = pd->pn_nodes; 526 else 527 again: 528 if ((*pn)->pn_type != pfstype_procdir) 529 *pn = (*pn)->pn_next; 530 531 while (*pn != NULL && (*pn)->pn_type == pfstype_procdir) { 532 if (*p == NULL) 533 *p = LIST_FIRST(&allproc); 534 else 535 *p = LIST_NEXT(*p, p_list); 536 if (*p != NULL) 537 break; 538 *pn = (*pn)->pn_next; 539 } 540 541 if ((*pn) == NULL) 542 return (-1); 543 544 if (!pfs_visible(td, *pn, *p ? (*p)->p_pid : pid)) 545 goto again; 546 547 return (0); 548 } 549 550 /* 551 * Return directory entries. 552 */ 553 static int 554 pfs_readdir(struct vop_readdir_args *va) 555 { 556 struct vnode *vn = va->a_vp; 557 struct pfs_info *pi = (struct pfs_info *)vn->v_mount->mnt_data; 558 struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data; 559 struct pfs_node *pd = pvd->pvd_pn; 560 pid_t pid = pvd->pvd_pid; 561 struct pfs_node *pn; 562 struct dirent entry; 563 struct uio *uio; 564 struct proc *p; 565 off_t offset; 566 int error, i, resid; 567 568 PFS_TRACE((pd->pn_name)); 569 570 if (vn->v_type != VDIR) 571 PFS_RETURN (ENOTDIR); 572 uio = va->a_uio; 573 574 /* check if the directory is visible to the caller */ 575 if (!pfs_visible(curthread, pd, pid)) 576 PFS_RETURN (ENOENT); 577 578 /* only allow reading entire entries */ 579 offset = uio->uio_offset; 580 resid = uio->uio_resid; 581 if (offset < 0 || offset % PFS_DELEN != 0 || resid < PFS_DELEN) 582 PFS_RETURN (EINVAL); 583 584 /* skip unwanted entries */ 585 sx_slock(&allproc_lock); 586 for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN) 587 if (pfs_iterate(curthread, pid, pd, &pn, &p) == -1) { 588 /* nothing left... */ 589 sx_sunlock(&allproc_lock); 590 PFS_RETURN (0); 591 } 592 593 /* fill in entries */ 594 entry.d_reclen = PFS_DELEN; 595 while (pfs_iterate(curthread, pid, pd, &pn, &p) != -1 && resid > 0) { 596 if (!pn->pn_parent) 597 pn->pn_parent = pd; 598 if (!pn->pn_fileno) 599 pfs_fileno_alloc(pi, pn); 600 if (pid != NO_PID) 601 entry.d_fileno = pn->pn_fileno * NO_PID + pid; 602 else 603 entry.d_fileno = pn->pn_fileno; 604 /* PFS_DELEN was picked to fit PFS_NAMLEN */ 605 for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i) 606 entry.d_name[i] = pn->pn_name[i]; 607 entry.d_name[i] = 0; 608 entry.d_namlen = i; 609 switch (pn->pn_type) { 610 case pfstype_procdir: 611 KASSERT(p != NULL, 612 ("reached procdir node with p == NULL")); 613 entry.d_fileno = pn->pn_fileno * NO_PID + p->p_pid; 614 entry.d_namlen = snprintf(entry.d_name, 615 PFS_NAMELEN, "%d", p->p_pid); 616 /* fall through */ 617 case pfstype_root: 618 case pfstype_dir: 619 case pfstype_this: 620 case pfstype_parent: 621 entry.d_type = DT_DIR; 622 break; 623 case pfstype_file: 624 entry.d_type = DT_REG; 625 break; 626 case pfstype_symlink: 627 entry.d_type = DT_LNK; 628 break; 629 default: 630 sx_sunlock(&allproc_lock); 631 panic("%s has unexpected node type: %d", pn->pn_name, pn->pn_type); 632 } 633 PFS_TRACE((entry.d_name)); 634 if ((error = uiomove((caddr_t)&entry, PFS_DELEN, uio))) { 635 sx_sunlock(&allproc_lock); 636 PFS_RETURN (error); 637 } 638 offset += PFS_DELEN; 639 resid -= PFS_DELEN; 640 } 641 642 sx_sunlock(&allproc_lock); 643 uio->uio_offset += offset; 644 PFS_RETURN (0); 645 } 646 647 /* 648 * Read a symbolic link 649 */ 650 static int 651 pfs_readlink(struct vop_readlink_args *va) 652 { 653 struct vnode *vn = va->a_vp; 654 struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data; 655 struct pfs_node *pn = pvd->pvd_pn; 656 struct uio *uio = va->a_uio; 657 struct proc *proc = NULL; 658 char buf[MAXPATHLEN], *ps; 659 struct sbuf sb; 660 int error, xlen; 661 662 PFS_TRACE((pn->pn_name)); 663 664 if (vn->v_type != VLNK) 665 PFS_RETURN (EINVAL); 666 667 if (pn->pn_func == NULL) 668 PFS_RETURN (EIO); 669 670 if (pvd->pvd_pid != NO_PID) { 671 if ((proc = pfind(pvd->pvd_pid)) == NULL) 672 PFS_RETURN (EIO); 673 _PHOLD(proc); 674 PROC_UNLOCK(proc); 675 } 676 677 /* sbuf_new() can't fail with a static buffer */ 678 sbuf_new(&sb, buf, sizeof buf, 0); 679 680 error = (pn->pn_func)(curthread, proc, pn, &sb, NULL); 681 682 if (proc != NULL) 683 PRELE(proc); 684 685 if (error) { 686 sbuf_delete(&sb); 687 PFS_RETURN (error); 688 } 689 690 /* XXX we should detect and handle overflows */ 691 sbuf_finish(&sb); 692 ps = sbuf_data(&sb) + uio->uio_offset; 693 xlen = sbuf_len(&sb) - uio->uio_offset; 694 xlen = imin(xlen, uio->uio_resid); 695 error = (xlen <= 0 ? 0 : uiomove(ps, xlen, uio)); 696 sbuf_delete(&sb); 697 PFS_RETURN (error); 698 } 699 700 /* 701 * Reclaim a vnode 702 */ 703 static int 704 pfs_reclaim(struct vop_reclaim_args *va) 705 { 706 PFS_TRACE((((struct pfs_vdata *)va->a_vp->v_data)->pvd_pn->pn_name)); 707 708 return (pfs_vncache_free(va->a_vp)); 709 } 710 711 /* 712 * Set attributes 713 */ 714 static int 715 pfs_setattr(struct vop_setattr_args *va) 716 { 717 PFS_TRACE((((struct pfs_vdata *)va->a_vp->v_data)->pvd_pn->pn_name)); 718 719 PFS_RETURN (EOPNOTSUPP); 720 } 721 722 /* 723 * Read from a file 724 */ 725 static int 726 pfs_write(struct vop_read_args *va) 727 { 728 struct vnode *vn = va->a_vp; 729 struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data; 730 struct pfs_node *pn = pvd->pvd_pn; 731 struct uio *uio = va->a_uio; 732 struct proc *proc = NULL; 733 struct sbuf sb; 734 int error; 735 736 PFS_TRACE((pn->pn_name)); 737 738 if (vn->v_type != VREG) 739 PFS_RETURN (EINVAL); 740 741 if (!(pn->pn_flags & PFS_WR)) 742 PFS_RETURN (EBADF); 743 744 if (pn->pn_func == NULL) 745 PFS_RETURN (EIO); 746 747 /* 748 * This is necessary because either process' privileges may 749 * have changed since the open() call. 750 */ 751 if (!pfs_visible(curthread, pn, pvd->pvd_pid)) 752 PFS_RETURN (EIO); 753 754 /* XXX duplicates bits of pfs_visible() */ 755 if (pvd->pvd_pid != NO_PID) { 756 if ((proc = pfind(pvd->pvd_pid)) == NULL) 757 PFS_RETURN (EIO); 758 _PHOLD(proc); 759 PROC_UNLOCK(proc); 760 } 761 762 if (pn->pn_flags & PFS_RAWWR) { 763 error = (pn->pn_func)(curthread, proc, pn, NULL, uio); 764 if (proc != NULL) 765 PRELE(proc); 766 PFS_RETURN (error); 767 } 768 769 sbuf_uionew(&sb, uio, &error); 770 if (error) 771 PFS_RETURN (error); 772 773 error = (pn->pn_func)(curthread, proc, pn, &sb, uio); 774 775 if (proc != NULL) 776 PRELE(proc); 777 778 sbuf_delete(&sb); 779 PFS_RETURN (error); 780 } 781 782 /* 783 * Vnode operations 784 */ 785 vop_t **pfs_vnodeop_p; 786 static struct vnodeopv_entry_desc pfs_vnodeop_entries[] = { 787 { &vop_default_desc, (vop_t *)vop_defaultop }, 788 { &vop_access_desc, (vop_t *)pfs_access }, 789 { &vop_close_desc, (vop_t *)pfs_close }, 790 { &vop_create_desc, (vop_t *)vop_eopnotsupp }, 791 { &vop_getattr_desc, (vop_t *)pfs_getattr }, 792 { &vop_getextattr_desc, (vop_t *)pfs_getextattr }, 793 { &vop_ioctl_desc, (vop_t *)pfs_ioctl }, 794 { &vop_link_desc, (vop_t *)vop_eopnotsupp }, 795 { &vop_lookup_desc, (vop_t *)pfs_lookup }, 796 { &vop_mkdir_desc, (vop_t *)vop_eopnotsupp }, 797 { &vop_mknod_desc, (vop_t *)vop_eopnotsupp }, 798 { &vop_open_desc, (vop_t *)pfs_open }, 799 { &vop_read_desc, (vop_t *)pfs_read }, 800 { &vop_readdir_desc, (vop_t *)pfs_readdir }, 801 { &vop_readlink_desc, (vop_t *)pfs_readlink }, 802 { &vop_reclaim_desc, (vop_t *)pfs_reclaim }, 803 { &vop_remove_desc, (vop_t *)vop_eopnotsupp }, 804 { &vop_rename_desc, (vop_t *)vop_eopnotsupp }, 805 { &vop_rmdir_desc, (vop_t *)vop_eopnotsupp }, 806 { &vop_setattr_desc, (vop_t *)pfs_setattr }, 807 { &vop_symlink_desc, (vop_t *)vop_eopnotsupp }, 808 { &vop_write_desc, (vop_t *)pfs_write }, 809 /* XXX I've probably forgotten a few that need vop_eopnotsupp */ 810 { NULL, (vop_t *)NULL } 811 }; 812 813 static struct vnodeopv_desc pfs_vnodeop_opv_desc = 814 { &pfs_vnodeop_p, pfs_vnodeop_entries }; 815 816 VNODEOP_SET(pfs_vnodeop_opv_desc); 817