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