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