You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

511 lines
12 KiB

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