puffs.c revision 1.20 1 /* $NetBSD: puffs.c,v 1.20 2007/01/02 15:53:05 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.20 2007/01/02 15:53:05 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 <puffs.h>
48 #include <puffsdump.h>
49 #include <stdarg.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <syslog.h>
54 #include <unistd.h>
55
56 #include "puffs_priv.h"
57
58 static int do_buildpath(struct puffs_cn *, void *);
59
60 #define FILLOP(lower, upper) \
61 do { \
62 if (pops->puffs_node_##lower) \
63 opmask[PUFFS_VN_##upper] = 1; \
64 } while (/*CONSTCOND*/0)
65 static void
66 fillvnopmask(struct puffs_ops *pops, uint8_t *opmask)
67 {
68
69 memset(opmask, 0, PUFFS_VN_MAX);
70
71 FILLOP(create, CREATE);
72 FILLOP(mknod, MKNOD);
73 FILLOP(open, OPEN);
74 FILLOP(close, CLOSE);
75 FILLOP(access, ACCESS);
76 FILLOP(getattr, GETATTR);
77 FILLOP(setattr, SETATTR);
78 FILLOP(poll, POLL); /* XXX: not ready in kernel */
79 FILLOP(revoke, REVOKE);
80 FILLOP(mmap, MMAP);
81 FILLOP(fsync, FSYNC);
82 FILLOP(seek, SEEK);
83 FILLOP(remove, REMOVE);
84 FILLOP(link, LINK);
85 FILLOP(rename, RENAME);
86 FILLOP(mkdir, MKDIR);
87 FILLOP(rmdir, RMDIR);
88 FILLOP(symlink, SYMLINK);
89 FILLOP(readdir, READDIR);
90 FILLOP(readlink, READLINK);
91 FILLOP(reclaim, RECLAIM);
92 FILLOP(inactive, INACTIVE);
93 FILLOP(print, PRINT);
94 FILLOP(read, READ);
95 FILLOP(write, WRITE);
96
97 /* XXX: not implemented in the kernel */
98 FILLOP(getextattr, GETEXTATTR);
99 FILLOP(setextattr, SETEXTATTR);
100 FILLOP(listextattr, LISTEXTATTR);
101 }
102 #undef FILLOP
103
104 int
105 puffs_getselectable(struct puffs_usermount *pu)
106 {
107
108 return pu->pu_fd;
109 }
110
111 int
112 puffs_setblockingmode(struct puffs_usermount *pu, int mode)
113 {
114 int x;
115
116 x = mode;
117 return ioctl(pu->pu_fd, FIONBIO, &x);
118 }
119
120 int
121 puffs_getstate(struct puffs_usermount *pu)
122 {
123
124 return pu->pu_state;
125 }
126
127 void
128 puffs_setstacksize(struct puffs_usermount *pu, size_t ss)
129 {
130
131 pu->pu_cc_stacksize = ss;
132 }
133
134 /*
135 * in case the server wants to use some other scheme for paths, it
136 * can (*must*) call this in mount.
137 */
138 int
139 puffs_setrootpath(struct puffs_usermount *pu, const char *rootpath)
140 {
141 struct puffs_node *pnr;
142
143 pnr = pu->pu_pn_root;
144 if (pnr == NULL) {
145 errno = ENOENT;
146 return -1;
147 }
148
149 free(pnr->pn_path);
150 pnr->pn_path = strdup(rootpath);
151 if (pnr->pn_path == NULL)
152 return -1;
153 pnr->pn_plen = strlen(pnr->pn_path) + 1; /* yes, count nul */
154
155 return 0;
156 }
157
158
159 enum {PUFFCALL_ANSWER, PUFFCALL_IGNORE, PUFFCALL_AGAIN};
160
161 struct puffs_usermount *
162 _puffs_mount(int develv, struct puffs_ops *pops, const char *dir, int mntflags,
163 const char *puffsname, void *priv, uint32_t pflags, size_t maxreqlen)
164 {
165 struct puffs_startreq sreq;
166 struct puffs_args pargs;
167 struct puffs_usermount *pu;
168 int fd = 0, rv;
169
170 if (develv != PUFFS_DEVEL_LIBVERSION) {
171 warnx("puffs_mount: mounting with lib version %d, need %d",
172 develv, PUFFS_DEVEL_LIBVERSION);
173 errno = EINVAL;
174 return NULL;
175 }
176
177 if (pops->puffs_fs_mount == NULL) {
178 errno = EINVAL;
179 return NULL;
180 }
181
182 fd = open("/dev/puffs", O_RDONLY);
183 if (fd == -1)
184 return NULL;
185 if (fd <= 2)
186 warnx("puffs_mount: device fd %d (<= 2), sure this is "
187 "what you want?", fd);
188
189 pargs.pa_vers = PUFFSDEVELVERS | PUFFSVERSION;
190 pargs.pa_flags = PUFFS_FLAG_KERN(pflags);
191 pargs.pa_fd = fd;
192 pargs.pa_maxreqlen = maxreqlen;
193 fillvnopmask(pops, pargs.pa_vnopmask);
194 (void)strlcpy(pargs.pa_name, puffsname, sizeof(pargs.pa_name));
195
196 pu = malloc(sizeof(struct puffs_usermount));
197 if (!pu)
198 return NULL;
199
200 pu->pu_flags = pflags;
201 pu->pu_ops = *pops;
202 free(pops);
203 pu->pu_fd = fd;
204 pu->pu_privdata = priv;
205 pu->pu_cc_stacksize = PUFFS_CC_STACKSIZE_DEFAULT;
206 LIST_INIT(&pu->pu_pnodelst);
207
208 pu->pu_state = PUFFS_STATE_MOUNTING;
209 if (mount(MOUNT_PUFFS, dir, mntflags, &pargs) == -1)
210 goto failfree;
211 pu->pu_maxreqlen = pargs.pa_maxreqlen;
212
213 if ((rv = pops->puffs_fs_mount(pu, &sreq.psr_cookie,
214 &sreq.psr_sb)) != 0) {
215 errno = rv;
216 goto failfree;
217 }
218
219 /* tell kernel we're flying */
220 if (ioctl(pu->pu_fd, PUFFSSTARTOP, &sreq) == -1)
221 goto failfree;
222
223 pu->pu_state = PUFFS_STATE_RUNNING;
224 return pu;
225
226 failfree:
227 /* can't unmount() from here for obvious reasons */
228 if (fd)
229 close(fd);
230 free(pu);
231 return NULL;
232 }
233
234 int
235 puffs_mainloop(struct puffs_usermount *pu, int flags)
236 {
237 struct puffs_getreq *pgr;
238 struct puffs_putreq *ppr;
239 int rv;
240
241 rv = -1;
242 pgr = puffs_makegetreq(pu, pu->pu_maxreqlen, 0);
243 if (pgr == NULL)
244 return -1;
245
246 ppr = puffs_makeputreq(pu);
247 if (ppr == NULL) {
248 puffs_destroygetreq(pgr);
249 return -1;
250 }
251
252 if ((flags & PUFFSLOOP_NODAEMON) == 0)
253 if (daemon(0, 0) == -1)
254 goto out;
255
256 /* XXX: should be a bit more robust with errors here */
257 while (puffs_getstate(pu) == PUFFS_STATE_RUNNING
258 || puffs_getstate(pu) == PUFFS_STATE_UNMOUNTING) {
259 puffs_resetputreq(ppr);
260
261 if (puffs_handlereqs(pu, pgr, ppr, 0) == -1) {
262 rv = -1;
263 break;
264 }
265 if (puffs_putputreq(ppr) == -1) {
266 rv = -1;
267 break;
268 }
269 }
270
271 out:
272 puffs_destroyputreq(ppr);
273 puffs_destroygetreq(pgr);
274 return rv;
275 }
276
277 int
278 puffs_handlereqs(struct puffs_usermount *pu, struct puffs_getreq *pgr,
279 struct puffs_putreq *ppr, int maxops)
280 {
281 struct puffs_req *preq;
282 int pval;
283
284 puffs_setmaxgetreq(pgr, maxops);
285 if (puffs_loadgetreq(pgr) == -1)
286 return -1;
287
288 /* interlink pgr and ppr for diagnostic asserts */
289 pgr->pgr_nppr++;
290 ppr->ppr_pgr = pgr;
291
292 pval = 0;
293 while ((preq = puffs_getreq(pgr)) != NULL
294 && pu->pu_state != PUFFS_STATE_UNMOUNTED)
295 pval = puffs_dopreq(pu, ppr, preq);
296
297 return pval;
298 }
299
300 int
301 puffs_dopreq(struct puffs_usermount *pu, struct puffs_putreq *ppr,
302 struct puffs_req *preq)
303 {
304 struct puffs_cc *pcc;
305 int rv;
306
307 if (pu->pu_flags & PUFFS_FLAG_OPDUMP)
308 puffsdump_req(preq);
309
310 pcc = puffs_cc_create(pu, preq);
311 rv = puffs_docc(ppr, pcc);
312
313 if ((pcc->pcc_flags & PCC_DONE) == 0)
314 return 0;
315
316 return rv;
317 }
318
319 int
320 puffs_docc(struct puffs_putreq *ppr, struct puffs_cc *pcc)
321 {
322 int rv;
323
324 assert((pcc->pcc_flags & PCC_DONE) == 0);
325
326 puffs_cc_continue(pcc);
327 rv = pcc->pcc_rv;
328
329 if ((pcc->pcc_flags & PCC_DONE) == 0)
330 rv = PUFFCALL_AGAIN;
331
332 /* check if we need to store this reply */
333 switch (rv) {
334 case PUFFCALL_ANSWER:
335 puffs_putreq_cc(ppr, pcc);
336 break;
337 case PUFFCALL_AGAIN:
338 case PUFFCALL_IGNORE:
339 break;
340 default:
341 assert(/*CONSTCOND*/0);
342 }
343
344 return 0;
345 }
346
347 /* library private, but linked from callcontext.c */
348
349 void
350 puffs_calldispatcher(struct puffs_cc *pcc)
351 {
352 struct puffs_usermount *pu = pcc->pcc_pu;
353 struct puffs_ops *pops = &pu->pu_ops;
354 struct puffs_req *preq = pcc->pcc_preq;
355 void *auxbuf = preq; /* help with typecasting */
356 int error, rv, buildpath;
357
358 assert(pcc->pcc_flags & (PCC_ONCE | PCC_REALCC));
359
360 if (PUFFSOP_WANTREPLY(preq->preq_opclass))
361 rv = PUFFCALL_ANSWER;
362 else
363 rv = PUFFCALL_IGNORE;
364
365 buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH;
366
367 if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VFS) {
368 switch (preq->preq_optype) {
369 case PUFFS_VFS_UNMOUNT:
370 {
371 struct puffs_vfsreq_unmount *auxt = auxbuf;
372
373 pu->pu_state = PUFFS_STATE_UNMOUNTING;
374 error = pops->puffs_fs_unmount(pcc,
375 auxt->pvfsr_flags, auxt->pvfsr_pid);
376 if (!error)
377 pu->pu_state = PUFFS_STATE_UNMOUNTED;
378 else
379 pu->pu_state = PUFFS_STATE_RUNNING;
380 break;
381 }
382 case PUFFS_VFS_STATVFS:
383 {
384 struct puffs_vfsreq_statvfs *auxt = auxbuf;
385
386 error = pops->puffs_fs_statvfs(pcc,
387 &auxt->pvfsr_sb, auxt->pvfsr_pid);
388 break;
389 }
390 case PUFFS_VFS_SYNC:
391 {
392 struct puffs_vfsreq_sync *auxt = auxbuf;
393
394 error = pops->puffs_fs_sync(pcc,
395 auxt->pvfsr_waitfor, &auxt->pvfsr_cred,
396 auxt->pvfsr_pid);
397 break;
398 }
399 default:
400 /*
401 * I guess the kernel sees this one coming
402 */
403 error = EINVAL;
404 break;
405 }
406
407 /* XXX: audit return values */
408 /* XXX: sync with kernel */
409 } else if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN) {
410 switch (preq->preq_optype) {
411 case PUFFS_VN_LOOKUP:
412 {
413 struct puffs_vnreq_lookup *auxt = auxbuf;
414 struct puffs_cn pcn;
415
416 pcn.pcn_pkcnp = &auxt->pvnr_cn;
417 if (buildpath) {
418 if (pcn.pcn_flags & PUFFS_ISDOTDOT) {
419 buildpath = 0;
420 } else {
421 error = do_buildpath(&pcn,
422 preq->preq_cookie);
423 if (error)
424 break;
425 }
426 }
427
428 /* lookup *must* be present */
429 error = pops->puffs_node_lookup(pcc, preq->preq_cookie,
430 &auxt->pvnr_newnode, &auxt->pvnr_vtype,
431 &auxt->pvnr_size, &auxt->pvnr_rdev, &pcn);
432
433 if (buildpath) {
434 if (error) {
435 free(pcn.pcn_fullpath);
436 } else {
437 struct puffs_node *pn;
438
439 /*
440 * did we get a new node or a
441 * recycled node?
442 * XXX: mapping assumption
443 */
444 pn = auxt->pvnr_newnode;
445 if (pn->pn_path == NULL) {
446 pn->pn_path = pcn.pcn_fullpath;
447 pn->pn_plen
448 = pcn.pcn_fullplen;
449 }
450 }
451 }
452
453 break;
454 }
455
456 case PUFFS_VN_CREATE:
457 {
458 struct puffs_vnreq_create *auxt = auxbuf;
459 struct puffs_cn pcn;
460 if (pops->puffs_node_create == NULL) {
461 error = 0;
462 break;
463 }
464
465 pcn.pcn_pkcnp = &auxt->pvnr_cn;
466 if (buildpath) {
467 error = do_buildpath(&pcn, preq->preq_cookie);
468 if (error)
469 break;
470 }
471
472 error = pops->puffs_node_create(pcc,
473 preq->preq_cookie, &auxt->pvnr_newnode,
474 &pcn, &auxt->pvnr_va);
475
476 if (buildpath) {
477 if (error) {
478 free(pcn.pcn_fullpath);
479 } else {
480 struct puffs_node *pn;
481
482 pn = auxt->pvnr_newnode;
483 pn->pn_path = pcn.pcn_fullpath;
484 pn->pn_plen = pcn.pcn_fullplen;
485 }
486 }
487
488 break;
489 }
490
491 case PUFFS_VN_MKNOD:
492 {
493 struct puffs_vnreq_mknod *auxt = auxbuf;
494 struct puffs_cn pcn;
495 if (pops->puffs_node_mknod == NULL) {
496 error = 0;
497 break;
498 }
499
500 pcn.pcn_pkcnp = &auxt->pvnr_cn;
501 if (buildpath) {
502 error = do_buildpath(&pcn, preq->preq_cookie);
503 if (error)
504 break;
505 }
506
507 error = pops->puffs_node_mknod(pcc,
508 preq->preq_cookie, &auxt->pvnr_newnode,
509 &pcn, &auxt->pvnr_va);
510
511 if (buildpath) {
512 if (error) {
513 free(pcn.pcn_fullpath);
514 } else {
515 struct puffs_node *pn;
516
517 pn = auxt->pvnr_newnode;
518 pn->pn_path = pcn.pcn_fullpath;
519 pn->pn_plen = pcn.pcn_fullplen;
520 }
521 }
522
523 break;
524 }
525
526 case PUFFS_VN_OPEN:
527 {
528 struct puffs_vnreq_open *auxt = auxbuf;
529 if (pops->puffs_node_open == NULL) {
530 error = 0;
531 break;
532 }
533
534 error = pops->puffs_node_open(pcc,
535 preq->preq_cookie, auxt->pvnr_mode,
536 &auxt->pvnr_cred, auxt->pvnr_pid);
537 break;
538 }
539
540 case PUFFS_VN_CLOSE:
541 {
542 struct puffs_vnreq_close *auxt = auxbuf;
543 if (pops->puffs_node_close == NULL) {
544 error = 0;
545 break;
546 }
547
548 error = pops->puffs_node_close(pcc,
549 preq->preq_cookie, auxt->pvnr_fflag,
550 &auxt->pvnr_cred, auxt->pvnr_pid);
551 break;
552 }
553
554 case PUFFS_VN_ACCESS:
555 {
556 struct puffs_vnreq_access *auxt = auxbuf;
557 if (pops->puffs_node_access == NULL) {
558 error = 0;
559 break;
560 }
561
562 error = pops->puffs_node_access(pcc,
563 preq->preq_cookie, auxt->pvnr_mode,
564 &auxt->pvnr_cred, auxt->pvnr_pid);
565 break;
566 }
567
568 case PUFFS_VN_GETATTR:
569 {
570 struct puffs_vnreq_getattr *auxt = auxbuf;
571 if (pops->puffs_node_getattr == NULL) {
572 error = EOPNOTSUPP;
573 break;
574 }
575
576 error = pops->puffs_node_getattr(pcc,
577 preq->preq_cookie, &auxt->pvnr_va,
578 &auxt->pvnr_cred, auxt->pvnr_pid);
579 break;
580 }
581
582 case PUFFS_VN_SETATTR:
583 {
584 struct puffs_vnreq_setattr *auxt = auxbuf;
585 if (pops->puffs_node_setattr == NULL) {
586 error = EOPNOTSUPP;
587 break;
588 }
589
590 error = pops->puffs_node_setattr(pcc,
591 preq->preq_cookie, &auxt->pvnr_va,
592 &auxt->pvnr_cred, auxt->pvnr_pid);
593 break;
594 }
595
596 case PUFFS_VN_MMAP:
597 {
598 struct puffs_vnreq_mmap *auxt = auxbuf;
599 if (pops->puffs_node_mmap == NULL) {
600 error = 0;
601 break;
602 }
603
604 error = pops->puffs_node_mmap(pcc,
605 preq->preq_cookie, auxt->pvnr_fflags,
606 &auxt->pvnr_cred, auxt->pvnr_pid);
607 break;
608 }
609
610 case PUFFS_VN_REVOKE:
611 {
612 struct puffs_vnreq_revoke *auxt = auxbuf;
613 if (pops->puffs_node_revoke == NULL) {
614 error = 0;
615 break;
616 }
617
618 error = pops->puffs_node_revoke(pcc,
619 preq->preq_cookie, auxt->pvnr_flags);
620 break;
621 }
622
623 case PUFFS_VN_FSYNC:
624 {
625 struct puffs_vnreq_fsync *auxt = auxbuf;
626 if (pops->puffs_node_fsync == NULL) {
627 error = 0;
628 break;
629 }
630
631 error = pops->puffs_node_fsync(pcc,
632 preq->preq_cookie, &auxt->pvnr_cred,
633 auxt->pvnr_flags, auxt->pvnr_offlo,
634 auxt->pvnr_offhi, auxt->pvnr_pid);
635 break;
636 }
637
638 case PUFFS_VN_SEEK:
639 {
640 struct puffs_vnreq_seek *auxt = auxbuf;
641 if (pops->puffs_node_seek == NULL) {
642 error = 0;
643 break;
644 }
645
646 error = pops->puffs_node_seek(pcc,
647 preq->preq_cookie, auxt->pvnr_oldoff,
648 auxt->pvnr_newoff, &auxt->pvnr_cred);
649 break;
650 }
651
652 case PUFFS_VN_REMOVE:
653 {
654 struct puffs_vnreq_remove *auxt = auxbuf;
655 struct puffs_cn pcn;
656 if (pops->puffs_node_remove == NULL) {
657 error = 0;
658 break;
659 }
660
661 pcn.pcn_pkcnp = &auxt->pvnr_cn;
662
663 error = pops->puffs_node_remove(pcc,
664 preq->preq_cookie, auxt->pvnr_cookie_targ, &pcn);
665 break;
666 }
667
668 case PUFFS_VN_LINK:
669 {
670 struct puffs_vnreq_link *auxt = auxbuf;
671 struct puffs_cn pcn;
672 if (pops->puffs_node_link == NULL) {
673 error = 0;
674 break;
675 }
676
677 pcn.pcn_pkcnp = &auxt->pvnr_cn;
678
679 error = pops->puffs_node_link(pcc,
680 preq->preq_cookie, auxt->pvnr_cookie_targ, &pcn);
681 break;
682 }
683
684 case PUFFS_VN_RENAME:
685 {
686 struct puffs_vnreq_rename *auxt = auxbuf;
687 struct puffs_cn pcn_src, pcn_targ;
688 struct puffs_node *pn_src;
689
690 if (pops->puffs_node_rename == NULL) {
691 error = 0;
692 break;
693 }
694
695 pcn_src.pcn_pkcnp = &auxt->pvnr_cn_src;
696 pcn_targ.pcn_pkcnp = &auxt->pvnr_cn_targ;
697 if (buildpath) {
698 pn_src = auxt->pvnr_cookie_src;
699 pcn_src.pcn_fullpath = pn_src->pn_path;
700 pcn_src.pcn_fullplen = pn_src->pn_plen;
701
702 error = do_buildpath(&pcn_targ,
703 auxt->pvnr_cookie_targdir);
704 if (error)
705 break;
706 }
707
708 error = pops->puffs_node_rename(pcc,
709 preq->preq_cookie, auxt->pvnr_cookie_src,
710 &pcn_src, auxt->pvnr_cookie_targdir,
711 auxt->pvnr_cookie_targ, &pcn_targ);
712
713 if (buildpath) {
714 if (error) {
715 free(pcn_targ.pcn_fullpath);
716 } else {
717 free(pn_src->pn_path);
718 pn_src->pn_path = pcn_targ.pcn_fullpath;
719 pn_src->pn_plen = pcn_targ.pcn_fullplen;
720 }
721 }
722 break;
723 }
724
725 case PUFFS_VN_MKDIR:
726 {
727 struct puffs_vnreq_mkdir *auxt = auxbuf;
728 struct puffs_cn pcn;
729 if (pops->puffs_node_mkdir == NULL) {
730 error = 0;
731 break;
732 }
733
734 pcn.pcn_pkcnp = &auxt->pvnr_cn;
735 if (buildpath) {
736 error = do_buildpath(&pcn, preq->preq_cookie);
737 if (error)
738 break;
739 }
740
741 error = pops->puffs_node_mkdir(pcc,
742 preq->preq_cookie, &auxt->pvnr_newnode,
743 &pcn, &auxt->pvnr_va);
744
745 if (buildpath) {
746 if (error) {
747 free(pcn.pcn_fullpath);
748 } else {
749 struct puffs_node *pn;
750
751 pn = auxt->pvnr_newnode;
752 pn->pn_path = pcn.pcn_fullpath;
753 pn->pn_plen = pcn.pcn_fullplen;
754 }
755 }
756
757 break;
758 }
759
760 case PUFFS_VN_RMDIR:
761 {
762 struct puffs_vnreq_rmdir *auxt = auxbuf;
763 struct puffs_cn pcn;
764 if (pops->puffs_node_rmdir == NULL) {
765 error = 0;
766 break;
767 }
768
769 pcn.pcn_pkcnp = &auxt->pvnr_cn;
770
771 error = pops->puffs_node_rmdir(pcc,
772 preq->preq_cookie, auxt->pvnr_cookie_targ, &pcn);
773 break;
774 }
775
776 case PUFFS_VN_SYMLINK:
777 {
778 struct puffs_vnreq_symlink *auxt = auxbuf;
779 struct puffs_cn pcn;
780 if (pops->puffs_node_symlink == NULL) {
781 error = 0;
782 break;
783 }
784
785 pcn.pcn_pkcnp = &auxt->pvnr_cn;
786 if (buildpath) {
787 error = do_buildpath(&pcn, preq->preq_cookie);
788 if (error)
789 break;
790 }
791
792 error = pops->puffs_node_symlink(pcc,
793 preq->preq_cookie, &auxt->pvnr_newnode,
794 &pcn, &auxt->pvnr_va, auxt->pvnr_link);
795
796 if (buildpath) {
797 if (error) {
798 free(pcn.pcn_fullpath);
799 } else {
800 struct puffs_node *pn;
801
802 pn = auxt->pvnr_newnode;
803 pn->pn_path = pcn.pcn_fullpath;
804 pn->pn_plen = pcn.pcn_fullplen;
805 }
806 }
807
808 break;
809 }
810
811 case PUFFS_VN_READDIR:
812 {
813 struct puffs_vnreq_readdir *auxt = auxbuf;
814 size_t res;
815
816 if (pops->puffs_node_readdir == NULL) {
817 error = 0;
818 break;
819 }
820
821 res = auxt->pvnr_resid;
822 error = pops->puffs_node_readdir(pcc,
823 preq->preq_cookie, auxt->pvnr_dent,
824 &auxt->pvnr_cred, &auxt->pvnr_offset,
825 &auxt->pvnr_resid);
826
827 /* need to move a bit more */
828 preq->preq_buflen = sizeof(struct puffs_vnreq_readdir)
829 + (res - auxt->pvnr_resid);
830 break;
831 }
832
833 case PUFFS_VN_READLINK:
834 {
835 struct puffs_vnreq_readlink *auxt = auxbuf;
836 if (pops->puffs_node_readlink == NULL) {
837 error = EOPNOTSUPP;
838 break;
839 }
840
841 error = pops->puffs_node_readlink(pcc,
842 preq->preq_cookie, &auxt->pvnr_cred,
843 auxt->pvnr_link, &auxt->pvnr_linklen);
844 break;
845 }
846
847 case PUFFS_VN_RECLAIM:
848 {
849 struct puffs_vnreq_reclaim *auxt = auxbuf;
850 if (pops->puffs_node_reclaim == NULL) {
851 error = 0;
852 break;
853 }
854
855 error = pops->puffs_node_reclaim(pcc,
856 preq->preq_cookie, auxt->pvnr_pid);
857 break;
858 }
859
860 case PUFFS_VN_INACTIVE:
861 {
862 struct puffs_vnreq_inactive *auxt = auxbuf;
863 if (pops->puffs_node_inactive == NULL) {
864 error = EOPNOTSUPP;
865 break;
866 }
867
868 error = pops->puffs_node_inactive(pcc,
869 preq->preq_cookie, auxt->pvnr_pid,
870 &auxt->pvnr_backendrefs);
871 break;
872 }
873
874 case PUFFS_VN_PATHCONF:
875 {
876 struct puffs_vnreq_pathconf *auxt = auxbuf;
877 if (pops->puffs_node_pathconf == NULL) {
878 error = 0;
879 break;
880 }
881
882 error = pops->puffs_node_pathconf(pcc,
883 preq->preq_cookie, auxt->pvnr_name,
884 &auxt->pvnr_retval);
885 break;
886 }
887
888 case PUFFS_VN_ADVLOCK:
889 {
890 struct puffs_vnreq_advlock *auxt = auxbuf;
891 if (pops->puffs_node_advlock == NULL) {
892 error = 0;
893 break;
894 }
895
896 error = pops->puffs_node_advlock(pcc,
897 preq->preq_cookie, auxt->pvnr_id, auxt->pvnr_op,
898 &auxt->pvnr_fl, auxt->pvnr_flags);
899 break;
900 }
901
902 case PUFFS_VN_PRINT:
903 {
904 if (pops->puffs_node_print == NULL) {
905 error = 0;
906 break;
907 }
908
909 error = pops->puffs_node_print(pcc,
910 preq->preq_cookie);
911 break;
912 }
913
914 case PUFFS_VN_READ:
915 {
916 struct puffs_vnreq_read *auxt = auxbuf;
917 size_t res;
918
919 if (pops->puffs_node_read == NULL) {
920 error = EIO;
921 break;
922 }
923
924 res = auxt->pvnr_resid;
925 error = pops->puffs_node_read(pcc,
926 preq->preq_cookie, auxt->pvnr_data,
927 auxt->pvnr_offset, &auxt->pvnr_resid,
928 &auxt->pvnr_cred, auxt->pvnr_ioflag);
929
930 /* need to move a bit more */
931 preq->preq_buflen = sizeof(struct puffs_vnreq_read)
932 + (res - auxt->pvnr_resid);
933 break;
934 }
935
936 case PUFFS_VN_WRITE:
937 {
938 struct puffs_vnreq_write *auxt = auxbuf;
939
940 if (pops->puffs_node_write == NULL) {
941 error = EIO;
942 break;
943 }
944
945 error = pops->puffs_node_write(pcc,
946 preq->preq_cookie, auxt->pvnr_data,
947 auxt->pvnr_offset, &auxt->pvnr_resid,
948 &auxt->pvnr_cred, auxt->pvnr_ioflag);
949
950 /* don't need to move data back to the kernel */
951 preq->preq_buflen = sizeof(struct puffs_vnreq_write);
952 break;
953 }
954
955 /* holy bitrot, ryydman! */
956 #if 0
957 case PUFFS_VN_IOCTL:
958 error = pops->puffs_node_ioctl1(pcc, preq->preq_cookie,
959 (struct puffs_vnreq_ioctl *)auxbuf, &pop);
960 if (error != 0)
961 break;
962 pop.pso_reqid = preq->preq_id;
963
964 /* let the kernel do it's intermediate duty */
965 error = ioctl(pu->pu_fd, PUFFSSIZEOP, &pop);
966 /*
967 * XXX: I don't actually know what the correct
968 * thing to do in case of an error is, so I'll
969 * just ignore it for the time being.
970 */
971 error = pops->puffs_node_ioctl2(pcc, preq->preq_cookie,
972 (struct puffs_vnreq_ioctl *)auxbuf, &pop);
973 break;
974
975 case PUFFS_VN_FCNTL:
976 error = pops->puffs_node_fcntl1(pcc, preq->preq_cookie,
977 (struct puffs_vnreq_fcntl *)auxbuf, &pop);
978 if (error != 0)
979 break;
980 pop.pso_reqid = preq->preq_id;
981
982 /* let the kernel do it's intermediate duty */
983 error = ioctl(pu->pu_fd, PUFFSSIZEOP, &pop);
984 /*
985 * XXX: I don't actually know what the correct
986 * thing to do in case of an error is, so I'll
987 * just ignore it for the time being.
988 */
989 error = pops->puffs_node_fcntl2(pcc, preq->preq_cookie,
990 (struct puffs_vnreq_fcntl *)auxbuf, &pop);
991 break;
992 #endif
993
994 default:
995 printf("inval op %d\n", preq->preq_optype);
996 error = EINVAL;
997 break;
998 }
999 } else {
1000 /*
1001 * this one also
1002 */
1003 error = EINVAL;
1004 }
1005
1006 preq->preq_rv = error;
1007
1008 pcc->pcc_rv = rv;
1009 pcc->pcc_flags |= PCC_DONE;
1010 }
1011
1012 static int
1013 do_buildpath(struct puffs_cn *pcn, void *parent)
1014 {
1015 struct puffs_node *pn_parent;
1016 size_t plen;
1017
1018 pn_parent = parent; /* XXX */
1019 assert(pn_parent->pn_path != NULL);
1020
1021 /* +1 not for nul but for / */
1022 plen = pn_parent->pn_plen + pcn->pcn_namelen + 1;
1023 pcn->pcn_fullpath = malloc(plen);
1024 if (!pcn->pcn_fullpath)
1025 return errno;
1026
1027 strcpy(pcn->pcn_fullpath, pn_parent->pn_path);
1028 strcat(pcn->pcn_fullpath, "/");
1029 strcat(pcn->pcn_fullpath, pcn->pcn_name);
1030 pcn->pcn_fullpath[plen-1] = '\0'; /* paranoia */
1031 pcn->pcn_fullplen = plen;
1032
1033 return 0;
1034 }
1035
1036
1037 #if 0
1038 case PUFFS_VN_POLL:
1039 {
1040 struct puffs_vnreq_poll *auxt = auxbuf;
1041 if (pops->puffs_node_poll == NULL) {
1042 error = 0;
1043 break;
1044 }
1045
1046 error = pops->puffs_node_poll(pcc,
1047 preq->preq_cookie, preq-);
1048 break;
1049 }
1050
1051 case PUFFS_VN_KQFILTER:
1052 {
1053 struct puffs_vnreq_kqfilter *auxt = auxbuf;
1054 if (pops->puffs_node_kqfilter == NULL) {
1055 error = 0;
1056 break;
1057 }
1058
1059 error = pops->puffs_node_kqfilter(pcc,
1060 preq->preq_cookie, );
1061 break;
1062 }
1063
1064 case PUFFS_VN_CLOSEEXTATTR:
1065 {
1066 struct puffs_vnreq_closeextattr *auxt = auxbuf;
1067 if (pops->puffs_closeextattr == NULL) {
1068 error = 0;
1069 break;
1070 }
1071
1072 error = pops->puffs_closeextattr(pcc,
1073 preq->preq_cookie, );
1074 break;
1075 }
1076
1077 case PUFFS_VN_GETEXTATTR:
1078 {
1079 struct puffs_vnreq_getextattr *auxt = auxbuf;
1080 if (pops->puffs_getextattr == NULL) {
1081 error = 0;
1082 break;
1083 }
1084
1085 error = pops->puffs_getextattr(pcc,
1086 preq->preq_cookie, );
1087 break;
1088 }
1089
1090 case PUFFS_VN_LISTEXTATTR:
1091 {
1092 struct puffs_vnreq_listextattr *auxt = auxbuf;
1093 if (pops->puffs_listextattr == NULL) {
1094 error = 0;
1095 break;
1096 }
1097
1098 error = pops->puffs_listextattr(pcc,
1099 preq->preq_cookie, );
1100 break;
1101 }
1102
1103 case PUFFS_VN_OPENEXTATTR:
1104 {
1105 struct puffs_vnreq_openextattr *auxt = auxbuf;
1106 if (pops->puffs_openextattr == NULL) {
1107 error = 0;
1108 break;
1109 }
1110
1111 error = pops->puffs_openextattr(pcc,
1112 preq->preq_cookie, );
1113 break;
1114 }
1115
1116 case PUFFS_VN_DELETEEXTATTR:
1117 {
1118 struct puffs_vnreq_deleteextattr *auxt = auxbuf;
1119 if (pops->puffs_deleteextattr == NULL) {
1120 error = 0;
1121 break;
1122 }
1123
1124 error = pops->puffs_deleteextattr(pcc,
1125 preq->preq_cookie, );
1126 break;
1127 }
1128
1129 case PUFFS_VN_SETEXTATTR:
1130 {
1131 struct puffs_vnreq_setextattr *auxt = auxbuf;
1132 if (pops->puffs_setextattr == NULL) {
1133 error = 0;
1134 break;
1135 }
1136
1137 error = pops->puffs_setextattr(pcc,
1138 preq->preq_cookie, );
1139 break;
1140 }
1141
1142 #endif
1143