Deleted Added
full compact
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 84187 2001-09-30 19:41:29Z des $
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)
85 return (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);
88 return (error);
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)
149 error = (pn->pn_attr)(curthread, proc, pn, vap);
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;
171 struct proc *proc;
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
193 /* check that owner process exists */
194 if (pvd->pvd_pid != NO_PID) {
195 if ((proc = pfind(pvd->pvd_pid)) == NULL)
196 PFS_RETURN (ENOENT);
197 PROC_UNLOCK(proc);
198 }
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);
207 goto got_vnode;
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;
226 error = pfs_vncache_alloc(vn->v_mount, vpp, pd->pn_parent, pid);
227 if (error)
228 PFS_RETURN (error);
229 goto got_vnode;
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:
252 if (!pn->pn_parent)
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);
257 got_vnode:
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;
273 struct proc *proc;
274 int error;
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
287 error = 0;
288 if (pvd->pvd_pid != NO_PID) {
289 if ((proc = pfind(pvd->pvd_pid)) == NULL)
290 PFS_RETURN (ENOENT);
291 /* XXX should lock va->a_td->td_proc? */
292 if (p_cansee(va->a_td->td_proc, proc) != 0)
293 error = ENOENT;
294 PROC_UNLOCK(proc);
295 }
296
297 PFS_RETURN (error);
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
368pfs_iterate(struct pfs_info *pi, struct pfs_node **pn, struct proc **p)
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)
382 return (0);
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)
424 if (pfs_iterate(pi, &pn, &p) == -1)
462 if (pfs_iterate(curthread, pid, &pn, &p) == -1)
463 break;
464
465 /* fill in entries */
466 entry.d_reclen = PFS_DELEN;
429 while (pfs_iterate(pi, &pn, &p) != -1 && resid > 0) {
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);
434 if (pvd->pvd_pid != NO_PID)
435 entry.d_fileno = pn->pn_fileno * NO_PID + pvd->pvd_pid;
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 },
639 /* XXX I've probably forgotten a few that need pfs_erofs */
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);