refuse.c revision 1.3 1 /*
2 * Copyright 2007 Alistair Crooks. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote
13 * products derived from this software without specific prior written
14 * permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
22 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 #include <err.h>
29 #include <errno.h>
30 #include <fuse.h>
31 #include <ucontext.h>
32 #include <unistd.h>
33
34 #include "defs.h"
35
36 typedef uint64_t fuse_ino_t;
37
38 struct fuse_config {
39 uid_t uid;
40 gid_t gid;
41 mode_t umask;
42 double entry_timeout;
43 double negative_timeout;
44 double attr_timeout;
45 double ac_attr_timeout;
46 int ac_attr_timeout_set;
47 int debug;
48 int hard_remove;
49 int use_ino;
50 int readdir_ino;
51 int set_mode;
52 int set_uid;
53 int set_gid;
54 int direct_io;
55 int kernel_cache;
56 int auto_cache;
57 int intr;
58 int intr_signal;
59 };
60
61 /* this is the private fuse structure */
62 struct fuse {
63 struct fuse_session *se; /* fuse session pointer */
64 struct fuse_operations op; /* switch table of operations */
65 int compat; /* compat level - not used in puffs_fuse */
66 struct node **name_table;
67 size_t name_table_size;
68 struct node **id_table;
69 size_t id_table_size;
70 fuse_ino_t ctr;
71 unsigned int generation;
72 unsigned int hidectr;
73 pthread_mutex_t lock;
74 pthread_rwlock_t tree_lock;
75 void *user_data;
76 struct fuse_config conf;
77 int intr_installed;
78 struct puffs_usermount *pu;
79 };
80
81 static ino_t fakeino = 3;
82
83 /* XXX: redome */
84 struct feh {
85 struct dirent *dent;
86 size_t reslen;
87 };
88
89 /* ARGSUSED2 */
90 static int
91 puffs_fuse_dirfiller(void *buf, const char *name,
92 const struct stat *stbuf, off_t off)
93 {
94 struct feh *feh = buf;
95 uint8_t dtype;
96
97 /* XXX: this is hacked *purely* for hellofs, so fiXXXme */
98 if (*name == '.')
99 dtype = DT_DIR;
100 else
101 dtype = DT_REG;
102
103 return puffs_nextdent(&feh->dent, name, fakeino++, dtype, &feh->reslen);
104 }
105
106 int
107 fuse_opt_add_arg(struct fuse_args *args, const char *arg)
108 {
109 char **oldargv;
110 int oldargc;
111
112 if (args->allocated) {
113 RENEW(char *, args->argv, args->argc + 1, "fuse_opt_add_arg1", return 0);
114 } else {
115 oldargv = args->argv;
116 oldargc = args->argc;
117 NEWARRAY(char *, args->argv, oldargc + 1, "fuse_opt_add_arg2", return 0);
118 (void) memcpy(args->argv, oldargv, oldargc * sizeof(char *));
119 args->allocated = 1;
120 }
121 args->argv[args->argc++] = strdup(arg);
122 return 1;
123 }
124
125 /* operation wrappers start here */
126
127 /* lookup the path */
128 /* ARGSUSED1 */
129 static int
130 puffs_fuse_node_lookup(struct puffs_cc *pcc, void *opc, void **newnode,
131 enum vtype *newtype, voff_t *newsize, dev_t *newrdev,
132 const struct puffs_cn *pcn)
133 {
134 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
135 struct stat st;
136 struct fuse *fuse;
137 const char *path = PCNPATH(pcn);
138 int ret;
139
140 /* XXX: THIS IS VERY WRONG */
141 fuse = (struct fuse *)pu->pu_privdata;
142 ret = fuse->op.getattr(path, &st);
143 ret = -ret; /* linux foo */
144 if (ret != 0) {
145 return ret;
146 }
147 *newnode = puffs_pn_new(pu, NULL);
148 *newtype = (S_ISDIR(st.st_mode)) ? VDIR : VREG;
149 *newsize = st.st_size;
150 return ret;
151 }
152
153 /* get attributes for the path name */
154 /* ARGSUSED3 */
155 static int
156 puffs_fuse_node_getattr(struct puffs_cc *pcc, void *opc, struct vattr *va,
157 const struct puffs_cred *pcr, pid_t pid)
158 {
159 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
160 struct puffs_node *pn = opc;
161 struct stat st;
162 struct fuse *fuse;
163 const char *path = PNPATH(pn);
164 int ret;
165
166 fuse = (struct fuse *)pu->pu_privdata;
167 if (fuse->op.getattr == NULL) {
168 return ENOSYS;
169 }
170
171 /* wrap up return code */
172 ret = (*fuse->op.getattr)(path, &st);
173
174 if (ret == 0) {
175 /* fill in va from st */
176 va->va_mode = st.st_mode;
177 va->va_nlink = st.st_nlink;
178 va->va_uid = st.st_uid;
179 va->va_gid = st.st_gid;
180 va->va_fsid = st.st_rdev;
181 va->va_fileid = st.st_ino;
182 va->va_size = st.st_size;
183 va->va_blocksize = st.st_blksize;
184 va->va_atime = st.st_atimespec;
185 va->va_mtime = st.st_mtimespec;
186 va->va_ctime = st.st_ctimespec;
187 va->va_birthtime = st.st_birthtimespec;
188 va->va_gen = st.st_gen;
189 va->va_flags = st.st_flags;
190 va->va_rdev = st.st_rdev;
191 va->va_bytes = st.st_size;
192 va->va_filerev = st.st_gen;
193 va->va_vaflags = st.st_flags;
194
195 }
196
197 return ret;
198 }
199
200 /* read the contents of the symbolic link */
201 /* ARGSUSED2 */
202 static int
203 puffs_fuse_node_readlink(struct puffs_cc *pcc, void *opc,
204 const struct puffs_cred *cred, char *linkname, size_t *linklen)
205 {
206 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
207 struct puffs_node *pn = opc;
208 struct fuse *fuse;
209 const char *path = PNPATH(pn);
210 int ret;
211
212 fuse = (struct fuse *)pu->pu_privdata;
213 if (fuse->op.readlink == NULL) {
214 return ENOSYS;
215 }
216
217 /* wrap up return code */
218 ret = (*fuse->op.readlink)(path, linkname, *linklen);
219
220 if (ret == 0) {
221 }
222
223 return ret;
224 }
225
226 /* make the special node */
227 /* ARGSUSED1 */
228 static int
229 puffs_fuse_node_mknod(struct puffs_cc *pcc, void *opc, void **newnode,
230 const struct puffs_cn *pcn, const struct vattr *va)
231 {
232 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
233 struct puffs_node *pn;
234 struct fuse *fuse;
235 mode_t mode = va->va_mode;
236 const char *path = PCNPATH(pcn);
237 int ret;
238
239 fuse = (struct fuse *)pu->pu_privdata;
240 if (fuse->op.mknod == NULL) {
241 return ENOSYS;
242 }
243
244 /* wrap up return code */
245 ret = (*fuse->op.mknod)(path, mode, va->va_rdev);
246
247 if (ret == 0) {
248 /* fix up nodes */
249 pn = puffs_pn_new(pu, NULL);
250 if (pn == NULL) {
251 unlink(PCNPATH(pcn));
252 return ENOMEM;
253 }
254 puffs_setvattr(&pn->pn_va, va);
255
256 *newnode = pn;
257 }
258
259 return ret;
260 }
261
262 /* make a directory */
263 /* ARGSUSED1 */
264 static int
265 puffs_fuse_node_mkdir(struct puffs_cc *pcc, void *opc, void **newnode,
266 const struct puffs_cn *pcn, const struct vattr *va)
267 {
268 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
269 struct puffs_node *pn;
270 struct fuse *fuse;
271 mode_t mode = va->va_mode;
272 const char *path = PCNPATH(pcn);
273 int ret;
274
275 fuse = (struct fuse *)pu->pu_privdata;
276 if (fuse->op.mkdir == NULL) {
277 return ENOSYS;
278 }
279
280 /* wrap up return code */
281 ret = (*fuse->op.mkdir)(path, mode);
282
283 if (ret == 0) {
284 /* fix up nodes */
285 pn = puffs_pn_new(pu, NULL);
286 if (pn == NULL) {
287 rmdir(PCNPATH(pcn));
288 return ENOMEM;
289 }
290 puffs_setvattr(&pn->pn_va, va);
291
292 *newnode = pn;
293 }
294
295 return ret;
296 }
297
298 /* remove the directory entry */
299 /* ARGSUSED1 */
300 static int
301 puffs_fuse_node_remove(struct puffs_cc *pcc, void *opc, void *targ,
302 const struct puffs_cn *pcn)
303 {
304 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
305 struct fuse *fuse;
306 const char *path = PCNPATH(pcn);
307 int ret;
308
309 fuse = (struct fuse *)pu->pu_privdata;
310 if (fuse->op.unlink == NULL) {
311 return ENOSYS;
312 }
313
314 /* wrap up return code */
315 ret = (*fuse->op.unlink)(path);
316
317 return ret;
318 }
319
320 /* remove the directory */
321 /* ARGSUSED1 */
322 static int
323 puffs_fuse_node_rmdir(struct puffs_cc *pcc, void *opc, void *targ,
324 const struct puffs_cn *pcn)
325 {
326 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
327 struct fuse *fuse;
328 const char *path = PCNPATH(pcn);
329 int ret;
330
331 fuse = (struct fuse *)pu->pu_privdata;
332 if (fuse->op.rmdir == NULL) {
333 return ENOSYS;
334 }
335
336 /* wrap up return code */
337 ret = (*fuse->op.rmdir)(path);
338
339 return ret;
340 }
341
342 /* create a symbolic link */
343 /* ARGSUSED1 */
344 static int
345 puffs_fuse_node_symlink(struct puffs_cc *pcc, void *opc, void **newnode,
346 const struct puffs_cn *pcn_src, const struct vattr *va,
347 const char *link_target)
348 {
349 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
350 struct puffs_node *pn;
351 struct fuse *fuse;
352 const char *path = PCNPATH(pcn_src);
353 int ret;
354
355 fuse = (struct fuse *)pu->pu_privdata;
356 if (fuse->op.symlink == NULL) {
357 return ENOSYS;
358 }
359
360 /* wrap up return code */
361 ret = (*fuse->op.symlink)(path, link_target);
362 /* XXX - check I haven't transposed these args */
363
364 if (ret == 0) {
365 /* fix up nodes */
366 pn = puffs_pn_new(pu, NULL);
367 if (pn == NULL) {
368 unlink(link_target);
369 return ENOMEM;
370 }
371 puffs_setvattr(&pn->pn_va, va);
372
373 *newnode = pn;
374 }
375
376 return ret;
377 }
378
379 /* rename a directory entry */
380 /* ARGSUSED1 */
381 static int
382 puffs_fuse_node_rename(struct puffs_cc *pcc, void *opc, void *src,
383 const struct puffs_cn *pcn_src, void *targ_dir, void *targ,
384 const struct puffs_cn *pcn_targ)
385 {
386 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
387 struct puffs_node *pn = opc;
388 struct vattr va;
389 struct fuse *fuse;
390 const char *path = PCNPATH(pcn_src);
391 int ret;
392
393 fuse = (struct fuse *)pu->pu_privdata;
394 if (fuse->op.rename == NULL) {
395 return ENOSYS;
396 }
397
398 /* wrap up return code */
399 ret = (*fuse->op.rename)(path, PCNPATH(pcn_targ));
400
401 if (ret == 0) {
402 (void) memcpy(&va, &pn->pn_va, sizeof(va));
403
404 puffs_pn_put(pn);
405
406 pn = puffs_pn_new(pu, NULL);
407 if (pn == NULL) {
408 return ENOMEM;
409 }
410 puffs_setvattr(&pn->pn_va, &va);
411
412 }
413
414 return ret;
415 }
416
417 /* create a link in the file system */
418 /* ARGSUSED1 */
419 static int
420 puffs_fuse_node_link(struct puffs_cc *pcc, void *opc, void *targ,
421 const struct puffs_cn *pcn)
422 {
423 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
424 struct puffs_node *pn = targ;
425 struct fuse *fuse;
426 int ret;
427
428 fuse = (struct fuse *)pu->pu_privdata;
429 if (fuse->op.link == NULL) {
430 return ENOSYS;
431 }
432
433 /* wrap up return code */
434 ret = (*fuse->op.link)(PNPATH(pn), PCNPATH(pcn));
435
436 if (ret == 0) {
437 /* fix up nodes */
438 pn = puffs_pn_new(pu, NULL);
439 if (pn == NULL) {
440 unlink(PCNPATH(pcn));
441 return ENOMEM;
442 }
443 }
444
445 return ret;
446 }
447
448 /*
449 We run into a slight problemette here - puffs provides
450 setattr/getattr, whilst fuse provides all the usual chown/chmod/chgrp
451 functionality. So that we don't miss out on anything when calling a
452 fuse operation, we have to get the vattr from the existing file,
453 find out what's changed, and then switch on that to call the fuse
454 function accordingly.
455 */
456 /* ARGSUSED3 */
457 static int
458 puffs_fuse_node_setattr(struct puffs_cc *pcc, void *opc,
459 const struct vattr *va, const struct puffs_cred *pcr, pid_t pid)
460 {
461 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
462 struct puffs_node *pn = opc;
463 struct fuse *fuse;
464 const char *path = PNPATH(pn);
465 mode_t mode;
466 uid_t uid;
467 gid_t gid;
468 int ret;
469
470 fuse = (struct fuse *)pu->pu_privdata;
471
472 ret = -1;
473
474 mode = va->va_mode;
475 uid = va->va_uid;
476 gid = va->va_gid;
477
478 if (mode != 0) {
479 if (fuse->op.chmod == NULL) {
480 return ENOSYS;
481 }
482 ret = (*fuse->op.chmod)(path, mode);
483 }
484 if (uid != 0 || gid != 0) {
485 if (fuse->op.chown == NULL) {
486 return ENOSYS;
487 }
488 ret = (*fuse->op.chown)(path, uid, gid);
489 }
490
491 if (ret == 0) {
492 }
493
494 return ret;
495 }
496
497 /* ARGSUSED2 */
498 static int
499 puffs_fuse_node_open(struct puffs_cc *pcc, void *opc, int flags,
500 const struct puffs_cred *cred, pid_t pid)
501 {
502 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
503 struct fuse_file_info file_info;
504 struct puffs_node *pn = opc;
505 struct fuse *fuse;
506 struct stat st;
507 const char *path = PNPATH(pn);
508 int ret;
509
510 fuse = (struct fuse *)pu->pu_privdata;
511 if (fuse->op.open == NULL) {
512 return ENOSYS;
513 }
514
515 (void) memset(&file_info, 0x0, sizeof(file_info));
516
517 /* examine type - if directory, return 0 rather than open */
518 ret = (fuse->op.getattr == NULL) ?
519 stat(path, &st) :
520 (*fuse->op.getattr)(path, &st);
521 if (ret == 0 && (st.st_mode & S_IFMT) == S_IFDIR) {
522 return 0;
523 }
524
525 if (strcmp(path, "/") == 0) {
526 return 0;
527 }
528
529 ret = (*fuse->op.open)(path, &file_info);
530
531 if (ret == 0) {
532 }
533
534 return ret;
535 }
536
537 /* read some more from the file */
538 /* ARGSUSED5 */
539 static int
540 puffs_fuse_node_read(struct puffs_cc *pcc, void *opc, uint8_t *buf,
541 off_t offset, size_t *resid, const struct puffs_cred *pcr,
542 int ioflag)
543 {
544 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
545 struct fuse_file_info file_info;
546 struct puffs_node *pn = opc;
547 struct fuse *fuse;
548 const char *path = PNPATH(pn);
549 int ret;
550
551 fuse = (struct fuse *)pu->pu_privdata;
552 if (fuse->op.read == NULL) {
553 return ENOSYS;
554 }
555
556 (void) memset(&file_info, 0x0, sizeof(file_info));
557 /* XXX fill in file_info here */
558
559 ret = (*fuse->op.read)(path, (char *)buf, *resid, offset, &file_info);
560
561 if (ret > 0) {
562 *resid -= ret;
563 }
564
565 return 0;
566 }
567
568 /* write to the file */
569 /* ARGSUSED0 */
570 static int
571 puffs_fuse_node_write(struct puffs_cc *pcc, void *opc, uint8_t *buf,
572 off_t offset, size_t *resid, const struct puffs_cred *pcr,
573 int ioflag)
574 {
575 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
576 struct fuse_file_info file_info;
577 struct puffs_node *pn = opc;
578 struct fuse *fuse;
579 const char *path = PNPATH(pn);
580 int ret;
581
582 fuse = (struct fuse *)pu->pu_privdata;
583 if (fuse->op.write == NULL) {
584 return ENOSYS;
585 }
586
587 (void) memset(&file_info, 0x0, sizeof(file_info));
588
589 /* XXX fill in file_info here */
590
591 ret = (*fuse->op.write)(path, (char *)buf, *resid, offset, &file_info);
592
593 if (ret > 0) {
594 *resid -= ret;
595 }
596
597 return ret;
598 }
599
600
601 /* ARGSUSED3 */
602 static int
603 puffs_fuse_node_readdir(struct puffs_cc *pcc, void *opc,
604 struct dirent *dent, const struct puffs_cred *pcr, off_t *readoff,
605 size_t *reslen)
606 {
607 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
608 struct fuse_file_info file_info;
609 struct puffs_node *pn = opc;
610 struct fuse *fuse;
611 const char *path = PNPATH(pn);
612 struct feh feh; /* XXX */
613 int ret;
614
615 fuse = (struct fuse *)pu->pu_privdata;
616 if (fuse->op.readdir == NULL) {
617 return ENOSYS;
618 }
619
620 /* XXX: how to handle this??? */
621 if (*readoff != 0) {
622 return 0;
623 }
624
625 (void) memset(&file_info, 0x0, sizeof(file_info));
626 /* XXX - fill in file_info here */
627
628 feh.dent = dent;
629 feh.reslen = *reslen;
630 ret = (*fuse->op.readdir)(path, &feh, puffs_fuse_dirfiller, *readoff, &file_info);
631 *reslen = feh.reslen;
632 *readoff = 1;
633
634 if (ret == 0) {
635 }
636
637 return ret;
638 }
639
640 /* ARGSUSED */
641 static int
642 puffs_fuse_node_reclaim(struct puffs_cc *pcc, void *opc, pid_t pid)
643 {
644 struct puffs_node *pn = opc;
645
646 puffs_pn_put(pn);
647
648 return 0;
649 }
650
651 /* ARGSUSED1 */
652 static int
653 puffs_fuse_fs_unmount(struct puffs_cc *pcc, int flags, pid_t pid)
654 {
655 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
656 struct fuse *fuse;
657
658 fuse = (struct fuse *)pu->pu_privdata;
659 if (fuse->op.destroy == NULL) {
660 return 0;
661 }
662 (*fuse->op.destroy)(fuse);
663 return 0;
664 }
665
666 /* ARGSUSED0 */
667 static int
668 puffs_fuse_fs_sync(struct puffs_cc *pcc, int flags,
669 const struct puffs_cred *cr, pid_t pid)
670 {
671 return 0;
672 }
673
674 /* ARGSUSED2 */
675 static int
676 puffs_fuse_fs_statvfs(struct puffs_cc *pcc, struct statvfs *svfsb, pid_t pid)
677 {
678 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
679 struct fuse *fuse;
680 int ret;
681
682 fuse = (struct fuse *)pu->pu_privdata;
683 if (fuse->op.statfs == NULL) {
684 if ((ret = statvfs(PNPATH(pu->pu_pn_root), svfsb)) == -1) {
685 return errno;
686 }
687 } else {
688 ret = (*fuse->op.statfs)(PNPATH(pu->pu_pn_root), svfsb);
689 }
690
691 return ret;
692 }
693
694
695
696
697 /* End of puffs_fuse operations */
698
699 /* ARGSUSED3 */
700 int
701 fuse_main_real(int argc, char **argv, const struct fuse_operations *ops,
702 size_t size, void *userdata)
703 {
704 struct puffs_usermount *pu;
705 struct puffs_pathobj *po_root;
706 struct puffs_ops *pops;
707 struct statvfs svfsb;
708 struct fuse *fuse;
709 char name[64];
710 char *slash;
711 int ret;
712
713 /* initialise the puffs operations structure */
714 PUFFSOP_INIT(pops);
715
716 PUFFSOP_SET(pops, puffs_fuse, fs, sync);
717 PUFFSOP_SET(pops, puffs_fuse, fs, statvfs);
718 PUFFSOP_SET(pops, puffs_fuse, fs, unmount);
719
720 /*
721 * XXX: all of these don't possibly need to be
722 * unconditionally set
723 */
724 PUFFSOP_SET(pops, puffs_fuse, node, lookup);
725 PUFFSOP_SET(pops, puffs_fuse, node, getattr);
726 PUFFSOP_SET(pops, puffs_fuse, node, readdir);
727 PUFFSOP_SET(pops, puffs_fuse, node, readlink);
728 PUFFSOP_SET(pops, puffs_fuse, node, mknod);
729 PUFFSOP_SET(pops, puffs_fuse, node, mkdir);
730 PUFFSOP_SET(pops, puffs_fuse, node, remove);
731 PUFFSOP_SET(pops, puffs_fuse, node, rmdir);
732 PUFFSOP_SET(pops, puffs_fuse, node, symlink);
733 PUFFSOP_SET(pops, puffs_fuse, node, rename);
734 PUFFSOP_SET(pops, puffs_fuse, node, link);
735 PUFFSOP_SET(pops, puffs_fuse, node, setattr);
736 PUFFSOP_SET(pops, puffs_fuse, node, open);
737 PUFFSOP_SET(pops, puffs_fuse, node, read);
738 PUFFSOP_SET(pops, puffs_fuse, node, write);
739 PUFFSOP_SET(pops, puffs_fuse, node, readdir);
740 PUFFSOP_SET(pops, puffs_fuse, node, read);
741 PUFFSOP_SET(pops, puffs_fuse, node, write);
742 PUFFSOP_SET(pops, puffs_fuse, node, reclaim);
743
744 NEW(struct fuse, fuse, "fuse_main_real", exit(EXIT_FAILURE));
745
746 /* copy fuse ops to their own stucture */
747 (void) memcpy(&fuse->op, ops, sizeof(fuse->op));
748
749 /* whilst this (assigning the pu_privdata in the puffs
750 * usermount struct to be the fuse struct) might seem like
751 * we are chasing our tail here, the logic is as follows:
752 + the operation wrapper gets called with the puffs
753 calling conventions
754 + we need to fix up args first
755 + then call the fuse user-supplied operation
756 + then we fix up any values on return that we need to
757 + and fix up any nodes, etc
758 * so we need to be able to get at the fuse ops from within the
759 * puffs_usermount struct
760 */
761 if ((slash = strrchr(*argv, '/')) == NULL) {
762 slash = *argv;
763 } else {
764 slash += 1;
765 }
766 (void) snprintf(name, sizeof(name), "refuse:%s", slash);
767 pu = puffs_mount(pops, argv[argc - 1], MNT_NODEV | MNT_NOSUID,
768 name, fuse,
769 PUFFS_FLAG_BUILDPATH | PUFFS_FLAG_OPDUMP, 0);
770 if (pu == NULL) {
771 err(EXIT_FAILURE, "puffs_mount");
772 }
773
774 fuse->pu = pu;
775 pu->pu_pn_root = puffs_pn_new(pu, NULL);
776 po_root = puffs_getrootpathobj(pu);
777 po_root->po_path = strdup("/");
778 po_root->po_len = 1;
779
780 statvfs(argv[argc - 1], &svfsb); /* XXX - not really the correct dir */
781 if (puffs_start(pu, pu->pu_pn_root, &svfsb) == -1) {
782 err(EXIT_FAILURE, "puffs_start");
783 }
784
785 ret = puffs_mainloop(fuse->pu, PUFFSLOOP_NODAEMON);
786
787 (void) free(po_root->po_path);
788 FREE(fuse);
789 return ret;
790 }
791
792 /* ARGSUSED0 */
793 int
794 fuse_opt_parse(struct fuse_args *args, void *data,
795 const struct fuse_opt *opts, fuse_opt_proc_t proc)
796 {
797 return 0;
798 }
799