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.

327 lines
6.9 KiB

  1. /*
  2. FUSE: Filesystem in Userspace
  3. Copyright (C) 2005-2008 Csaba Henk <csaba.henk@creo.hu>
  4. This program can be distributed under the terms of the GNU LGPLv2.
  5. See the file COPYING.LIB.
  6. */
  7. #include "fuse_i.h"
  8. #include "fuse_misc.h"
  9. #include "fuse_opt.h"
  10. #include <sys/stat.h>
  11. #include <sys/wait.h>
  12. #include <sys/sysctl.h>
  13. #include <sys/user.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <unistd.h>
  17. #include <stddef.h>
  18. #include <fcntl.h>
  19. #include <errno.h>
  20. #include <string.h>
  21. #include <paths.h>
  22. #include <limits.h>
  23. #define FUSERMOUNT_PROG "mount_fusefs"
  24. #define FUSE_DEV_TRUNK "/dev/fuse"
  25. enum {
  26. KEY_RO,
  27. KEY_HELP,
  28. KEY_VERSION,
  29. KEY_KERN
  30. };
  31. struct mount_opts {
  32. int allow_other;
  33. int ishelp;
  34. char *kernel_opts;
  35. };
  36. #define FUSE_DUAL_OPT_KEY(templ, key) \
  37. FUSE_OPT_KEY(templ, key), FUSE_OPT_KEY("no" templ, key)
  38. static const struct fuse_opt fuse_mount_opts[] = {
  39. { "allow_other", offsetof(struct mount_opts, allow_other), 1 },
  40. FUSE_OPT_KEY("-r", KEY_RO),
  41. FUSE_OPT_KEY("-h", KEY_HELP),
  42. FUSE_OPT_KEY("--help", KEY_HELP),
  43. FUSE_OPT_KEY("-V", KEY_VERSION),
  44. FUSE_OPT_KEY("--version", KEY_VERSION),
  45. /* standard FreeBSD mount options */
  46. FUSE_DUAL_OPT_KEY("dev", KEY_KERN),
  47. FUSE_DUAL_OPT_KEY("async", KEY_KERN),
  48. FUSE_DUAL_OPT_KEY("atime", KEY_KERN),
  49. FUSE_DUAL_OPT_KEY("dev", KEY_KERN),
  50. FUSE_DUAL_OPT_KEY("exec", KEY_KERN),
  51. FUSE_DUAL_OPT_KEY("suid", KEY_KERN),
  52. FUSE_DUAL_OPT_KEY("symfollow", KEY_KERN),
  53. FUSE_DUAL_OPT_KEY("rdonly", KEY_KERN),
  54. FUSE_DUAL_OPT_KEY("sync", KEY_KERN),
  55. FUSE_DUAL_OPT_KEY("union", KEY_KERN),
  56. FUSE_DUAL_OPT_KEY("userquota", KEY_KERN),
  57. FUSE_DUAL_OPT_KEY("groupquota", KEY_KERN),
  58. FUSE_DUAL_OPT_KEY("clusterr", KEY_KERN),
  59. FUSE_DUAL_OPT_KEY("clusterw", KEY_KERN),
  60. FUSE_DUAL_OPT_KEY("suiddir", KEY_KERN),
  61. FUSE_DUAL_OPT_KEY("snapshot", KEY_KERN),
  62. FUSE_DUAL_OPT_KEY("multilabel", KEY_KERN),
  63. FUSE_DUAL_OPT_KEY("acls", KEY_KERN),
  64. FUSE_DUAL_OPT_KEY("force", KEY_KERN),
  65. FUSE_DUAL_OPT_KEY("update", KEY_KERN),
  66. FUSE_DUAL_OPT_KEY("ro", KEY_KERN),
  67. FUSE_DUAL_OPT_KEY("rw", KEY_KERN),
  68. FUSE_DUAL_OPT_KEY("auto", KEY_KERN),
  69. /* options supported under both Linux and FBSD */
  70. FUSE_DUAL_OPT_KEY("allow_other", KEY_KERN),
  71. FUSE_DUAL_OPT_KEY("default_permissions",KEY_KERN),
  72. FUSE_OPT_KEY("max_read=", KEY_KERN),
  73. FUSE_OPT_KEY("subtype=", KEY_KERN),
  74. /* FBSD FUSE specific mount options */
  75. FUSE_DUAL_OPT_KEY("private", KEY_KERN),
  76. FUSE_DUAL_OPT_KEY("neglect_shares", KEY_KERN),
  77. FUSE_DUAL_OPT_KEY("push_symlinks_in", KEY_KERN),
  78. FUSE_OPT_KEY("nosync_unmount", KEY_KERN),
  79. /* stock FBSD mountopt parsing routine lets anything be negated... */
  80. /*
  81. * Linux specific mount options, but let just the mount util
  82. * handle them
  83. */
  84. FUSE_OPT_KEY("fsname=", KEY_KERN),
  85. FUSE_OPT_KEY("nonempty", KEY_KERN),
  86. FUSE_OPT_KEY("large_read", KEY_KERN),
  87. FUSE_OPT_END
  88. };
  89. static void mount_help(void)
  90. {
  91. fprintf(stderr,
  92. );
  93. system(FUSERMOUNT_PROG " --help");
  94. fputc('\n', stderr);
  95. }
  96. static void mount_version(void)
  97. {
  98. system(FUSERMOUNT_PROG " --version");
  99. }
  100. static int fuse_mount_opt_proc(void *data, const char *arg, int key,
  101. struct fuse_args *outargs)
  102. {
  103. struct mount_opts *mo = data;
  104. switch (key) {
  105. case KEY_RO:
  106. arg = "ro";
  107. /* fall through */
  108. case KEY_KERN:
  109. return fuse_opt_add_opt(&mo->kernel_opts, arg);
  110. case KEY_HELP:
  111. mount_help();
  112. mo->ishelp = 1;
  113. break;
  114. case KEY_VERSION:
  115. mount_version();
  116. mo->ishelp = 1;
  117. break;
  118. }
  119. return 1;
  120. }
  121. static void do_unmount(char *dev, int fd)
  122. {
  123. char device_path[SPECNAMELEN + 12];
  124. const char *argv[4];
  125. const char umount_cmd[] = "/sbin/umount";
  126. pid_t pid;
  127. snprintf(device_path, SPECNAMELEN + 12, _PATH_DEV "%s", dev);
  128. argv[0] = umount_cmd;
  129. argv[1] = "-f";
  130. argv[2] = device_path;
  131. argv[3] = NULL;
  132. pid = fork();
  133. if (pid == -1)
  134. return;
  135. if (pid == 0) {
  136. close(fd);
  137. execvp(umount_cmd, (char **)argv);
  138. exit(1);
  139. }
  140. waitpid(pid, NULL, 0);
  141. }
  142. void fuse_kern_unmount(const char *mountpoint, int fd)
  143. {
  144. char *ep, dev[128];
  145. struct stat sbuf;
  146. (void)mountpoint;
  147. if (fstat(fd, &sbuf) == -1)
  148. goto out;
  149. devname_r(sbuf.st_rdev, S_IFCHR, dev, 128);
  150. if (strncmp(dev, "fuse", 4))
  151. goto out;
  152. strtol(dev + 4, &ep, 10);
  153. if (*ep != '\0')
  154. goto out;
  155. do_unmount(dev, fd);
  156. out:
  157. close(fd);
  158. }
  159. /* Check if kernel is doing init in background */
  160. static int init_backgrounded(void)
  161. {
  162. unsigned ibg, len;
  163. len = sizeof(ibg);
  164. if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg, &len, NULL, 0))
  165. return 0;
  166. return ibg;
  167. }
  168. static int fuse_mount_core(const char *mountpoint, const char *opts)
  169. {
  170. const char *mountprog = FUSERMOUNT_PROG;
  171. int fd;
  172. char *fdnam, *dev;
  173. pid_t pid, cpid;
  174. int status;
  175. fdnam = getenv("FUSE_DEV_FD");
  176. if (fdnam) {
  177. char *ep;
  178. fd = strtol(fdnam, &ep, 10);
  179. if (*ep != '\0') {
  180. fprintf(stderr, "invalid value given in FUSE_DEV_FD\n");
  181. return -1;
  182. }
  183. if (fd < 0)
  184. return -1;
  185. goto mount;
  186. }
  187. dev = getenv("FUSE_DEV_NAME");
  188. if (! dev)
  189. dev = (char *)FUSE_DEV_TRUNK;
  190. if ((fd = open(dev, O_RDWR)) < 0) {
  191. perror("fuse: failed to open fuse device");
  192. return -1;
  193. }
  194. mount:
  195. if (getenv("FUSE_NO_MOUNT") || ! mountpoint)
  196. goto out;
  197. pid = fork();
  198. cpid = pid;
  199. if (pid == -1) {
  200. perror("fuse: fork() failed");
  201. close(fd);
  202. return -1;
  203. }
  204. if (pid == 0) {
  205. if (! init_backgrounded()) {
  206. /*
  207. * If init is not backgrounded, we have to
  208. * call the mount util backgrounded, to avoid
  209. * deadlock.
  210. */
  211. pid = fork();
  212. if (pid == -1) {
  213. perror("fuse: fork() failed");
  214. close(fd);
  215. exit(1);
  216. }
  217. }
  218. if (pid == 0) {
  219. const char *argv[32];
  220. int a = 0;
  221. if (! fdnam && asprintf(&fdnam, "%d", fd) == -1) {
  222. perror("fuse: failed to assemble mount arguments");
  223. exit(1);
  224. }
  225. argv[a++] = mountprog;
  226. if (opts) {
  227. argv[a++] = "-o";
  228. argv[a++] = opts;
  229. }
  230. argv[a++] = fdnam;
  231. argv[a++] = mountpoint;
  232. argv[a++] = NULL;
  233. execvp(mountprog, (char **) argv);
  234. perror("fuse: failed to exec mount program");
  235. exit(1);
  236. }
  237. exit(0);
  238. }
  239. if (waitpid(cpid, &status, 0) == -1 || WEXITSTATUS(status) != 0) {
  240. perror("fuse: failed to mount file system");
  241. close(fd);
  242. return -1;
  243. }
  244. out:
  245. return fd;
  246. }
  247. int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
  248. {
  249. struct mount_opts mo;
  250. int res = -1;
  251. memset(&mo, 0, sizeof(mo));
  252. /* mount util should not try to spawn the daemon */
  253. setenv("MOUNT_FUSEFS_SAFE", "1", 1);
  254. /* to notify the mount util it's called from lib */
  255. setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1);
  256. if (args &&
  257. fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
  258. return -1;
  259. if (mo.ishelp)
  260. return 0;
  261. res = fuse_mount_core(mountpoint, mo.kernel_opts);
  262. out:
  263. free(mo.kernel_opts);
  264. return res;
  265. }