refuse.c revision 1.1 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 /* call context */
82
83 struct puffs_cc {
84 struct puffs_usermount *pcc_pu;
85 struct puffs_req *pcc_preq;
86
87 ucontext_t pcc_uc; /* "continue" */
88 ucontext_t pcc_uc_ret; /* "yield" */
89 void *pcc_stack;
90
91 int pcc_flags;
92
93 /* these are for threading information to the implementation */
94 void *pcc_priv;
95 int pcc_rv;
96
97 TAILQ_ENTRY(puffs_cc) entries;
98 };
99
100 static ino_t fakeino = 3;
101
102 struct feh {
103 struct dirent *dent;
104 size_t reslen;
105 };
106
107 /* ARGSUSED2 */
108 static int
109 puffs_fuse_dirfiller(void *buf, const char *name,
110 const struct stat *stbuf, off_t off)
111 {
112 struct feh *feh = buf;
113 uint8_t dtype;
114
115 /* gazeesus & other similar dudes */
116 if (*name == '.')
117 dtype = DT_DIR;
118 else
119 dtype = DT_REG;
120
121 return puffs_nextdent(&feh->dent, name, fakeino++, dtype, &feh->reslen);
122 }
123
124 int
125 fuse_opt_add_arg(struct fuse_args *args, const char *arg)
126 {
127 char **oldargv;
128 int oldargc;
129
130 if (args->allocated) {
131 RENEW(char *, args->argv, args->argc + 1, "fuse_opt_add_arg1", return 0);
132 } else {
133 oldargv = args->argv;
134 oldargc = args->argc;
135 NEWARRAY(char *, args->argv, oldargc + 1, "fuse_opt_add_arg2", return 0);
136 (void) memcpy(args->argv, oldargv, oldargc * sizeof(char *));
137 args->allocated = 1;
138 }
139 args->argv[args->argc++] = strdup(arg);
140 return 1;
141 }
142
143 /* operation wrappers start here */
144
145 /* lookup the path */
146 /* ARGSUSED1 */
147 static int
148 puffs_fuse_node_lookup(struct puffs_cc *pcc, void *opc, void **newnode,
149 enum vtype *newtype, voff_t *newsize, dev_t *newrdev,
150 const struct puffs_cn *pcn)
151 {
152 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
153 struct stat st;
154 struct fuse *fuse;
155 const char *path = PCNPATH(pcn);
156 int ret;
157
158 /* XXX: THIS IS VERY WRONG */
159 fuse = (struct fuse *)pu->pu_privdata;
160 ret = fuse->op.getattr(path, &st);
161 ret = -ret; /* linux foo */
162 if (ret != 0) {
163 return ret;
164 }
165 *newnode = puffs_pn_new(pu, NULL);
166 *newtype = (S_ISDIR(st.st_mode)) ? VDIR : VREG;
167 *newsize = st.st_size;
168 return ret;
169 }
170
171 /* get attributes for the path name */
172 /* ARGSUSED3 */
173 static int
174 puffs_fuse_node_getattr(struct puffs_cc *pcc, void *opc, struct vattr *va,
175 const struct puffs_cred *pcr, pid_t pid)
176 {
177 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
178 struct puffs_node *pn = opc;
179 struct stat st;
180 struct fuse *fuse;
181 const char *path = PNPATH(pn);
182 int ret;
183
184 fuse = (struct fuse *)pu->pu_privdata;
185 if (fuse->op.getattr == NULL) {
186 return ENOSYS;
187 }
188
189 /* wrap up return code */
190 ret = (*fuse->op.getattr)(path, &st);
191
192 if (ret == 0) {
193 /* fill in va from st */
194 va->va_mode = st.st_mode;
195 va->va_nlink = st.st_nlink;
196 va->va_uid = st.st_uid;
197 va->va_gid = st.st_gid;
198 va->va_fsid = st.st_rdev;
199 va->va_fileid = st.st_ino;
200 va->va_size = st.st_size;
201 va->va_blocksize = st.st_blksize;
202 va->va_atime = st.st_atimespec;
203 va->va_mtime = st.st_mtimespec;
204 va->va_ctime = st.st_ctimespec;
205 va->va_birthtime = st.st_birthtimespec;
206 va->va_gen = st.st_gen;
207 va->va_flags = st.st_flags;
208 va->va_rdev = st.st_rdev;
209 va->va_bytes = st.st_size;
210 va->va_filerev = st.st_gen;
211 va->va_vaflags = st.st_flags;
212
213 }
214
215 return ret;
216 }
217
218 /* read the contents of the symbolic link */
219 /* ARGSUSED2 */
220 static int
221 puffs_fuse_node_readlink(struct puffs_cc *pcc, void *opc,
222 const struct puffs_cred *cred, char *linkname, size_t *linklen)
223 {
224 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
225 struct puffs_node *pn = opc;
226 struct fuse *fuse;
227 const char *path = PNPATH(pn);
228 int ret;
229
230 fuse = (struct fuse *)pu->pu_privdata;
231 if (fuse->op.readlink == NULL) {
232 return ENOSYS;
233 }
234
235 /* wrap up return code */
236 ret = (*fuse->op.readlink)(path, linkname, *linklen);
237
238 if (ret == 0) {
239 }
240
241 return ret;
242 }
243
244 /* make the special node */
245 /* ARGSUSED1 */
246 static int
247 puffs_fuse_node_mknod(struct puffs_cc *pcc, void *opc, void **newnode,
248 const struct puffs_cn *pcn, const struct vattr *va)
249 {
250 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
251 struct puffs_node *pn;
252 struct fuse *fuse;
253 mode_t mode = va->va_mode;
254 const char *path = PCNPATH(pcn);
255 int ret;
256
257 fuse = (struct fuse *)pu->pu_privdata;
258 if (fuse->op.mknod == NULL) {
259 return ENOSYS;
260 }
261
262 /* wrap up return code */
263 ret = (*fuse->op.mknod)(path, mode, va->va_rdev);
264
265 if (ret == 0) {
266 /* fix up nodes */
267 pn = puffs_pn_new(pu, NULL);
268 if (pn == NULL) {
269 unlink(PCNPATH(pcn));
270 return ENOMEM;
271 }
272 puffs_setvattr(&pn->pn_va, va);
273
274 *newnode = pn;
275 }
276
277 return ret;
278 }
279
280 /* make a directory */
281 /* ARGSUSED1 */
282 static int
283 puffs_fuse_node_mkdir(struct puffs_cc *pcc, void *opc, void **newnode,
284 const struct puffs_cn *pcn, const struct vattr *va)
285 {
286 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
287 struct puffs_node *pn;
288 struct fuse *fuse;
289 mode_t mode = va->va_mode;
290 const char *path = PCNPATH(pcn);
291 int ret;
292
293 fuse = (struct fuse *)pu->pu_privdata;
294 if (fuse->op.mkdir == NULL) {
295 return ENOSYS;
296 }
297
298 /* wrap up return code */
299 ret = (*fuse->op.mkdir)(path, mode);
300
301 if (ret == 0) {
302 /* fix up nodes */
303 pn = puffs_pn_new(pu, NULL);
304 if (pn == NULL) {
305 rmdir(PCNPATH(pcn));
306 return ENOMEM;
307 }
308 puffs_setvattr(&pn->pn_va, va);
309
310 *newnode = pn;
311 }
312
313 return ret;
314 }
315
316 /* remove the directory entry */
317 /* ARGSUSED1 */
318 static int
319 puffs_fuse_node_remove(struct puffs_cc *pcc, void *opc, void *targ,
320 const struct puffs_cn *pcn)
321 {
322 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
323 struct puffs_node *pn = opc;
324 struct fuse *fuse;
325 const char *path = PCNPATH(pcn);
326 int ret;
327
328 fuse = (struct fuse *)pu->pu_privdata;
329 if (fuse->op.unlink == NULL) {
330 return ENOSYS;
331 }
332
333 /* wrap up return code */
334 ret = (*fuse->op.unlink)(path);
335
336 if (ret == 0) {
337 puffs_pn_put(pn);
338 }
339
340 return ret;
341 }
342
343 /* remove the directory */
344 /* ARGSUSED1 */
345 static int
346 puffs_fuse_node_rmdir(struct puffs_cc *pcc, void *opc, void *targ,
347 const struct puffs_cn *pcn)
348 {
349 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
350 struct puffs_node *pn = opc;
351 struct fuse *fuse;
352 const char *path = PCNPATH(pcn);
353 int ret;
354
355 fuse = (struct fuse *)pu->pu_privdata;
356 if (fuse->op.rmdir == NULL) {
357 return ENOSYS;
358 }
359
360 /* wrap up return code */
361 ret = (*fuse->op.rmdir)(path);
362
363 if (ret == 0) {
364 puffs_pn_put(pn);
365 }
366
367 return ret;
368 }
369
370 /* create a symbolic link */
371 /* ARGSUSED1 */
372 static int
373 puffs_fuse_node_symlink(struct puffs_cc *pcc, void *opc, void **newnode,
374 const struct puffs_cn *pcn_src, const struct vattr *va,
375 const char *link_target)
376 {
377 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
378 struct puffs_node *pn;
379 struct fuse *fuse;
380 const char *path = PCNPATH(pcn_src);
381 int ret;
382
383 fuse = (struct fuse *)pu->pu_privdata;
384 if (fuse->op.symlink == NULL) {
385 return ENOSYS;
386 }
387
388 /* wrap up return code */
389 ret = (*fuse->op.symlink)(path, link_target);
390 /* XXX - check I haven't transposed these args */
391
392 if (ret == 0) {
393 /* fix up nodes */
394 pn = puffs_pn_new(pu, NULL);
395 if (pn == NULL) {
396 unlink(link_target);
397 return ENOMEM;
398 }
399 puffs_setvattr(&pn->pn_va, va);
400
401 *newnode = pn;
402 }
403
404 return ret;
405 }
406
407 /* rename a directory entry */
408 /* ARGSUSED1 */
409 static int
410 puffs_fuse_node_rename(struct puffs_cc *pcc, void *opc, void *src,
411 const struct puffs_cn *pcn_src, void *targ_dir, void *targ,
412 const struct puffs_cn *pcn_targ)
413 {
414 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
415 struct puffs_node *pn = opc;
416 struct vattr va;
417 struct fuse *fuse;
418 const char *path = PCNPATH(pcn_src);
419 int ret;
420
421 fuse = (struct fuse *)pu->pu_privdata;
422 if (fuse->op.rename == NULL) {
423 return ENOSYS;
424 }
425
426 /* wrap up return code */
427 ret = (*fuse->op.rename)(path, PCNPATH(pcn_targ));
428
429 if (ret == 0) {
430 (void) memcpy(&va, &pn->pn_va, sizeof(va));
431
432 puffs_pn_put(pn);
433
434 pn = puffs_pn_new(pu, NULL);
435 if (pn == NULL) {
436 return ENOMEM;
437 }
438 puffs_setvattr(&pn->pn_va, &va);
439
440 }
441
442 return ret;
443 }
444
445 /* create a link in the file system */
446 /* ARGSUSED1 */
447 static int
448 puffs_fuse_node_link(struct puffs_cc *pcc, void *opc, void *targ,
449 const struct puffs_cn *pcn)
450 {
451 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
452 struct puffs_node *pn = targ;
453 struct fuse *fuse;
454 int ret;
455
456 fuse = (struct fuse *)pu->pu_privdata;
457 if (fuse->op.link == NULL) {
458 return ENOSYS;
459 }
460
461 /* wrap up return code */
462 ret = (*fuse->op.link)(PNPATH(pn), PCNPATH(pcn));
463
464 if (ret == 0) {
465 /* fix up nodes */
466 pn = puffs_pn_new(pu, NULL);
467 if (pn == NULL) {
468 unlink(PCNPATH(pcn));
469 return ENOMEM;
470 }
471 }
472
473 return ret;
474 }
475
476 /*
477 We run into a slight problemette here - puffs provides
478 setattr/getattr, whilst fuse provides all the usual chown/chmod/chgrp
479 functionality. So that we don't miss out on anything when calling a
480 fuse operation, we have to get the vattr from the existing file,
481 find out what's changed, and then switch on that to call the fuse
482 function accordingly.
483 */
484 /* ARGSUSED3 */
485 static int
486 puffs_fuse_node_setattr(struct puffs_cc *pcc, void *opc,
487 const struct vattr *va, const struct puffs_cred *pcr, pid_t pid)
488 {
489 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
490 struct puffs_node *pn = opc;
491 struct fuse *fuse;
492 const char *path = PNPATH(pn);
493 mode_t mode;
494 uid_t uid;
495 gid_t gid;
496 int ret;
497
498 fuse = (struct fuse *)pu->pu_privdata;
499
500 ret = -1;
501
502 mode = va->va_mode;
503 uid = va->va_uid;
504 gid = va->va_gid;
505
506 if (mode != 0) {
507 if (fuse->op.chmod == NULL) {
508 return ENOSYS;
509 }
510 ret = (*fuse->op.chmod)(path, mode);
511 }
512 if (uid != 0 || gid != 0) {
513 if (fuse->op.chown == NULL) {
514 return ENOSYS;
515 }
516 ret = (*fuse->op.chown)(path, uid, gid);
517 }
518
519 if (ret == 0) {
520 }
521
522 return ret;
523 }
524
525 /* ARGSUSED2 */
526 static int
527 puffs_fuse_node_open(struct puffs_cc *pcc, void *opc, int flags,
528 const struct puffs_cred *cred, pid_t pid)
529 {
530 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
531 struct fuse_file_info file_info;
532 struct puffs_node *pn = opc;
533 struct fuse *fuse;
534 struct stat st;
535 const char *path = PNPATH(pn);
536 int ret;
537
538 fuse = (struct fuse *)pu->pu_privdata;
539 if (fuse->op.open == NULL) {
540 return ENOSYS;
541 }
542
543 (void) memset(&file_info, 0x0, sizeof(file_info));
544
545 /* examine type - if directory, return 0 rather than open */
546 ret = (fuse->op.getattr == NULL) ?
547 stat(path, &st) :
548 (*fuse->op.getattr)(path, &st);
549 if (ret == 0 && (st.st_mode & S_IFMT) == S_IFDIR) {
550 return 0;
551 }
552
553 if (strcmp(path, "/") == 0) {
554 return 0;
555 }
556
557 ret = (*fuse->op.open)(path, &file_info);
558
559 if (ret == 0) {
560 }
561
562 return ret;
563 }
564
565 /* read some more from the file */
566 /* ARGSUSED5 */
567 static int
568 puffs_fuse_node_read(struct puffs_cc *pcc, void *opc, uint8_t *buf,
569 off_t offset, size_t *resid, const struct puffs_cred *pcr,
570 int ioflag)
571 {
572 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
573 struct fuse_file_info file_info;
574 struct puffs_node *pn = opc;
575 struct fuse *fuse;
576 const char *path = PNPATH(pn);
577 int ret;
578
579 fuse = (struct fuse *)pu->pu_privdata;
580 if (fuse->op.read == NULL) {
581 return ENOSYS;
582 }
583
584 (void) memset(&file_info, 0x0, sizeof(file_info));
585 /* XXX fill in file_info here */
586
587 ret = (*fuse->op.read)(path, (char *)buf, *resid, offset, &file_info);
588
589 if (ret > 0) {
590 *resid -= ret;
591 }
592
593 return 0;
594 }
595
596 /* write to the file */
597 /* ARGSUSED0 */
598 static int
599 puffs_fuse_node_write(struct puffs_cc *pcc, void *opc, uint8_t *buf,
600 off_t offset, size_t *resid, const struct puffs_cred *pcr,
601 int ioflag)
602 {
603 #if 0
604 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
605 struct fuse_file_info file_info;
606 struct puffs_node *pn = opc;
607 struct fuse *fuse;
608 const char *path = PNPATH(pn);
609 int ret;
610
611 fuse = (struct fuse *)pu->pu_privdata;
612 if (fuse->op.write == NULL) {
613 return ENOSYS;
614 }
615
616 (void) memset(&file_info, 0x0, sizeof(file_info));
617
618 /* XXX fill in file_info here */
619
620 ret = (*fuse->op.write)(path, (char *)buf, *resid, offset, &file_info);
621
622 if (ret > 0) {
623 *resid -= ret;
624 }
625
626 return ret;
627 #else
628 /*
629 * XXX: currently puffs vfs will suck if you have read but
630 * no write, so just dummyfy this
631 */
632 return 0;
633 #endif
634 }
635
636
637 /* ARGSUSED3 */
638 static int
639 puffs_fuse_node_readdir(struct puffs_cc *pcc, void *opc,
640 struct dirent *dent, const struct puffs_cred *pcr, off_t *readoff,
641 size_t *reslen)
642 {
643 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
644 struct fuse_file_info file_info;
645 struct puffs_node *pn = opc;
646 struct fuse *fuse;
647 const char *path = PNPATH(pn);
648 struct feh feh; /* XXX */
649 int ret;
650
651 fuse = (struct fuse *)pu->pu_privdata;
652 if (fuse->op.readdir == NULL) {
653 return ENOSYS;
654 }
655
656 /* XXX: how to handle this??? */
657 if (*readoff != 0) {
658 return 0;
659 }
660
661 (void) memset(&file_info, 0x0, sizeof(file_info));
662 /* XXX - fill in file_info here */
663
664 feh.dent = dent;
665 feh.reslen = *reslen;
666 ret = (*fuse->op.readdir)(path, &feh, puffs_fuse_dirfiller, *readoff, &file_info);
667 *reslen = feh.reslen;
668 *readoff = 1;
669
670 if (ret == 0) {
671 }
672
673 return ret;
674 }
675
676 /* ARGSUSED1 */
677 static int
678 puffs_fuse_fs_unmount(struct puffs_cc *pcc, int flags, pid_t pid)
679 {
680 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
681 struct fuse *fuse;
682
683 fuse = (struct fuse *)pu->pu_privdata;
684 if (fuse->op.destroy == NULL) {
685 return ENOSYS;
686 }
687 (*fuse->op.destroy)(fuse);
688 return 0;
689 }
690
691 /* ARGSUSED0 */
692 static int
693 puffs_fuse_fs_sync(struct puffs_cc *pcc, int flags,
694 const struct puffs_cred *cr, pid_t pid)
695 {
696 return 0;
697 }
698
699 /* ARGSUSED2 */
700 static int
701 puffs_fuse_fs_statvfs(struct puffs_cc *pcc, struct statvfs *svfsb, pid_t pid)
702 {
703 struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
704 struct fuse *fuse;
705 int ret;
706
707 fuse = (struct fuse *)pu->pu_privdata;
708 if (fuse->op.statfs == NULL) {
709 if ((ret = statvfs(PNPATH(pu->pu_pn_root), svfsb)) == -1) {
710 return errno;
711 }
712 } else {
713 ret = (*fuse->op.statfs)(PNPATH(pu->pu_pn_root), svfsb);
714 }
715
716 return ret;
717 }
718
719
720
721
722 /* End of puffs_fuse operations */
723
724 /* ARGSUSED3 */
725 int
726 fuse_main_real(int argc, char **argv, const struct fuse_operations *ops,
727 size_t size, void *userdata)
728 {
729 struct puffs_usermount *pu;
730 struct puffs_pathobj *po_root;
731 struct puffs_ops *pops;
732 struct statvfs svfsb;
733 struct fuse *fuse;
734 char name[64];
735 char *slash;
736 int ret;
737
738 /* initialise the puffs operations structure */
739 PUFFSOP_INIT(pops);
740
741 PUFFSOP_SET(pops, puffs_fuse, fs, sync);
742 PUFFSOP_SET(pops, puffs_fuse, fs, statvfs);
743 PUFFSOP_SET(pops, puffs_fuse, fs, unmount);
744
745 PUFFSOP_SET(pops, puffs_fuse, node, lookup);
746 PUFFSOP_SET(pops, puffs_fuse, node, getattr);
747 PUFFSOP_SET(pops, puffs_fuse, node, readdir);
748 PUFFSOP_SET(pops, puffs_fuse, node, readlink);
749 PUFFSOP_SET(pops, puffs_fuse, node, mknod);
750 PUFFSOP_SET(pops, puffs_fuse, node, mkdir);
751 PUFFSOP_SET(pops, puffs_fuse, node, remove);
752 PUFFSOP_SET(pops, puffs_fuse, node, rmdir);
753 PUFFSOP_SET(pops, puffs_fuse, node, symlink);
754 PUFFSOP_SET(pops, puffs_fuse, node, rename);
755 PUFFSOP_SET(pops, puffs_fuse, node, link);
756 PUFFSOP_SET(pops, puffs_fuse, node, setattr);
757 PUFFSOP_SET(pops, puffs_fuse, node, open);
758 PUFFSOP_SET(pops, puffs_fuse, node, read);
759 PUFFSOP_SET(pops, puffs_fuse, node, write);
760 PUFFSOP_SET(pops, puffs_fuse, node, readdir);
761 PUFFSOP_SET(pops, puffs_fuse, node, read);
762 PUFFSOP_SET(pops, puffs_fuse, node, write);
763
764 NEW(struct fuse, fuse, "fuse_main_real", exit(EXIT_FAILURE));
765
766 /* copy fuse ops to their own stucture */
767 (void) memcpy(&fuse->op, ops, sizeof(fuse->op));
768
769 /* whilst this (assigning the pu_privdata in the puffs
770 * usermount struct to be the fuse struct) might seem like
771 * we are chasing our tail here, the logic is as follows:
772 + the operation wrapper gets called with the puffs
773 calling conventions
774 + we need to fix up args first
775 + then call the fuse user-supplied operation
776 + then we fix up any values on return that we need to
777 + and fix up any nodes, etc
778 * so we need to be able to get at the fuse ops from within the
779 * puffs_usermount struct
780 */
781 if ((slash = strrchr(*argv, '/')) == NULL) {
782 slash = *argv;
783 } else {
784 slash += 1;
785 }
786 (void) snprintf(name, sizeof(name), "refuse:%s", slash);
787 pu = puffs_mount(pops, argv[argc - 1], MNT_NODEV | MNT_NOSUID,
788 name, fuse,
789 PUFFS_FLAG_BUILDPATH | PUFFS_FLAG_OPDUMP, 0);
790 if (pu == NULL) {
791 err(EXIT_FAILURE, "puffs_mount");
792 }
793
794 fuse->pu = pu;
795 pu->pu_pn_root = puffs_pn_new(pu, NULL);
796 po_root = puffs_getrootpathobj(pu);
797 po_root->po_path = strdup("/");
798 po_root->po_len = 1;
799
800 statvfs(argv[argc - 1], &svfsb); /* XXX - not really the correct dir */
801 if (puffs_start(pu, pu->pu_pn_root, &svfsb) == -1) {
802 err(EXIT_FAILURE, "puffs_start");
803 }
804
805 ret = puffs_mainloop(fuse->pu, PUFFSLOOP_NODAEMON);
806
807 (void) free(po_root->po_path);
808 FREE(fuse);
809 return ret;
810 }
811
812 /* ARGSUSED0 */
813 int
814 fuse_opt_parse(struct fuse_args *args, void *data,
815 const struct fuse_opt *opts, fuse_opt_proc_t proc)
816 {
817 return 0;
818 }
819