1 /* 2 FUSE: Filesystem in Userspace 3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> 4 5 This program can be distributed under the terms of the GNU LGPLv2. 6 See the file COPYING.LIB. 7 */ 8 9 #include "config.h" 10 #include "fuse_i.h" 11 #include "fuse_misc.h" 12 #include "fuse_opt.h" 13 #include "fuse_lowlevel.h" 14 #include "fuse_common_compat.h" 15 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <stddef.h> 19 #include <unistd.h> 20 #include <string.h> 21 #include <limits.h> 22 #include <errno.h> 23 #include <sys/param.h> 24 25 enum { 26 KEY_HELP, 27 KEY_HELP_NOHEADER, 28 KEY_VERSION, 29 }; 30 31 struct helper_opts { 32 int singlethread; 33 int foreground; 34 int fsname; 35 char *mountpoint; 36 }; 37 38 #define FUSE_HELPER_OPT(t, p) { t, offsetof(struct helper_opts, p), 1 } 39 40 static const struct fuse_opt fuse_helper_opts[] = { 41 FUSE_HELPER_OPT("-d", foreground), 42 FUSE_HELPER_OPT("debug", foreground), 43 FUSE_HELPER_OPT("-f", foreground), 44 FUSE_HELPER_OPT("-s", singlethread), 45 FUSE_HELPER_OPT("fsname=", fsname), 46 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_END 56 }; 57 58 static void usage(const char *progname) 59 { 60 fprintf(stderr, 61 "usage: %s mountpoint [options]\n\n", progname); 62 fprintf(stderr, 63 "general options:\n" 64 " -o opt,[opt...] mount options\n" 65 " -h --help print help\n" 66 " -V --version print version\n" 67 "\n"); 68 } 69 70 static void helper_help(void) 71 { 72 fprintf(stderr, 73 "FUSE options:\n" 74 " -d -o debug enable debug output (implies -f)\n" 75 " -f foreground operation\n" 76 " -s disable multi-threaded operation\n" 77 "\n" 78 ); 79 } 80 81 static void helper_version(void) 82 { 83 fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION); 84 } 85 86 static int fuse_helper_opt_proc(void *data, const char *arg, int key, 87 struct fuse_args *outargs) 88 { 89 struct helper_opts *hopts = data; 90 91 switch (key) { 92 case KEY_HELP: 93 usage(outargs->argv[0]); 94 /* fall through */ 95 96 case KEY_HELP_NOHEADER: 97 helper_help(); 98 return fuse_opt_add_arg(outargs, "-h"); 99 100 case KEY_VERSION: 101 helper_version(); 102 return 1; 103 104 case FUSE_OPT_KEY_NONOPT: 105 if (!hopts->mountpoint) { 106 char mountpoint[PATH_MAX]; 107 if (realpath(arg, mountpoint) == NULL) { 108 fprintf(stderr, 109 "fuse: bad mount point `%s': %s\n", 110 arg, strerror(errno)); 111 return -1; 112 } 113 return fuse_opt_add_opt(&hopts->mountpoint, mountpoint); 114 } else { 115 fprintf(stderr, "fuse: invalid argument `%s'\n", arg); 116 return -1; 117 } 118 119 default: 120 return 1; 121 } 122 } 123 124 static int add_default_fsname(const char *progname, struct fuse_args *args) 125 { 126 int res; 127 char *fsname_opt; 128 const char *basename = strrchr(progname, '/'); 129 if (basename == NULL) 130 basename = progname; 131 else if (basename[1] != '\0') 132 basename++; 133 134 fsname_opt = (char *) malloc(strlen(basename) + 64); 135 if (fsname_opt == NULL) { 136 fprintf(stderr, "fuse: memory allocation failed\n"); 137 return -1; 138 } 139 sprintf(fsname_opt, "-ofsname=%s", basename); 140 res = fuse_opt_add_arg(args, fsname_opt); 141 free(fsname_opt); 142 return res; 143 } 144 145 int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint, 146 int *multithreaded, int *foreground) 147 { 148 int res; 149 struct helper_opts hopts; 150 151 memset(&hopts, 0, sizeof(hopts)); 152 res = fuse_opt_parse(args, &hopts, fuse_helper_opts, 153 fuse_helper_opt_proc); 154 if (res == -1) 155 return -1; 156 157 if (!hopts.fsname) { 158 res = add_default_fsname(args->argv[0], args); 159 if (res == -1) 160 goto err; 161 } 162 if (mountpoint) 163 *mountpoint = hopts.mountpoint; 164 else 165 free(hopts.mountpoint); 166 167 if (multithreaded) 168 *multithreaded = !hopts.singlethread; 169 if (foreground) 170 *foreground = hopts.foreground; 171 return 0; 172 173 err: 174 free(hopts.mountpoint); 175 return -1; 176 } 177 178 int fuse_daemonize(int foreground) 179 { 180 if (!foreground) { 181 int nullfd; 182 int waiter[2]; 183 char completed; 184 185 if (pipe(waiter)) { 186 perror("fuse_daemonize: pipe"); 187 return -1; 188 } 189 190 /* 191 * demonize current process by forking it and killing the 192 * parent. This makes current process as a child of 'init'. 193 */ 194 switch(fork()) { 195 case -1: 196 perror("fuse_daemonize: fork"); 197 return -1; 198 case 0: 199 break; 200 default: 201 read(waiter[0], &completed, sizeof(completed)); 202 _exit(0); 203 } 204 205 if (setsid() == -1) { 206 perror("fuse_daemonize: setsid"); 207 return -1; 208 } 209 210 (void) chdir("/"); 211 212 nullfd = open("/dev/null", O_RDWR, 0); 213 if (nullfd != -1) { 214 (void) dup2(nullfd, 0); 215 (void) dup2(nullfd, 1); 216 (void) dup2(nullfd, 2); 217 if (nullfd > 2) 218 close(nullfd); 219 } 220 221 /* Propagate completion of daemon initializatation */ 222 completed = 1; 223 write(waiter[1], &completed, sizeof(completed)); 224 close(waiter[0]); 225 close(waiter[1]); 226 } 227 return 0; 228 } 229 230 static struct fuse_chan *fuse_mount_common(const char *mountpoint, 231 struct fuse_args *args) 232 { 233 struct fuse_chan *ch; 234 int fd; 235 236 /* 237 * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos 238 * would ensue. 239 */ 240 do { 241 fd = open("/dev/null", O_RDWR); 242 if (fd > 2) 243 close(fd); 244 } while (fd >= 0 && fd <= 2); 245 246 fd = fuse_mount_compat25(mountpoint, args); 247 if (fd == -1) 248 return NULL; 249 250 ch = fuse_kern_chan_new(fd); 251 if (!ch) 252 fuse_kern_unmount(mountpoint, fd); 253 254 return ch; 255 } 256 257 struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args) 258 { 259 return fuse_mount_common(mountpoint, args); 260 } 261 262 static void fuse_unmount_common(const char *mountpoint, struct fuse_chan *ch) 263 { 264 if (mountpoint) { 265 int fd = ch ? fuse_chan_clearfd(ch) : -1; 266 fuse_kern_unmount(mountpoint, fd); 267 if (ch) 268 fuse_chan_destroy(ch); 269 } 270 } 271 272 void fuse_unmount(const char *mountpoint, struct fuse_chan *ch) 273 { 274 fuse_unmount_common(mountpoint, ch); 275 } 276 277 struct fuse *fuse_setup_common(int argc, char *argv[], 278 const struct fuse_operations *op, 279 size_t op_size, 280 char **mountpoint, 281 int *multithreaded, 282 int *fd, 283 void *user_data, 284 int compat) 285 { 286 struct fuse_args args = FUSE_ARGS_INIT(argc, argv); 287 struct fuse_chan *ch; 288 struct fuse *fuse; 289 int foreground; 290 int res; 291 292 res = fuse_parse_cmdline(&args, mountpoint, multithreaded, &foreground); 293 if (res == -1) 294 return NULL; 295 296 ch = fuse_mount_common(*mountpoint, &args); 297 if (!ch) { 298 fuse_opt_free_args(&args); 299 goto err_free; 300 } 301 302 fuse = fuse_new_common(ch, &args, op, op_size, user_data, compat); 303 fuse_opt_free_args(&args); 304 if (fuse == NULL) 305 goto err_unmount; 306 307 res = fuse_daemonize(foreground); 308 if (res == -1) 309 goto err_unmount; 310 311 res = fuse_set_signal_handlers(fuse_get_session(fuse)); 312 if (res == -1) 313 goto err_unmount; 314 315 if (fd) 316 *fd = fuse_chan_fd(ch); 317 318 return fuse; 319 320 err_unmount: 321 fuse_unmount_common(*mountpoint, ch); 322 if (fuse) 323 fuse_destroy(fuse); 324 err_free: 325 free(*mountpoint); 326 return NULL; 327 } 328 329 struct fuse *fuse_setup(int argc, char *argv[], 330 const struct fuse_operations *op, size_t op_size, 331 char **mountpoint, int *multithreaded, void *user_data) 332 { 333 return fuse_setup_common(argc, argv, op, op_size, mountpoint, 334 multithreaded, NULL, user_data, 0); 335 } 336 337 static void fuse_teardown_common(struct fuse *fuse, char *mountpoint) 338 { 339 struct fuse_session *se = fuse_get_session(fuse); 340 struct fuse_chan *ch = fuse_session_next_chan(se, NULL); 341 fuse_remove_signal_handlers(se); 342 fuse_unmount_common(mountpoint, ch); 343 fuse_destroy(fuse); 344 free(mountpoint); 345 } 346 347 void fuse_teardown(struct fuse *fuse, char *mountpoint) 348 { 349 fuse_teardown_common(fuse, mountpoint); 350 } 351 352 static int fuse_main_common(int argc, char *argv[], 353 const struct fuse_operations *op, size_t op_size, 354 void *user_data, int compat) 355 { 356 struct fuse *fuse; 357 char *mountpoint; 358 int multithreaded; 359 int res; 360 361 fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint, 362 &multithreaded, NULL, user_data, compat); 363 if (fuse == NULL) 364 return 1; 365 366 if (multithreaded) 367 res = fuse_loop_mt(fuse); 368 else 369 res = fuse_loop(fuse); 370 371 fuse_teardown_common(fuse, mountpoint); 372 if (res == -1) 373 return 1; 374 375 return 0; 376 } 377 378 int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, 379 size_t op_size, void *user_data) 380 { 381 return fuse_main_common(argc, argv, op, op_size, user_data, 0); 382 } 383 384 #undef fuse_main 385 int fuse_main(void); 386 int fuse_main(void) 387 { 388 fprintf(stderr, "fuse_main(): This function does not exist\n"); 389 return -1; 390 } 391 392 int fuse_version(void) 393 { 394 return FUSE_VERSION; 395 } 396 397 #include "fuse_compat.h" 398 399 #if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__DragonFly__) 400 401 struct fuse *fuse_setup_compat22(int argc, char *argv[], 402 const struct fuse_operations_compat22 *op, 403 size_t op_size, char **mountpoint, 404 int *multithreaded, int *fd) 405 { 406 return fuse_setup_common(argc, argv, (struct fuse_operations *) op, 407 op_size, mountpoint, multithreaded, fd, NULL, 408 22); 409 } 410 411 struct fuse *fuse_setup_compat2(int argc, char *argv[], 412 const struct fuse_operations_compat2 *op, 413 char **mountpoint, int *multithreaded, 414 int *fd) 415 { 416 return fuse_setup_common(argc, argv, (struct fuse_operations *) op, 417 sizeof(struct fuse_operations_compat2), 418 mountpoint, multithreaded, fd, NULL, 21); 419 } 420 421 int fuse_main_real_compat22(int argc, char *argv[], 422 const struct fuse_operations_compat22 *op, 423 size_t op_size) 424 { 425 return fuse_main_common(argc, argv, (struct fuse_operations *) op, 426 op_size, NULL, 22); 427 } 428 429 void fuse_main_compat1(int argc, char *argv[], 430 const struct fuse_operations_compat1 *op) 431 { 432 fuse_main_common(argc, argv, (struct fuse_operations *) op, 433 sizeof(struct fuse_operations_compat1), NULL, 11); 434 } 435 436 int fuse_main_compat2(int argc, char *argv[], 437 const struct fuse_operations_compat2 *op) 438 { 439 return fuse_main_common(argc, argv, (struct fuse_operations *) op, 440 sizeof(struct fuse_operations_compat2), NULL, 441 21); 442 } 443 444 int fuse_mount_compat1(const char *mountpoint, const char *args[]) 445 { 446 /* just ignore mount args for now */ 447 (void) args; 448 return fuse_mount_compat22(mountpoint, NULL); 449 } 450 451 FUSE_SYMVER(".symver fuse_setup_compat2,__fuse_setup@"); 452 FUSE_SYMVER(".symver fuse_setup_compat22,fuse_setup@FUSE_2.2"); 453 FUSE_SYMVER(".symver fuse_teardown,__fuse_teardown@"); 454 FUSE_SYMVER(".symver fuse_main_compat2,fuse_main@"); 455 FUSE_SYMVER(".symver fuse_main_real_compat22,fuse_main_real@FUSE_2.2"); 456 457 #endif /* __FreeBSD__ || __NetBSD__ */ 458 459 460 struct fuse *fuse_setup_compat25(int argc, char *argv[], 461 const struct fuse_operations_compat25 *op, 462 size_t op_size, char **mountpoint, 463 int *multithreaded, int *fd) 464 { 465 return fuse_setup_common(argc, argv, (struct fuse_operations *) op, 466 op_size, mountpoint, multithreaded, fd, NULL, 467 25); 468 } 469 470 int fuse_main_real_compat25(int argc, char *argv[], 471 const struct fuse_operations_compat25 *op, 472 size_t op_size) 473 { 474 return fuse_main_common(argc, argv, (struct fuse_operations *) op, 475 op_size, NULL, 25); 476 } 477 478 void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint) 479 { 480 (void) fd; 481 fuse_teardown_common(fuse, mountpoint); 482 } 483 484 int fuse_mount_compat25(const char *mountpoint, struct fuse_args *args) 485 { 486 return fuse_kern_mount(mountpoint, args); 487 } 488 489 FUSE_SYMVER(".symver fuse_setup_compat25,fuse_setup@FUSE_2.5"); 490 FUSE_SYMVER(".symver fuse_teardown_compat22,fuse_teardown@FUSE_2.2"); 491 FUSE_SYMVER(".symver fuse_main_real_compat25,fuse_main_real@FUSE_2.5"); 492 FUSE_SYMVER(".symver fuse_mount_compat25,fuse_mount@FUSE_2.5"); 493