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