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 --- 11 unchanged lines hidden (view full) --- 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: head/sys/fs/pseudofs/pseudofs_vnops.c 84246 2001-10-01 04:22:20Z des $ |
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> --- 25 unchanged lines hidden (view full) --- 62#else 63#define PFS_TRACE(foo) \ 64 do { /* nothing */ } while (0) 65#define PFS_RETURN(err) \ 66 return (err) 67#endif 68 69/* |
70 * Returns non-zero if given file is visible to given process 71 */ 72static int 73pfs_visible(struct thread *td, struct pfs_node *pn, pid_t pid) 74{ 75 struct proc *proc; 76 int r; 77 78 PFS_TRACE(("%s (pid: %d, req: %d)", 79 pn->pn_name, pid, td->td_proc->p_pid)); 80 if (pid == NO_PID) 81 PFS_RETURN (1); 82 83 r = 1; 84 if ((proc = pfind(pid)) == NULL) 85 PFS_RETURN (0); 86 /* XXX should lock td->td_proc? */ 87 if (p_cansee(td->td_proc, proc) != 0 || 88 (pn->pn_vis != NULL && !(pn->pn_vis)(td, proc, pn))) 89 r = 0; 90 PROC_UNLOCK(proc); 91 PFS_RETURN (r); 92} 93 94/* |
95 * Verify permissions 96 */ 97static int 98pfs_access(struct vop_access_args *va) 99{ 100 struct vnode *vn = va->a_vp; 101 struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data; 102 struct pfs_node *pn = pvd->pvd_pn; 103 struct vattr vattr; 104 int error; 105 106 PFS_TRACE((pn->pn_name)); 107 108 error = VOP_GETATTR(vn, &vattr, va->a_cred, va->a_td); 109 if (error) |
110 PFS_RETURN (error); |
111 error = vaccess(vn->v_type, vattr.va_mode, vattr.va_uid, 112 vattr.va_gid, va->a_mode, va->a_cred, NULL); |
113 PFS_RETURN (error); |
114} 115 116/* 117 * Close a file or directory 118 */ 119static int 120pfs_close(struct vop_close_args *va) 121{ --- 44 unchanged lines hidden (view full) --- 166 } 167 168 if (pvd->pvd_pid != NO_PID) { 169 if ((proc = pfind(pvd->pvd_pid)) == NULL) 170 PFS_RETURN (ENOENT); 171 vap->va_uid = proc->p_ucred->cr_ruid; 172 vap->va_gid = proc->p_ucred->cr_rgid; 173 if (pn->pn_attr != NULL) |
174 error = (pn->pn_attr)(va->a_td, proc, pn, vap); |
175 PROC_UNLOCK(proc); 176 } else { 177 vap->va_uid = 0; 178 vap->va_gid = 0; 179 } 180 181 PFS_RETURN (error); 182} --- 5 unchanged lines hidden (view full) --- 188pfs_lookup(struct vop_lookup_args *va) 189{ 190 struct vnode *vn = va->a_dvp; 191 struct vnode **vpp = va->a_vpp; 192 struct componentname *cnp = va->a_cnp; 193 struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data; 194 struct pfs_node *pd = pvd->pvd_pn; 195 struct pfs_node *pn, *pdn = NULL; |
196 pid_t pid = pvd->pvd_pid; 197 char *pname; 198 int error, i, namelen; 199 200 PFS_TRACE(("%.*s", (int)cnp->cn_namelen, cnp->cn_nameptr)); 201 202 if (vn->v_type != VDIR) 203 PFS_RETURN (ENOTDIR); --- 5 unchanged lines hidden (view full) --- 209 */ 210 if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) 211 PFS_RETURN (EOPNOTSUPP); 212 213 /* shortcut: check if the name is too long */ 214 if (cnp->cn_namelen >= PFS_NAMELEN) 215 PFS_RETURN (ENOENT); 216 |
217 /* check that parent directory is visisble... */ 218 if (!pfs_visible(curthread, pd, pvd->pvd_pid)) 219 PFS_RETURN (ENOENT); |
220 221 /* self */ 222 namelen = cnp->cn_namelen; 223 pname = cnp->cn_nameptr; 224 if (namelen == 1 && *pname == '.') { 225 pn = pd; 226 *vpp = vn; 227 VREF(vn); |
228 PFS_RETURN (0); |
229 } 230 231 /* parent */ 232 if (cnp->cn_flags & ISDOTDOT) { 233 if (pd->pn_type == pfstype_root) 234 PFS_RETURN (EIO); 235 KASSERT(pd->pn_parent, ("non-root directory has no parent")); 236 /* 237 * This one is tricky. Descendents of procdir nodes 238 * inherit their parent's process affinity, but 239 * there's no easy reverse mapping. For simplicity, 240 * we assume that if this node is a procdir, its 241 * parent isn't (which is correct as long as 242 * descendents of procdir nodes are never procdir 243 * nodes themselves) 244 */ 245 if (pd->pn_type == pfstype_procdir) 246 pid = NO_PID; |
247 pn = pd->pn_parent; 248 goto got_pnode; |
249 } 250 251 /* named node */ 252 for (pn = pd->pn_nodes; pn->pn_type; ++pn) 253 if (pn->pn_type == pfstype_procdir) 254 pdn = pn; 255 else if (pn->pn_name[namelen] == '\0' 256 && bcmp(pname, pn->pn_name, namelen) == 0) --- 6 unchanged lines hidden (view full) --- 263 if ((pid = pid * 10 + pname[i] - '0') > PID_MAX) 264 break; 265 if (i == cnp->cn_namelen) 266 goto got_pnode; 267 } 268 269 PFS_RETURN (ENOENT); 270 got_pnode: |
271 if (pn != pd->pn_parent && !pn->pn_parent) |
272 pn->pn_parent = pd; |
273 if (!pfs_visible(curthread, pn, pvd->pvd_pid)) 274 PFS_RETURN (ENOENT); |
275 error = pfs_vncache_alloc(vn->v_mount, vpp, pn, pid); 276 if (error) 277 PFS_RETURN (error); |
278 if (cnp->cn_flags & MAKEENTRY) 279 cache_enter(vn, *vpp, cnp); 280 PFS_RETURN (0); 281} 282 283/* 284 * Open a file or directory. 285 */ 286static int 287pfs_open(struct vop_open_args *va) 288{ 289 struct vnode *vn = va->a_vp; 290 struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data; 291 struct pfs_node *pn = pvd->pvd_pn; 292 int mode = va->a_mode; |
293 294 PFS_TRACE(("%s (mode 0x%x)", pn->pn_name, mode)); 295 |
296 /* 297 * check if the file is visible to the caller 298 * 299 * XXX Not sure if this is necessary, as the VFS system calls 300 * XXX pfs_lookup() and pfs_access() first, and pfs_lookup() 301 * XXX calls pfs_visible(). There's a race condition here, but 302 * XXX calling pfs_visible() from here doesn't really close it, 303 * XXX and the only consequence of that race is an EIO further 304 * XXX down the line. 305 */ 306 if (!pfs_visible(va->a_td, pn, pvd->pvd_pid)) 307 PFS_RETURN (ENOENT); 308 |
309 /* check if the requested mode is permitted */ 310 if (((mode & FREAD) && !(mode & PFS_RD)) || 311 ((mode & FWRITE) && !(mode & PFS_WR))) 312 PFS_RETURN (EPERM); 313 314 /* we don't support locking */ 315 if ((mode & O_SHLOCK) || (mode & O_EXLOCK)) 316 PFS_RETURN (EOPNOTSUPP); 317 |
318 PFS_RETURN (0); |
319} 320 321/* 322 * Read from a file 323 */ 324static int 325pfs_read(struct vop_read_args *va) 326{ --- 9 unchanged lines hidden (view full) --- 336 PFS_TRACE((pn->pn_name)); 337 338 if (vn->v_type != VREG) 339 PFS_RETURN (EINVAL); 340 341 if (!(pn->pn_flags & PFS_RD)) 342 PFS_RETURN (EBADF); 343 |
344 /* 345 * This is necessary because either process' privileges may 346 * have changed since the open() call. 347 */ 348 if (!pfs_visible(curthread, pn, pvd->pvd_pid)) 349 PFS_RETURN (EIO); 350 351 /* XXX duplicates bits of pfs_visible() */ |
352 if (pvd->pvd_pid != NO_PID) { 353 if ((proc = pfind(pvd->pvd_pid)) == NULL) 354 PFS_RETURN (EIO); 355 _PHOLD(proc); 356 PROC_UNLOCK(proc); 357 } 358 359 if (pn->pn_flags & PFS_RAWRD) { --- 29 unchanged lines hidden (view full) --- 389 sbuf_delete(sb); 390 PFS_RETURN (error); 391} 392 393/* 394 * Iterate through directory entries 395 */ 396static int |
397pfs_iterate(struct thread *td, pid_t pid, struct pfs_node **pn, struct proc **p) |
398{ 399 if ((*pn)->pn_type == pfstype_none) 400 return (-1); 401 |
402 again: |
403 if ((*pn)->pn_type != pfstype_procdir) 404 ++*pn; 405 406 while ((*pn)->pn_type == pfstype_procdir) { 407 if (*p == NULL) 408 *p = LIST_FIRST(&allproc); 409 else 410 *p = LIST_NEXT(*p, p_list); 411 if (*p != NULL) |
412 break; |
413 ++*pn; 414 } 415 416 if ((*pn)->pn_type == pfstype_none) 417 return (-1); |
418 419 if (!pfs_visible(td, *pn, *p ? (*p)->p_pid : pid)) 420 goto again; |
421 422 return (0); 423} 424 425/* 426 * Return directory entries. 427 */ 428static int 429pfs_readdir(struct vop_readdir_args *va) 430{ 431 struct vnode *vn = va->a_vp; 432 struct pfs_info *pi = (struct pfs_info *)vn->v_mount->mnt_data; 433 struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data; 434 struct pfs_node *pd = pvd->pvd_pn; |
435 pid_t pid = pvd->pvd_pid; |
436 struct pfs_node *pn; 437 struct dirent entry; 438 struct uio *uio; 439 struct proc *p; 440 off_t offset; 441 int error, i, resid; 442 443 PFS_TRACE((pd->pn_name)); 444 445 if (vn->v_type != VDIR) 446 PFS_RETURN (ENOTDIR); 447 uio = va->a_uio; 448 |
449 /* check if the directory is visible to the caller */ 450 if (!pfs_visible(curthread, pd, pid)) 451 PFS_RETURN (ENOENT); 452 |
453 /* only allow reading entire entries */ 454 offset = uio->uio_offset; 455 resid = uio->uio_resid; 456 if (offset < 0 || offset % PFS_DELEN != 0 || resid < PFS_DELEN) 457 PFS_RETURN (EINVAL); 458 459 /* skip unwanted entries */ 460 sx_slock(&allproc_lock); 461 for (pn = pd->pn_nodes, p = NULL; offset > 0; offset -= PFS_DELEN) |
462 if (pfs_iterate(curthread, pid, &pn, &p) == -1) |
463 break; 464 465 /* fill in entries */ 466 entry.d_reclen = PFS_DELEN; |
467 while (pfs_iterate(curthread, pid, &pn, &p) != -1 && resid > 0) { |
468 if (!pn->pn_parent) 469 pn->pn_parent = pd; 470 if (!pn->pn_fileno) 471 pfs_fileno_alloc(pi, pn); |
472 if (pid != NO_PID) 473 entry.d_fileno = pn->pn_fileno * NO_PID + pid; |
474 else 475 entry.d_fileno = pn->pn_fileno; 476 /* PFS_DELEN was picked to fit PFS_NAMLEN */ 477 for (i = 0; i < PFS_NAMELEN - 1 && pn->pn_name[i] != '\0'; ++i) 478 entry.d_name[i] = pn->pn_name[i]; 479 entry.d_name[i] = 0; 480 entry.d_namlen = i; 481 switch (pn->pn_type) { --- 84 unchanged lines hidden (view full) --- 566} 567 568/* 569 * Reclaim a vnode 570 */ 571static int 572pfs_reclaim(struct vop_reclaim_args *va) 573{ |
574 struct vnode *vn = va->a_vp; 575 struct pfs_vdata *pvd = (struct pfs_vdata *)vn->v_data; 576 struct pfs_node *pn = pvd->pvd_pn; 577 578 PFS_TRACE((pn->pn_name)); 579 |
580 return (pfs_vncache_free(va->a_vp)); 581} 582 583/* 584 * Set attributes 585 */ 586static int 587pfs_setattr(struct vop_setattr_args *va) --- 27 unchanged lines hidden (view full) --- 615 PFS_TRACE((pn->pn_name)); 616 617 if (vn->v_type != VREG) 618 PFS_RETURN (EINVAL); 619 620 if (!(pn->pn_flags & PFS_WR)) 621 PFS_RETURN (EBADF); 622 |
623 /* 624 * This is necessary because either process' privileges may 625 * have changed since the open() call. 626 */ 627 if (!pfs_visible(curthread, pn, pvd->pvd_pid)) 628 PFS_RETURN (EIO); 629 630 /* XXX duplicates bits of pfs_visible() */ |
631 if (pvd->pvd_pid != NO_PID) { 632 if ((proc = pfind(pvd->pvd_pid)) == NULL) 633 PFS_RETURN (EIO); 634 _PHOLD(proc); 635 PROC_UNLOCK(proc); 636 } 637 638 if (pn->pn_flags & PFS_RAWWR) { --- 44 unchanged lines hidden (view full) --- 683 { &vop_readlink_desc, (vop_t *)pfs_readlink }, 684 { &vop_reclaim_desc, (vop_t *)pfs_reclaim }, 685 { &vop_remove_desc, (vop_t *)pfs_badop }, 686 { &vop_rename_desc, (vop_t *)pfs_badop }, 687 { &vop_rmdir_desc, (vop_t *)pfs_badop }, 688 { &vop_setattr_desc, (vop_t *)pfs_setattr }, 689 { &vop_symlink_desc, (vop_t *)pfs_badop }, 690 { &vop_write_desc, (vop_t *)pfs_write }, |
691 /* XXX I've probably forgotten a few that need pfs_badop */ |
692 { NULL, (vop_t *)NULL } 693}; 694 695static struct vnodeopv_desc pfs_vnodeop_opv_desc = 696 { &pfs_vnodeop_p, pfs_vnodeop_entries }; 697 698VNODEOP_SET(pfs_vnodeop_opv_desc); |