puffs.c revision 1.36 1 /* $NetBSD: puffs.c,v 1.36 2007/04/13 13:35:46 pooka 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.36 2007/04/13 13:35:46 pooka 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 <mntopts.h>
48 #include <puffs.h>
49 #include <puffsdump.h>
50 #include <stdarg.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <syslog.h>
55 #include <unistd.h>
56
57 #include "puffs_priv.h"
58
59 /* Most file systems want this for opts, so just give it to them */
60 const struct mntopt puffsmopts[] = {
61 MOPT_STDOPTS,
62 PUFFSMOPT_STD,
63 MOPT_NULL,
64 };
65
66 #define FILLOP(lower, upper) \
67 do { \
68 if (pops->puffs_node_##lower) \
69 opmask[PUFFS_VN_##upper] = 1; \
70 } while (/*CONSTCOND*/0)
71 static void
72 fillvnopmask(struct puffs_ops *pops, uint8_t *opmask)
73 {
74
75 memset(opmask, 0, PUFFS_VN_MAX);
76
77 FILLOP(create, CREATE);
78 FILLOP(mknod, MKNOD);
79 FILLOP(open, OPEN);
80 FILLOP(close, CLOSE);
81 FILLOP(access, ACCESS);
82 FILLOP(getattr, GETATTR);
83 FILLOP(setattr, SETATTR);
84 FILLOP(poll, POLL); /* XXX: not ready in kernel */
85 FILLOP(mmap, MMAP);
86 FILLOP(fsync, FSYNC);
87 FILLOP(seek, SEEK);
88 FILLOP(remove, REMOVE);
89 FILLOP(link, LINK);
90 FILLOP(rename, RENAME);
91 FILLOP(mkdir, MKDIR);
92 FILLOP(rmdir, RMDIR);
93 FILLOP(symlink, SYMLINK);
94 FILLOP(readdir, READDIR);
95 FILLOP(readlink, READLINK);
96 FILLOP(reclaim, RECLAIM);
97 FILLOP(inactive, INACTIVE);
98 FILLOP(print, PRINT);
99 FILLOP(read, READ);
100 FILLOP(write, WRITE);
101
102 /* XXX: not implemented in the kernel */
103 FILLOP(getextattr, GETEXTATTR);
104 FILLOP(setextattr, SETEXTATTR);
105 FILLOP(listextattr, LISTEXTATTR);
106 }
107 #undef FILLOP
108
109 int
110 puffs_getselectable(struct puffs_usermount *pu)
111 {
112
113 return pu->pu_kargs.pa_fd;
114 }
115
116 int
117 puffs_setblockingmode(struct puffs_usermount *pu, int mode)
118 {
119 int x;
120
121 x = mode;
122 return ioctl(pu->pu_kargs.pa_fd, FIONBIO, &x);
123 }
124
125 int
126 puffs_getstate(struct puffs_usermount *pu)
127 {
128
129 return pu->pu_state;
130 }
131
132 void
133 puffs_setstacksize(struct puffs_usermount *pu, size_t ss)
134 {
135
136 pu->pu_cc_stacksize = ss;
137 }
138
139 struct puffs_pathobj *
140 puffs_getrootpathobj(struct puffs_usermount *pu)
141 {
142 struct puffs_node *pnr;
143
144 pnr = pu->pu_pn_root;
145 if (pnr == NULL) {
146 errno = ENOENT;
147 return NULL;
148 }
149
150 return &pnr->pn_po;
151 }
152
153 void
154 puffs_setroot(struct puffs_usermount *pu, struct puffs_node *pn)
155 {
156
157 pu->pu_pn_root = pn;
158 }
159
160 struct puffs_node *
161 puffs_getroot(struct puffs_usermount *pu)
162 {
163
164 return pu->pu_pn_root;
165 }
166
167 void *
168 puffs_getspecific(struct puffs_usermount *pu)
169 {
170
171 return pu->pu_privdata;
172 }
173
174 size_t
175 puffs_getmaxreqlen(struct puffs_usermount *pu)
176 {
177
178 return pu->pu_kargs.pa_maxreqlen;
179 }
180
181 void
182 puffs_set_pathbuild(struct puffs_usermount *pu, pu_pathbuild_fn fn)
183 {
184
185 pu->pu_pathbuild = fn;
186 }
187
188 void
189 puffs_set_pathtransform(struct puffs_usermount *pu, pu_pathtransform_fn fn)
190 {
191
192 pu->pu_pathtransform = fn;
193 }
194
195 void
196 puffs_set_pathcmp(struct puffs_usermount *pu, pu_pathcmp_fn fn)
197 {
198
199 pu->pu_pathcmp = fn;
200 }
201
202 void
203 puffs_set_pathfree(struct puffs_usermount *pu, pu_pathfree_fn fn)
204 {
205
206 pu->pu_pathfree = fn;
207 }
208
209 void
210 puffs_set_namemod(struct puffs_usermount *pu, pu_namemod_fn fn)
211 {
212
213 pu->pu_namemod = fn;
214 }
215
216 int
217 puffs_domount(struct puffs_usermount *pu, const char *dir, int mntflags)
218 {
219
220 #if 1
221 /* XXXkludgehere */
222 /* kauth doesn't provide this service any longer */
223 if (geteuid() != 0)
224 mntflags |= MNT_NOSUID | MNT_NODEV;
225 #endif
226
227 if (mount(MOUNT_PUFFS, dir, mntflags, &pu->pu_kargs) == -1)
228 return -1;
229 pu->pu_state = PUFFS_STATE_MOUNTING;
230
231 return 0;
232 }
233
234 struct puffs_usermount *
235 _puffs_init(int develv, struct puffs_ops *pops, const char *puffsname,
236 void *priv, uint32_t pflags)
237 {
238 struct puffs_usermount *pu;
239 struct puffs_kargs *pargs;
240 int fd;
241
242 if (develv != PUFFS_DEVEL_LIBVERSION) {
243 warnx("puffs_mount: mounting with lib version %d, need %d",
244 develv, PUFFS_DEVEL_LIBVERSION);
245 errno = EINVAL;
246 return NULL;
247 }
248
249 fd = open("/dev/puffs", O_RDONLY);
250 if (fd == -1)
251 return NULL;
252 if (fd <= 2)
253 warnx("puffs_mount: device fd %d (<= 2), sure this is "
254 "what you want?", fd);
255
256 pu = malloc(sizeof(struct puffs_usermount));
257 if (pu == NULL)
258 goto failfree;
259
260 pargs = &pu->pu_kargs;
261 memset(pargs, 0, sizeof(struct puffs_kargs));
262 pargs->pa_vers = PUFFSDEVELVERS | PUFFSVERSION;
263 pargs->pa_flags = PUFFS_FLAG_KERN(pflags);
264 pargs->pa_fd = fd;
265 fillvnopmask(pops, pargs->pa_vnopmask);
266 (void)strlcpy(pargs->pa_name, puffsname, sizeof(pargs->pa_name));
267
268 pu->pu_flags = pflags;
269 pu->pu_ops = *pops;
270 free(pops); /* XXX */
271
272 pu->pu_privdata = priv;
273 pu->pu_cc_stacksize = PUFFS_CC_STACKSIZE_DEFAULT;
274 LIST_INIT(&pu->pu_pnodelst);
275
276 /* defaults for some user-settable translation functions */
277 pu->pu_cmap = NULL; /* identity translation */
278
279 pu->pu_pathbuild = puffs_stdpath_buildpath;
280 pu->pu_pathfree = puffs_stdpath_freepath;
281 pu->pu_pathcmp = puffs_stdpath_cmppath;
282 pu->pu_pathtransform = NULL;
283 pu->pu_namemod = NULL;
284
285 pu->pu_state = PUFFS_STATE_BEFOREMOUNT;
286
287 return pu;
288
289 failfree:
290 /* can't unmount() from here for obvious reasons */
291 close(fd);
292 free(pu);
293 return NULL;
294 }
295
296 struct puffs_usermount *
297 _puffs_mount(int develv, struct puffs_ops *pops, const char *dir, int mntflags,
298 const char *puffsname, void *priv, uint32_t pflags)
299 {
300 struct puffs_usermount *pu;
301 int sverrno;
302
303 pu = _puffs_init(develv, pops, puffsname, priv, pflags);
304 if (pu == NULL)
305 return NULL;
306
307 if (puffs_domount(pu, dir, mntflags) == -1) {
308 sverrno = errno;
309 puffs_exit(pu, 1);
310 errno = sverrno;
311 return NULL;
312 }
313
314 return pu;
315 }
316
317 int
318 puffs_start(struct puffs_usermount *pu, void *rootcookie, struct statvfs *sbp)
319 {
320 struct puffs_startreq sreq;
321
322 memset(&sreq, 0, sizeof(struct puffs_startreq));
323 sreq.psr_cookie = rootcookie;
324 sreq.psr_sb = *sbp;
325
326 /* tell kernel we're flying */
327 if (ioctl(pu->pu_kargs.pa_fd, PUFFSSTARTOP, &sreq) == -1)
328 return -1;
329
330 pu->pu_state = PUFFS_STATE_RUNNING;
331
332 return 0;
333 }
334
335 /*
336 * XXX: there's currently no clean way to request unmount from
337 * within the user server, so be very brutal about it.
338 */
339 /*ARGSUSED1*/
340 int
341 puffs_exit(struct puffs_usermount *pu, int force)
342 {
343 struct puffs_node *pn, *pn_next;
344
345 force = 1; /* currently */
346
347 if (pu->pu_kargs.pa_fd)
348 close(pu->pu_kargs.pa_fd);
349
350 pn = LIST_FIRST(&pu->pu_pnodelst);
351 while (pn) {
352 pn_next = LIST_NEXT(pn, pn_entries);
353 puffs_pn_put(pn);
354 pn = pn_next;
355 }
356 free(pu);
357
358 return 0; /* always succesful for now, WILL CHANGE */
359 }
360
361 int
362 puffs_mainloop(struct puffs_usermount *pu, int flags)
363 {
364 struct puffs_getreq *pgr;
365 struct puffs_putreq *ppr;
366 int rv;
367
368 rv = -1;
369 pgr = puffs_req_makeget(pu, puffs_getmaxreqlen(pu), 0);
370 if (pgr == NULL)
371 return -1;
372
373 ppr = puffs_req_makeput(pu);
374 if (ppr == NULL) {
375 puffs_req_destroyget(pgr);
376 return -1;
377 }
378
379 if ((flags & PUFFSLOOP_NODAEMON) == 0)
380 if (daemon(1, 0) == -1)
381 goto out;
382
383 /* XXX: should be a bit more robust with errors here */
384 while (puffs_getstate(pu) == PUFFS_STATE_RUNNING
385 || puffs_getstate(pu) == PUFFS_STATE_UNMOUNTING) {
386 puffs_req_resetput(ppr);
387
388 if (puffs_req_handle(pu, pgr, ppr, 0) == -1) {
389 rv = -1;
390 break;
391 }
392 if (puffs_req_putput(ppr) == -1) {
393 rv = -1;
394 break;
395 }
396 }
397
398 out:
399 puffs_req_destroyput(ppr);
400 puffs_req_destroyget(pgr);
401 return rv;
402 }
403
404 int
405 puffs_dopreq(struct puffs_usermount *pu, struct puffs_req *preq,
406 struct puffs_putreq *ppr)
407 {
408 struct puffs_cc *pcc;
409 int rv;
410
411 /*
412 * XXX: the structure is currently a mess. anyway, trap
413 * the cacheops here already, since they don't need a cc.
414 * I really should get around to revamping the operation
415 * dispatching code one of these days.
416 */
417 if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_CACHE) {
418 struct puffs_cacheinfo *pci = (void *)preq;
419
420 if (pu->pu_ops.puffs_cache_write == NULL)
421 return 0;
422
423 pu->pu_ops.puffs_cache_write(pu, preq->preq_cookie,
424 pci->pcache_nruns, pci->pcache_runs);
425 }
426
427 if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
428 puffsdump_req(preq);
429
430 pcc = puffs_cc_create(pu);
431
432 /* XXX: temporary kludging */
433 pcc->pcc_preq = malloc(preq->preq_buflen);
434 if (pcc->pcc_preq == NULL)
435 return -1;
436 (void) memcpy(pcc->pcc_preq, preq, preq->preq_buflen);
437
438 rv = puffs_docc(pcc, ppr);
439
440 if ((pcc->pcc_flags & PCC_DONE) == 0)
441 return 0;
442
443 return rv;
444 }
445
446 enum {PUFFCALL_ANSWER, PUFFCALL_IGNORE, PUFFCALL_AGAIN};
447
448 int
449 puffs_docc(struct puffs_cc *pcc, struct puffs_putreq *ppr)
450 {
451 struct puffs_usermount *pu = pcc->pcc_pu;
452 int rv;
453
454 assert((pcc->pcc_flags & PCC_DONE) == 0);
455
456 puffs_cc_continue(pcc);
457 rv = pcc->pcc_rv;
458
459 if ((pcc->pcc_flags & PCC_DONE) == 0)
460 rv = PUFFCALL_AGAIN;
461
462 /* check if we need to store this reply */
463 switch (rv) {
464 case PUFFCALL_ANSWER:
465 if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
466 puffsdump_rv(pcc->pcc_preq);
467
468 puffs_req_putcc(ppr, pcc);
469 break;
470 case PUFFCALL_IGNORE:
471 puffs_cc_destroy(pcc);
472 break;
473 case PUFFCALL_AGAIN:
474 break;
475 default:
476 assert(/*CONSTCOND*/0);
477 }
478
479 return 0;
480 }
481
482 /* library private, but linked from callcontext.c */
483
484 void
485 puffs_calldispatcher(struct puffs_cc *pcc)
486 {
487 struct puffs_usermount *pu = pcc->pcc_pu;
488 struct puffs_ops *pops = &pu->pu_ops;
489 struct puffs_req *preq = pcc->pcc_preq;
490 void *auxbuf = preq; /* help with typecasting */
491 int error, rv, buildpath;
492
493 assert(pcc->pcc_flags & (PCC_ONCE | PCC_REALCC));
494
495 if (PUFFSOP_WANTREPLY(preq->preq_opclass))
496 rv = PUFFCALL_ANSWER;
497 else
498 rv = PUFFCALL_IGNORE;
499
500 buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH;
501
502 if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) {
503 switch (preq->preq_optype) {
504 case PUFFS_VFS_UNMOUNT:
505 {
506 struct puffs_vfsreq_unmount *auxt = auxbuf;
507
508 pu->pu_state = PUFFS_STATE_UNMOUNTING;
509 error = pops->puffs_fs_unmount(pcc,
510 auxt->pvfsr_flags, auxt->pvfsr_pid);
511 if (!error)
512 pu->pu_state = PUFFS_STATE_UNMOUNTED;
513 else
514 pu->pu_state = PUFFS_STATE_RUNNING;
515 break;
516 }
517
518 case PUFFS_VFS_STATVFS:
519 {
520 struct puffs_vfsreq_statvfs *auxt = auxbuf;
521
522 error = pops->puffs_fs_statvfs(pcc,
523 &auxt->pvfsr_sb, auxt->pvfsr_pid);
524 break;
525 }
526
527 case PUFFS_VFS_SYNC:
528 {
529 struct puffs_vfsreq_sync *auxt = auxbuf;
530
531 error = pops->puffs_fs_sync(pcc,
532 auxt->pvfsr_waitfor, &auxt->pvfsr_cred,
533 auxt->pvfsr_pid);
534 break;
535 }
536
537 case PUFFS_VFS_FHTOVP:
538 {
539 struct puffs_vfsreq_fhtonode *auxt = auxbuf;
540
541 error = pops->puffs_fs_fhtonode(pcc, auxt->pvfsr_data,
542 auxt->pvfsr_dsize, &auxt->pvfsr_fhcookie,
543 &auxt->pvfsr_vtype, &auxt->pvfsr_size,
544 &auxt->pvfsr_rdev);
545
546 break;
547 }
548
549 case PUFFS_VFS_VPTOFH:
550 {
551 struct puffs_vfsreq_nodetofh *auxt = auxbuf;
552
553 error = pops->puffs_fs_nodetofh(pcc,
554 auxt->pvfsr_fhcookie, auxt->pvfsr_data,
555 &auxt->pvfsr_dsize);
556
557 break;
558 }
559
560 case PUFFS_VFS_SUSPEND:
561 {
562 struct puffs_vfsreq_suspend *auxt = auxbuf;
563
564 error = 0;
565 if (pops->puffs_fs_suspend == NULL)
566 break;
567
568 pops->puffs_fs_suspend(pcc, auxt->pvfsr_status);
569 break;
570 }
571
572 default:
573 /*
574 * I guess the kernel sees this one coming
575 */
576 error = EINVAL;
577 break;
578 }
579
580 /* XXX: audit return values */
581 /* XXX: sync with kernel */
582 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
583 switch (preq->preq_optype) {
584 case PUFFS_VN_LOOKUP:
585 {
586 struct puffs_vnreq_lookup *auxt = auxbuf;
587 struct puffs_cn pcn;
588
589 pcn.pcn_pkcnp = &auxt->pvnr_cn;
590 if (buildpath) {
591 error = puffs_path_pcnbuild(pu, &pcn,
592 preq->preq_cookie);
593 if (error)
594 break;
595 }
596
597 /* lookup *must* be present */
598 error = pops->puffs_node_lookup(pcc, preq->preq_cookie,
599 &auxt->pvnr_newnode, &auxt->pvnr_vtype,
600 &auxt->pvnr_size, &auxt->pvnr_rdev, &pcn);
601
602 if (buildpath) {
603 if (error) {
604 pu->pu_pathfree(pu, &pcn.pcn_po_full);
605 } else {
606 struct puffs_node *pn;
607
608 /*
609 * did we get a new node or a
610 * recycled node?
611 */
612 pn = PU_CMAP(pu, auxt->pvnr_newnode);
613 if (pn->pn_po.po_path == NULL)
614 pn->pn_po = pcn.pcn_po_full;
615 else
616 pu->pu_pathfree(pu,
617 &pcn.pcn_po_full);
618 }
619 }
620
621 break;
622 }
623
624 case PUFFS_VN_CREATE:
625 {
626 struct puffs_vnreq_create *auxt = auxbuf;
627 struct puffs_cn pcn;
628 if (pops->puffs_node_create == NULL) {
629 error = 0;
630 break;
631 }
632
633 pcn.pcn_pkcnp = &auxt->pvnr_cn;
634 if (buildpath) {
635 error = puffs_path_pcnbuild(pu, &pcn,
636 preq->preq_cookie);
637 if (error)
638 break;
639 }
640
641 error = pops->puffs_node_create(pcc,
642 preq->preq_cookie, &auxt->pvnr_newnode,
643 &pcn, &auxt->pvnr_va);
644
645 if (buildpath) {
646 if (error) {
647 pu->pu_pathfree(pu, &pcn.pcn_po_full);
648 } else {
649 struct puffs_node *pn;
650
651 pn = PU_CMAP(pu, auxt->pvnr_newnode);
652 pn->pn_po = pcn.pcn_po_full;
653 }
654 }
655
656 break;
657 }
658
659 case PUFFS_VN_MKNOD:
660 {
661 struct puffs_vnreq_mknod *auxt = auxbuf;
662 struct puffs_cn pcn;
663 if (pops->puffs_node_mknod == NULL) {
664 error = 0;
665 break;
666 }
667
668 pcn.pcn_pkcnp = &auxt->pvnr_cn;
669 if (buildpath) {
670 error = puffs_path_pcnbuild(pu, &pcn,
671 preq->preq_cookie);
672 if (error)
673 break;
674 }
675
676 error = pops->puffs_node_mknod(pcc,
677 preq->preq_cookie, &auxt->pvnr_newnode,
678 &pcn, &auxt->pvnr_va);
679
680 if (buildpath) {
681 if (error) {
682 pu->pu_pathfree(pu, &pcn.pcn_po_full);
683 } else {
684 struct puffs_node *pn;
685
686 pn = PU_CMAP(pu, auxt->pvnr_newnode);
687 pn->pn_po = pcn.pcn_po_full;
688 }
689 }
690
691 break;
692 }
693
694 case PUFFS_VN_OPEN:
695 {
696 struct puffs_vnreq_open *auxt = auxbuf;
697 if (pops->puffs_node_open == NULL) {
698 error = 0;
699 break;
700 }
701
702 error = pops->puffs_node_open(pcc,
703 preq->preq_cookie, auxt->pvnr_mode,
704 &auxt->pvnr_cred, auxt->pvnr_pid);
705 break;
706 }
707
708 case PUFFS_VN_CLOSE:
709 {
710 struct puffs_vnreq_close *auxt = auxbuf;
711 if (pops->puffs_node_close == NULL) {
712 error = 0;
713 break;
714 }
715
716 error = pops->puffs_node_close(pcc,
717 preq->preq_cookie, auxt->pvnr_fflag,
718 &auxt->pvnr_cred, auxt->pvnr_pid);
719 break;
720 }
721
722 case PUFFS_VN_ACCESS:
723 {
724 struct puffs_vnreq_access *auxt = auxbuf;
725 if (pops->puffs_node_access == NULL) {
726 error = 0;
727 break;
728 }
729
730 error = pops->puffs_node_access(pcc,
731 preq->preq_cookie, auxt->pvnr_mode,
732 &auxt->pvnr_cred, auxt->pvnr_pid);
733 break;
734 }
735
736 case PUFFS_VN_GETATTR:
737 {
738 struct puffs_vnreq_getattr *auxt = auxbuf;
739 if (pops->puffs_node_getattr == NULL) {
740 error = EOPNOTSUPP;
741 break;
742 }
743
744 error = pops->puffs_node_getattr(pcc,
745 preq->preq_cookie, &auxt->pvnr_va,
746 &auxt->pvnr_cred, auxt->pvnr_pid);
747 break;
748 }
749
750 case PUFFS_VN_SETATTR:
751 {
752 struct puffs_vnreq_setattr *auxt = auxbuf;
753 if (pops->puffs_node_setattr == NULL) {
754 error = EOPNOTSUPP;
755 break;
756 }
757
758 error = pops->puffs_node_setattr(pcc,
759 preq->preq_cookie, &auxt->pvnr_va,
760 &auxt->pvnr_cred, auxt->pvnr_pid);
761 break;
762 }
763
764 case PUFFS_VN_MMAP:
765 {
766 struct puffs_vnreq_mmap *auxt = auxbuf;
767 if (pops->puffs_node_mmap == NULL) {
768 error = 0;
769 break;
770 }
771
772 error = pops->puffs_node_mmap(pcc,
773 preq->preq_cookie, auxt->pvnr_fflags,
774 &auxt->pvnr_cred, auxt->pvnr_pid);
775 break;
776 }
777
778 case PUFFS_VN_FSYNC:
779 {
780 struct puffs_vnreq_fsync *auxt = auxbuf;
781 if (pops->puffs_node_fsync == NULL) {
782 error = 0;
783 break;
784 }
785
786 error = pops->puffs_node_fsync(pcc,
787 preq->preq_cookie, &auxt->pvnr_cred,
788 auxt->pvnr_flags, auxt->pvnr_offlo,
789 auxt->pvnr_offhi, auxt->pvnr_pid);
790 break;
791 }
792
793 case PUFFS_VN_SEEK:
794 {
795 struct puffs_vnreq_seek *auxt = auxbuf;
796 if (pops->puffs_node_seek == NULL) {
797 error = 0;
798 break;
799 }
800
801 error = pops->puffs_node_seek(pcc,
802 preq->preq_cookie, auxt->pvnr_oldoff,
803 auxt->pvnr_newoff, &auxt->pvnr_cred);
804 break;
805 }
806
807 case PUFFS_VN_REMOVE:
808 {
809 struct puffs_vnreq_remove *auxt = auxbuf;
810 struct puffs_cn pcn;
811 if (pops->puffs_node_remove == NULL) {
812 error = 0;
813 break;
814 }
815
816 pcn.pcn_pkcnp = &auxt->pvnr_cn;
817
818 error = pops->puffs_node_remove(pcc,
819 preq->preq_cookie, auxt->pvnr_cookie_targ, &pcn);
820 break;
821 }
822
823 case PUFFS_VN_LINK:
824 {
825 struct puffs_vnreq_link *auxt = auxbuf;
826 struct puffs_cn pcn;
827 if (pops->puffs_node_link == NULL) {
828 error = 0;
829 break;
830 }
831
832 pcn.pcn_pkcnp = &auxt->pvnr_cn;
833 if (buildpath) {
834 error = puffs_path_pcnbuild(pu, &pcn,
835 preq->preq_cookie);
836 if (error)
837 break;
838 }
839
840 error = pops->puffs_node_link(pcc,
841 preq->preq_cookie, auxt->pvnr_cookie_targ, &pcn);
842 if (buildpath)
843 pu->pu_pathfree(pu, &pcn.pcn_po_full);
844
845 break;
846 }
847
848 case PUFFS_VN_RENAME:
849 {
850 struct puffs_vnreq_rename *auxt = auxbuf;
851 struct puffs_cn pcn_src, pcn_targ;
852 struct puffs_node *pn_src;
853
854 if (pops->puffs_node_rename == NULL) {
855 error = 0;
856 break;
857 }
858
859 pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src;
860 pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ;
861 if (buildpath) {
862 pn_src = auxt->pvnr_cookie_src;
863 pcn_src.pcn_po_full = pn_src->pn_po;
864
865 error = puffs_path_pcnbuild(pu, &pcn_targ,
866 auxt->pvnr_cookie_targdir);
867 if (error)
868 break;
869 }
870
871 error = pops->puffs_node_rename(pcc,
872 preq->preq_cookie, auxt->pvnr_cookie_src,
873 &pcn_src, auxt->pvnr_cookie_targdir,
874 auxt->pvnr_cookie_targ, &pcn_targ);
875
876 if (buildpath) {
877 if (error) {
878 pu->pu_pathfree(pu,
879 &pcn_targ.pcn_po_full);
880 } else {
881 struct puffs_pathinfo pi;
882 struct puffs_pathobj po_old;
883
884 /* handle this node */
885 po_old = pn_src->pn_po;
886 pn_src->pn_po = pcn_targ.pcn_po_full;
887
888 if (pn_src->pn_va.va_type != VDIR) {
889 pu->pu_pathfree(pu, &po_old);
890 break;
891 }
892
893 /* handle all child nodes for DIRs */
894 pi.pi_old = &pcn_src.pcn_po_full;
895 pi.pi_new = &pcn_targ.pcn_po_full;
896
897 if (puffs_pn_nodewalk(pu,
898 puffs_path_prefixadj, &pi) != NULL)
899 error = ENOMEM;
900 pu->pu_pathfree(pu, &po_old);
901 }
902 }
903 break;
904 }
905
906 case PUFFS_VN_MKDIR:
907 {
908 struct puffs_vnreq_mkdir *auxt = auxbuf;
909 struct puffs_cn pcn;
910 if (pops->puffs_node_mkdir == NULL) {
911 error = 0;
912 break;
913 }
914
915 pcn.pcn_pkcnp = &auxt->pvnr_cn;
916 if (buildpath) {
917 error = puffs_path_pcnbuild(pu, &pcn,
918 preq->preq_cookie);
919 if (error)
920 break;
921 }
922
923 error = pops->puffs_node_mkdir(pcc,
924 preq->preq_cookie, &auxt->pvnr_newnode,
925 &pcn, &auxt->pvnr_va);
926
927 if (buildpath) {
928 if (error) {
929 pu->pu_pathfree(pu, &pcn.pcn_po_full);
930 } else {
931 struct puffs_node *pn;
932
933 pn = PU_CMAP(pu, auxt->pvnr_newnode);
934 pn->pn_po = pcn.pcn_po_full;
935 }
936 }
937
938 break;
939 }
940
941 case PUFFS_VN_RMDIR:
942 {
943 struct puffs_vnreq_rmdir *auxt = auxbuf;
944 struct puffs_cn pcn;
945 if (pops->puffs_node_rmdir == NULL) {
946 error = 0;
947 break;
948 }
949
950 pcn.pcn_pkcnp = &auxt->pvnr_cn;
951
952 error = pops->puffs_node_rmdir(pcc,
953 preq->preq_cookie, auxt->pvnr_cookie_targ, &pcn);
954 break;
955 }
956
957 case PUFFS_VN_SYMLINK:
958 {
959 struct puffs_vnreq_symlink *auxt = auxbuf;
960 struct puffs_cn pcn;
961 if (pops->puffs_node_symlink == NULL) {
962 error = 0;
963 break;
964 }
965
966 pcn.pcn_pkcnp = &auxt->pvnr_cn;
967 if (buildpath) {
968 error = puffs_path_pcnbuild(pu, &pcn,
969 preq->preq_cookie);
970 if (error)
971 break;
972 }
973
974 error = pops->puffs_node_symlink(pcc,
975 preq->preq_cookie, &auxt->pvnr_newnode,
976 &pcn, &auxt->pvnr_va, auxt->pvnr_link);
977
978 if (buildpath) {
979 if (error) {
980 pu->pu_pathfree(pu, &pcn.pcn_po_full);
981 } else {
982 struct puffs_node *pn;
983
984 pn = PU_CMAP(pu, auxt->pvnr_newnode);
985 pn->pn_po = pcn.pcn_po_full;
986 }
987 }
988
989 break;
990 }
991
992 case PUFFS_VN_READDIR:
993 {
994 struct puffs_vnreq_readdir *auxt = auxbuf;
995 struct dirent *dent;
996 off_t *cookies;
997 size_t res;
998
999 if (pops->puffs_node_readdir == NULL) {
1000 error = 0;
1001 break;
1002 }
1003
1004 if (auxt->pvnr_ncookies) {
1005 /* LINTED: pvnr_data is __aligned() */
1006 cookies = (off_t *)auxt->pvnr_data;
1007 } else {
1008 cookies = NULL;
1009 }
1010 /* LINTED: dentoff is aligned in the kernel */
1011 dent = (struct dirent *)
1012 (auxt->pvnr_data + auxt->pvnr_dentoff);
1013
1014 res = auxt->pvnr_resid;
1015 error = pops->puffs_node_readdir(pcc,
1016 preq->preq_cookie, dent, &auxt->pvnr_offset,
1017 &auxt->pvnr_resid, &auxt->pvnr_cred,
1018 &auxt->pvnr_eofflag, cookies, &auxt->pvnr_ncookies);
1019
1020 /* need to move a bit more */
1021 preq->preq_buflen = sizeof(struct puffs_vnreq_readdir)
1022 + auxt->pvnr_dentoff + (res - auxt->pvnr_resid);
1023 break;
1024 }
1025
1026 case PUFFS_VN_READLINK:
1027 {
1028 struct puffs_vnreq_readlink *auxt = auxbuf;
1029 if (pops->puffs_node_readlink == NULL) {
1030 error = EOPNOTSUPP;
1031 break;
1032 }
1033
1034 error = pops->puffs_node_readlink(pcc,
1035 preq->preq_cookie, &auxt->pvnr_cred,
1036 auxt->pvnr_link, &auxt->pvnr_linklen);
1037 break;
1038 }
1039
1040 case PUFFS_VN_RECLAIM:
1041 {
1042 struct puffs_vnreq_reclaim *auxt = auxbuf;
1043 if (pops->puffs_node_reclaim == NULL) {
1044 error = 0;
1045 break;
1046 }
1047
1048 error = pops->puffs_node_reclaim(pcc,
1049 preq->preq_cookie, auxt->pvnr_pid);
1050 break;
1051 }
1052
1053 case PUFFS_VN_INACTIVE:
1054 {
1055 struct puffs_vnreq_inactive *auxt = auxbuf;
1056 if (pops->puffs_node_inactive == NULL) {
1057 error = EOPNOTSUPP;
1058 break;
1059 }
1060
1061 error = pops->puffs_node_inactive(pcc,
1062 preq->preq_cookie, auxt->pvnr_pid,
1063 &auxt->pvnr_backendrefs);
1064 break;
1065 }
1066
1067 case PUFFS_VN_PATHCONF:
1068 {
1069 struct puffs_vnreq_pathconf *auxt = auxbuf;
1070 if (pops->puffs_node_pathconf == NULL) {
1071 error = 0;
1072 break;
1073 }
1074
1075 error = pops->puffs_node_pathconf(pcc,
1076 preq->preq_cookie, auxt->pvnr_name,
1077 &auxt->pvnr_retval);
1078 break;
1079 }
1080
1081 case PUFFS_VN_ADVLOCK:
1082 {
1083 struct puffs_vnreq_advlock *auxt = auxbuf;
1084 if (pops->puffs_node_advlock == NULL) {
1085 error = 0;
1086 break;
1087 }
1088
1089 error = pops->puffs_node_advlock(pcc,
1090 preq->preq_cookie, auxt->pvnr_id, auxt->pvnr_op,
1091 &auxt->pvnr_fl, auxt->pvnr_flags);
1092 break;
1093 }
1094
1095 case PUFFS_VN_PRINT:
1096 {
1097 if (pops->puffs_node_print == NULL) {
1098 error = 0;
1099 break;
1100 }
1101
1102 error = pops->puffs_node_print(pcc,
1103 preq->preq_cookie);
1104 break;
1105 }
1106
1107 case PUFFS_VN_READ:
1108 {
1109 struct puffs_vnreq_read *auxt = auxbuf;
1110 size_t res;
1111
1112 if (pops->puffs_node_read == NULL) {
1113 error = EIO;
1114 break;
1115 }
1116
1117 res = auxt->pvnr_resid;
1118 error = pops->puffs_node_read(pcc,
1119 preq->preq_cookie, auxt->pvnr_data,
1120 auxt->pvnr_offset, &auxt->pvnr_resid,
1121 &auxt->pvnr_cred, auxt->pvnr_ioflag);
1122
1123 /* need to move a bit more */
1124 preq->preq_buflen = sizeof(struct puffs_vnreq_read)
1125 + (res - auxt->pvnr_resid);
1126 break;
1127 }
1128
1129 case PUFFS_VN_WRITE:
1130 {
1131 struct puffs_vnreq_write *auxt = auxbuf;
1132
1133 if (pops->puffs_node_write == NULL) {
1134 error = EIO;
1135 break;
1136 }
1137
1138 error = pops->puffs_node_write(pcc,
1139 preq->preq_cookie, auxt->pvnr_data,
1140 auxt->pvnr_offset, &auxt->pvnr_resid,
1141 &auxt->pvnr_cred, auxt->pvnr_ioflag);
1142
1143 /* don't need to move data back to the kernel */
1144 preq->preq_buflen = sizeof(struct puffs_vnreq_write);
1145 break;
1146 }
1147
1148 /* holy bitrot, ryydman! */
1149 #if 0
1150 case PUFFS_VN_IOCTL:
1151 error = pops->puffs_node_ioctl1(pcc, preq->preq_cookie,
1152 (struct puffs_vnreq_ioctl *)auxbuf, &pop);
1153 if (error != 0)
1154 break;
1155 pop.pso_reqid = preq->preq_id;
1156
1157 /* let the kernel do it's intermediate duty */
1158 error = ioctl(pu->pu_kargs.pa_fd, PUFFSSIZEOP, &pop);
1159 /*
1160 * XXX: I don't actually know what the correct
1161 * thing to do in case of an error is, so I'll
1162 * just ignore it for the time being.
1163 */
1164 error = pops->puffs_node_ioctl2(pcc, preq->preq_cookie,
1165 (struct puffs_vnreq_ioctl *)auxbuf, &pop);
1166 break;
1167
1168 case PUFFS_VN_FCNTL:
1169 error = pops->puffs_node_fcntl1(pcc, preq->preq_cookie,
1170 (struct puffs_vnreq_fcntl *)auxbuf, &pop);
1171 if (error != 0)
1172 break;
1173 pop.pso_reqid = preq->preq_id;
1174
1175 /* let the kernel do it's intermediate duty */
1176 error = ioctl(pu->pu_kargs.pa_fd, PUFFSSIZEOP, &pop);
1177 /*
1178 * XXX: I don't actually know what the correct
1179 * thing to do in case of an error is, so I'll
1180 * just ignore it for the time being.
1181 */
1182 error = pops->puffs_node_fcntl2(pcc, preq->preq_cookie,
1183 (struct puffs_vnreq_fcntl *)auxbuf, &pop);
1184 break;
1185 #endif
1186
1187 default:
1188 printf("inval op %d\n", preq->preq_optype);
1189 error = EINVAL;
1190 break;
1191 }
1192 } else {
1193 /*
1194 * this one also
1195 */
1196 error = EINVAL;
1197 }
1198
1199 preq->preq_rv = error;
1200
1201 pcc->pcc_rv = rv;
1202 pcc->pcc_flags |= PCC_DONE;
1203 }
1204
1205
1206 #if 0
1207 case PUFFS_VN_POLL:
1208 {
1209 struct puffs_vnreq_poll *auxt = auxbuf;
1210 if (pops->puffs_node_poll == NULL) {
1211 error = 0;
1212 break;
1213 }
1214
1215 error = pops->puffs_node_poll(pcc,
1216 preq->preq_cookie, preq-);
1217 break;
1218 }
1219
1220 case PUFFS_VN_KQFILTER:
1221 {
1222 struct puffs_vnreq_kqfilter *auxt = auxbuf;
1223 if (pops->puffs_node_kqfilter == NULL) {
1224 error = 0;
1225 break;
1226 }
1227
1228 error = pops->puffs_node_kqfilter(pcc,
1229 preq->preq_cookie, );
1230 break;
1231 }
1232
1233 case PUFFS_VN_CLOSEEXTATTR:
1234 {
1235 struct puffs_vnreq_closeextattr *auxt = auxbuf;
1236 if (pops->puffs_closeextattr == NULL) {
1237 error = 0;
1238 break;
1239 }
1240
1241 error = pops->puffs_closeextattr(pcc,
1242 preq->preq_cookie, );
1243 break;
1244 }
1245
1246 case PUFFS_VN_GETEXTATTR:
1247 {
1248 struct puffs_vnreq_getextattr *auxt = auxbuf;
1249 if (pops->puffs_getextattr == NULL) {
1250 error = 0;
1251 break;
1252 }
1253
1254 error = pops->puffs_getextattr(pcc,
1255 preq->preq_cookie, );
1256 break;
1257 }
1258
1259 case PUFFS_VN_LISTEXTATTR:
1260 {
1261 struct puffs_vnreq_listextattr *auxt = auxbuf;
1262 if (pops->puffs_listextattr == NULL) {
1263 error = 0;
1264 break;
1265 }
1266
1267 error = pops->puffs_listextattr(pcc,
1268 preq->preq_cookie, );
1269 break;
1270 }
1271
1272 case PUFFS_VN_OPENEXTATTR:
1273 {
1274 struct puffs_vnreq_openextattr *auxt = auxbuf;
1275 if (pops->puffs_openextattr == NULL) {
1276 error = 0;
1277 break;
1278 }
1279
1280 error = pops->puffs_openextattr(pcc,
1281 preq->preq_cookie, );
1282 break;
1283 }
1284
1285 case PUFFS_VN_DELETEEXTATTR:
1286 {
1287 struct puffs_vnreq_deleteextattr *auxt = auxbuf;
1288 if (pops->puffs_deleteextattr == NULL) {
1289 error = 0;
1290 break;
1291 }
1292
1293 error = pops->puffs_deleteextattr(pcc,
1294 preq->preq_cookie, );
1295 break;
1296 }
1297
1298 case PUFFS_VN_SETEXTATTR:
1299 {
1300 struct puffs_vnreq_setextattr *auxt = auxbuf;
1301 if (pops->puffs_setextattr == NULL) {
1302 error = 0;
1303 break;
1304 }
1305
1306 error = pops->puffs_setextattr(pcc,
1307 preq->preq_cookie, );
1308 break;
1309 }
1310
1311 #endif
1312