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.

227 lines
4.9 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  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 (type && !type[0])
  88. type = NULL;
  89. if (argc < 3) {
  90. fprintf(stderr,
  91. "usage: %s %s destination [-t type] [-o opt[,opts...]]\n",
  92. progname, type ? "source" : "type#[source]");
  93. exit(1);
  94. }
  95. source = argv[1];
  96. if (!source[0])
  97. source = NULL;
  98. mountpoint = argv[2];
  99. for (i = 3; i < argc; i++) {
  100. if (strcmp(argv[i], "-v") == 0) {
  101. continue;
  102. } else if (strcmp(argv[i], "-t") == 0) {
  103. i++;
  104. if (i == argc) {
  105. fprintf(stderr,
  106. "%s: missing argument to option '-t'\n",
  107. progname);
  108. exit(1);
  109. }
  110. type = argv[i];
  111. if (strncmp(type, "fuse.", 5) == 0)
  112. type += 5;
  113. if (!type[0]) {
  114. fprintf(stderr,
  115. "%s: empty type given as argument to option '-t'\n",
  116. progname);
  117. exit(1);
  118. }
  119. } else if (strcmp(argv[i], "-o") == 0) {
  120. char *opts;
  121. char *opt;
  122. i++;
  123. if (i == argc)
  124. break;
  125. opts = xstrdup(argv[i]);
  126. opt = strtok(opts, ",");
  127. while (opt) {
  128. int j;
  129. int ignore = 0;
  130. const char *ignore_opts[] = { "",
  131. "user",
  132. "nouser",
  133. "users",
  134. "auto",
  135. "noauto",
  136. "_netdev",
  137. NULL};
  138. if (strncmp(opt, "setuid=", 7) == 0) {
  139. setuid = xstrdup(opt + 7);
  140. ignore = 1;
  141. }
  142. for (j = 0; ignore_opts[j]; j++)
  143. if (strcmp(opt, ignore_opts[j]) == 0)
  144. ignore = 1;
  145. if (!ignore) {
  146. if (strcmp(opt, "nodev") == 0)
  147. dev = 0;
  148. else if (strcmp(opt, "nosuid") == 0)
  149. suid = 0;
  150. options = add_option(opt, options);
  151. }
  152. opt = strtok(NULL, ",");
  153. }
  154. }
  155. }
  156. if (dev)
  157. options = add_option("dev", options);
  158. if (suid)
  159. options = add_option("suid", options);
  160. if (!type) {
  161. if (source) {
  162. type = xstrdup(source);
  163. source = strchr(type, '#');
  164. if (source)
  165. *source++ = '\0';
  166. if (!type[0]) {
  167. fprintf(stderr, "%s: empty filesystem type\n",
  168. progname);
  169. exit(1);
  170. }
  171. } else {
  172. fprintf(stderr, "%s: empty source\n", progname);
  173. exit(1);
  174. }
  175. }
  176. add_arg(&command, type);
  177. if (source)
  178. add_arg(&command, source);
  179. add_arg(&command, mountpoint);
  180. if (options) {
  181. add_arg(&command, "-o");
  182. add_arg(&command, options);
  183. }
  184. if (setuid && setuid[0]) {
  185. char *sucommand = command;
  186. command = NULL;
  187. add_arg(&command, "su");
  188. add_arg(&command, "-");
  189. add_arg(&command, setuid);
  190. add_arg(&command, "-c");
  191. add_arg(&command, sucommand);
  192. } else if (!getenv("HOME")) {
  193. /* Hack to make filesystems work in the boot environment */
  194. setenv("HOME", "/root", 0);
  195. }
  196. execl("/bin/sh", "/bin/sh", "-c", command, NULL);
  197. fprintf(stderr, "%s: failed to execute /bin/sh: %s\n", progname,
  198. strerror(errno));
  199. return 1;
  200. }