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.

363 lines
7.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 "mount_util.h"
  8. #include <stdio.h>
  9. #include <unistd.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <signal.h>
  13. #include <dirent.h>
  14. #include <errno.h>
  15. #include <fcntl.h>
  16. #include <limits.h>
  17. #include <paths.h>
  18. #ifndef __NetBSD__
  19. #include <mntent.h>
  20. #endif
  21. #include <sys/stat.h>
  22. #include <sys/wait.h>
  23. #include <sys/mount.h>
  24. #include <sys/param.h>
  25. #ifdef __NetBSD__
  26. #define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0)
  27. #define mtab_needs_update(mnt) 0
  28. #else
  29. static int mtab_needs_update(const char *mnt)
  30. {
  31. int res;
  32. struct stat stbuf;
  33. /* If mtab is within new mount, don't touch it */
  34. if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 &&
  35. _PATH_MOUNTED[strlen(mnt)] == '/')
  36. return 0;
  37. /*
  38. * Skip mtab update if /etc/mtab:
  39. *
  40. * - doesn't exist,
  41. * - is a symlink,
  42. * - is on a read-only filesystem.
  43. */
  44. res = lstat(_PATH_MOUNTED, &stbuf);
  45. if (res == -1) {
  46. if (errno == ENOENT)
  47. return 0;
  48. } else {
  49. uid_t ruid;
  50. int err;
  51. if (S_ISLNK(stbuf.st_mode))
  52. return 0;
  53. ruid = getuid();
  54. if (ruid != 0)
  55. setreuid(0, -1);
  56. res = access(_PATH_MOUNTED, W_OK);
  57. err = (res == -1) ? errno : 0;
  58. if (ruid != 0)
  59. setreuid(ruid, -1);
  60. if (err == EROFS)
  61. return 0;
  62. }
  63. return 1;
  64. }
  65. #endif /* __NetBSD__ */
  66. static int add_mount(const char *progname, const char *fsname,
  67. const char *mnt, const char *type, const char *opts)
  68. {
  69. int res;
  70. int status;
  71. sigset_t blockmask;
  72. sigset_t oldmask;
  73. sigemptyset(&blockmask);
  74. sigaddset(&blockmask, SIGCHLD);
  75. res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
  76. if (res == -1) {
  77. fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
  78. return -1;
  79. }
  80. res = fork();
  81. if (res == -1) {
  82. fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
  83. goto out_restore;
  84. }
  85. if (res == 0) {
  86. char *env = NULL;
  87. sigprocmask(SIG_SETMASK, &oldmask, NULL);
  88. setuid(geteuid());
  89. execle("/bin/mount", "/bin/mount", "--no-canonicalize", "-i",
  90. "-f", "-t", type, "-o", opts, fsname, mnt, NULL, &env);
  91. fprintf(stderr, "%s: failed to execute /bin/mount: %s\n",
  92. progname, strerror(errno));
  93. exit(1);
  94. }
  95. res = waitpid(res, &status, 0);
  96. if (res == -1)
  97. fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
  98. if (status != 0)
  99. res = -1;
  100. out_restore:
  101. sigprocmask(SIG_SETMASK, &oldmask, NULL);
  102. return res;
  103. }
  104. int fuse_mnt_add_mount(const char *progname, const char *fsname,
  105. const char *mnt, const char *type, const char *opts)
  106. {
  107. if (!mtab_needs_update(mnt))
  108. return 0;
  109. return add_mount(progname, fsname, mnt, type, opts);
  110. }
  111. static int exec_umount(const char *progname, const char *rel_mnt, int lazy)
  112. {
  113. int res;
  114. int status;
  115. sigset_t blockmask;
  116. sigset_t oldmask;
  117. sigemptyset(&blockmask);
  118. sigaddset(&blockmask, SIGCHLD);
  119. res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
  120. if (res == -1) {
  121. fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
  122. return -1;
  123. }
  124. res = fork();
  125. if (res == -1) {
  126. fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
  127. goto out_restore;
  128. }
  129. if (res == 0) {
  130. char *env = NULL;
  131. sigprocmask(SIG_SETMASK, &oldmask, NULL);
  132. setuid(geteuid());
  133. if (lazy) {
  134. execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
  135. "-l", NULL, &env);
  136. } else {
  137. execle("/bin/umount", "/bin/umount", "-i", rel_mnt,
  138. NULL, &env);
  139. }
  140. fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
  141. progname, strerror(errno));
  142. exit(1);
  143. }
  144. res = waitpid(res, &status, 0);
  145. if (res == -1)
  146. fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
  147. if (status != 0) {
  148. res = -1;
  149. }
  150. out_restore:
  151. sigprocmask(SIG_SETMASK, &oldmask, NULL);
  152. return res;
  153. }
  154. int fuse_mnt_umount(const char *progname, const char *abs_mnt,
  155. const char *rel_mnt, int lazy)
  156. {
  157. int res;
  158. if (!mtab_needs_update(abs_mnt)) {
  159. res = umount2(rel_mnt, lazy ? 2 : 0);
  160. if (res == -1)
  161. fprintf(stderr, "%s: failed to unmount %s: %s\n",
  162. progname, abs_mnt, strerror(errno));
  163. return res;
  164. }
  165. return exec_umount(progname, rel_mnt, lazy);
  166. }
  167. static int remove_mount(const char *progname, const char *mnt)
  168. {
  169. int res;
  170. int status;
  171. sigset_t blockmask;
  172. sigset_t oldmask;
  173. sigemptyset(&blockmask);
  174. sigaddset(&blockmask, SIGCHLD);
  175. res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
  176. if (res == -1) {
  177. fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
  178. return -1;
  179. }
  180. res = fork();
  181. if (res == -1) {
  182. fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
  183. goto out_restore;
  184. }
  185. if (res == 0) {
  186. char *env = NULL;
  187. sigprocmask(SIG_SETMASK, &oldmask, NULL);
  188. setuid(geteuid());
  189. execle("/bin/umount", "/bin/umount", "--no-canonicalize", "-i",
  190. "--fake", mnt, NULL, &env);
  191. fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
  192. progname, strerror(errno));
  193. exit(1);
  194. }
  195. res = waitpid(res, &status, 0);
  196. if (res == -1)
  197. fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
  198. if (status != 0)
  199. res = -1;
  200. out_restore:
  201. sigprocmask(SIG_SETMASK, &oldmask, NULL);
  202. return res;
  203. }
  204. int fuse_mnt_remove_mount(const char *progname, const char *mnt)
  205. {
  206. if (!mtab_needs_update(mnt))
  207. return 0;
  208. return remove_mount(progname, mnt);
  209. }
  210. char *fuse_mnt_resolve_path(const char *progname, const char *orig)
  211. {
  212. char buf[PATH_MAX];
  213. char *copy;
  214. char *dst;
  215. char *end;
  216. char *lastcomp;
  217. const char *toresolv;
  218. if (!orig[0]) {
  219. fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname,
  220. orig);
  221. return NULL;
  222. }
  223. copy = strdup(orig);
  224. if (copy == NULL) {
  225. fprintf(stderr, "%s: failed to allocate memory\n", progname);
  226. return NULL;
  227. }
  228. toresolv = copy;
  229. lastcomp = NULL;
  230. for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
  231. if (end[0] != '/') {
  232. char *tmp;
  233. end[1] = '\0';
  234. tmp = strrchr(copy, '/');
  235. if (tmp == NULL) {
  236. lastcomp = copy;
  237. toresolv = ".";
  238. } else {
  239. lastcomp = tmp + 1;
  240. if (tmp == copy)
  241. toresolv = "/";
  242. }
  243. if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
  244. lastcomp = NULL;
  245. toresolv = copy;
  246. }
  247. else if (tmp)
  248. tmp[0] = '\0';
  249. }
  250. if (realpath(toresolv, buf) == NULL) {
  251. fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
  252. strerror(errno));
  253. free(copy);
  254. return NULL;
  255. }
  256. if (lastcomp == NULL)
  257. dst = strdup(buf);
  258. else {
  259. dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
  260. if (dst) {
  261. unsigned buflen = strlen(buf);
  262. if (buflen && buf[buflen-1] == '/')
  263. sprintf(dst, "%s%s", buf, lastcomp);
  264. else
  265. sprintf(dst, "%s/%s", buf, lastcomp);
  266. }
  267. }
  268. free(copy);
  269. if (dst == NULL)
  270. fprintf(stderr, "%s: failed to allocate memory\n", progname);
  271. return dst;
  272. }
  273. int fuse_mnt_check_empty(const char *progname, const char *mnt,
  274. mode_t rootmode, off_t rootsize)
  275. {
  276. int isempty = 1;
  277. if (S_ISDIR(rootmode)) {
  278. struct dirent *ent;
  279. DIR *dp = opendir(mnt);
  280. if (dp == NULL) {
  281. fprintf(stderr,
  282. "%s: failed to open mountpoint for reading: %s\n",
  283. progname, strerror(errno));
  284. return -1;
  285. }
  286. while ((ent = readdir(dp)) != NULL) {
  287. if (strcmp(ent->d_name, ".") != 0 &&
  288. strcmp(ent->d_name, "..") != 0) {
  289. isempty = 0;
  290. break;
  291. }
  292. }
  293. closedir(dp);
  294. } else if (rootsize)
  295. isempty = 0;
  296. if (!isempty) {
  297. fprintf(stderr, "%s: mountpoint is not empty\n", progname);
  298. fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);
  299. return -1;
  300. }
  301. return 0;
  302. }
  303. int fuse_mnt_check_fuseblk(void)
  304. {
  305. char buf[256];
  306. FILE *f = fopen("/proc/filesystems", "r");
  307. if (!f)
  308. return 1;
  309. while (fgets(buf, sizeof(buf), f))
  310. if (strstr(buf, "fuseblk\n")) {
  311. fclose(f);
  312. return 1;
  313. }
  314. fclose(f);
  315. return 0;
  316. }