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