libfuse: refcount fuse_chan objects
[fuse.git] / lib / helper.c
blobcca21b528c35716fb11d79f0652ab144cf2b3f1f
1 /*
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.
7 */
9 #include "config.h"
10 #include "fuse_i.h"
11 #include "fuse_misc.h"
12 #include "fuse_opt.h"
13 #include "fuse_lowlevel.h"
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <stddef.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <limits.h>
21 #include <errno.h>
22 #include <sys/param.h>
24 enum {
25 KEY_HELP,
26 KEY_HELP_NOHEADER,
27 KEY_VERSION,
30 struct helper_opts {
31 int singlethread;
32 int foreground;
33 int nodefault_subtype;
34 char *mountpoint;
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),
56 FUSE_OPT_END
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"
66 "\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"
75 "\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;
88 switch (key) {
89 case KEY_HELP:
90 usage(outargs->argv[0]);
91 /* fall through */
93 case KEY_HELP_NOHEADER:
94 helper_help();
95 return fuse_opt_add_arg(outargs, "-h");
97 case KEY_VERSION:
98 helper_version();
99 return 1;
101 case FUSE_OPT_KEY_NONOPT:
102 if (!hopts->mountpoint) {
103 char mountpoint[PATH_MAX];
104 if (realpath(arg, mountpoint) == NULL) {
105 fprintf(stderr,
106 "fuse: bad mount point `%s': %s\n",
107 arg, strerror(errno));
108 return -1;
110 return fuse_opt_add_opt(&hopts->mountpoint, mountpoint);
111 } else {
112 fprintf(stderr, "fuse: invalid argument `%s'\n", arg);
113 return -1;
116 default:
117 return 1;
121 static int add_default_subtype(const char *progname, struct fuse_args *args)
123 int res;
124 char *subtype_opt;
125 const char *basename = strrchr(progname, '/');
126 if (basename == NULL)
127 basename = progname;
128 else if (basename[1] != '\0')
129 basename++;
131 subtype_opt = (char *) malloc(strlen(basename) + 64);
132 if (subtype_opt == NULL) {
133 fprintf(stderr, "fuse: memory allocation failed\n");
134 return -1;
136 sprintf(subtype_opt, "-osubtype=%s", basename);
137 res = fuse_opt_add_arg(args, subtype_opt);
138 free(subtype_opt);
139 return res;
142 int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint,
143 int *multithreaded, int *foreground)
145 int res;
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);
151 if (res == -1)
152 return -1;
154 if (!hopts.nodefault_subtype) {
155 res = add_default_subtype(args->argv[0], args);
156 if (res == -1)
157 goto err;
159 if (mountpoint)
160 *mountpoint = hopts.mountpoint;
161 else
162 free(hopts.mountpoint);
164 if (multithreaded)
165 *multithreaded = !hopts.singlethread;
166 if (foreground)
167 *foreground = hopts.foreground;
168 return 0;
170 err:
171 free(hopts.mountpoint);
172 return -1;
175 int fuse_daemonize(int foreground)
177 if (!foreground) {
178 int nullfd;
181 * demonize current process by forking it and killing the
182 * parent. This makes current process as a child of 'init'.
184 switch(fork()) {
185 case -1:
186 perror("fuse_daemonize: fork");
187 return -1;
188 case 0:
189 break;
190 default:
191 _exit(0);
194 if (setsid() == -1) {
195 perror("fuse_daemonize: setsid");
196 return -1;
199 (void) chdir("/");
201 nullfd = open("/dev/null", O_RDWR, 0);
202 if (nullfd != -1) {
203 (void) dup2(nullfd, 0);
204 (void) dup2(nullfd, 1);
205 (void) dup2(nullfd, 2);
206 if (nullfd > 2)
207 close(nullfd);
209 } else {
210 (void) chdir("/");
212 return 0;
215 struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args)
217 struct fuse_chan *ch;
218 int fd;
221 * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
222 * would ensue.
224 do {
225 fd = open("/dev/null", O_RDWR);
226 if (fd > 2)
227 close(fd);
228 } while (fd >= 0 && fd <= 2);
230 fd = fuse_kern_mount(mountpoint, args);
231 if (fd == -1)
232 return NULL;
234 ch = fuse_chan_new(fd);
235 if (!ch)
236 fuse_kern_unmount(mountpoint, fd);
238 return ch;
241 void fuse_unmount(const char *mountpoint, struct fuse_chan *ch)
243 if (mountpoint) {
244 int fd = ch ? fuse_chan_clearfd(ch) : -1;
245 fuse_kern_unmount(mountpoint, fd);
246 fuse_chan_put(ch);
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;
256 struct fuse *fuse;
257 int foreground;
258 int res;
260 res = fuse_parse_cmdline(&args, mountpoint, multithreaded, &foreground);
261 if (res == -1)
262 return NULL;
264 ch = fuse_mount(*mountpoint, &args);
265 if (!ch) {
266 fuse_opt_free_args(&args);
267 goto err_free;
270 fuse = fuse_new(ch, &args, op, op_size, user_data);
271 fuse_opt_free_args(&args);
272 if (fuse == NULL)
273 goto err_unmount;
275 res = fuse_daemonize(foreground);
276 if (res == -1)
277 goto err_unmount;
279 res = fuse_set_signal_handlers(fuse_get_session(fuse));
280 if (res == -1)
281 goto err_unmount;
283 return fuse;
285 err_unmount:
286 fuse_unmount(*mountpoint, ch);
287 if (fuse)
288 fuse_destroy(fuse);
289 err_free:
290 free(*mountpoint);
291 return NULL;
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);
300 fuse_destroy(fuse);
301 free(mountpoint);
304 int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
305 size_t op_size, void *user_data)
307 struct fuse *fuse;
308 char *mountpoint;
309 int multithreaded;
310 int res;
312 fuse = fuse_setup(argc, argv, op, op_size, &mountpoint,
313 &multithreaded, user_data);
314 if (fuse == NULL)
315 return 1;
317 if (multithreaded)
318 res = fuse_loop_mt(fuse);
319 else
320 res = fuse_loop(fuse);
322 fuse_teardown(fuse, mountpoint);
323 if (res == -1)
324 return 1;
326 return 0;
329 int fuse_version(void)
331 return FUSE_VERSION;