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.

407 lines
8.7 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. int fd;
  207. long bufsize;
  208. long pagesize;
  209. struct fuse_chan *ch;
  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. pagesize = sysconf(_SC_PAGESIZE);
  224. bufsize = ((FUSE_MAX_MAX_PAGES + 1) * pagesize);
  225. ch = fuse_chan_new(fd,bufsize);
  226. if(!ch)
  227. fuse_kern_unmount(mountpoint_, fd);
  228. return ch;
  229. }
  230. struct fuse_chan *
  231. fuse_mount(const char *mountpoint_,
  232. struct fuse_args *args_)
  233. {
  234. return fuse_mount_common(mountpoint_,args_);
  235. }
  236. static void fuse_unmount_common(const char *mountpoint, struct fuse_chan *ch)
  237. {
  238. if (mountpoint) {
  239. int fd = ch ? fuse_chan_clearfd(ch) : -1;
  240. fuse_kern_unmount(mountpoint, fd);
  241. if (ch)
  242. fuse_chan_destroy(ch);
  243. }
  244. }
  245. void fuse_unmount(const char *mountpoint, struct fuse_chan *ch)
  246. {
  247. fuse_unmount_common(mountpoint, ch);
  248. }
  249. struct fuse *
  250. fuse_setup_common(int argc,
  251. char *argv[],
  252. const struct fuse_operations *op,
  253. size_t op_size,
  254. char **mountpoint,
  255. int *fd)
  256. {
  257. struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
  258. struct fuse_chan *ch;
  259. struct fuse *fuse;
  260. int foreground;
  261. int res;
  262. res = fuse_parse_cmdline(&args, mountpoint, &foreground);
  263. if (res == -1)
  264. return NULL;
  265. ch = fuse_mount_common(*mountpoint, &args);
  266. if (!ch) {
  267. fuse_opt_free_args(&args);
  268. goto err_free;
  269. }
  270. fuse = fuse_new_common(ch, &args, op, op_size);
  271. fuse_opt_free_args(&args);
  272. if (fuse == NULL)
  273. goto err_unmount;
  274. res = fuse_daemonize(foreground);
  275. if (res == -1)
  276. goto err_unmount;
  277. res = fuse_set_signal_handlers(fuse_get_session(fuse));
  278. if (res == -1)
  279. goto err_unmount;
  280. if (fd)
  281. *fd = fuse_chan_fd(ch);
  282. return fuse;
  283. err_unmount:
  284. fuse_unmount_common(*mountpoint, ch);
  285. if (fuse)
  286. fuse_destroy(fuse);
  287. err_free:
  288. free(*mountpoint);
  289. return NULL;
  290. }
  291. struct fuse *fuse_setup(int argc, char *argv[],
  292. const struct fuse_operations *op, size_t op_size,
  293. char **mountpoint)
  294. {
  295. return fuse_setup_common(argc, argv, op, op_size, mountpoint,
  296. NULL);
  297. }
  298. static void fuse_teardown_common(struct fuse *fuse, char *mountpoint)
  299. {
  300. struct fuse_session *se = fuse_get_session(fuse);
  301. struct fuse_chan *ch = se->ch;
  302. fuse_remove_signal_handlers(se);
  303. fuse_unmount_common(mountpoint, ch);
  304. fuse_destroy(fuse);
  305. free(mountpoint);
  306. }
  307. void fuse_teardown(struct fuse *fuse, char *mountpoint)
  308. {
  309. fuse_teardown_common(fuse, mountpoint);
  310. }
  311. static int fuse_main_common(int argc, char *argv[],
  312. const struct fuse_operations *op, size_t op_size)
  313. {
  314. struct fuse *fuse;
  315. char *mountpoint;
  316. int res;
  317. fuse = fuse_setup_common(argc, argv, op, op_size,
  318. &mountpoint,
  319. NULL);
  320. if (fuse == NULL)
  321. return 1;
  322. res = fuse_loop_mt(fuse);
  323. fuse_teardown_common(fuse, mountpoint);
  324. if (res == -1)
  325. return 1;
  326. return 0;
  327. }
  328. int fuse_main_real(int argc,
  329. char *argv[],
  330. const struct fuse_operations *op,
  331. size_t op_size)
  332. {
  333. return fuse_main_common(argc, argv, op, op_size);
  334. }
  335. #undef fuse_main
  336. int fuse_main(void);
  337. int fuse_main(void)
  338. {
  339. fprintf(stderr, "fuse_main(): This function does not exist\n");
  340. return -1;
  341. }
  342. int fuse_version(void)
  343. {
  344. return FUSE_VERSION;
  345. }