fix lookup Oops
[fuse.git] / lib / helper.c
blob63aefd51b3f0012dbe7ad6fa2a8586d388a899eb
1 /*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
5 This program can be distributed under the terms of the GNU LGPL.
6 See the file COPYING.LIB.
7 */
9 #include "config.h"
10 #include "fuse_i.h"
11 #include "fuse_opt.h"
12 #include "fuse_lowlevel.h"
13 #include "fuse_common_compat.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>
23 enum {
24 KEY_HELP,
25 KEY_HELP_NOHEADER,
26 KEY_VERSION,
29 struct helper_opts {
30 int singlethread;
31 int foreground;
32 int fsname;
33 char *mountpoint;
36 #define FUSE_HELPER_OPT(t, p) { t, offsetof(struct helper_opts, p), 1 }
38 static const struct fuse_opt fuse_helper_opts[] = {
39 FUSE_HELPER_OPT("-d", foreground),
40 FUSE_HELPER_OPT("debug", foreground),
41 FUSE_HELPER_OPT("-f", foreground),
42 FUSE_HELPER_OPT("-s", singlethread),
43 FUSE_HELPER_OPT("fsname=", fsname),
45 FUSE_OPT_KEY("-h", KEY_HELP),
46 FUSE_OPT_KEY("--help", KEY_HELP),
47 FUSE_OPT_KEY("-ho", KEY_HELP_NOHEADER),
48 FUSE_OPT_KEY("-V", KEY_VERSION),
49 FUSE_OPT_KEY("--version", KEY_VERSION),
50 FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
51 FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
52 FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP),
53 FUSE_OPT_END
56 static void usage(const char *progname)
58 fprintf(stderr,
59 "usage: %s mountpoint [options]\n\n", progname);
60 fprintf(stderr,
61 "general options:\n"
62 " -o opt,[opt...] mount options\n"
63 " -h --help print help\n"
64 " -V --version print version\n"
65 "\n");
68 static void helper_help(void)
70 fprintf(stderr,
71 "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"
79 static void helper_version(void)
81 fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION);
84 static int fuse_helper_opt_proc(void *data, const char *arg, int key,
85 struct fuse_args *outargs)
87 struct helper_opts *hopts = data;
89 switch (key) {
90 case KEY_HELP:
91 usage(outargs->argv[0]);
92 /* fall through */
94 case KEY_HELP_NOHEADER:
95 helper_help();
96 return fuse_opt_add_arg(outargs, "-h");
98 case KEY_VERSION:
99 helper_version();
100 return 1;
102 case FUSE_OPT_KEY_NONOPT:
103 if (!hopts->mountpoint) {
104 char mountpoint[PATH_MAX];
105 if (realpath(arg, mountpoint) == NULL) {
106 fprintf(stderr, "fuse: bad mount point `%s': %s\n", arg, strerror(errno));
107 return -1;
109 return fuse_opt_add_opt(&hopts->mountpoint, mountpoint);
110 } else {
111 fprintf(stderr, "fuse: invalid argument `%s'\n", arg);
112 return -1;
115 default:
116 return 1;
120 static int add_default_fsname(const char *progname, struct fuse_args *args)
122 int res;
123 char *fsname_opt;
124 const char *basename = strrchr(progname, '/');
125 if (basename == NULL)
126 basename = progname;
127 else if (basename[1] != '\0')
128 basename++;
130 fsname_opt = (char *) malloc(strlen(basename) + 64);
131 if (fsname_opt == NULL) {
132 fprintf(stderr, "fuse: memory allocation failed\n");
133 return -1;
135 sprintf(fsname_opt, "-ofsname=%s", basename);
136 res = fuse_opt_add_arg(args, fsname_opt);
137 free(fsname_opt);
138 return res;
141 int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint,
142 int *multithreaded, int *foreground)
144 int res;
145 struct helper_opts hopts;
147 memset(&hopts, 0, sizeof(hopts));
148 res = fuse_opt_parse(args, &hopts, fuse_helper_opts, fuse_helper_opt_proc);
149 if (res == -1)
150 return -1;
152 if (!hopts.fsname) {
153 res = add_default_fsname(args->argv[0], args);
154 if (res == -1)
155 goto err;
157 if (mountpoint)
158 *mountpoint = hopts.mountpoint;
159 else
160 free(hopts.mountpoint);
162 if (multithreaded)
163 *multithreaded = !hopts.singlethread;
164 if (foreground)
165 *foreground = hopts.foreground;
166 return 0;
168 err:
169 free(hopts.mountpoint);
170 return -1;
173 int fuse_daemonize(int foreground)
175 int res;
177 if (!foreground) {
178 res = daemon(0, 0);
179 if (res == -1) {
180 perror("fuse: failed to daemonize program\n");
181 return -1;
183 } else {
184 /* Ensure consistant behavior across debug and normal modes */
185 res = chdir("/");
186 if (res == -1) {
187 perror("fuse: failed to change working directory to /\n");
188 return -1;
191 return 0;
194 static struct fuse_chan *fuse_mount_common(const char *mountpoint,
195 struct fuse_args *args)
197 struct fuse_chan *ch;
198 int fd = fuse_mount_compat25(mountpoint, args);
199 if (fd == -1)
200 return NULL;
202 ch = fuse_kern_chan_new(fd);
203 if (!ch)
204 fuse_kern_unmount(mountpoint, fd);
206 return ch;
209 struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args)
211 return fuse_mount_common(mountpoint, args);
214 static void fuse_unmount_common(const char *mountpoint, struct fuse_chan *ch)
216 int fd = ch ? fuse_chan_fd(ch) : -1;
217 fuse_kern_unmount(mountpoint, fd);
218 fuse_chan_destroy(ch);
221 void fuse_unmount(const char *mountpoint, struct fuse_chan *ch)
223 fuse_unmount_common(mountpoint, ch);
226 static struct fuse *fuse_setup_common(int argc, char *argv[],
227 const struct fuse_operations *op,
228 size_t op_size,
229 char **mountpoint,
230 int *multithreaded,
231 int *fd,
232 void *user_data,
233 int compat)
235 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
236 struct fuse_chan *ch;
237 struct fuse *fuse;
238 int foreground;
239 int res;
241 res = fuse_parse_cmdline(&args, mountpoint, multithreaded, &foreground);
242 if (res == -1)
243 return NULL;
245 ch = fuse_mount_common(*mountpoint, &args);
246 if (!ch) {
247 fuse_opt_free_args(&args);
248 goto err_free;
251 fuse = fuse_new_common(ch, &args, op, op_size, user_data, compat);
252 fuse_opt_free_args(&args);
253 if (fuse == NULL)
254 goto err_unmount;
256 res = fuse_daemonize(foreground);
257 if (res == -1)
258 goto err_unmount;
260 res = fuse_set_signal_handlers(fuse_get_session(fuse));
261 if (res == -1)
262 goto err_unmount;
264 if (fd)
265 *fd = fuse_chan_fd(ch);
267 return fuse;
269 err_unmount:
270 fuse_unmount_common(*mountpoint, ch);
271 if (fuse)
272 fuse_destroy(fuse);
273 err_free:
274 free(*mountpoint);
275 return NULL;
278 struct fuse *fuse_setup(int argc, char *argv[],
279 const struct fuse_operations *op, size_t op_size,
280 char **mountpoint, int *multithreaded, void *user_data)
282 return fuse_setup_common(argc, argv, op, op_size, mountpoint,
283 multithreaded, NULL, user_data, 0);
286 static void fuse_teardown_common(struct fuse *fuse, char *mountpoint)
288 struct fuse_session *se = fuse_get_session(fuse);
289 struct fuse_chan *ch = fuse_session_next_chan(se, NULL);
290 fuse_remove_signal_handlers(se);
291 fuse_unmount_common(mountpoint, ch);
292 fuse_destroy(fuse);
293 free(mountpoint);
296 void fuse_teardown(struct fuse *fuse, char *mountpoint)
298 fuse_teardown_common(fuse, mountpoint);
301 static int fuse_main_common(int argc, char *argv[],
302 const struct fuse_operations *op, size_t op_size,
303 void *user_data, int compat)
305 struct fuse *fuse;
306 char *mountpoint;
307 int multithreaded;
308 int res;
310 fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint,
311 &multithreaded, NULL, user_data, compat);
312 if (fuse == NULL)
313 return 1;
315 if (multithreaded)
316 res = fuse_loop_mt(fuse);
317 else
318 res = fuse_loop(fuse);
320 fuse_teardown_common(fuse, mountpoint);
321 if (res == -1)
322 return 1;
324 return 0;
327 int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
328 size_t op_size, void *user_data)
330 return fuse_main_common(argc, argv, op, op_size, user_data, 0);
333 #undef fuse_main
334 int fuse_main(void)
336 fprintf(stderr, "fuse_main(): This function does not exist\n");
337 return -1;
340 #include "fuse_compat.h"
342 #ifndef __FreeBSD__
344 struct fuse *fuse_setup_compat22(int argc, char *argv[],
345 const struct fuse_operations_compat22 *op,
346 size_t op_size, char **mountpoint,
347 int *multithreaded, int *fd)
349 return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
350 op_size, mountpoint, multithreaded, fd, NULL, 22);
353 struct fuse *fuse_setup_compat2(int argc, char *argv[],
354 const struct fuse_operations_compat2 *op,
355 char **mountpoint, int *multithreaded,
356 int *fd)
358 return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
359 sizeof(struct fuse_operations_compat2),
360 mountpoint, multithreaded, fd, NULL, 21);
363 int fuse_main_real_compat22(int argc, char *argv[],
364 const struct fuse_operations_compat22 *op,
365 size_t op_size)
367 return fuse_main_common(argc, argv, (struct fuse_operations *) op, op_size,
368 NULL, 22);
371 void fuse_main_compat1(int argc, char *argv[],
372 const struct fuse_operations_compat1 *op)
374 fuse_main_common(argc, argv, (struct fuse_operations *) op,
375 sizeof(struct fuse_operations_compat1), NULL, 11);
378 int fuse_main_compat2(int argc, char *argv[],
379 const struct fuse_operations_compat2 *op)
381 return fuse_main_common(argc, argv, (struct fuse_operations *) op,
382 sizeof(struct fuse_operations_compat2), NULL, 21);
385 int fuse_mount_compat1(const char *mountpoint, const char *args[])
387 /* just ignore mount args for now */
388 (void) args;
389 return fuse_mount_compat22(mountpoint, NULL);
392 __asm__(".symver fuse_setup_compat2,__fuse_setup@");
393 __asm__(".symver fuse_setup_compat22,fuse_setup@FUSE_2.2");
394 __asm__(".symver fuse_teardown,__fuse_teardown@");
395 __asm__(".symver fuse_main_compat2,fuse_main@");
396 __asm__(".symver fuse_main_real_compat22,fuse_main_real@FUSE_2.2");
398 #endif /* __FreeBSD__ */
401 struct fuse *fuse_setup_compat25(int argc, char *argv[],
402 const struct fuse_operations_compat25 *op,
403 size_t op_size, char **mountpoint,
404 int *multithreaded, int *fd)
406 return fuse_setup_common(argc, argv, (struct fuse_operations *) op,
407 op_size, mountpoint, multithreaded, fd, NULL, 25);
410 int fuse_main_real_compat25(int argc, char *argv[],
411 const struct fuse_operations_compat25 *op,
412 size_t op_size)
414 return fuse_main_common(argc, argv, (struct fuse_operations *) op, op_size,
415 NULL, 25);
418 void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint)
420 (void) fd;
421 fuse_teardown_common(fuse, mountpoint);
424 int fuse_mount_compat25(const char *mountpoint, struct fuse_args *args)
426 return fuse_kern_mount(mountpoint, args);
429 __asm__(".symver fuse_setup_compat25,fuse_setup@FUSE_2.5");
430 __asm__(".symver fuse_teardown_compat22,fuse_teardown@FUSE_2.2");
431 __asm__(".symver fuse_main_real_compat25,fuse_main_real@FUSE_2.5");
432 __asm__(".symver fuse_mount_compat25,fuse_mount@FUSE_2.5");