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.

402 lines
8.6 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 <stdio.h>
  13. #include <stdlib.h>
  14. #include <stddef.h>
  15. #include <unistd.h>
  16. #include <string.h>
  17. #include <limits.h>
  18. #include <errno.h>
  19. #include <sys/param.h>
  20. enum {
  21. KEY_HELP,
  22. KEY_HELP_NOHEADER,
  23. KEY_VERSION,
  24. };
  25. struct helper_opts
  26. {
  27. int foreground;
  28. int nodefault_subtype;
  29. char *mountpoint;
  30. };
  31. #define FUSE_HELPER_OPT(t, p) { t, offsetof(struct helper_opts, p), 1 }
  32. static
  33. const
  34. struct fuse_opt fuse_helper_opts[] =
  35. {
  36. FUSE_HELPER_OPT("-d", foreground),
  37. FUSE_HELPER_OPT("debug", foreground),
  38. FUSE_HELPER_OPT("-f", foreground),
  39. FUSE_HELPER_OPT("fsname=", nodefault_subtype),
  40. FUSE_HELPER_OPT("subtype=", nodefault_subtype),
  41. FUSE_OPT_KEY("-h", KEY_HELP),
  42. FUSE_OPT_KEY("--help", KEY_HELP),
  43. FUSE_OPT_KEY("-ho", KEY_HELP_NOHEADER),
  44. FUSE_OPT_KEY("-V", KEY_VERSION),
  45. FUSE_OPT_KEY("--version", KEY_VERSION),
  46. FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
  47. FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
  48. FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP),
  49. FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP),
  50. FUSE_OPT_END
  51. };
  52. static void usage(const char *progname)
  53. {
  54. fprintf(stderr,
  55. "usage: %s mountpoint [options]\n\n", progname);
  56. fprintf(stderr,
  57. "general options:\n"
  58. " -o opt,[opt...] mount options\n"
  59. " -h --help print help\n"
  60. " -V --version print version\n"
  61. "\n");
  62. }
  63. static void helper_help(void)
  64. {
  65. fprintf(stderr,
  66. "FUSE options:\n"
  67. " -d -o debug enable debug output (implies -f)\n"
  68. " -f foreground 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
  128. fuse_parse_cmdline(struct fuse_args *args_,
  129. char **mountpoint_,
  130. int *foreground_)
  131. {
  132. int res;
  133. struct helper_opts hopts;
  134. memset(&hopts, 0, sizeof(hopts));
  135. res = fuse_opt_parse(args_,
  136. &hopts,
  137. fuse_helper_opts,
  138. fuse_helper_opt_proc);
  139. if(res == -1)
  140. return -1;
  141. if(!hopts.nodefault_subtype)
  142. {
  143. res = add_default_subtype(args_->argv[0], args_);
  144. if(res == -1)
  145. goto err;
  146. }
  147. if(mountpoint_)
  148. *mountpoint_ = hopts.mountpoint;
  149. else
  150. free(hopts.mountpoint);
  151. if(foreground_)
  152. *foreground_ = hopts.foreground;
  153. return 0;
  154. err:
  155. free(hopts.mountpoint);
  156. return -1;
  157. }
  158. int fuse_daemonize(int foreground)
  159. {
  160. if (!foreground) {
  161. int nullfd;
  162. int waiter[2];
  163. char completed;
  164. if (pipe(waiter)) {
  165. perror("fuse_daemonize: pipe");
  166. return -1;
  167. }
  168. /*
  169. * demonize current process by forking it and killing the
  170. * parent. This makes current process as a child of 'init'.
  171. */
  172. switch(fork()) {
  173. case -1:
  174. perror("fuse_daemonize: fork");
  175. return -1;
  176. case 0:
  177. break;
  178. default:
  179. read(waiter[0], &completed, sizeof(completed));
  180. _exit(0);
  181. }
  182. if (setsid() == -1) {
  183. perror("fuse_daemonize: setsid");
  184. return -1;
  185. }
  186. (void) chdir("/");
  187. nullfd = open("/dev/null", O_RDWR, 0);
  188. if (nullfd != -1) {
  189. (void) dup2(nullfd, 0);
  190. (void) dup2(nullfd, 1);
  191. (void) dup2(nullfd, 2);
  192. if (nullfd > 2)
  193. close(nullfd);
  194. }
  195. /* Propagate completion of daemon initializatation */
  196. completed = 1;
  197. write(waiter[1], &completed, sizeof(completed));
  198. close(waiter[0]);
  199. close(waiter[1]);
  200. }
  201. return 0;
  202. }
  203. static
  204. struct fuse_chan *
  205. fuse_mount_common(const char *mountpoint_,
  206. struct fuse_args *args_)
  207. {
  208. struct fuse_chan *ch;
  209. int fd;
  210. /*
  211. * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
  212. * would ensue.
  213. */
  214. do
  215. {
  216. fd = open("/dev/null", O_RDWR);
  217. if(fd > 2)
  218. close(fd);
  219. } while(fd >= 0 && fd <= 2);
  220. fd = fuse_kern_mount(mountpoint_,args_);
  221. if(fd == -1)
  222. return NULL;
  223. ch = fuse_kern_chan_new(fd);
  224. if(!ch)
  225. fuse_kern_unmount(mountpoint_, fd);
  226. return ch;
  227. }
  228. struct fuse_chan *
  229. fuse_mount(const char *mountpoint_,
  230. struct fuse_args *args_)
  231. {
  232. return fuse_mount_common(mountpoint_,args_);
  233. }
  234. static void fuse_unmount_common(const char *mountpoint, struct fuse_chan *ch)
  235. {
  236. if (mountpoint) {
  237. int fd = ch ? fuse_chan_clearfd(ch) : -1;
  238. fuse_kern_unmount(mountpoint, fd);
  239. if (ch)
  240. fuse_chan_destroy(ch);
  241. }
  242. }
  243. void fuse_unmount(const char *mountpoint, struct fuse_chan *ch)
  244. {
  245. fuse_unmount_common(mountpoint, ch);
  246. }
  247. struct fuse *fuse_setup_common(int argc, char *argv[],
  248. const struct fuse_operations *op,
  249. size_t op_size,
  250. char **mountpoint,
  251. int *fd)
  252. {
  253. struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
  254. struct fuse_chan *ch;
  255. struct fuse *fuse;
  256. int foreground;
  257. int res;
  258. res = fuse_parse_cmdline(&args, mountpoint, &foreground);
  259. if (res == -1)
  260. return NULL;
  261. ch = fuse_mount_common(*mountpoint, &args);
  262. if (!ch) {
  263. fuse_opt_free_args(&args);
  264. goto err_free;
  265. }
  266. fuse = fuse_new_common(ch, &args, op, op_size);
  267. fuse_opt_free_args(&args);
  268. if (fuse == NULL)
  269. goto err_unmount;
  270. res = fuse_daemonize(foreground);
  271. if (res == -1)
  272. goto err_unmount;
  273. res = fuse_set_signal_handlers(fuse_get_session(fuse));
  274. if (res == -1)
  275. goto err_unmount;
  276. if (fd)
  277. *fd = fuse_chan_fd(ch);
  278. return fuse;
  279. err_unmount:
  280. fuse_unmount_common(*mountpoint, ch);
  281. if (fuse)
  282. fuse_destroy(fuse);
  283. err_free:
  284. free(*mountpoint);
  285. return NULL;
  286. }
  287. struct fuse *fuse_setup(int argc, char *argv[],
  288. const struct fuse_operations *op, size_t op_size,
  289. char **mountpoint)
  290. {
  291. return fuse_setup_common(argc, argv, op, op_size, mountpoint,
  292. NULL);
  293. }
  294. static void fuse_teardown_common(struct fuse *fuse, char *mountpoint)
  295. {
  296. struct fuse_session *se = fuse_get_session(fuse);
  297. struct fuse_chan *ch = fuse_session_next_chan(se, NULL);
  298. fuse_remove_signal_handlers(se);
  299. fuse_unmount_common(mountpoint, ch);
  300. fuse_destroy(fuse);
  301. free(mountpoint);
  302. }
  303. void fuse_teardown(struct fuse *fuse, char *mountpoint)
  304. {
  305. fuse_teardown_common(fuse, mountpoint);
  306. }
  307. static int fuse_main_common(int argc, char *argv[],
  308. const struct fuse_operations *op, size_t op_size)
  309. {
  310. struct fuse *fuse;
  311. char *mountpoint;
  312. int res;
  313. fuse = fuse_setup_common(argc, argv, op, op_size,
  314. &mountpoint,
  315. NULL);
  316. if (fuse == NULL)
  317. return 1;
  318. res = fuse_loop_mt(fuse);
  319. fuse_teardown_common(fuse, mountpoint);
  320. if (res == -1)
  321. return 1;
  322. return 0;
  323. }
  324. int fuse_main_real(int argc,
  325. char *argv[],
  326. const struct fuse_operations *op,
  327. size_t op_size)
  328. {
  329. return fuse_main_common(argc, argv, op, op_size);
  330. }
  331. #undef fuse_main
  332. int fuse_main(void);
  333. int fuse_main(void)
  334. {
  335. fprintf(stderr, "fuse_main(): This function does not exist\n");
  336. return -1;
  337. }
  338. int fuse_version(void)
  339. {
  340. return FUSE_VERSION;
  341. }