Home | History | Annotate | Line # | Download | only in libpuffs
puffs.c revision 1.18
      1 /*	$NetBSD: puffs.c,v 1.18 2006/12/14 18:15:59 alc Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2005, 2006  Antti Kantee.  All Rights Reserved.
      5  *
      6  * Development of this software was supported by the
      7  * Google Summer of Code program and the Ulla Tuominen Foundation.
      8  * The Google SoC project was mentored by Bill Studenmund.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. The name of the company nor the name of the author may be used to
     19  *    endorse or promote products derived from this software without specific
     20  *    prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     23  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     24  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     25  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  */
     34 
     35 #include <sys/cdefs.h>
     36 #if !defined(lint)
     37 __RCSID("$NetBSD: puffs.c,v 1.18 2006/12/14 18:15:59 alc Exp $");
     38 #endif /* !lint */
     39 
     40 #include <sys/param.h>
     41 #include <sys/mount.h>
     42 
     43 #include <assert.h>
     44 #include <err.h>
     45 #include <errno.h>
     46 #include <fcntl.h>
     47 #include <puffs.h>
     48 #include <puffsdump.h>
     49 #include <stdio.h>
     50 #include <stdlib.h>
     51 #include <string.h>
     52 #include <syslog.h>
     53 #include <unistd.h>
     54 
     55 static int puffcall(struct puffs_usermount *, struct puffs_req *, size_t *);
     56 
     57 #define FILLOP(lower, upper)						\
     58 do {									\
     59 	if (pops->puffs_node_##lower)					\
     60 		opmask[PUFFS_VN_##upper] = 1;				\
     61 } while (/*CONSTCOND*/0)
     62 static void
     63 fillvnopmask(struct puffs_ops *pops, uint8_t *opmask)
     64 {
     65 
     66 	memset(opmask, 0, PUFFS_VN_MAX);
     67 
     68 	FILLOP(create,   CREATE);
     69 	FILLOP(mknod,    MKNOD);
     70 	FILLOP(open,     OPEN);
     71 	FILLOP(close,    CLOSE);
     72 	FILLOP(access,   ACCESS);
     73 	FILLOP(getattr,  GETATTR);
     74 	FILLOP(setattr,  SETATTR);
     75 	FILLOP(poll,     POLL); /* XXX: not ready in kernel */
     76 	FILLOP(revoke,   REVOKE);
     77 	FILLOP(mmap,     MMAP);
     78 	FILLOP(fsync,    FSYNC);
     79 	FILLOP(seek,     SEEK);
     80 	FILLOP(remove,   REMOVE);
     81 	FILLOP(link,     LINK);
     82 	FILLOP(rename,   RENAME);
     83 	FILLOP(mkdir,    MKDIR);
     84 	FILLOP(rmdir,    RMDIR);
     85 	FILLOP(symlink,  SYMLINK);
     86 	FILLOP(readdir,  READDIR);
     87 	FILLOP(readlink, READLINK);
     88 	FILLOP(reclaim,  RECLAIM);
     89 	FILLOP(inactive, INACTIVE);
     90 	FILLOP(print,    PRINT);
     91 	FILLOP(read,     READ);
     92 	FILLOP(write,    WRITE);
     93 
     94 	/* XXX: not implemented in the kernel */
     95 	FILLOP(getextattr, GETEXTATTR);
     96 	FILLOP(setextattr, SETEXTATTR);
     97 	FILLOP(listextattr, LISTEXTATTR);
     98 
     99 	/* XXX */
    100 	FILLOP(ioctl1, IOCTL);
    101 	FILLOP(fcntl1, FCNTL);
    102 }
    103 #undef FILLOP
    104 
    105 struct puffs_usermount *
    106 puffs_mount(struct puffs_ops *pops, const char *dir, int mntflags,
    107 	const char *puffsname, uint32_t pflags, size_t maxreqlen)
    108 {
    109 	struct puffs_startreq sreq;
    110 	struct puffs_args pargs;
    111 	struct puffs_usermount *pu;
    112 	int fd = 0, rv;
    113 
    114 	if (pops->puffs_fs_mount == NULL) {
    115 		errno = EINVAL;
    116 		return NULL;
    117 	}
    118 
    119 	fd = open("/dev/puffs", O_RDONLY);
    120 	if (fd == -1)
    121 		return NULL;
    122 	if (fd <= 2)
    123 		warnx("puffs_mount: device fd %d (<= 2), sure this is "
    124 		    "what you want?", fd);
    125 
    126 	pargs.pa_vers = 0; /* XXX: for now */
    127 	pargs.pa_flags = PUFFS_FLAG_KERN(pflags);
    128 	pargs.pa_fd = fd;
    129 	pargs.pa_maxreqlen = maxreqlen;
    130 	fillvnopmask(pops, pargs.pa_vnopmask);
    131 	(void)strlcpy(pargs.pa_name, puffsname, sizeof(pargs.pa_name));
    132 
    133 	pu = malloc(sizeof(struct puffs_usermount));
    134 	if (!pu)
    135 		return NULL;
    136 
    137 	pu->pu_flags = pflags;
    138 	pu->pu_ops = *pops;
    139 	pu->pu_fd = fd;
    140 	if ((pu->pu_rootpath = strdup(dir)) == NULL)
    141 		goto failfree;
    142 	LIST_INIT(&pu->pu_pnodelst);
    143 
    144 	if (mount(MOUNT_PUFFS, dir, mntflags, &pargs) == -1)
    145 		goto failfree;
    146 	pu->pu_maxreqlen = pargs.pa_maxreqlen;
    147 
    148 	if ((rv = pops->puffs_fs_mount(pu, &sreq.psr_cookie)) != 0) {
    149 		errno = rv;
    150 		goto failfree;
    151 	}
    152 
    153 	if ((rv = pops->puffs_fs_statvfs(pu, &sreq.psr_sb, 0)) != 0) {
    154 		errno = rv;
    155 		goto failfree;
    156 	}
    157 
    158 	/* tell kernel we're flying */
    159 	if (ioctl(pu->pu_fd, PUFFSSTARTOP, &sreq) == -1)
    160 		goto failfree;
    161 
    162 	return pu;
    163 
    164  failfree:
    165 	/* can't unmount() from here for obvious reasons */
    166 	if (fd)
    167 		close(fd);
    168 	free(pu);
    169 	return NULL;
    170 }
    171 
    172 int
    173 puffs_mainloop(struct puffs_usermount *pu, int flags)
    174 {
    175 	uint8_t *buf;
    176 	int rv;
    177 
    178 	rv = 0;
    179 
    180 	buf = malloc(pu->pu_maxreqlen);
    181 	if (!buf)
    182 		return -1;
    183 
    184 	if ((flags & PUFFSLOOP_NODAEMON) == 0) {
    185 		rv = daemon(0, 0);
    186 		if (rv != 0)
    187 			goto fail;
    188 	}
    189 
    190 	do {
    191 		rv = puffs_oneop(pu, buf, pu->pu_maxreqlen);
    192 	} while (rv == 0);
    193 
    194 fail:
    195 	free(buf);
    196 	return rv;
    197 }
    198 
    199 enum {PUFFCALL_ANSWER, PUFFCALL_IGNORE, PUFFCALL_UNMOUNT};
    200 int
    201 puffs_oneop(struct puffs_usermount *pu, uint8_t *buf, size_t buflen)
    202 {
    203 	struct puffs_getreq *pgr;
    204 	struct puffs_putreq *ppr;
    205 	struct puffs_req *preq;
    206 	int rv, unmounting, pval;
    207 
    208 	rv = unmounting = 0;
    209 
    210 	/* setup fetch */
    211 	pgr = puffs_makegetreq(pu, buf, buflen, 0);
    212 	if (!pgr)
    213 		return -1;
    214 
    215 	/* setup reply essentials */
    216 	ppr = puffs_makeputreq(pu);
    217 	if (!ppr) {
    218 		puffs_destroygetreq(pgr);
    219 		return -1;
    220 	}
    221 
    222 	while ((preq = puffs_getreq(pgr)) != NULL && unmounting == 0) {
    223 		pval = puffcall(pu, preq, &preq->preq_buflen);
    224 
    225 		/* check if we need to store this reply */
    226 		switch (pval) {
    227 		case PUFFCALL_UNMOUNT:
    228 			unmounting = 1;
    229 			/* FALLTHROUGH */
    230 		case PUFFCALL_ANSWER:
    231 			puffs_putreq(ppr, preq);
    232 			break;
    233 		case PUFFCALL_IGNORE:
    234 			break;
    235 
    236 		default:
    237 			assert(/*CONSTCOND*/0);
    238 		}
    239 	}
    240 	puffs_destroygetreq(pgr);
    241 
    242 	if (puffs_putputreq(ppr) == -1)
    243 		rv = -1;
    244 	puffs_destroyputreq(ppr);
    245 
    246 	return rv;
    247 }
    248 
    249 int
    250 puffs_getselectable(struct puffs_usermount *pu)
    251 {
    252 
    253 	return pu->pu_fd;
    254 }
    255 
    256 int
    257 puffs_setblockingmode(struct puffs_usermount *pu, int mode)
    258 {
    259 	int x;
    260 
    261 	x = mode;
    262 	return ioctl(pu->pu_fd, FIONBIO, &x);
    263 }
    264 
    265 static int
    266 puffcall(struct puffs_usermount *pu, struct puffs_req *preq, size_t *blenp)
    267 {
    268 	struct puffs_ops *pops = &pu->pu_ops;
    269 	struct puffs_sizeop pop;
    270 	void *auxbuf;
    271 	int error, rv;
    272 
    273 	if (PUFFSOP_WANTREPLY(preq->preq_opclass))
    274 		rv = PUFFCALL_ANSWER;
    275 	else
    276 		rv = PUFFCALL_IGNORE;
    277 	auxbuf = preq;
    278 
    279 	if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
    280 		puffsdump_req(preq);
    281 
    282 	*blenp = 0; /* default: "let kernel decide" */
    283 
    284 	if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) {
    285 		switch (preq->preq_optype) {
    286 		case PUFFS_VFS_UNMOUNT:
    287 		{
    288 			struct puffs_vfsreq_unmount *auxt = auxbuf;
    289 
    290 			error = pops->puffs_fs_unmount(pu,
    291 			    auxt->pvfsr_flags, auxt->pvfsr_pid);
    292 			rv = PUFFCALL_UNMOUNT;
    293 			break;
    294 		}
    295 		case PUFFS_VFS_STATVFS:
    296 		{
    297 			struct puffs_vfsreq_statvfs *auxt = auxbuf;
    298 
    299 			error = pops->puffs_fs_statvfs(pu,
    300 			    &auxt->pvfsr_sb, auxt->pvfsr_pid);
    301 			break;
    302 		}
    303 		case PUFFS_VFS_SYNC:
    304 		{
    305 			struct puffs_vfsreq_sync *auxt = auxbuf;
    306 
    307 			error = pops->puffs_fs_sync(pu,
    308 			    auxt->pvfsr_waitfor, &auxt->pvfsr_cred,
    309 			    auxt->pvfsr_pid);
    310 			break;
    311 		}
    312 		default:
    313 			/*
    314 			 * I guess the kernel sees this one coming
    315 			 */
    316 			error = EINVAL;
    317 			break;
    318 		}
    319 
    320 	/* XXX: audit return values */
    321 	/* XXX: sync with kernel */
    322 	} else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
    323 		switch (preq->preq_optype) {
    324 		case PUFFS_VN_LOOKUP:
    325 		{
    326 			struct puffs_vnreq_lookup *auxt = auxbuf;
    327 
    328 			/* lookup *must* be present */
    329 			error = pops->puffs_node_lookup(pu, preq->preq_cookie,
    330 			    &auxt->pvnr_newnode, &auxt->pvnr_vtype,
    331 			    &auxt->pvnr_size, &auxt->pvnr_rdev,
    332 			    &auxt->pvnr_cn);
    333 			break;
    334 		}
    335 
    336 		case PUFFS_VN_CREATE:
    337 		{
    338 			struct puffs_vnreq_create *auxt = auxbuf;
    339 			if (pops->puffs_node_create == NULL) {
    340 				error = 0;
    341 				break;
    342 			}
    343 
    344 			error = pops->puffs_node_create(pu,
    345 			    preq->preq_cookie, &auxt->pvnr_newnode,
    346 			    &auxt->pvnr_cn, &auxt->pvnr_va);
    347 			break;
    348 		}
    349 
    350 		case PUFFS_VN_MKNOD:
    351 		{
    352 			struct puffs_vnreq_mknod *auxt = auxbuf;
    353 			if (pops->puffs_node_mknod == NULL) {
    354 				error = 0;
    355 				break;
    356 			}
    357 
    358 			error = pops->puffs_node_mknod(pu,
    359 			    preq->preq_cookie, &auxt->pvnr_newnode,
    360 			    &auxt->pvnr_cn, &auxt->pvnr_va);
    361 			break;
    362 		}
    363 
    364 		case PUFFS_VN_OPEN:
    365 		{
    366 			struct puffs_vnreq_open *auxt = auxbuf;
    367 			if (pops->puffs_node_open == NULL) {
    368 				error = 0;
    369 				break;
    370 			}
    371 
    372 			error = pops->puffs_node_open(pu,
    373 			    preq->preq_cookie, auxt->pvnr_mode,
    374 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    375 			break;
    376 		}
    377 
    378 		case PUFFS_VN_CLOSE:
    379 		{
    380 			struct puffs_vnreq_close *auxt = auxbuf;
    381 			if (pops->puffs_node_close == NULL) {
    382 				error = 0;
    383 				break;
    384 			}
    385 
    386 			error = pops->puffs_node_close(pu,
    387 			    preq->preq_cookie, auxt->pvnr_fflag,
    388 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    389 			break;
    390 		}
    391 
    392 		case PUFFS_VN_ACCESS:
    393 		{
    394 			struct puffs_vnreq_access *auxt = auxbuf;
    395 			if (pops->puffs_node_access == NULL) {
    396 				error = 0;
    397 				break;
    398 			}
    399 
    400 			error = pops->puffs_node_access(pu,
    401 			    preq->preq_cookie, auxt->pvnr_mode,
    402 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    403 			break;
    404 		}
    405 
    406 		case PUFFS_VN_GETATTR:
    407 		{
    408 			struct puffs_vnreq_getattr *auxt = auxbuf;
    409 			if (pops->puffs_node_getattr == NULL) {
    410 				error = EOPNOTSUPP;
    411 				break;
    412 			}
    413 
    414 			error = pops->puffs_node_getattr(pu,
    415 			    preq->preq_cookie, &auxt->pvnr_va,
    416 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    417 			break;
    418 		}
    419 
    420 		case PUFFS_VN_SETATTR:
    421 		{
    422 			struct puffs_vnreq_setattr *auxt = auxbuf;
    423 			if (pops->puffs_node_setattr == NULL) {
    424 				error = EOPNOTSUPP;
    425 				break;
    426 			}
    427 
    428 			error = pops->puffs_node_setattr(pu,
    429 			    preq->preq_cookie, &auxt->pvnr_va,
    430 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    431 			break;
    432 		}
    433 
    434 		case PUFFS_VN_MMAP:
    435 		{
    436 			struct puffs_vnreq_mmap *auxt = auxbuf;
    437 			if (pops->puffs_node_mmap == NULL) {
    438 				error = 0;
    439 				break;
    440 			}
    441 
    442 			error = pops->puffs_node_mmap(pu,
    443 			    preq->preq_cookie, auxt->pvnr_fflags,
    444 			    &auxt->pvnr_cred, auxt->pvnr_pid);
    445 			break;
    446 		}
    447 
    448 		case PUFFS_VN_REVOKE:
    449 		{
    450 			struct puffs_vnreq_revoke *auxt = auxbuf;
    451 			if (pops->puffs_node_revoke == NULL) {
    452 				error = 0;
    453 				break;
    454 			}
    455 
    456 			error = pops->puffs_node_revoke(pu,
    457 			    preq->preq_cookie, auxt->pvnr_flags);
    458 			break;
    459 		}
    460 
    461 		case PUFFS_VN_FSYNC:
    462 		{
    463 			struct puffs_vnreq_fsync *auxt = auxbuf;
    464 			if (pops->puffs_node_fsync == NULL) {
    465 				error = 0;
    466 				break;
    467 			}
    468 
    469 			error = pops->puffs_node_fsync(pu,
    470 			    preq->preq_cookie, &auxt->pvnr_cred,
    471 			    auxt->pvnr_flags, auxt->pvnr_offlo,
    472 			    auxt->pvnr_offhi, auxt->pvnr_pid);
    473 			break;
    474 		}
    475 
    476 		case PUFFS_VN_SEEK:
    477 		{
    478 			struct puffs_vnreq_seek *auxt = auxbuf;
    479 			if (pops->puffs_node_seek == NULL) {
    480 				error = 0;
    481 				break;
    482 			}
    483 
    484 			error = pops->puffs_node_seek(pu,
    485 			    preq->preq_cookie, auxt->pvnr_oldoff,
    486 			    auxt->pvnr_newoff, &auxt->pvnr_cred);
    487 			break;
    488 		}
    489 
    490 		case PUFFS_VN_REMOVE:
    491 		{
    492 			struct puffs_vnreq_remove *auxt = auxbuf;
    493 			if (pops->puffs_node_remove == NULL) {
    494 				error = 0;
    495 				break;
    496 			}
    497 
    498 			error = pops->puffs_node_remove(pu,
    499 			    preq->preq_cookie, auxt->pvnr_cookie_targ,
    500 			    &auxt->pvnr_cn);
    501 			break;
    502 		}
    503 
    504 		case PUFFS_VN_LINK:
    505 		{
    506 			struct puffs_vnreq_link *auxt = auxbuf;
    507 			if (pops->puffs_node_link == NULL) {
    508 				error = 0;
    509 				break;
    510 			}
    511 
    512 			error = pops->puffs_node_link(pu,
    513 			    preq->preq_cookie, auxt->pvnr_cookie_targ,
    514 			    &auxt->pvnr_cn);
    515 			break;
    516 		}
    517 
    518 		case PUFFS_VN_RENAME:
    519 		{
    520 			struct puffs_vnreq_rename *auxt = auxbuf;
    521 			if (pops->puffs_node_rename == NULL) {
    522 				error = 0;
    523 				break;
    524 			}
    525 
    526 			error = pops->puffs_node_rename(pu,
    527 			    preq->preq_cookie, auxt->pvnr_cookie_src,
    528 			    &auxt->pvnr_cn_src, auxt->pvnr_cookie_targdir,
    529 			    auxt->pvnr_cookie_targ, &auxt->pvnr_cn_targ);
    530 			break;
    531 		}
    532 
    533 		case PUFFS_VN_MKDIR:
    534 		{
    535 			struct puffs_vnreq_mkdir *auxt = auxbuf;
    536 			if (pops->puffs_node_mkdir == NULL) {
    537 				error = 0;
    538 				break;
    539 			}
    540 
    541 			error = pops->puffs_node_mkdir(pu,
    542 			    preq->preq_cookie, &auxt->pvnr_newnode,
    543 			    &auxt->pvnr_cn, &auxt->pvnr_va);
    544 			break;
    545 		}
    546 
    547 		case PUFFS_VN_RMDIR:
    548 		{
    549 			struct puffs_vnreq_rmdir *auxt = auxbuf;
    550 			if (pops->puffs_node_rmdir == NULL) {
    551 				error = 0;
    552 				break;
    553 			}
    554 
    555 			error = pops->puffs_node_rmdir(pu,
    556 			    preq->preq_cookie, auxt->pvnr_cookie_targ,
    557 			    &auxt->pvnr_cn);
    558 			break;
    559 		}
    560 
    561 		case PUFFS_VN_SYMLINK:
    562 		{
    563 			struct puffs_vnreq_symlink *auxt = auxbuf;
    564 			if (pops->puffs_node_symlink == NULL) {
    565 				error = 0;
    566 				break;
    567 			}
    568 
    569 			error = pops->puffs_node_symlink(pu,
    570 			    preq->preq_cookie, &auxt->pvnr_newnode,
    571 			    &auxt->pvnr_cn, &auxt->pvnr_va, auxt->pvnr_link);
    572 			break;
    573 		}
    574 
    575 		case PUFFS_VN_READDIR:
    576 		{
    577 			struct puffs_vnreq_readdir *auxt = auxbuf;
    578 			size_t res;
    579 
    580 			if (pops->puffs_node_readdir == NULL) {
    581 				error = 0;
    582 				break;
    583 			}
    584 
    585 			res = auxt->pvnr_resid;
    586 			error = pops->puffs_node_readdir(pu,
    587 			    preq->preq_cookie, auxt->pvnr_dent,
    588 			    &auxt->pvnr_cred, &auxt->pvnr_offset,
    589 			    &auxt->pvnr_resid);
    590 
    591 			/* need to move a bit more */
    592 			*blenp = sizeof(struct puffs_vnreq_readdir)
    593 			    + (res - auxt->pvnr_resid);
    594 			break;
    595 		}
    596 
    597 		case PUFFS_VN_READLINK:
    598 		{
    599 			struct puffs_vnreq_readlink *auxt = auxbuf;
    600 			if (pops->puffs_node_readlink == NULL) {
    601 				error = EOPNOTSUPP;
    602 				break;
    603 			}
    604 
    605 			error = pops->puffs_node_readlink(pu,
    606 			    preq->preq_cookie, &auxt->pvnr_cred,
    607 			    auxt->pvnr_link, &auxt->pvnr_linklen);
    608 			break;
    609 		}
    610 
    611 		case PUFFS_VN_RECLAIM:
    612 		{
    613 			struct puffs_vnreq_reclaim *auxt = auxbuf;
    614 			if (pops->puffs_node_reclaim == NULL) {
    615 				error = 0;
    616 				break;
    617 			}
    618 
    619 			error = pops->puffs_node_reclaim(pu,
    620 			    preq->preq_cookie, auxt->pvnr_pid);
    621 			break;
    622 		}
    623 
    624 		case PUFFS_VN_INACTIVE:
    625 		{
    626 			struct puffs_vnreq_inactive *auxt = auxbuf;
    627 			if (pops->puffs_node_inactive == NULL) {
    628 				error = EOPNOTSUPP;
    629 				break;
    630 			}
    631 
    632 			error = pops->puffs_node_inactive(pu,
    633 			    preq->preq_cookie, auxt->pvnr_pid,
    634 			    &auxt->pvnr_backendrefs);
    635 			break;
    636 		}
    637 
    638 		case PUFFS_VN_PATHCONF:
    639 		{
    640 			struct puffs_vnreq_pathconf *auxt = auxbuf;
    641 			if (pops->puffs_node_pathconf == NULL) {
    642 				error = 0;
    643 				break;
    644 			}
    645 
    646 			error = pops->puffs_node_pathconf(pu,
    647 			    preq->preq_cookie, auxt->pvnr_name,
    648 			    &auxt->pvnr_retval);
    649 			break;
    650 		}
    651 
    652 		case PUFFS_VN_ADVLOCK:
    653 		{
    654 			struct puffs_vnreq_advlock *auxt = auxbuf;
    655 			if (pops->puffs_node_advlock == NULL) {
    656 				error = 0;
    657 				break;
    658 			}
    659 
    660 			error = pops->puffs_node_advlock(pu,
    661 			    preq->preq_cookie, auxt->pvnr_id, auxt->pvnr_op,
    662 			    &auxt->pvnr_fl, auxt->pvnr_flags);
    663 			break;
    664 		}
    665 
    666 		case PUFFS_VN_PRINT:
    667 		{
    668 			if (pops->puffs_node_print == NULL) {
    669 				error = 0;
    670 				break;
    671 			}
    672 
    673 			error = pops->puffs_node_print(pu,
    674 			    preq->preq_cookie);
    675 			break;
    676 		}
    677 
    678 		case PUFFS_VN_READ:
    679 		{
    680 			struct puffs_vnreq_read *auxt = auxbuf;
    681 			size_t res;
    682 
    683 			if (pops->puffs_node_read == NULL) {
    684 				error = EIO;
    685 				break;
    686 			}
    687 
    688 			res = auxt->pvnr_resid;
    689 			error = pops->puffs_node_read(pu,
    690 			    preq->preq_cookie, auxt->pvnr_data,
    691 			    auxt->pvnr_offset, &auxt->pvnr_resid,
    692 			    &auxt->pvnr_cred, auxt->pvnr_ioflag);
    693 
    694 			/* need to move a bit more */
    695 			*blenp = sizeof(struct puffs_vnreq_read)
    696 			    + (res - auxt->pvnr_resid);
    697 			break;
    698 		}
    699 
    700 		case PUFFS_VN_WRITE:
    701 		{
    702 			struct puffs_vnreq_write *auxt = auxbuf;
    703 
    704 			if (pops->puffs_node_write == NULL) {
    705 				error = EIO;
    706 				break;
    707 			}
    708 
    709 			error = pops->puffs_node_write(pu,
    710 			    preq->preq_cookie, auxt->pvnr_data,
    711 			    auxt->pvnr_offset, &auxt->pvnr_resid,
    712 			    &auxt->pvnr_cred, auxt->pvnr_ioflag);
    713 
    714 			/* don't need to move data back to the kernel */
    715 			*blenp = sizeof(struct puffs_vnreq_write);
    716 			break;
    717 		}
    718 
    719 		case PUFFS_VN_IOCTL:
    720 			error = pops->puffs_node_ioctl1(pu, preq->preq_cookie,
    721 			     (struct puffs_vnreq_ioctl *)auxbuf, &pop);
    722 			if (error != 0)
    723 				break;
    724 			pop.pso_reqid = preq->preq_id;
    725 
    726 			/* let the kernel do it's intermediate duty */
    727 			error = ioctl(pu->pu_fd, PUFFSSIZEOP, &pop);
    728 			/*
    729 			 * XXX: I don't actually know what the correct
    730 			 * thing to do in case of an error is, so I'll
    731 			 * just ignore it for the time being.
    732 			 */
    733 			error = pops->puffs_node_ioctl2(pu, preq->preq_cookie,
    734 			    (struct puffs_vnreq_ioctl *)auxbuf, &pop);
    735 			break;
    736 
    737 		case PUFFS_VN_FCNTL:
    738 			error = pops->puffs_node_fcntl1(pu, preq->preq_cookie,
    739 			     (struct puffs_vnreq_fcntl *)auxbuf, &pop);
    740 			if (error != 0)
    741 				break;
    742 			pop.pso_reqid = preq->preq_id;
    743 
    744 			/* let the kernel do it's intermediate duty */
    745 			error = ioctl(pu->pu_fd, PUFFSSIZEOP, &pop);
    746 			/*
    747 			 * XXX: I don't actually know what the correct
    748 			 * thing to do in case of an error is, so I'll
    749 			 * just ignore it for the time being.
    750 			 */
    751 			error = pops->puffs_node_fcntl2(pu, preq->preq_cookie,
    752 			    (struct puffs_vnreq_fcntl *)auxbuf, &pop);
    753 			break;
    754 
    755 		default:
    756 			printf("inval op %d\n", preq->preq_optype);
    757 			error = EINVAL;
    758 			break;
    759 		}
    760 	} else {
    761 		/*
    762 		 * this one also
    763 		 */
    764 		error = EINVAL;
    765 	}
    766 
    767 	preq->preq_rv = error;
    768 	return rv;
    769 }
    770 
    771 
    772 #if 0
    773 		case PUFFS_VN_POLL:
    774 		{
    775 			struct puffs_vnreq_poll *auxt = auxbuf;
    776 			if (pops->puffs_node_poll == NULL) {
    777 				error = 0;
    778 				break;
    779 			}
    780 
    781 			error = pops->puffs_node_poll(pu,
    782 			    preq->preq_cookie, preq-);
    783 			break;
    784 		}
    785 
    786 		case PUFFS_VN_KQFILTER:
    787 		{
    788 			struct puffs_vnreq_kqfilter *auxt = auxbuf;
    789 			if (pops->puffs_node_kqfilter == NULL) {
    790 				error = 0;
    791 				break;
    792 			}
    793 
    794 			error = pops->puffs_node_kqfilter(pu,
    795 			    preq->preq_cookie, );
    796 			break;
    797 		}
    798 
    799 		case PUFFS_VN_CLOSEEXTATTR:
    800 		{
    801 			struct puffs_vnreq_closeextattr *auxt = auxbuf;
    802 			if (pops->puffs_closeextattr == NULL) {
    803 				error = 0;
    804 				break;
    805 			}
    806 
    807 			error = pops->puffs_closeextattr(pu,
    808 			    preq->preq_cookie, );
    809 			break;
    810 		}
    811 
    812 		case PUFFS_VN_GETEXTATTR:
    813 		{
    814 			struct puffs_vnreq_getextattr *auxt = auxbuf;
    815 			if (pops->puffs_getextattr == NULL) {
    816 				error = 0;
    817 				break;
    818 			}
    819 
    820 			error = pops->puffs_getextattr(pu,
    821 			    preq->preq_cookie, );
    822 			break;
    823 		}
    824 
    825 		case PUFFS_VN_LISTEXTATTR:
    826 		{
    827 			struct puffs_vnreq_listextattr *auxt = auxbuf;
    828 			if (pops->puffs_listextattr == NULL) {
    829 				error = 0;
    830 				break;
    831 			}
    832 
    833 			error = pops->puffs_listextattr(pu,
    834 			    preq->preq_cookie, );
    835 			break;
    836 		}
    837 
    838 		case PUFFS_VN_OPENEXTATTR:
    839 		{
    840 			struct puffs_vnreq_openextattr *auxt = auxbuf;
    841 			if (pops->puffs_openextattr == NULL) {
    842 				error = 0;
    843 				break;
    844 			}
    845 
    846 			error = pops->puffs_openextattr(pu,
    847 			    preq->preq_cookie, );
    848 			break;
    849 		}
    850 
    851 		case PUFFS_VN_DELETEEXTATTR:
    852 		{
    853 			struct puffs_vnreq_deleteextattr *auxt = auxbuf;
    854 			if (pops->puffs_deleteextattr == NULL) {
    855 				error = 0;
    856 				break;
    857 			}
    858 
    859 			error = pops->puffs_deleteextattr(pu,
    860 			    preq->preq_cookie, );
    861 			break;
    862 		}
    863 
    864 		case PUFFS_VN_SETEXTATTR:
    865 		{
    866 			struct puffs_vnreq_setextattr *auxt = auxbuf;
    867 			if (pops->puffs_setextattr == NULL) {
    868 				error = 0;
    869 				break;
    870 			}
    871 
    872 			error = pops->puffs_setextattr(pu,
    873 			    preq->preq_cookie, );
    874 			break;
    875 		}
    876 
    877 #endif
    878