xref: /openbsd-src/lib/libfuse/fuse.c (revision 5b859c19fe53bbea08f5c342e0a4470e99f883e1)
1 /* $OpenBSD: fuse.c,v 1.24 2014/05/20 13:32:22 syl 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 <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 
30 #include "fuse_opt.h"
31 #include "fuse_private.h"
32 #include "debug.h"
33 
34 static struct fuse_session *sigse;
35 static struct fuse_context *ictx = NULL;
36 static int max_read = FUSEBUFMAXSIZE;
37 
38 enum {
39 	KEY_HELP,
40 	KEY_HELP_WITHOUT_HEADER,
41 	KEY_VERSION,
42 	KEY_MAXREAD,
43 	KEY_STUB
44 };
45 
46 static struct fuse_opt fuse_core_opts[] = {
47 	FUSE_OPT_KEY("-h",			KEY_HELP),
48 	FUSE_OPT_KEY("--help",			KEY_HELP),
49 	FUSE_OPT_KEY("-ho",			KEY_HELP_WITHOUT_HEADER),
50 	FUSE_OPT_KEY("-V",			KEY_VERSION),
51 	FUSE_OPT_KEY("--version",		KEY_VERSION),
52 	FUSE_OPT_KEY("max_read=",		KEY_MAXREAD),
53 	FUSE_OPT_KEY("debug",			KEY_STUB),
54 	FUSE_OPT_KEY("-d",			KEY_STUB),
55 	FUSE_OPT_KEY("-f",			KEY_STUB),
56 	FUSE_OPT_KEY("-s",			KEY_STUB),
57 	FUSE_OPT_KEY("use_ino",			KEY_STUB),
58 	FUSE_OPT_KEY("default_permissions",	KEY_STUB),
59 	FUSE_OPT_KEY("fsname=",			KEY_STUB),
60 	FUSE_OPT_END
61 };
62 
63 int
64 fuse_loop(struct fuse *fuse)
65 {
66 	struct fusebuf fbuf;
67 	struct fuse_context ctx;
68 	struct fb_ioctl_xch ioexch;
69 	struct kevent ev;
70 	ssize_t n;
71 	int ret;
72 
73 	fuse->fc->kq = kqueue();
74 	if (fuse->fc->kq == -1)
75 		return (-1);
76 
77 	EV_SET(&fuse->fc->event, fuse->fc->fd, EVFILT_READ, EV_ADD |
78 	    EV_ENABLE, 0, 0, 0);
79 
80 	while (!fuse->fc->dead) {
81 		ret = kevent(fuse->fc->kq, &fuse->fc->event, 1, &ev, 1, NULL);
82 		if (ret == -1)
83 			DPERROR(__func__);
84 		else if (ret > 0) {
85 			n = read(fuse->fc->fd, &fbuf, sizeof(fbuf));
86 			if (n != sizeof(fbuf)) {
87 				fprintf(stderr, "%s: bad fusebuf read\n",
88 				    __func__);
89 				return (-1);
90 			}
91 
92 			/* check if there is data something present */
93 			if (fbuf.fb_len) {
94 				fbuf.fb_dat = malloc(fbuf.fb_len);
95 				if (fbuf.fb_dat == NULL)
96 					return (-1);
97 				ioexch.fbxch_uuid = fbuf.fb_uuid;
98 				ioexch.fbxch_len = fbuf.fb_len;
99 				ioexch.fbxch_data = fbuf.fb_dat;
100 
101 				if (ioctl(fuse->fc->fd, FIOCGETFBDAT,
102 				    &ioexch)) {
103 					free(fbuf.fb_dat);
104 					return (-1);
105 				}
106 			}
107 
108 			ctx.fuse = fuse;
109 			ctx.uid = fuse->conf.uid;
110 			ctx.gid = fuse->conf.gid;
111 			ctx.pid = fuse->conf.pid;
112 			ctx.umask = fuse->conf.umask;
113 			ctx.private_data = fuse->private_data;
114 			ictx = &ctx;
115 
116 			ret = ifuse_exec_opcode(fuse, &fbuf);
117 			if (ret) {
118 				ictx = NULL;
119 				return (-1);
120 			}
121 
122 			n = write(fuse->fc->fd, &fbuf, sizeof(fbuf));
123 			if (fbuf.fb_len) {
124 				if (fbuf.fb_dat == NULL) {
125 					fprintf(stderr, "%s: fb_dat is Null\n",
126 					    __func__);
127 					return (-1);
128 				}
129 				ioexch.fbxch_uuid = fbuf.fb_uuid;
130 				ioexch.fbxch_len = fbuf.fb_len;
131 				ioexch.fbxch_data = fbuf.fb_dat;
132 
133 				if (ioctl(fuse->fc->fd, FIOCSETFBDAT, &ioexch)) {
134 					free(fbuf.fb_dat);
135 					return (-1);
136 				}
137 				free(fbuf.fb_dat);
138 			}
139 			ictx = NULL;
140 
141 			if (n != FUSEBUFSIZE) {
142 				errno = EINVAL;
143 				return (-1);
144 			}
145 		}
146 	}
147 
148 	return (0);
149 }
150 
151 struct fuse_chan *
152 fuse_mount(const char *dir, unused struct fuse_args *args)
153 {
154 	struct fusefs_args fargs;
155 	struct fuse_chan *fc;
156 	const char *errcause;
157 
158 	fc = calloc(1, sizeof(*fc));
159 	if (fc == NULL)
160 		return (NULL);
161 
162 	fc->dir = realpath(dir, NULL);
163 	if (fc->dir == NULL)
164 		goto bad;
165 
166 	if ((fc->fd = open("/dev/fuse0", O_RDWR)) == -1) {
167 		perror(__func__);
168 		goto bad;
169 	}
170 
171 	fargs.fd = fc->fd;
172 	fargs.max_read = max_read;
173 	if (mount(MOUNT_FUSEFS, fc->dir, 0, &fargs)) {
174 		switch (errno) {
175 		case EMFILE:
176 			errcause = "mount table full";
177 			break;
178 		case EOPNOTSUPP:
179 			errcause = "filesystem not supported by kernel";
180 			break;
181 		default:
182 			errcause = strerror(errno);
183 			break;
184 		}
185 		fprintf(stderr, "%s on %s: %s\n", __func__, dir, errcause);
186 		goto bad;
187 	}
188 
189 	return (fc);
190 bad:
191 	if (fc->fd != -1)
192 		close(fc->fd);
193 	free(fc->dir);
194 	free(fc);
195 	return (NULL);
196 }
197 
198 void
199 fuse_unmount(const char *dir, unused struct fuse_chan *ch)
200 {
201 	if (ch->dead)
202 		return;
203 
204 	if (unmount(dir, MNT_UPDATE) == -1)
205 		DPERROR(__func__);
206 }
207 
208 int
209 fuse_is_lib_option(unused const char *opt)
210 {
211 	return (fuse_opt_match(fuse_core_opts, opt));
212 }
213 
214 int
215 fuse_chan_fd(struct fuse_chan *ch)
216 {
217 	return (ch->fd);
218 }
219 
220 struct fuse_session *
221 fuse_get_session(struct fuse *f)
222 {
223 	return (&f->se);
224 }
225 
226 int
227 fuse_loop_mt(unused struct fuse *fuse)
228 {
229 	return (0);
230 }
231 
232 struct fuse *
233 fuse_new(struct fuse_chan *fc, unused struct fuse_args *args,
234     const struct fuse_operations *ops, unused size_t size,
235     unused void *userdata)
236 {
237 	struct fuse *fuse;
238 	struct fuse_vnode *root;
239 
240 	if ((fuse = calloc(1, sizeof(*fuse))) == NULL)
241 		return (NULL);
242 
243 	/* copy fuse ops to their own structure */
244 	memcpy(&fuse->op, ops, sizeof(fuse->op));
245 
246 	fuse->fc = fc;
247 	fuse->max_ino = FUSE_ROOT_INO;
248 	fuse->se.args = fuse;
249 	fuse->private_data = userdata;
250 
251 	if ((root = alloc_vn(fuse, "/", FUSE_ROOT_INO, 0)) == NULL) {
252 		free(fuse);
253 		return (NULL);
254 	}
255 
256 	tree_init(&fuse->vnode_tree);
257 	tree_init(&fuse->name_tree);
258 	if (!set_vn(fuse, root)) {
259 		free(fuse);
260 		return (NULL);
261 	}
262 
263 	return (fuse);
264 }
265 
266 int
267 fuse_daemonize(unused int foreground)
268 {
269 #ifdef DEBUG
270 	return (daemon(0,1));
271 #else
272 	return (daemon(0,0));
273 #endif
274 }
275 
276 void
277 fuse_destroy(unused struct fuse *f)
278 {
279 	close(f->fc->fd);
280 	free(f->fc->dir);
281 	free(f->fc);
282 	free(f);
283 }
284 
285 static void
286 ifuse_get_signal(unused int num)
287 {
288 	struct fuse *f;
289 	pid_t child;
290 	int status;
291 
292 	if (sigse != NULL) {
293 		child = fork();
294 
295 		if (child < 0)
296 			return ;
297 
298 		f = sigse->args;
299 		if (child == 0) {
300 			fuse_unmount(f->fc->dir, f->fc);
301 			sigse = NULL;
302 			exit(0);
303 		}
304 
305 		fuse_loop(f);
306 		wait(&status);
307 	}
308 }
309 
310 void
311 fuse_remove_signal_handlers(unused struct fuse_session *se)
312 {
313 	sigse = NULL;
314 	signal(SIGHUP, SIG_DFL);
315 	signal(SIGINT, SIG_DFL);
316 	signal(SIGTERM, SIG_DFL);
317 	signal(SIGPIPE, SIG_DFL);
318 }
319 
320 int
321 fuse_set_signal_handlers(unused struct fuse_session *se)
322 {
323 	sigse = se;
324 	signal(SIGHUP, ifuse_get_signal);
325 	signal(SIGINT, ifuse_get_signal);
326 	signal(SIGTERM, ifuse_get_signal);
327 	signal(SIGPIPE, SIG_IGN);
328 	return (0);
329 }
330 
331 static void
332 dump_help(void)
333 {
334 	fprintf(stderr, "FUSE options:\n"
335 	    "    -d   -o debug          enable debug output (implies -f)\n"
336 	    "    -V                     print fuse version\n"
337 	    "\n");
338 }
339 
340 static void
341 dump_version(void)
342 {
343 	fprintf(stderr, "FUSE library version %i\n", FUSE_USE_VERSION);
344 }
345 
346 static int
347 ifuse_process_opt(void *data, const char *arg, int key,
348     unused struct fuse_args *args)
349 {
350 	struct fuse_core_opt *opt = data;
351 	struct stat st;
352 	const char *err;
353 	int res;
354 
355 	switch (key) {
356 		case KEY_STUB:
357 			return (0);
358 		case KEY_HELP:
359 		case KEY_HELP_WITHOUT_HEADER:
360 			dump_help();
361 			return (0);
362 		case KEY_VERSION:
363 			dump_version();
364 			return (1);
365 		case KEY_MAXREAD:
366 			res = strtonum(arg, 0, FUSEBUFMAXSIZE, &err);
367 			if (err) {
368 				fprintf(stderr, "fuse: max_read %s\n", err);
369 				return (-1);
370 			}
371 			max_read = res;
372 			break;
373 		case FUSE_OPT_KEY_NONOPT:
374 			if (opt->mp == NULL) {
375 				opt->mp = realpath(arg, opt->mp);
376 				if (opt->mp == NULL) {
377 					fprintf(stderr, "fuse: realpath: "
378 					    "%s : %s\n", arg, strerror(errno));
379 					return (-1);
380 				}
381 
382 				res = stat(opt->mp, &st);
383 				if (res == -1) {
384 					fprintf(stderr, "fuse: bad mount point "
385 					    "%s : %s\n", arg, strerror(errno));
386 					return (-1);
387 				}
388 
389 				if (!S_ISDIR(st.st_mode)) {
390 					fprintf(stderr, "fuse: bad mount point "
391 					    "%s : %s\n", arg,
392 					    strerror(ENOTDIR));
393 					return (-1);
394 				}
395 			} else {
396 				fprintf(stderr, "fuse: invalid argument %s\n",
397 				    arg);
398 				return (-1);
399 			}
400 			break;
401 		default:
402 			fprintf(stderr, "fuse: unknown option %s\n", arg);
403 			return (-1);
404 	}
405 	return (0);
406 }
407 
408 int
409 fuse_parse_cmdline(struct fuse_args *args, char **mp, int *mt, unused int *fg)
410 {
411 	struct fuse_core_opt opt;
412 
413 #ifdef DEBUG
414 	ifuse_debug_init();
415 #endif
416 	bzero(&opt, sizeof(opt));
417 	if (fuse_opt_parse(args, &opt, fuse_core_opts, ifuse_process_opt) == -1)
418 		return (-1);
419 
420 	if (opt.mp == NULL) {
421 		fprintf(stderr, "fuse: missing mountpoint parameter\n");
422 		return (-1);
423 	}
424 
425 	*mp = strdup(opt.mp);
426 	*mt = 0;
427 
428 	return (0);
429 }
430 
431 struct fuse_context *
432 fuse_get_context(void)
433 {
434 	return (ictx);
435 }
436 
437 int
438 fuse_version(void)
439 {
440 	return (FUSE_VERSION);
441 }
442 
443 void
444 fuse_teardown(struct fuse *fuse, char *mp)
445 {
446 	fuse_unmount(mp, fuse->fc);
447 	fuse_destroy(fuse);
448 }
449 
450 int
451 fuse_invalidate(unused struct fuse *f, unused const char *path)
452 {
453 	return (EINVAL);
454 }
455 
456 struct fuse *
457 fuse_setup(int argc, char **argv, const struct fuse_operations *ops,
458     size_t size, char **mp, int *mt, void *data)
459 {
460 	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
461 	struct fuse_chan *fc;
462 	struct fuse *fuse;
463 	int fg;
464 
465 	if (fuse_parse_cmdline(&args, mp, mt, &fg))
466 		goto err;
467 
468 	fuse_daemonize(0);
469 
470 	if ((fc = fuse_mount(*mp, NULL)) == NULL)
471 		goto err;
472 
473 	if ((fuse = fuse_new(fc, NULL, ops, size, data)) == NULL) {
474 		free(fc);
475 		goto err;
476 	}
477 
478 	return (fuse);
479 err:
480 	if (*mp)
481 		free(*mp);
482 	return (NULL);
483 }
484 
485 int
486 fuse_main(int argc, char **argv, const struct fuse_operations *ops, void *data)
487 {
488 	struct fuse *fuse;
489 	char *mp = NULL;
490 	int mt;
491 
492 	fuse = fuse_setup(argc, argv, ops, sizeof(*ops), &mp, &mt, data);
493 	if (!fuse)
494 		return (-1);
495 
496 	return (fuse_loop(fuse));
497 }
498