xref: /openbsd/lib/libfuse/fuse.c (revision df69c215)
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