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.

397 lines
8.5 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  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_chan.h"
  9. #include "fuse_i.h"
  10. #include "fuse_lowlevel.h"
  11. #include "fuse_misc.h"
  12. #include "fuse_opt.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. "\n"
  73. );
  74. }
  75. static void helper_version(void)
  76. {
  77. fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION);
  78. }
  79. static int fuse_helper_opt_proc(void *data, const char *arg, int key,
  80. struct fuse_args *outargs)
  81. {
  82. struct helper_opts *hopts = data;
  83. switch (key) {
  84. case KEY_HELP:
  85. usage(outargs->argv[0]);
  86. /* fall through */
  87. case KEY_HELP_NOHEADER:
  88. helper_help();
  89. return fuse_opt_add_arg(outargs, "-h");
  90. case KEY_VERSION:
  91. helper_version();
  92. return 1;
  93. case FUSE_OPT_KEY_NONOPT:
  94. if (!hopts->mountpoint) {
  95. char mountpoint[PATH_MAX];
  96. if (realpath(arg, mountpoint) == NULL) {
  97. fprintf(stderr,
  98. "fuse: bad mount point `%s': %s\n",
  99. arg, strerror(errno));
  100. return -1;
  101. }
  102. return fuse_opt_add_opt(&hopts->mountpoint, mountpoint);
  103. } else {
  104. fprintf(stderr, "fuse: invalid argument `%s'\n", arg);
  105. return -1;
  106. }
  107. default:
  108. return 1;
  109. }
  110. }
  111. static int add_default_subtype(const char *progname, struct fuse_args *args)
  112. {
  113. int res;
  114. char *subtype_opt;
  115. const char *basename = strrchr(progname, '/');
  116. if (basename == NULL)
  117. basename = progname;
  118. else if (basename[1] != '\0')
  119. basename++;
  120. subtype_opt = (char *) malloc(strlen(basename) + 64);
  121. if (subtype_opt == NULL) {
  122. fprintf(stderr, "fuse: memory allocation failed\n");
  123. return -1;
  124. }
  125. sprintf(subtype_opt, "-osubtype=%s", basename);
  126. res = fuse_opt_add_arg(args, subtype_opt);
  127. free(subtype_opt);
  128. return res;
  129. }
  130. int
  131. fuse_parse_cmdline(struct fuse_args *args_,
  132. char **mountpoint_,
  133. int *foreground_)
  134. {
  135. int res;
  136. struct helper_opts hopts;
  137. memset(&hopts, 0, sizeof(hopts));
  138. res = fuse_opt_parse(args_,
  139. &hopts,
  140. fuse_helper_opts,
  141. fuse_helper_opt_proc);
  142. if(res == -1)
  143. return -1;
  144. if(!hopts.nodefault_subtype)
  145. {
  146. res = add_default_subtype(args_->argv[0], args_);
  147. if(res == -1)
  148. goto err;
  149. }
  150. if(mountpoint_)
  151. *mountpoint_ = hopts.mountpoint;
  152. else
  153. free(hopts.mountpoint);
  154. if(foreground_)
  155. *foreground_ = hopts.foreground;
  156. return 0;
  157. err:
  158. free(hopts.mountpoint);
  159. return -1;
  160. }
  161. int fuse_daemonize(int foreground)
  162. {
  163. if (!foreground) {
  164. int nullfd;
  165. int waiter[2];
  166. char completed;
  167. if (pipe(waiter)) {
  168. perror("fuse_daemonize: pipe");
  169. return -1;
  170. }
  171. /*
  172. * demonize current process by forking it and killing the
  173. * parent. This makes current process as a child of 'init'.
  174. */
  175. switch(fork()) {
  176. case -1:
  177. perror("fuse_daemonize: fork");
  178. return -1;
  179. case 0:
  180. break;
  181. default:
  182. read(waiter[0], &completed, sizeof(completed));
  183. _exit(0);
  184. }
  185. if (setsid() == -1) {
  186. perror("fuse_daemonize: setsid");
  187. return -1;
  188. }
  189. (void) chdir("/");
  190. nullfd = open("/dev/null", O_RDWR, 0);
  191. if (nullfd != -1) {
  192. (void) dup2(nullfd, 0);
  193. (void) dup2(nullfd, 1);
  194. (void) dup2(nullfd, 2);
  195. if (nullfd > 2)
  196. close(nullfd);
  197. }
  198. /* Propagate completion of daemon initializatation */
  199. completed = 1;
  200. write(waiter[1], &completed, sizeof(completed));
  201. close(waiter[0]);
  202. close(waiter[1]);
  203. }
  204. return 0;
  205. }
  206. static
  207. int
  208. fuse_mount_common(const char *mountpoint_,
  209. struct fuse_args *args_)
  210. {
  211. int fd;
  212. /*
  213. * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
  214. * would ensue.
  215. */
  216. do
  217. {
  218. fd = open("/dev/null", O_RDWR);
  219. if(fd > 2)
  220. close(fd);
  221. } while(fd >= 0 && fd <= 2);
  222. fd = fuse_kern_mount(mountpoint_,args_);
  223. if(fd == -1)
  224. return -1;
  225. return fd;
  226. }
  227. int
  228. fuse_mount(const char *mountpoint_,
  229. struct fuse_args *args_)
  230. {
  231. return fuse_mount_common(mountpoint_,args_);
  232. }
  233. void
  234. fuse_unmount(const char *mountpoint,
  235. int devfuse_fd)
  236. {
  237. if(mountpoint == NULL)
  238. return;
  239. fuse_kern_unmount(mountpoint,devfuse_fd);
  240. }
  241. struct fuse *
  242. fuse_setup_common(int argc,
  243. char *argv[],
  244. const struct fuse_operations *op,
  245. size_t op_size,
  246. char **mountpoint,
  247. void *user_data)
  248. {
  249. struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
  250. int res;
  251. int foreground;
  252. int devfuse_fd;
  253. struct fuse *fuse;
  254. res = fuse_parse_cmdline(&args, mountpoint, &foreground);
  255. if (res == -1)
  256. return NULL;
  257. devfuse_fd = fuse_mount_common(*mountpoint, &args);
  258. if(devfuse_fd == -1)
  259. {
  260. fuse_opt_free_args(&args);
  261. goto err_free;
  262. }
  263. fuse = fuse_new_common(devfuse_fd, &args, op, op_size, user_data);
  264. fuse_opt_free_args(&args);
  265. if (fuse == NULL)
  266. goto err_unmount;
  267. res = fuse_daemonize(foreground);
  268. if (res == -1)
  269. goto err_unmount;
  270. res = fuse_set_signal_handlers(fuse_get_session(fuse));
  271. if (res == -1)
  272. goto err_unmount;
  273. return fuse;
  274. err_unmount:
  275. fuse_kern_unmount(*mountpoint,devfuse_fd);
  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, void *user_data)
  285. {
  286. return fuse_setup_common(argc, argv, op, op_size, mountpoint, user_data);
  287. }
  288. static void fuse_teardown_common(struct fuse *fuse, char *mountpoint)
  289. {
  290. struct fuse_session *se = fuse_get_session(fuse);
  291. fuse_remove_signal_handlers(se);
  292. fuse_kern_unmount(mountpoint,se->devfuse_fd);
  293. fuse_destroy(fuse);
  294. free(mountpoint);
  295. }
  296. void
  297. fuse_teardown(struct fuse *fuse,
  298. char *mountpoint)
  299. {
  300. fuse_teardown_common(fuse,mountpoint);
  301. }
  302. static
  303. int
  304. fuse_main_common(int argc, char *argv[],
  305. const struct fuse_operations *op, size_t op_size,
  306. void *user_data)
  307. {
  308. struct fuse *fuse;
  309. char *mountpoint;
  310. int res;
  311. fuse = fuse_setup_common(argc, argv, op, op_size, &mountpoint,
  312. user_data);
  313. if(fuse == NULL)
  314. return 1;
  315. res = fuse_loop_mt(fuse);
  316. fuse_teardown_common(fuse,mountpoint);
  317. if (res == -1)
  318. return 1;
  319. return 0;
  320. }
  321. int
  322. fuse_main_real(int argc, char *argv[],
  323. 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);
  327. }
  328. int
  329. fuse_main(int argc,
  330. char *argv[],
  331. const struct fuse_operations *op,
  332. void *user_data)
  333. {
  334. return fuse_main_real(argc, argv, op, sizeof(*(op)), user_data);
  335. }
  336. int fuse_version(void)
  337. {
  338. return FUSE_VERSION;
  339. }