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.

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