1 |
dpavlin |
4 |
/* |
2 |
|
|
FUSE: Filesystem in Userspace |
3 |
|
|
Copyright (C) 2001-2004 Miklos Szeredi <miklos@szeredi.hu> |
4 |
|
|
|
5 |
|
|
This program can be distributed under the terms of the GNU LGPL. |
6 |
|
|
See the file COPYING.LIB. |
7 |
|
|
*/ |
8 |
|
|
|
9 |
|
|
#include "fuse.h" |
10 |
|
|
|
11 |
|
|
#include <stdio.h> |
12 |
|
|
#include <stdlib.h> |
13 |
|
|
#include <unistd.h> |
14 |
|
|
#include <string.h> |
15 |
|
|
#include <limits.h> |
16 |
|
|
#include <signal.h> |
17 |
|
|
|
18 |
|
|
static struct fuse *fuse; |
19 |
|
|
|
20 |
|
|
struct fuse *fuse_get(void) |
21 |
|
|
{ |
22 |
|
|
return fuse; |
23 |
|
|
} |
24 |
|
|
|
25 |
|
|
static void usage(char *progname) |
26 |
|
|
{ |
27 |
|
|
fprintf(stderr, |
28 |
|
|
"usage: %s mountpoint [options]\n" |
29 |
|
|
"Options:\n" |
30 |
|
|
" -d enable debug output (implies -f)\n" |
31 |
|
|
" -f foreground operation\n" |
32 |
|
|
" -s disable multithreaded operation\n" |
33 |
|
|
" -o opt,[opt...] mount options\n" |
34 |
|
|
" -h print help\n" |
35 |
|
|
"\n" |
36 |
|
|
"Mount options:\n" |
37 |
|
|
" default_permissions enable permission checking\n" |
38 |
|
|
" allow_other allow access to other users\n" |
39 |
|
|
" kernel_cache cache files in kernel\n" |
40 |
|
|
" large_read issue large read requests (2.4 only)\n" |
41 |
|
|
" direct_io use direct I/O\n" |
42 |
|
|
" max_read=N set maximum size of read requests\n" |
43 |
|
|
" hard_remove immediate removal (don't hide files)\n" |
44 |
|
|
" debug enable debug output\n" |
45 |
|
|
" fsname=NAME set filesystem name in mtab\n", |
46 |
|
|
progname); |
47 |
|
|
exit(1); |
48 |
|
|
} |
49 |
|
|
|
50 |
|
|
static void invalid_option(char *argv[], int argctr) |
51 |
|
|
{ |
52 |
|
|
fprintf(stderr, "invalid option: %s\n\n", argv[argctr]); |
53 |
|
|
usage(argv[0]); |
54 |
|
|
} |
55 |
|
|
|
56 |
|
|
static void exit_handler() |
57 |
|
|
{ |
58 |
|
|
if (fuse != NULL) |
59 |
|
|
fuse_exit(fuse); |
60 |
|
|
} |
61 |
|
|
|
62 |
|
|
static void set_one_signal_handler(int signal, void (*handler)(int)) |
63 |
|
|
{ |
64 |
|
|
struct sigaction sa; |
65 |
|
|
struct sigaction old_sa; |
66 |
|
|
|
67 |
|
|
memset(&sa, 0, sizeof(struct sigaction)); |
68 |
|
|
sa.sa_handler = handler; |
69 |
|
|
sigemptyset(&(sa.sa_mask)); |
70 |
|
|
sa.sa_flags = 0; |
71 |
|
|
|
72 |
|
|
if (sigaction(signal, NULL, &old_sa) == -1) { |
73 |
|
|
perror("FUSE: cannot get old signal handler"); |
74 |
|
|
exit(1); |
75 |
|
|
} |
76 |
|
|
|
77 |
|
|
if (old_sa.sa_handler == SIG_DFL && |
78 |
|
|
sigaction(signal, &sa, NULL) == -1) { |
79 |
|
|
perror("Cannot set signal handler"); |
80 |
|
|
exit(1); |
81 |
|
|
} |
82 |
|
|
} |
83 |
|
|
|
84 |
|
|
static void set_signal_handlers() |
85 |
|
|
{ |
86 |
|
|
set_one_signal_handler(SIGHUP, exit_handler); |
87 |
|
|
set_one_signal_handler(SIGINT, exit_handler); |
88 |
|
|
set_one_signal_handler(SIGTERM, exit_handler); |
89 |
|
|
set_one_signal_handler(SIGPIPE, SIG_IGN); |
90 |
|
|
} |
91 |
|
|
|
92 |
|
|
static int fuse_do(int fuse_fd, const char *opts, int multithreaded, |
93 |
|
|
int background, const struct fuse_operations *op) |
94 |
|
|
{ |
95 |
|
|
int pid; |
96 |
|
|
|
97 |
|
|
fuse = fuse_new(fuse_fd, opts, op); |
98 |
|
|
if (fuse == NULL) |
99 |
|
|
return 1; |
100 |
|
|
|
101 |
|
|
if (background) { |
102 |
|
|
pid = fork(); |
103 |
|
|
if (pid == -1) |
104 |
|
|
return 1; |
105 |
|
|
|
106 |
|
|
if (pid) |
107 |
|
|
exit(0); |
108 |
|
|
} |
109 |
|
|
|
110 |
|
|
set_signal_handlers(); |
111 |
|
|
|
112 |
|
|
if (multithreaded) |
113 |
|
|
fuse_loop_mt(fuse); |
114 |
|
|
else |
115 |
|
|
fuse_loop(fuse); |
116 |
|
|
|
117 |
|
|
fuse_destroy(fuse); |
118 |
|
|
|
119 |
|
|
return 0; |
120 |
|
|
} |
121 |
|
|
|
122 |
|
|
static void add_option_to(const char *opt, char **optp) |
123 |
|
|
{ |
124 |
|
|
unsigned len = strlen(opt); |
125 |
|
|
if (*optp) { |
126 |
|
|
unsigned oldlen = strlen(*optp); |
127 |
|
|
*optp = realloc(*optp, oldlen + 1 + len + 1); |
128 |
|
|
(*optp)[oldlen] = ','; |
129 |
|
|
strcpy(*optp + oldlen + 1, opt); |
130 |
|
|
} else { |
131 |
|
|
*optp = malloc(len + 1); |
132 |
|
|
strcpy(*optp, opt); |
133 |
|
|
} |
134 |
|
|
} |
135 |
|
|
|
136 |
|
|
static void add_options(char **lib_optp, char **kernel_optp, const char *opts) |
137 |
|
|
{ |
138 |
|
|
char *xopts = strdup(opts); |
139 |
|
|
char *s = xopts; |
140 |
|
|
char *opt; |
141 |
|
|
|
142 |
|
|
while((opt = strsep(&s, ",")) != NULL) { |
143 |
|
|
if (fuse_is_lib_option(opt)) |
144 |
|
|
add_option_to(opt, lib_optp); |
145 |
|
|
else |
146 |
|
|
add_option_to(opt, kernel_optp); |
147 |
|
|
} |
148 |
|
|
free(xopts); |
149 |
|
|
} |
150 |
|
|
|
151 |
|
|
void fuse_main(int argc, char *argv[], const struct fuse_operations *op) |
152 |
|
|
{ |
153 |
|
|
int argctr; |
154 |
|
|
int multithreaded; |
155 |
|
|
int background; |
156 |
|
|
int fuse_fd; |
157 |
|
|
char *fuse_mountpoint = NULL; |
158 |
|
|
char *basename; |
159 |
|
|
char *kernel_opts = NULL; |
160 |
|
|
char *lib_opts = NULL; |
161 |
|
|
char *fsname_opt; |
162 |
|
|
int err; |
163 |
|
|
|
164 |
|
|
basename = strrchr(argv[0], '/'); |
165 |
|
|
if (basename == NULL) |
166 |
|
|
basename = argv[0]; |
167 |
|
|
else if (basename[1] != '\0') |
168 |
|
|
basename++; |
169 |
|
|
|
170 |
|
|
fsname_opt = malloc(strlen(basename) + 64); |
171 |
|
|
sprintf(fsname_opt, "fsname=%s", basename); |
172 |
|
|
add_options(&lib_opts, &kernel_opts, fsname_opt); |
173 |
|
|
free(fsname_opt); |
174 |
|
|
|
175 |
|
|
multithreaded = 1; |
176 |
|
|
background = 1; |
177 |
|
|
for (argctr = 1; argctr < argc; argctr ++) { |
178 |
|
|
if (argv[argctr][0] == '-') { |
179 |
|
|
if (strlen(argv[argctr]) == 2) |
180 |
|
|
switch (argv[argctr][1]) { |
181 |
|
|
case 'o': |
182 |
|
|
if (argctr + 1 == argc || argv[argctr+1][0] == '-') { |
183 |
|
|
fprintf(stderr, "missing option after -o\n\n"); |
184 |
|
|
usage(argv[0]); |
185 |
|
|
} |
186 |
|
|
argctr ++; |
187 |
|
|
add_options(&lib_opts, &kernel_opts, argv[argctr]); |
188 |
|
|
break; |
189 |
|
|
|
190 |
|
|
case 'd': |
191 |
|
|
add_options(&lib_opts, &kernel_opts, "debug"); |
192 |
|
|
background = 0; |
193 |
|
|
break; |
194 |
|
|
|
195 |
|
|
case 'f': |
196 |
|
|
background = 0; |
197 |
|
|
break; |
198 |
|
|
|
199 |
|
|
case 's': |
200 |
|
|
multithreaded = 0; |
201 |
|
|
break; |
202 |
|
|
|
203 |
|
|
case 'h': |
204 |
|
|
usage(argv[0]); |
205 |
|
|
break; |
206 |
|
|
|
207 |
|
|
default: |
208 |
|
|
invalid_option(argv, argctr); |
209 |
|
|
} |
210 |
|
|
else { |
211 |
|
|
if (argv[argctr][1] == 'o') |
212 |
|
|
add_options(&lib_opts, &kernel_opts, &argv[argctr][2]); |
213 |
|
|
else |
214 |
|
|
invalid_option(argv, argctr); |
215 |
|
|
} |
216 |
|
|
} else if (fuse_mountpoint == NULL) |
217 |
|
|
fuse_mountpoint = strdup(argv[argctr]); |
218 |
|
|
else |
219 |
|
|
invalid_option(argv, argctr); |
220 |
|
|
} |
221 |
|
|
|
222 |
|
|
if (fuse_mountpoint == NULL) { |
223 |
|
|
fprintf(stderr, "missing mountpoint\n\n"); |
224 |
|
|
usage(argv[0]); |
225 |
|
|
} |
226 |
|
|
|
227 |
|
|
fuse_fd = fuse_mount(fuse_mountpoint, kernel_opts); |
228 |
|
|
if (fuse_fd == -1) |
229 |
|
|
exit(1); |
230 |
|
|
if (kernel_opts) |
231 |
|
|
free(kernel_opts); |
232 |
|
|
|
233 |
|
|
err = fuse_do(fuse_fd, lib_opts, multithreaded, background, op); |
234 |
|
|
if (lib_opts) |
235 |
|
|
free(lib_opts); |
236 |
|
|
close(fuse_fd); |
237 |
|
|
fuse_unmount(fuse_mountpoint); |
238 |
|
|
if (err) |
239 |
|
|
exit(err); |
240 |
|
|
} |
241 |
|
|
|