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.

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