1 /* $OpenBSD: fuse.c,v 1.51 2019/06/28 13:32:42 deraadt Exp $ */
2 /*
3 * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/wait.h>
19 #include <sys/types.h>
20 #include <sys/ioctl.h>
21
22 #include <miscfs/fuse/fusefs.h>
23
24 #include <errno.h>
25 #include <signal.h>
26 #include <stddef.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30
31 #include "fuse_opt.h"
32 #include "fuse_private.h"
33 #include "debug.h"
34
35 static struct fuse_context *ictx = NULL;
36
37 enum {
38 KEY_DEBUG,
39 KEY_FOREGROUND,
40 KEY_HELP,
41 KEY_HELP_WITHOUT_HEADER,
42 KEY_VERSION,
43 KEY_MAXREAD,
44 KEY_STUB
45 };
46
47 /* options supported by fuse_parse_cmdline */
48 static struct fuse_opt fuse_core_opts[] = {
49 FUSE_OPT_KEY("-d", KEY_DEBUG),
50 FUSE_OPT_KEY("debug", KEY_DEBUG),
51 FUSE_OPT_KEY("-f", KEY_FOREGROUND),
52 FUSE_OPT_KEY("-h", KEY_HELP),
53 FUSE_OPT_KEY("--help", KEY_HELP),
54 FUSE_OPT_KEY("-ho", KEY_HELP_WITHOUT_HEADER),
55 FUSE_OPT_KEY("-s", KEY_STUB),
56 FUSE_OPT_KEY("-V", KEY_VERSION),
57 FUSE_OPT_KEY("--version", KEY_VERSION),
58 FUSE_OPT_END
59 };
60
61 /* options supported by fuse_new */
62 #define FUSE_LIB_OPT(o, m) {o, offsetof(struct fuse_config, m), 1}
63 static struct fuse_opt fuse_lib_opts[] = {
64 FUSE_OPT_KEY("ac_attr_timeout=", KEY_STUB),
65 FUSE_OPT_KEY("attr_timeout=", KEY_STUB),
66 FUSE_OPT_KEY("auto_cache", KEY_STUB),
67 FUSE_OPT_KEY("noauto_cache", KEY_STUB),
68 FUSE_OPT_KEY("big_writes", KEY_STUB),
69 FUSE_OPT_KEY("debug", KEY_DEBUG),
70 FUSE_OPT_KEY("-d", KEY_DEBUG),
71 FUSE_OPT_KEY("entry_timeout=", KEY_STUB),
72 FUSE_LIB_OPT("gid=", set_gid),
73 FUSE_LIB_OPT("gid=%u", gid),
74 FUSE_OPT_KEY("hard_remove", KEY_STUB),
75 FUSE_OPT_KEY("intr_signal", KEY_STUB),
76 FUSE_OPT_KEY("kernel_cache", KEY_STUB),
77 FUSE_OPT_KEY("large_read", KEY_STUB),
78 FUSE_OPT_KEY("modules=", KEY_STUB),
79 FUSE_OPT_KEY("negative_timeout=", KEY_STUB),
80 FUSE_OPT_KEY("readdir_ino", KEY_STUB),
81 FUSE_OPT_KEY("relatime", KEY_STUB),
82 FUSE_OPT_KEY("subtype=", KEY_STUB),
83 FUSE_LIB_OPT("uid=", set_uid),
84 FUSE_LIB_OPT("uid=%u", uid),
85 FUSE_LIB_OPT("use_ino", use_ino),
86 FUSE_OPT_KEY("dmask=%o", KEY_STUB),
87 FUSE_OPT_KEY("fmask=%o", KEY_STUB),
88 FUSE_LIB_OPT("umask=", set_mode),
89 FUSE_LIB_OPT("umask=%o", umask),
90 FUSE_OPT_END
91 };
92
93 /* options supported by fuse_mount */
94 #define FUSE_MOUNT_OPT(o, m) {o, offsetof(struct fuse_mount_opts, m), 1}
95 static struct fuse_opt fuse_mount_opts[] = {
96 FUSE_MOUNT_OPT("allow_other", allow_other),
97 FUSE_OPT_KEY("allow_root", KEY_STUB),
98 FUSE_OPT_KEY("async_read", KEY_STUB),
99 FUSE_OPT_KEY("blkdev", KEY_STUB),
100 FUSE_OPT_KEY("blksize=", KEY_STUB),
101 FUSE_MOUNT_OPT("default_permissions", def_perms),
102 FUSE_OPT_KEY("direct_io", KEY_STUB),
103 FUSE_MOUNT_OPT("fsname=%s", fsname),
104 FUSE_MOUNT_OPT("max_read=%u", max_read),
105 FUSE_OPT_KEY("max_readahead", KEY_STUB),
106 FUSE_OPT_KEY("max_write", KEY_STUB),
107 FUSE_MOUNT_OPT("noatime", noatime),
108 FUSE_MOUNT_OPT("nonempty", nonempty),
109 FUSE_MOUNT_OPT("-r", rdonly),
110 FUSE_MOUNT_OPT("ro", rdonly),
111 FUSE_OPT_KEY("ro_fallback", KEY_STUB),
112 FUSE_OPT_KEY("sync_read", KEY_STUB),
113 FUSE_OPT_END
114 };
115
116 static void
ifuse_try_unmount(struct fuse * f)117 ifuse_try_unmount(struct fuse *f)
118 {
119 pid_t child;
120
121 /* unmount in another thread so fuse_loop() doesn't deadlock */
122 child = fork();
123
124 if (child == -1) {
125 DPERROR(__func__);
126 return;
127 }
128
129 if (child == 0) {
130 fuse_remove_signal_handlers(fuse_get_session(f));
131 errno = 0;
132 fuse_unmount(f->fc->dir, f->fc);
133 _exit(errno);
134 }
135 }
136
137 static void
ifuse_child_exit(const struct fuse * f)138 ifuse_child_exit(const struct fuse *f)
139 {
140 int status;
141
142 if (waitpid(WAIT_ANY, &status, WNOHANG) == -1)
143 fprintf(stderr, "fuse: %s\n", strerror(errno));
144
145 if (WIFEXITED(status) && (WEXITSTATUS(status) != 0))
146 fprintf(stderr, "fuse: %s: %s\n",
147 f->fc->dir, strerror(WEXITSTATUS(status)));
148
149 return;
150 }
151
152 int
fuse_loop(struct fuse * fuse)153 fuse_loop(struct fuse *fuse)
154 {
155 struct fusebuf fbuf;
156 struct fuse_context ctx;
157 struct fb_ioctl_xch ioexch;
158 struct kevent event[5];
159 struct kevent ev;
160 ssize_t n;
161 int ret;
162
163 if (fuse == NULL)
164 return (-1);
165
166 fuse->fc->kq = kqueue();
167 if (fuse->fc->kq == -1)
168 return (-1);
169
170 EV_SET(&event[0], fuse->fc->fd, EVFILT_READ, EV_ADD |
171 EV_ENABLE, 0, 0, 0);
172
173 /* signal events */
174 EV_SET(&event[1], SIGCHLD, EVFILT_SIGNAL, EV_ADD |
175 EV_ENABLE, 0, 0, 0);
176 EV_SET(&event[2], SIGHUP, EVFILT_SIGNAL, EV_ADD |
177 EV_ENABLE, 0, 0, 0);
178 EV_SET(&event[3], SIGINT, EVFILT_SIGNAL, EV_ADD |
179 EV_ENABLE, 0, 0, 0);
180 EV_SET(&event[4], SIGTERM, EVFILT_SIGNAL, EV_ADD |
181 EV_ENABLE, 0, 0, 0);
182
183 while (!fuse->fc->dead) {
184 ret = kevent(fuse->fc->kq, &event[0], 5, &ev, 1, NULL);
185 if (ret == -1) {
186 if (errno != EINTR)
187 DPERROR(__func__);
188 } else if (ret > 0 && ev.filter == EVFILT_SIGNAL) {
189 int signum = ev.ident;
190 switch (signum) {
191 case SIGCHLD:
192 ifuse_child_exit(fuse);
193 break;
194 case SIGHUP:
195 case SIGINT:
196 case SIGTERM:
197 ifuse_try_unmount(fuse);
198 break;
199 default:
200 fprintf(stderr, "%s: %s\n", __func__,
201 strsignal(signum));
202 }
203 } else if (ret > 0) {
204 n = read(fuse->fc->fd, &fbuf, sizeof(fbuf));
205 if (n != sizeof(fbuf)) {
206 fprintf(stderr, "%s: bad fusebuf read\n",
207 __func__);
208 return (-1);
209 }
210
211 /* check if there is data something present */
212 if (fbuf.fb_len) {
213 fbuf.fb_dat = malloc(fbuf.fb_len);
214 if (fbuf.fb_dat == NULL)
215 return (-1);
216 ioexch.fbxch_uuid = fbuf.fb_uuid;
217 ioexch.fbxch_len = fbuf.fb_len;
218 ioexch.fbxch_data = fbuf.fb_dat;
219
220 if (ioctl(fuse->fc->fd, FIOCGETFBDAT,
221 &ioexch) == -1) {
222 free(fbuf.fb_dat);
223 return (-1);
224 }
225 }
226
227 ctx.fuse = fuse;
228 ctx.uid = fbuf.fb_uid;
229 ctx.gid = fbuf.fb_gid;
230 ctx.pid = fbuf.fb_tid;
231 ctx.umask = fbuf.fb_umask;
232 ctx.private_data = fuse->private_data;
233 ictx = &ctx;
234
235 ret = ifuse_exec_opcode(fuse, &fbuf);
236 if (ret) {
237 ictx = NULL;
238 return (-1);
239 }
240
241 n = write(fuse->fc->fd, &fbuf, sizeof(fbuf));
242 if (fbuf.fb_len) {
243 if (fbuf.fb_dat == NULL) {
244 fprintf(stderr, "%s: fb_dat is Null\n",
245 __func__);
246 return (-1);
247 }
248 ioexch.fbxch_uuid = fbuf.fb_uuid;
249 ioexch.fbxch_len = fbuf.fb_len;
250 ioexch.fbxch_data = fbuf.fb_dat;
251
252 if (ioctl(fuse->fc->fd, FIOCSETFBDAT, &ioexch) == -1) {
253 free(fbuf.fb_dat);
254 return (-1);
255 }
256 free(fbuf.fb_dat);
257 }
258 ictx = NULL;
259
260 if (n != FUSEBUFSIZE) {
261 errno = EINVAL;
262 return (-1);
263 }
264 }
265 }
266
267 return (0);
268 }
269 DEF(fuse_loop);
270
271 struct fuse_chan *
fuse_mount(const char * dir,struct fuse_args * args)272 fuse_mount(const char *dir, struct fuse_args *args)
273 {
274 struct fusefs_args fargs;
275 struct fuse_mount_opts opts;
276 struct fuse_chan *fc;
277 const char *errcause;
278 int mnt_flags;
279
280 if (dir == NULL)
281 return (NULL);
282
283 fc = calloc(1, sizeof(*fc));
284 if (fc == NULL)
285 return (NULL);
286
287 fc->dir = realpath(dir, NULL);
288 if (fc->dir == NULL)
289 goto bad;
290
291 if ((fc->fd = open("/dev/fuse0", O_RDWR)) == -1) {
292 perror(__func__);
293 goto bad;
294 }
295
296 memset(&opts, 0, sizeof(opts));
297 if (fuse_opt_parse(args, &opts, fuse_mount_opts, NULL) == -1)
298 goto bad;
299
300 mnt_flags = 0;
301 if (opts.rdonly)
302 mnt_flags |= MNT_RDONLY;
303 if (opts.noatime)
304 mnt_flags |= MNT_NOATIME;
305
306 if (opts.max_read > FUSEBUFMAXSIZE) {
307 fprintf(stderr, "fuse: invalid max_read (%d > %d)\n",
308 opts.max_read, FUSEBUFMAXSIZE);
309 goto bad;
310 }
311
312 memset(&fargs, 0, sizeof(fargs));
313 fargs.fd = fc->fd;
314 fargs.max_read = opts.max_read;
315 fargs.allow_other = opts.allow_other;
316
317 if (mount(MOUNT_FUSEFS, fc->dir, mnt_flags, &fargs)) {
318 switch (errno) {
319 case EMFILE:
320 errcause = "mount table full";
321 break;
322 case EOPNOTSUPP:
323 errcause = "filesystem not supported by kernel";
324 break;
325 default:
326 errcause = strerror(errno);
327 break;
328 }
329 fprintf(stderr, "%s on %s: %s\n", __func__, dir, errcause);
330 goto bad;
331 }
332
333 return (fc);
334 bad:
335 if (fc->fd != -1)
336 close(fc->fd);
337 free(fc->dir);
338 free(fc);
339 return (NULL);
340 }
341 DEF(fuse_mount);
342
343 void
fuse_unmount(const char * dir,struct fuse_chan * ch)344 fuse_unmount(const char *dir, struct fuse_chan *ch)
345 {
346 if (ch == NULL || ch->dead)
347 return;
348
349 if (unmount(dir, MNT_UPDATE) == -1)
350 DPERROR(__func__);
351 }
352 DEF(fuse_unmount);
353
354 int
fuse_is_lib_option(const char * opt)355 fuse_is_lib_option(const char *opt)
356 {
357 return (fuse_opt_match(fuse_lib_opts, opt));
358 }
359
360 int
fuse_chan_fd(struct fuse_chan * ch)361 fuse_chan_fd(struct fuse_chan *ch)
362 {
363 if (ch == NULL)
364 return (-1);
365
366 return (ch->fd);
367 }
368
369 struct fuse_session *
fuse_get_session(struct fuse * f)370 fuse_get_session(struct fuse *f)
371 {
372 return (&f->se);
373 }
374 DEF(fuse_get_session);
375
376 int
fuse_loop_mt(unused struct fuse * fuse)377 fuse_loop_mt(unused struct fuse *fuse)
378 {
379 return (-1);
380 }
381
382 static int
ifuse_lib_opt_proc(void * data,const char * arg,int key,unused struct fuse_args * args)383 ifuse_lib_opt_proc(void *data, const char *arg, int key,
384 unused struct fuse_args *args)
385 {
386 switch (key) {
387 case KEY_STUB:
388 return (0);
389 case KEY_DEBUG:
390 ifuse_debug_init();
391 break;
392 default:
393 fprintf(stderr, "fuse: unrecognised option %s\n", arg);
394 return (-1);
395 }
396
397 /* Keep unknown options. */
398 return (1);
399 }
400
401 struct fuse *
fuse_new(struct fuse_chan * fc,struct fuse_args * args,const struct fuse_operations * ops,unused size_t size,void * userdata)402 fuse_new(struct fuse_chan *fc, struct fuse_args *args,
403 const struct fuse_operations *ops, unused size_t size,
404 void *userdata)
405 {
406 struct fuse *fuse;
407 struct fuse_vnode *root;
408
409 if (fc == NULL || ops == NULL)
410 return (NULL);
411
412 if ((fuse = calloc(1, sizeof(*fuse))) == NULL)
413 return (NULL);
414
415 /* copy fuse ops to their own structure */
416 memcpy(&fuse->op, ops, sizeof(fuse->op));
417
418 if (fuse_opt_parse(args, &fuse->conf, fuse_lib_opts,
419 ifuse_lib_opt_proc) == -1) {
420 free(fuse);
421 return (NULL);
422 }
423
424 fuse->fc = fc;
425 fuse->max_ino = FUSE_ROOT_INO;
426 fuse->se.args = fuse;
427 fuse->private_data = userdata;
428
429 if ((root = alloc_vn(fuse, "/", FUSE_ROOT_INO, 0)) == NULL) {
430 free(fuse);
431 return (NULL);
432 }
433
434 tree_init(&fuse->vnode_tree);
435 tree_init(&fuse->name_tree);
436 if (!set_vn(fuse, root)) {
437 free(fuse);
438 return (NULL);
439 }
440
441 return (fuse);
442 }
443 DEF(fuse_new);
444
445 int
fuse_daemonize(int foreground)446 fuse_daemonize(int foreground)
447 {
448 if (foreground)
449 return (0);
450
451 return (daemon(0, 0));
452 }
453 DEF(fuse_daemonize);
454
455 void
fuse_destroy(struct fuse * f)456 fuse_destroy(struct fuse *f)
457 {
458 if (f == NULL)
459 return;
460
461 /*
462 * Even though these were allocated in fuse_mount(), we can't free them
463 * in fuse_unmount() since fuse_loop() will not have terminated yet so
464 * we free them here.
465 */
466 close(f->fc->fd);
467 free(f->fc->dir);
468 free(f->fc);
469 free(f);
470 }
471 DEF(fuse_destroy);
472
473 void
fuse_remove_signal_handlers(unused struct fuse_session * se)474 fuse_remove_signal_handlers(unused struct fuse_session *se)
475 {
476 struct sigaction old_sa;
477
478 if (sigaction(SIGHUP, NULL, &old_sa) == 0)
479 if (old_sa.sa_handler == SIG_IGN)
480 signal(SIGHUP, SIG_DFL);
481
482 if (sigaction(SIGINT, NULL, &old_sa) == 0)
483 if (old_sa.sa_handler == SIG_IGN)
484 signal(SIGINT, SIG_DFL);
485
486 if (sigaction(SIGTERM, NULL, &old_sa) == 0)
487 if (old_sa.sa_handler == SIG_IGN)
488 signal(SIGTERM, SIG_DFL);
489
490 if (sigaction(SIGPIPE, NULL, &old_sa) == 0)
491 if (old_sa.sa_handler == SIG_IGN)
492 signal(SIGPIPE, SIG_DFL);
493
494 if (sigaction(SIGCHLD, NULL, &old_sa) == 0)
495 if (old_sa.sa_handler == SIG_IGN)
496 signal(SIGCHLD, SIG_DFL);
497 }
498 DEF(fuse_remove_signal_handlers);
499
500 int
fuse_set_signal_handlers(unused struct fuse_session * se)501 fuse_set_signal_handlers(unused struct fuse_session *se)
502 {
503 struct sigaction old_sa;
504
505 if (sigaction(SIGHUP, NULL, &old_sa) == -1)
506 return (-1);
507 if (old_sa.sa_handler == SIG_DFL)
508 signal(SIGHUP, SIG_IGN);
509
510 if (sigaction(SIGINT, NULL, &old_sa) == -1)
511 return (-1);
512 if (old_sa.sa_handler == SIG_DFL)
513 signal(SIGINT, SIG_IGN);
514
515 if (sigaction(SIGTERM, NULL, &old_sa) == -1)
516 return (-1);
517 if (old_sa.sa_handler == SIG_DFL)
518 signal(SIGTERM, SIG_IGN);
519
520 if (sigaction(SIGPIPE, NULL, &old_sa) == -1)
521 return (-1);
522 if (old_sa.sa_handler == SIG_DFL)
523 signal(SIGPIPE, SIG_IGN);
524
525 if (sigaction(SIGCHLD, NULL, &old_sa) == -1)
526 return (-1);
527 if (old_sa.sa_handler == SIG_DFL)
528 signal(SIGCHLD, SIG_IGN);
529
530 return (0);
531 }
532
533 static void
dump_help(void)534 dump_help(void)
535 {
536 fprintf(stderr, "FUSE options:\n"
537 " -d -o debug enable debug output (implies -f)\n"
538 " -f run in foreground\n"
539 " -V --version print fuse version\n"
540 "\n");
541 }
542
543 static void
dump_version(void)544 dump_version(void)
545 {
546 fprintf(stderr, "FUSE library version: %d.%d\n", FUSE_MAJOR_VERSION,
547 FUSE_MINOR_VERSION);
548 }
549
550 static int
ifuse_process_opt(void * data,const char * arg,int key,unused struct fuse_args * args)551 ifuse_process_opt(void *data, const char *arg, int key,
552 unused struct fuse_args *args)
553 {
554 struct fuse_core_opts *opt = data;
555 struct stat st;
556 int res;
557
558 switch (key) {
559 case KEY_STUB:
560 return (0);
561 case KEY_DEBUG:
562 ifuse_debug_init();
563 /* falls through */
564 case KEY_FOREGROUND:
565 opt->foreground = 1;
566 return (0);
567 case KEY_HELP:
568 case KEY_HELP_WITHOUT_HEADER:
569 dump_help();
570 return (-1);
571 case KEY_VERSION:
572 dump_version();
573 return (-1);
574 case FUSE_OPT_KEY_NONOPT:
575 if (opt->mp == NULL) {
576 opt->mp = realpath(arg, opt->mp);
577 if (opt->mp == NULL) {
578 fprintf(stderr, "fuse: realpath: "
579 "%s : %s\n", arg, strerror(errno));
580 return (-1);
581 }
582
583 res = stat(opt->mp, &st);
584 if (res == -1) {
585 fprintf(stderr, "fuse: bad mount point "
586 "%s : %s\n", arg, strerror(errno));
587 return (-1);
588 }
589
590 if (!S_ISDIR(st.st_mode)) {
591 fprintf(stderr, "fuse: bad mount point "
592 "%s : %s\n", arg, strerror(ENOTDIR));
593 return (-1);
594 }
595 }
596 return (0);
597 }
598
599 /* Pass through unknown options. */
600 return (1);
601 }
602
603 int
fuse_parse_cmdline(struct fuse_args * args,char ** mp,int * mt,int * fg)604 fuse_parse_cmdline(struct fuse_args *args, char **mp, int *mt, int *fg)
605 {
606 struct fuse_core_opts opt;
607
608 memset(&opt, 0, sizeof(opt));
609 if (fuse_opt_parse(args, &opt, fuse_core_opts, ifuse_process_opt) == -1)
610 return (-1);
611
612 if (opt.mp == NULL) {
613 fprintf(stderr, "fuse: missing mountpoint parameter\n");
614 return (-1);
615 }
616
617 if (mp != NULL) {
618 *mp = strdup(opt.mp);
619 if (*mp == NULL)
620 return (-1);
621 }
622
623 if (mt != NULL)
624 *mt = 0;
625
626 if (fg != NULL)
627 *fg = opt.foreground;
628
629 return (0);
630 }
631 DEF(fuse_parse_cmdline);
632
633 struct fuse_context *
fuse_get_context(void)634 fuse_get_context(void)
635 {
636 return (ictx);
637 }
638 DEF(fuse_get_context);
639
640 int
fuse_version(void)641 fuse_version(void)
642 {
643 return (FUSE_VERSION);
644 }
645
646 void
fuse_teardown(struct fuse * fuse,char * mp)647 fuse_teardown(struct fuse *fuse, char *mp)
648 {
649 if (fuse == NULL || mp == NULL)
650 return;
651
652 fuse_remove_signal_handlers(fuse_get_session(fuse));
653 fuse_unmount(mp, fuse->fc);
654 fuse_destroy(fuse);
655 }
656
657 int
fuse_invalidate(unused struct fuse * f,unused const char * path)658 fuse_invalidate(unused struct fuse *f, unused const char *path)
659 {
660 return (EINVAL);
661 }
662
663 struct fuse *
fuse_setup(int argc,char ** argv,const struct fuse_operations * ops,size_t size,char ** mp,int * mt,void * data)664 fuse_setup(int argc, char **argv, const struct fuse_operations *ops,
665 size_t size, char **mp, int *mt, void *data)
666 {
667 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
668 struct fuse_chan *fc;
669 struct fuse *fuse;
670 char *dir;
671 int fg;
672
673 dir = NULL;
674 if (fuse_parse_cmdline(&args, &dir, mt, &fg))
675 goto err;
676
677 fuse_daemonize(fg);
678
679 if ((fc = fuse_mount(dir, &args)) == NULL)
680 goto err;
681
682 if ((fuse = fuse_new(fc, &args, ops, size, data)) == NULL) {
683 fuse_unmount(dir, fc);
684 close(fc->fd);
685 free(fc->dir);
686 free(fc);
687 goto err;
688 }
689
690 /* args are no longer needed */
691 fuse_opt_free_args(&args);
692
693 if (fuse_set_signal_handlers(fuse_get_session(fuse)) == -1) {
694 fuse_unmount(dir, fc);
695 fuse_destroy(fuse);
696 goto err;
697 }
698
699 /* the caller frees dir, but we do it if the caller doesn't want it */
700 if (mp == NULL)
701 free(dir);
702 else
703 *mp = dir;
704
705 return (fuse);
706 err:
707 free(dir);
708 return (NULL);
709 }
710 DEF(fuse_setup);
711
712 int
fuse_main(int argc,char ** argv,const struct fuse_operations * ops,void * data)713 fuse_main(int argc, char **argv, const struct fuse_operations *ops, void *data)
714 {
715 struct fuse *fuse;
716
717 fuse = fuse_setup(argc, argv, ops, sizeof(*ops), NULL, NULL, data);
718 if (fuse == NULL)
719 return (-1);
720
721 return (fuse_loop(fuse));
722 }
723