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

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