1 |
/* |
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 |
|