2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
5 This program can be distributed under the terms of the GNU LGPLv2.
6 See the file COPYING.LIB.
11 #include "fuse_misc.h"
13 #include "fuse_lowlevel.h"
22 #include <sys/param.h>
33 int nodefault_subtype
;
37 #define FUSE_HELPER_OPT(t, p) { t, offsetof(struct helper_opts, p), 1 }
39 static const struct fuse_opt fuse_helper_opts
[] = {
40 FUSE_HELPER_OPT("-d", foreground
),
41 FUSE_HELPER_OPT("debug", foreground
),
42 FUSE_HELPER_OPT("-f", foreground
),
43 FUSE_HELPER_OPT("-s", singlethread
),
44 FUSE_HELPER_OPT("fsname=", nodefault_subtype
),
45 FUSE_HELPER_OPT("subtype=", nodefault_subtype
),
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_KEY("subtype=", FUSE_OPT_KEY_KEEP
),
59 static void usage(const char *progname
)
61 printf("usage: %s mountpoint [options]\n\n", progname
);
62 printf("general options:\n"
63 " -o opt,[opt...] mount options\n"
64 " -h --help print help\n"
65 " -V --version print version\n"
69 static void helper_help(void)
71 printf("FUSE options:\n"
72 " -d -o debug enable debug output (implies -f)\n"
73 " -f foreground operation\n"
74 " -s disable multi-threaded operation\n"
78 static void helper_version(void)
80 printf("FUSE library version: %s\n", PACKAGE_VERSION
);
83 static int fuse_helper_opt_proc(void *data
, const char *arg
, int key
,
84 struct fuse_args
*outargs
)
86 struct helper_opts
*hopts
= data
;
90 usage(outargs
->argv
[0]);
93 case KEY_HELP_NOHEADER
:
95 return fuse_opt_add_arg(outargs
, "-h");
101 case FUSE_OPT_KEY_NONOPT
:
102 if (!hopts
->mountpoint
) {
103 char mountpoint
[PATH_MAX
];
104 if (realpath(arg
, mountpoint
) == NULL
) {
106 "fuse: bad mount point `%s': %s\n",
107 arg
, strerror(errno
));
110 return fuse_opt_add_opt(&hopts
->mountpoint
, mountpoint
);
112 fprintf(stderr
, "fuse: invalid argument `%s'\n", arg
);
121 static int add_default_subtype(const char *progname
, struct fuse_args
*args
)
125 const char *basename
= strrchr(progname
, '/');
126 if (basename
== NULL
)
128 else if (basename
[1] != '\0')
131 subtype_opt
= (char *) malloc(strlen(basename
) + 64);
132 if (subtype_opt
== NULL
) {
133 fprintf(stderr
, "fuse: memory allocation failed\n");
136 sprintf(subtype_opt
, "-osubtype=%s", basename
);
137 res
= fuse_opt_add_arg(args
, subtype_opt
);
142 int fuse_parse_cmdline(struct fuse_args
*args
, char **mountpoint
,
143 int *multithreaded
, int *foreground
)
146 struct helper_opts hopts
;
148 memset(&hopts
, 0, sizeof(hopts
));
149 res
= fuse_opt_parse(args
, &hopts
, fuse_helper_opts
,
150 fuse_helper_opt_proc
);
154 if (!hopts
.nodefault_subtype
) {
155 res
= add_default_subtype(args
->argv
[0], args
);
160 *mountpoint
= hopts
.mountpoint
;
162 free(hopts
.mountpoint
);
165 *multithreaded
= !hopts
.singlethread
;
167 *foreground
= hopts
.foreground
;
171 free(hopts
.mountpoint
);
175 int fuse_daemonize(int foreground
)
181 * demonize current process by forking it and killing the
182 * parent. This makes current process as a child of 'init'.
186 perror("fuse_daemonize: fork");
194 if (setsid() == -1) {
195 perror("fuse_daemonize: setsid");
201 nullfd
= open("/dev/null", O_RDWR
, 0);
203 (void) dup2(nullfd
, 0);
204 (void) dup2(nullfd
, 1);
205 (void) dup2(nullfd
, 2);
215 struct fuse_chan
*fuse_mount(const char *mountpoint
, struct fuse_args
*args
)
217 struct fuse_chan
*ch
;
221 * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
225 fd
= open("/dev/null", O_RDWR
);
228 } while (fd
>= 0 && fd
<= 2);
230 fd
= fuse_kern_mount(mountpoint
, args
);
234 ch
= fuse_chan_new(fd
);
236 fuse_kern_unmount(mountpoint
, fd
);
241 void fuse_unmount(const char *mountpoint
, struct fuse_chan
*ch
)
244 int fd
= ch
? fuse_chan_clearfd(ch
) : -1;
245 fuse_kern_unmount(mountpoint
, fd
);
250 static struct fuse
*fuse_setup(int argc
, char *argv
[],
251 const struct fuse_operations
*op
, size_t op_size
,
252 char **mountpoint
, int *multithreaded
, void *user_data
)
254 struct fuse_args args
= FUSE_ARGS_INIT(argc
, argv
);
255 struct fuse_chan
*ch
;
260 res
= fuse_parse_cmdline(&args
, mountpoint
, multithreaded
, &foreground
);
264 ch
= fuse_mount(*mountpoint
, &args
);
266 fuse_opt_free_args(&args
);
270 fuse
= fuse_new(ch
, &args
, op
, op_size
, user_data
);
271 fuse_opt_free_args(&args
);
275 res
= fuse_daemonize(foreground
);
279 res
= fuse_set_signal_handlers(fuse_get_session(fuse
));
286 fuse_unmount(*mountpoint
, ch
);
294 static void fuse_teardown(struct fuse
*fuse
, char *mountpoint
)
296 struct fuse_session
*se
= fuse_get_session(fuse
);
297 struct fuse_chan
*ch
= fuse_session_chan(se
);
298 fuse_remove_signal_handlers(se
);
299 fuse_unmount(mountpoint
, ch
);
304 int fuse_main_real(int argc
, char *argv
[], const struct fuse_operations
*op
,
305 size_t op_size
, void *user_data
)
312 fuse
= fuse_setup(argc
, argv
, op
, op_size
, &mountpoint
,
313 &multithreaded
, user_data
);
318 res
= fuse_loop_mt(fuse
);
320 res
= fuse_loop(fuse
);
322 fuse_teardown(fuse
, mountpoint
);
329 int fuse_version(void)