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