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