1 /*
2   FUSE: Filesystem in Userspace
3   Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
4 
5   This program can be distributed under the terms of the GNU LGPLv2.
6   See the file COPYING.LIB.
7 */
8 
9 #include "config.h"
10 #include "fuse_i.h"
11 #include "fuse_misc.h"
12 #include "fuse_opt.h"
13 #include "fuse_lowlevel.h"
14 #include "fuse_common_compat.h"
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <stddef.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <limits.h>
22 #include <errno.h>
23 #include <sys/param.h>
24 
25 enum  {
26 	KEY_HELP,
27 	KEY_HELP_NOHEADER,
28 	KEY_VERSION,
29 };
30 
31 struct helper_opts {
32 	int singlethread;
33 	int foreground;
34 	int fsname;
35 	char *mountpoint;
36 };
37 
38 #define FUSE_HELPER_OPT(t, p) { t, offsetof(struct helper_opts, p), 1 }
39 
40 static const struct fuse_opt fuse_helper_opts[] = {
41 	FUSE_HELPER_OPT("-d",		foreground),
42 	FUSE_HELPER_OPT("debug",	foreground),
43 	FUSE_HELPER_OPT("-f",		foreground),
44 	FUSE_HELPER_OPT("-s",		singlethread),
45 	FUSE_HELPER_OPT("fsname=",	fsname),
46 
47 	FUSE_OPT_KEY("-h",		KEY_HELP),
48 	FUSE_OPT_KEY("--help",		KEY_HELP),
49 	FUSE_OPT_KEY("-ho",		KEY_HELP_NOHEADER),
50 	FUSE_OPT_KEY("-V",		KEY_VERSION),
51 	FUSE_OPT_KEY("--version",	KEY_VERSION),
52 	FUSE_OPT_KEY("-d",		FUSE_OPT_KEY_KEEP),
53 	FUSE_OPT_KEY("debug",		FUSE_OPT_KEY_KEEP),
54 	FUSE_OPT_KEY("fsname=",		FUSE_OPT_KEY_KEEP),
55 	FUSE_OPT_END
56 };
57 
58 static void usage(const char *progname)
59 {
60 	fprintf(stderr,
61 		"usage: %s mountpoint [options]\n\n", progname);
62 	fprintf(stderr,
63 		"general options:\n"
64 		"    -o opt,[opt...]        mount options\n"
65 		"    -h   --help            print help\n"
66 		"    -V   --version         print version\n"
67 		"\n");
68 }
69 
70 static void helper_help(void)
71 {
72 	fprintf(stderr,
73 		"FUSE options:\n"
74 		"    -d   -o debug          enable debug output (implies -f)\n"
75 		"    -f                     foreground operation\n"
76 		"    -s                     disable multi-threaded operation\n"
77 		"\n"
78 		);
79 }
80 
81 static void helper_version(void)
82 {
83 	fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION);
84 }
85 
86 static int fuse_helper_opt_proc(void *data, const char *arg, int key,
87 				struct fuse_args *outargs)
88 {
89 	struct helper_opts *hopts = data;
90 
91 	switch (key) {
92 	case KEY_HELP:
93 		usage(outargs->argv[0]);
94 		/* fall through */
95 
96 	case KEY_HELP_NOHEADER:
97 		helper_help();
98 		return fuse_opt_add_arg(outargs, "-h");
99 
100 	case KEY_VERSION:
101 		helper_version();
102 		return 1;
103 
104 	case FUSE_OPT_KEY_NONOPT:
105 		if (!hopts->mountpoint) {
106 			char mountpoint[PATH_MAX];
107 			if (realpath(arg, mountpoint) == NULL) {
108 				fprintf(stderr,
109 					"fuse: bad mount point `%s': %s\n",
110 					arg, strerror(errno));
111 				return -1;
112 			}
113 			return fuse_opt_add_opt(&hopts->mountpoint, mountpoint);
114 		} else {
115 			fprintf(stderr, "fuse: invalid argument `%s'\n", arg);
116 			return -1;
117 		}
118 
119 	default:
120 		return 1;
121 	}
122 }
123 
124 static int add_default_fsname(const char *progname, struct fuse_args *args)
125 {
126 	int res;
127 	char *fsname_opt;
128 	const char *basename = strrchr(progname, '/');
129 	if (basename == NULL)
130 		basename = progname;
131 	else if (basename[1] != '\0')
132 		basename++;
133 
134 	fsname_opt = (char *) malloc(strlen(basename) + 64);
135 	if (fsname_opt == NULL) {
136 		fprintf(stderr, "fuse: memory allocation failed\n");
137 		return -1;
138 	}
139 	sprintf(fsname_opt, "-ofsname=%s", basename);
140 	res = fuse_opt_add_arg(args, fsname_opt);
141 	free(fsname_opt);
142 	return res;
143 }
144 
145 int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint,
146 		       int *multithreaded, int *foreground)
147 {
148 	int res;
149 	struct helper_opts hopts;
150 
151 	memset(&hopts, 0, sizeof(hopts));
152 	res = fuse_opt_parse(args, &hopts, fuse_helper_opts,
153 			     fuse_helper_opt_proc);
154 	if (res == -1)
155 		return -1;
156 
157 	if (!hopts.fsname) {
158 		res = add_default_fsname(args->argv[0], args);
159 		if (res == -1)
160 			goto err;
161 	}
162 	if (mountpoint)
163 		*mountpoint = hopts.mountpoint;
164 	else
165 		free(hopts.mountpoint);
166 
167 	if (multithreaded)
168 		*multithreaded = !hopts.singlethread;
169 	if (foreground)
170 		*foreground = hopts.foreground;
171 	return 0;
172 
173 err:
174 	free(hopts.mountpoint);
175 	return -1;
176 }
177 
178 int fuse_daemonize(int foreground)
179 {
180 	if (!foreground) {
181 		int nullfd;
182 		int waiter[2];
183 		char completed;
184 
185 		if (pipe(waiter)) {
186 			perror("fuse_daemonize: pipe");
187 			return -1;
188 		}
189 
190 		/*
191 		 * demonize current process by forking it and killing the
192 		 * parent.  This makes current process as a child of 'init'.
193 		 */
194 		switch(fork()) {
195 		case -1:
196 			perror("fuse_daemonize: fork");
197 			return -1;
198 		case 0:
199 			break;
200 		default:
201 			read(waiter[0], &completed, sizeof(completed));
202 			_exit(0);
203 		}
204 
205 		if (setsid() == -1) {
206 			perror("fuse_daemonize: setsid");
207 			return -1;
208 		}
209 
210 		(void) chdir("/");
211 
212 		nullfd = open("/dev/null", O_RDWR, 0);
213 		if (nullfd != -1) {
214 			(void) dup2(nullfd, 0);
215 			(void) dup2(nullfd, 1);
216 			(void) dup2(nullfd, 2);
217 			if (nullfd > 2)
218 				close(nullfd);
219 		}
220 
221 		/* Propagate completion of daemon initializatation */
222 		completed = 1;
223 		write(waiter[1], &completed, sizeof(completed));
224 		close(waiter[0]);
225 		close(waiter[1]);
226 	}
227 	return 0;
228 }
229 
230 static struct fuse_chan *fuse_mount_common(const char *mountpoint,
231 					   struct fuse_args *args)
232 {
233 	struct fuse_chan *ch;
234 	int fd;
235 
236 	/*
237 	 * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
238 	 * would ensue.
239 	 */
240 	do {
241 		fd = open("/dev/null", O_RDWR);
242 		if (fd > 2)
243 			close(fd);
244 	} while (fd >= 0 && fd <= 2);
245 
246 	fd = fuse_mount_compat25(mountpoint, args);
247 	if (fd == -1)
248 		return NULL;
249 
250 	ch = fuse_kern_chan_new(fd);
251 	if (!ch)
252 		fuse_kern_unmount(mountpoint, fd);
253 
254 	return ch;
255 }
256 
257 struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args)
258 {
259 	return fuse_mount_common(mountpoint, args);
260 }
261 
262 static void fuse_unmount_common(const char *mountpoint, struct fuse_chan *ch)
263 {
264 	if (mountpoint) {
265 		int fd = ch ? fuse_chan_clearfd(ch) : -1;
266 		fuse_kern_unmount(mountpoint, fd);
267 		if (ch)
268 			fuse_chan_destroy(ch);
269 	}
270 }
271 
272 void fuse_unmount(const char *mountpoint, struct fuse_chan *ch)
273 {
274 	fuse_unmount_common(mountpoint, ch);
275 }
276 
277 struct fuse *fuse_setup_common(int argc, char *argv[],
278 			       const struct fuse_operations *op,
279 			       size_t op_size,
280 			       char **mountpoint,
281 			       int *multithreaded,
282 			       int *fd,
283 			       void *user_data,
284 			       int compat)
285 {
286 	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
287 	struct fuse_chan *ch;
288 	struct fuse *fuse;
289 	int foreground;
290 	int res;
291 
292 	res = fuse_parse_cmdline(&args, mountpoint, multithreaded, &foreground);
293 	if (res == -1)
294 		return NULL;
295 
296 	ch = fuse_mount_common(*mountpoint, &args);
297 	if (!ch) {
298 		fuse_opt_free_args(&args);
299 		goto err_free;
300 	}
301 
302 	fuse = fuse_new_common(ch, &args, op, op_size, user_data, compat);
303 	fuse_opt_free_args(&args);
304 	if (fuse == NULL)
305 		goto err_unmount;
306 
307 	res = fuse_daemonize(foreground);
308 	if (res == -1)
309 		goto err_unmount;
310 
311 	res = fuse_set_signal_handlers(fuse_get_session(fuse));
312 	if (res == -1)
313 		goto err_unmount;
314 
315 	if (fd)
316 		*fd = fuse_chan_fd(ch);
317 
318 	return fuse;
319 
320 err_unmount:
321 	fuse_unmount_common(*mountpoint, ch);
322 	if (fuse)
323 		fuse_destroy(fuse);
324 err_free:
325 	free(*mountpoint);
326 	return NULL;
327 }
328 
329 struct fuse *fuse_setup(int argc, char *argv[],
330 			const struct fuse_operations *op, size_t op_size,
331 			char **mountpoint, int *multithreaded, void *user_data)
332 {
333 	return fuse_setup_common(argc, argv, op, op_size, mountpoint,
334 				 multithreaded, NULL, user_data, 0);
335 }
336 
337 static void fuse_teardown_common(struct fuse *fuse, char *mountpoint)
338 {
339 	struct fuse_session *se = fuse_get_session(fuse);
340 	struct fuse_chan *ch = fuse_session_next_chan(se, NULL);
341 	fuse_remove_signal_handlers(se);
342 	fuse_unmount_common(mountpoint, ch);
343 	fuse_destroy(fuse);
344 	free(mountpoint);
345 }
346 
347 void fuse_teardown(struct fuse *fuse, char *mountpoint)
348 {
349 	fuse_teardown_common(fuse, mountpoint);
350 }
351 
352 static int fuse_main_common(int argc, char *argv[],
353 			    const struct fuse_operations *op, size_t op_size,
354 			    void *user_data, int compat)
355 {
356 	struct fuse *fuse;
357 	char *mountpoint;
358 	int multithreaded;
359 	int res;
360 
361 	fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint,
362 				 &multithreaded, NULL, user_data, compat);
363 	if (fuse == NULL)
364 		return 1;
365 
366 	if (multithreaded)
367 		res = fuse_loop_mt(fuse);
368 	else
369 		res = fuse_loop(fuse);
370 
371 	fuse_teardown_common(fuse, mountpoint);
372 	if (res == -1)
373 		return 1;
374 
375 	return 0;
376 }
377 
378 int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
379 		   size_t op_size, void *user_data)
380 {
381 	return fuse_main_common(argc, argv, op, op_size, user_data, 0);
382 }
383 
384 #undef fuse_main
385 int fuse_main(void);
386 int fuse_main(void)
387 {
388 	fprintf(stderr, "fuse_main(): This function does not exist\n");
389 	return -1;
390 }
391 
392 int fuse_version(void)
393 {
394 	return FUSE_VERSION;
395 }
396 
397 #include "fuse_compat.h"
398 
399 #if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__DragonFly__)
400 
401 struct fuse *fuse_setup_compat22(int argc, char *argv[],
402 				 const struct fuse_operations_compat22 *op,
403 				 size_t op_size, char **mountpoint,
404 				 int *multithreaded, int *fd)
405 {
406 	return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
407 				 op_size, mountpoint, multithreaded, fd, NULL,
408 				 22);
409 }
410 
411 struct fuse *fuse_setup_compat2(int argc, char *argv[],
412 				const struct fuse_operations_compat2 *op,
413 				char **mountpoint, int *multithreaded,
414 				int *fd)
415 {
416 	return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
417 				 sizeof(struct fuse_operations_compat2),
418 				 mountpoint, multithreaded, fd, NULL, 21);
419 }
420 
421 int fuse_main_real_compat22(int argc, char *argv[],
422 			    const struct fuse_operations_compat22 *op,
423 			    size_t op_size)
424 {
425 	return fuse_main_common(argc, argv, (struct fuse_operations *) op,
426 				op_size, NULL, 22);
427 }
428 
429 void fuse_main_compat1(int argc, char *argv[],
430 		       const struct fuse_operations_compat1 *op)
431 {
432 	fuse_main_common(argc, argv, (struct fuse_operations *) op,
433 			 sizeof(struct fuse_operations_compat1), NULL, 11);
434 }
435 
436 int fuse_main_compat2(int argc, char *argv[],
437 		      const struct fuse_operations_compat2 *op)
438 {
439 	return fuse_main_common(argc, argv, (struct fuse_operations *) op,
440 				sizeof(struct fuse_operations_compat2), NULL,
441 				21);
442 }
443 
444 int fuse_mount_compat1(const char *mountpoint, const char *args[])
445 {
446 	/* just ignore mount args for now */
447 	(void) args;
448 	return fuse_mount_compat22(mountpoint, NULL);
449 }
450 
451 FUSE_SYMVER(".symver fuse_setup_compat2,__fuse_setup@");
452 FUSE_SYMVER(".symver fuse_setup_compat22,fuse_setup@FUSE_2.2");
453 FUSE_SYMVER(".symver fuse_teardown,__fuse_teardown@");
454 FUSE_SYMVER(".symver fuse_main_compat2,fuse_main@");
455 FUSE_SYMVER(".symver fuse_main_real_compat22,fuse_main_real@FUSE_2.2");
456 
457 #endif /* __FreeBSD__ || __NetBSD__ */
458 
459 
460 struct fuse *fuse_setup_compat25(int argc, char *argv[],
461 				 const struct fuse_operations_compat25 *op,
462 				 size_t op_size, char **mountpoint,
463 				 int *multithreaded, int *fd)
464 {
465 	return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
466 				 op_size, mountpoint, multithreaded, fd, NULL,
467 				 25);
468 }
469 
470 int fuse_main_real_compat25(int argc, char *argv[],
471 			    const struct fuse_operations_compat25 *op,
472 			    size_t op_size)
473 {
474 	return fuse_main_common(argc, argv, (struct fuse_operations *) op,
475 				op_size, NULL, 25);
476 }
477 
478 void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint)
479 {
480 	(void) fd;
481 	fuse_teardown_common(fuse, mountpoint);
482 }
483 
484 int fuse_mount_compat25(const char *mountpoint, struct fuse_args *args)
485 {
486 	return fuse_kern_mount(mountpoint, args);
487 }
488 
489 FUSE_SYMVER(".symver fuse_setup_compat25,fuse_setup@FUSE_2.5");
490 FUSE_SYMVER(".symver fuse_teardown_compat22,fuse_teardown@FUSE_2.2");
491 FUSE_SYMVER(".symver fuse_main_real_compat25,fuse_main_real@FUSE_2.5");
492 FUSE_SYMVER(".symver fuse_mount_compat25,fuse_mount@FUSE_2.5");
493