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.

231 lines
4.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 GPL.
  5. See the file COPYING.
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <unistd.h>
  11. #include <errno.h>
  12. static char *progname;
  13. static char *xstrdup(const char *s)
  14. {
  15. char *t = strdup(s);
  16. if (!t) {
  17. fprintf(stderr, "%s: failed to allocate memory\n", progname);
  18. exit(1);
  19. }
  20. return t;
  21. }
  22. static void *xrealloc(void *oldptr, size_t size)
  23. {
  24. void *ptr = realloc(oldptr, size);
  25. if (!ptr) {
  26. fprintf(stderr, "%s: failed to allocate memory\n", progname);
  27. exit(1);
  28. }
  29. return ptr;
  30. }
  31. static void add_arg(char **cmdp, const char *opt)
  32. {
  33. size_t optlen = strlen(opt);
  34. size_t cmdlen = *cmdp ? strlen(*cmdp) : 0;
  35. char *cmd = xrealloc(*cmdp, cmdlen + optlen * 4 + 4);
  36. char *s;
  37. s = cmd + cmdlen;
  38. if (*cmdp)
  39. *s++ = ' ';
  40. *s++ = '\'';
  41. for (; *opt; opt++) {
  42. if (*opt == '\'') {
  43. *s++ = '\'';
  44. *s++ = '\\';
  45. *s++ = '\'';
  46. *s++ = '\'';
  47. } else
  48. *s++ = *opt;
  49. }
  50. *s++ = '\'';
  51. *s = '\0';
  52. *cmdp = cmd;
  53. }
  54. static char *add_option(const char *opt, char *options)
  55. {
  56. int oldlen = options ? strlen(options) : 0;
  57. options = xrealloc(options, oldlen + 1 + strlen(opt) + 1);
  58. if (!oldlen)
  59. strcpy(options, opt);
  60. else {
  61. strcat(options, ",");
  62. strcat(options, opt);
  63. }
  64. return options;
  65. }
  66. int main(int argc, char *argv[])
  67. {
  68. char *type = NULL;
  69. char *source;
  70. const char *mountpoint;
  71. char *basename;
  72. char *options = NULL;
  73. char *command = NULL;
  74. char *setuid = NULL;
  75. int i;
  76. int dev = 1;
  77. int suid = 1;
  78. progname = argv[0];
  79. basename = strrchr(argv[0], '/');
  80. if (basename)
  81. basename++;
  82. else
  83. basename = argv[0];
  84. type = "mergerfs";
  85. if (strncmp(basename, "mount.fuse.", 11) == 0)
  86. type = basename + 11;
  87. if (strncmp(basename, "mount.fuseblk.", 14) == 0)
  88. type = basename + 14;
  89. if (type && !type[0])
  90. type = NULL;
  91. if (argc < 3) {
  92. fprintf(stderr,
  93. "usage: %s %s destination [-t type] [-o opt[,opts...]]\n",
  94. progname, type ? "source" : "type#[source]");
  95. exit(1);
  96. }
  97. source = argv[1];
  98. if (!source[0])
  99. source = NULL;
  100. mountpoint = argv[2];
  101. for (i = 3; i < argc; i++) {
  102. if (strcmp(argv[i], "-v") == 0) {
  103. continue;
  104. } else if (strcmp(argv[i], "-t") == 0) {
  105. i++;
  106. if (i == argc) {
  107. fprintf(stderr,
  108. "%s: missing argument to option '-t'\n",
  109. progname);
  110. exit(1);
  111. }
  112. type = argv[i];
  113. if (strncmp(type, "fuse.", 5) == 0)
  114. type += 5;
  115. else if (strncmp(type, "fuseblk.", 8) == 0)
  116. type += 8;
  117. if (!type[0]) {
  118. fprintf(stderr,
  119. "%s: empty type given as argument to option '-t'\n",
  120. progname);
  121. exit(1);
  122. }
  123. } else if (strcmp(argv[i], "-o") == 0) {
  124. char *opts;
  125. char *opt;
  126. i++;
  127. if (i == argc)
  128. break;
  129. opts = xstrdup(argv[i]);
  130. opt = strtok(opts, ",");
  131. while (opt) {
  132. int j;
  133. int ignore = 0;
  134. const char *ignore_opts[] = { "",
  135. "user",
  136. "nouser",
  137. "users",
  138. "auto",
  139. "noauto",
  140. "_netdev",
  141. NULL};
  142. if (strncmp(opt, "setuid=", 7) == 0) {
  143. setuid = xstrdup(opt + 7);
  144. ignore = 1;
  145. }
  146. for (j = 0; ignore_opts[j]; j++)
  147. if (strcmp(opt, ignore_opts[j]) == 0)
  148. ignore = 1;
  149. if (!ignore) {
  150. if (strcmp(opt, "nodev") == 0)
  151. dev = 0;
  152. else if (strcmp(opt, "nosuid") == 0)
  153. suid = 0;
  154. options = add_option(opt, options);
  155. }
  156. opt = strtok(NULL, ",");
  157. }
  158. }
  159. }
  160. if (dev)
  161. options = add_option("dev", options);
  162. if (suid)
  163. options = add_option("suid", options);
  164. if (!type) {
  165. if (source) {
  166. type = xstrdup(source);
  167. source = strchr(type, '#');
  168. if (source)
  169. *source++ = '\0';
  170. if (!type[0]) {
  171. fprintf(stderr, "%s: empty filesystem type\n",
  172. progname);
  173. exit(1);
  174. }
  175. } else {
  176. fprintf(stderr, "%s: empty source\n", progname);
  177. exit(1);
  178. }
  179. }
  180. add_arg(&command, type);
  181. if (source)
  182. add_arg(&command, source);
  183. add_arg(&command, mountpoint);
  184. if (options) {
  185. add_arg(&command, "-o");
  186. add_arg(&command, options);
  187. }
  188. if (setuid && setuid[0]) {
  189. char *sucommand = command;
  190. command = NULL;
  191. add_arg(&command, "su");
  192. add_arg(&command, "-");
  193. add_arg(&command, setuid);
  194. add_arg(&command, "-c");
  195. add_arg(&command, sucommand);
  196. } else if (!getenv("HOME")) {
  197. /* Hack to make filesystems work in the boot environment */
  198. setenv("HOME", "/root", 0);
  199. }
  200. execl("/bin/sh", "/bin/sh", "-c", command, NULL);
  201. fprintf(stderr, "%s: failed to execute /bin/sh: %s\n", progname,
  202. strerror(errno));
  203. return 1;
  204. }