refuse.c revision 1.2 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 puffs_node *pn = opc;
306 struct fuse *fuse;
307 const char *path = PCNPATH(pcn);
308 int ret;
309
310 fuse = (struct fuse *)pu->pu_privdata;
311 if (fuse->op.unlink == NULL) {
312 return ENOSYS;
313 }
314
315 /* wrap up return code */
316 ret = (*fuse->op.unlink)(path);
317
318 if (ret == 0) {
319 puffs_pn_put(pn);
320 }
321
322 return ret;
323 }
324
325 /* remove the directory */
326 /* ARGSUSED1 */
327 static int
328 puffs_fuse_node_rmdir(struct puffs_cc *pcc, void *opc, void *targ,
329 const struct puffs_cn *pcn)
330 {
331 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
332 struct puffs_node *pn = opc;
333 struct fuse *fuse;
334 const char *path = PCNPATH(pcn);
335 int ret;
336
337 fuse = (struct fuse *)pu->pu_privdata;
338 if (fuse->op.rmdir == NULL) {
339 return ENOSYS;
340 }
341
342 /* wrap up return code */
343 ret = (*fuse->op.rmdir)(path);
344
345 if (ret == 0) {
346 puffs_pn_put(pn);
347 }
348
349 return ret;
350 }
351
352 /* create a symbolic link */
353 /* ARGSUSED1 */
354 static int
355 puffs_fuse_node_symlink(struct puffs_cc *pcc, void *opc, void **newnode,
356 const struct puffs_cn *pcn_src, const struct vattr *va,
357 const char *link_target)
358 {
359 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
360 struct puffs_node *pn;
361 struct fuse *fuse;
362 const char *path = PCNPATH(pcn_src);
363 int ret;
364
365 fuse = (struct fuse *)pu->pu_privdata;
366 if (fuse->op.symlink == NULL) {
367 return ENOSYS;
368 }
369
370 /* wrap up return code */
371 ret = (*fuse->op.symlink)(path, link_target);
372 /* XXX - check I haven't transposed these args */
373
374 if (ret == 0) {
375 /* fix up nodes */
376 pn = puffs_pn_new(pu, NULL);
377 if (pn == NULL) {
378 unlink(link_target);
379 return ENOMEM;
380 }
381 puffs_setvattr(&pn->pn_va, va);
382
383 *newnode = pn;
384 }
385
386 return ret;
387 }
388
389 /* rename a directory entry */
390 /* ARGSUSED1 */
391 static int
392 puffs_fuse_node_rename(struct puffs_cc *pcc, void *opc, void *src,
393 const struct puffs_cn *pcn_src, void *targ_dir, void *targ,
394 const struct puffs_cn *pcn_targ)
395 {
396 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
397 struct puffs_node *pn = opc;
398 struct vattr va;
399 struct fuse *fuse;
400 const char *path = PCNPATH(pcn_src);
401 int ret;
402
403 fuse = (struct fuse *)pu->pu_privdata;
404 if (fuse->op.rename == NULL) {
405 return ENOSYS;
406 }
407
408 /* wrap up return code */
409 ret = (*fuse->op.rename)(path, PCNPATH(pcn_targ));
410
411 if (ret == 0) {
412 (void) memcpy(&va, &pn->pn_va, sizeof(va));
413
414 puffs_pn_put(pn);
415
416 pn = puffs_pn_new(pu, NULL);
417 if (pn == NULL) {
418 return ENOMEM;
419 }
420 puffs_setvattr(&pn->pn_va, &va);
421
422 }
423
424 return ret;
425 }
426
427 /* create a link in the file system */
428 /* ARGSUSED1 */
429 static int
430 puffs_fuse_node_link(struct puffs_cc *pcc, void *opc, void *targ,
431 const struct puffs_cn *pcn)
432 {
433 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
434 struct puffs_node *pn = targ;
435 struct fuse *fuse;
436 int ret;
437
438 fuse = (struct fuse *)pu->pu_privdata;
439 if (fuse->op.link == NULL) {
440 return ENOSYS;
441 }
442
443 /* wrap up return code */
444 ret = (*fuse->op.link)(PNPATH(pn), PCNPATH(pcn));
445
446 if (ret == 0) {
447 /* fix up nodes */
448 pn = puffs_pn_new(pu, NULL);
449 if (pn == NULL) {
450 unlink(PCNPATH(pcn));
451 return ENOMEM;
452 }
453 }
454
455 return ret;
456 }
457
458 /*
459 We run into a slight problemette here - puffs provides
460 setattr/getattr, whilst fuse provides all the usual chown/chmod/chgrp
461 functionality. So that we don't miss out on anything when calling a
462 fuse operation, we have to get the vattr from the existing file,
463 find out what's changed, and then switch on that to call the fuse
464 function accordingly.
465 */
466 /* ARGSUSED3 */
467 static int
468 puffs_fuse_node_setattr(struct puffs_cc *pcc, void *opc,
469 const struct vattr *va, const struct puffs_cred *pcr, pid_t pid)
470 {
471 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
472 struct puffs_node *pn = opc;
473 struct fuse *fuse;
474 const char *path = PNPATH(pn);
475 mode_t mode;
476 uid_t uid;
477 gid_t gid;
478 int ret;
479
480 fuse = (struct fuse *)pu->pu_privdata;
481
482 ret = -1;
483
484 mode = va->va_mode;
485 uid = va->va_uid;
486 gid = va->va_gid;
487
488 if (mode != 0) {
489 if (fuse->op.chmod == NULL) {
490 return ENOSYS;
491 }
492 ret = (*fuse->op.chmod)(path, mode);
493 }
494 if (uid != 0 || gid != 0) {
495 if (fuse->op.chown == NULL) {
496 return ENOSYS;
497 }
498 ret = (*fuse->op.chown)(path, uid, gid);
499 }
500
501 if (ret == 0) {
502 }
503
504 return ret;
505 }
506
507 /* ARGSUSED2 */
508 static int
509 puffs_fuse_node_open(struct puffs_cc *pcc, void *opc, int flags,
510 const struct puffs_cred *cred, pid_t pid)
511 {
512 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
513 struct fuse_file_info file_info;
514 struct puffs_node *pn = opc;
515 struct fuse *fuse;
516 struct stat st;
517 const char *path = PNPATH(pn);
518 int ret;
519
520 fuse = (struct fuse *)pu->pu_privdata;
521 if (fuse->op.open == NULL) {
522 return ENOSYS;
523 }
524
525 (void) memset(&file_info, 0x0, sizeof(file_info));
526
527 /* examine type - if directory, return 0 rather than open */
528 ret = (fuse->op.getattr == NULL) ?
529 stat(path, &st) :
530 (*fuse->op.getattr)(path, &st);
531 if (ret == 0 && (st.st_mode & S_IFMT) == S_IFDIR) {
532 return 0;
533 }
534
535 if (strcmp(path, "/") == 0) {
536 return 0;
537 }
538
539 ret = (*fuse->op.open)(path, &file_info);
540
541 if (ret == 0) {
542 }
543
544 return ret;
545 }
546
547 /* read some more from the file */
548 /* ARGSUSED5 */
549 static int
550 puffs_fuse_node_read(struct puffs_cc *pcc, void *opc, uint8_t *buf,
551 off_t offset, size_t *resid, const struct puffs_cred *pcr,
552 int ioflag)
553 {
554 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
555 struct fuse_file_info file_info;
556 struct puffs_node *pn = opc;
557 struct fuse *fuse;
558 const char *path = PNPATH(pn);
559 int ret;
560
561 fuse = (struct fuse *)pu->pu_privdata;
562 if (fuse->op.read == NULL) {
563 return ENOSYS;
564 }
565
566 (void) memset(&file_info, 0x0, sizeof(file_info));
567 /* XXX fill in file_info here */
568
569 ret = (*fuse->op.read)(path, (char *)buf, *resid, offset, &file_info);
570
571 if (ret > 0) {
572 *resid -= ret;
573 }
574
575 return 0;
576 }
577
578 /* write to the file */
579 /* ARGSUSED0 */
580 static int
581 puffs_fuse_node_write(struct puffs_cc *pcc, void *opc, uint8_t *buf,
582 off_t offset, size_t *resid, const struct puffs_cred *pcr,
583 int ioflag)
584 {
585 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
586 struct fuse_file_info file_info;
587 struct puffs_node *pn = opc;
588 struct fuse *fuse;
589 const char *path = PNPATH(pn);
590 int ret;
591
592 fuse = (struct fuse *)pu->pu_privdata;
593 if (fuse->op.write == NULL) {
594 return ENOSYS;
595 }
596
597 (void) memset(&file_info, 0x0, sizeof(file_info));
598
599 /* XXX fill in file_info here */
600
601 ret = (*fuse->op.write)(path, (char *)buf, *resid, offset, &file_info);
602
603 if (ret > 0) {
604 *resid -= ret;
605 }
606
607 return ret;
608 }
609
610
611 /* ARGSUSED3 */
612 static int
613 puffs_fuse_node_readdir(struct puffs_cc *pcc, void *opc,
614 struct dirent *dent, const struct puffs_cred *pcr, off_t *readoff,
615 size_t *reslen)
616 {
617 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
618 struct fuse_file_info file_info;
619 struct puffs_node *pn = opc;
620 struct fuse *fuse;
621 const char *path = PNPATH(pn);
622 struct feh feh; /* XXX */
623 int ret;
624
625 fuse = (struct fuse *)pu->pu_privdata;
626 if (fuse->op.readdir == NULL) {
627 return ENOSYS;
628 }
629
630 /* XXX: how to handle this??? */
631 if (*readoff != 0) {
632 return 0;
633 }
634
635 (void) memset(&file_info, 0x0, sizeof(file_info));
636 /* XXX - fill in file_info here */
637
638 feh.dent = dent;
639 feh.reslen = *reslen;
640 ret = (*fuse->op.readdir)(path, &feh, puffs_fuse_dirfiller, *readoff, &file_info);
641 *reslen = feh.reslen;
642 *readoff = 1;
643
644 if (ret == 0) {
645 }
646
647 return ret;
648 }
649
650 /* ARGSUSED1 */
651 static int
652 puffs_fuse_fs_unmount(struct puffs_cc *pcc, int flags, pid_t pid)
653 {
654 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
655 struct fuse *fuse;
656
657 fuse = (struct fuse *)pu->pu_privdata;
658 if (fuse->op.destroy == NULL) {
659 return 0;
660 }
661 (*fuse->op.destroy)(fuse);
662 return 0;
663 }
664
665 /* ARGSUSED0 */
666 static int
667 puffs_fuse_fs_sync(struct puffs_cc *pcc, int flags,
668 const struct puffs_cred *cr, pid_t pid)
669 {
670 return 0;
671 }
672
673 /* ARGSUSED2 */
674 static int
675 puffs_fuse_fs_statvfs(struct puffs_cc *pcc, struct statvfs *svfsb, pid_t pid)
676 {
677 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
678 struct fuse *fuse;
679 int ret;
680
681 fuse = (struct fuse *)pu->pu_privdata;
682 if (fuse->op.statfs == NULL) {
683 if ((ret = statvfs(PNPATH(pu->pu_pn_root), svfsb)) == -1) {
684 return errno;
685 }
686 } else {
687 ret = (*fuse->op.statfs)(PNPATH(pu->pu_pn_root), svfsb);
688 }
689
690 return ret;
691 }
692
693
694
695
696 /* End of puffs_fuse operations */
697
698 /* ARGSUSED3 */
699 int
700 fuse_main_real(int argc, char **argv, const struct fuse_operations *ops,
701 size_t size, void *userdata)
702 {
703 struct puffs_usermount *pu;
704 struct puffs_pathobj *po_root;
705 struct puffs_ops *pops;
706 struct statvfs svfsb;
707 struct fuse *fuse;
708 char name[64];
709 char *slash;
710 int ret;
711
712 /* initialise the puffs operations structure */
713 PUFFSOP_INIT(pops);
714
715 PUFFSOP_SET(pops, puffs_fuse, fs, sync);
716 PUFFSOP_SET(pops, puffs_fuse, fs, statvfs);
717 PUFFSOP_SET(pops, puffs_fuse, fs, unmount);
718
719 /*
720 * XXX: all of these don't possibly need to be
721 * unconditionally set
722 */
723 PUFFSOP_SET(pops, puffs_fuse, node, lookup);
724 PUFFSOP_SET(pops, puffs_fuse, node, getattr);
725 PUFFSOP_SET(pops, puffs_fuse, node, readdir);
726 PUFFSOP_SET(pops, puffs_fuse, node, readlink);
727 PUFFSOP_SET(pops, puffs_fuse, node, mknod);
728 PUFFSOP_SET(pops, puffs_fuse, node, mkdir);
729 PUFFSOP_SET(pops, puffs_fuse, node, remove);
730 PUFFSOP_SET(pops, puffs_fuse, node, rmdir);
731 PUFFSOP_SET(pops, puffs_fuse, node, symlink);
732 PUFFSOP_SET(pops, puffs_fuse, node, rename);
733 PUFFSOP_SET(pops, puffs_fuse, node, link);
734 PUFFSOP_SET(pops, puffs_fuse, node, setattr);
735 PUFFSOP_SET(pops, puffs_fuse, node, open);
736 PUFFSOP_SET(pops, puffs_fuse, node, read);
737 PUFFSOP_SET(pops, puffs_fuse, node, write);
738 PUFFSOP_SET(pops, puffs_fuse, node, readdir);
739 PUFFSOP_SET(pops, puffs_fuse, node, read);
740 PUFFSOP_SET(pops, puffs_fuse, node, write);
741 /* XXX: reclaim is missing */
742
743 NEW(struct fuse, fuse, "fuse_main_real", exit(EXIT_FAILURE));
744
745 /* copy fuse ops to their own stucture */
746 (void) memcpy(&fuse->op, ops, sizeof(fuse->op));
747
748 /* whilst this (assigning the pu_privdata in the puffs
749 * usermount struct to be the fuse struct) might seem like
750 * we are chasing our tail here, the logic is as follows:
751 + the operation wrapper gets called with the puffs
752 calling conventions
753 + we need to fix up args first
754 + then call the fuse user-supplied operation
755 + then we fix up any values on return that we need to
756 + and fix up any nodes, etc
757 * so we need to be able to get at the fuse ops from within the
758 * puffs_usermount struct
759 */
760 if ((slash = strrchr(*argv, '/')) == NULL) {
761 slash = *argv;
762 } else {
763 slash += 1;
764 }
765 (void) snprintf(name, sizeof(name), "refuse:%s", slash);
766 pu = puffs_mount(pops, argv[argc - 1], MNT_NODEV | MNT_NOSUID,
767 name, fuse,
768 PUFFS_FLAG_BUILDPATH | PUFFS_FLAG_OPDUMP, 0);
769 if (pu == NULL) {
770 err(EXIT_FAILURE, "puffs_mount");
771 }
772
773 fuse->pu = pu;
774 pu->pu_pn_root = puffs_pn_new(pu, NULL);
775 po_root = puffs_getrootpathobj(pu);
776 po_root->po_path = strdup("/");
777 po_root->po_len = 1;
778
779 statvfs(argv[argc - 1], &svfsb); /* XXX - not really the correct dir */
780 if (puffs_start(pu, pu->pu_pn_root, &svfsb) == -1) {
781 err(EXIT_FAILURE, "puffs_start");
782 }
783
784 ret = puffs_mainloop(fuse->pu, PUFFSLOOP_NODAEMON);
785
786 (void) free(po_root->po_path);
787 FREE(fuse);
788 return ret;
789 }
790
791 /* ARGSUSED0 */
792 int
793 fuse_opt_parse(struct fuse_args *args, void *data,
794 const struct fuse_opt *opts, fuse_opt_proc_t proc)
795 {
796 return 0;
797 }
798