GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libfuse/fuse.c Lines: 0 203 0.0 %
Date: 2017-11-07 Branches: 0 92 0.0 %

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