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.

637 lines
15 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
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 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_common_compat.h"
  12. #include "mount_util.h"
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <unistd.h>
  16. #include <stddef.h>
  17. #include <string.h>
  18. #include <fcntl.h>
  19. #include <errno.h>
  20. #include <sys/poll.h>
  21. #include <sys/socket.h>
  22. #include <sys/un.h>
  23. #include <sys/wait.h>
  24. #include <sys/mount.h>
  25. #ifdef __NetBSD__
  26. #include <perfuse.h>
  27. #define MS_RDONLY MNT_RDONLY
  28. #define MS_NOSUID MNT_NOSUID
  29. #define MS_NODEV MNT_NODEV
  30. #define MS_NOEXEC MNT_NOEXEC
  31. #define MS_SYNCHRONOUS MNT_SYNCHRONOUS
  32. #define MS_NOATIME MNT_NOATIME
  33. #define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0)
  34. #endif
  35. #define FUSERMOUNT_PROG "fusermount"
  36. #define FUSE_COMMFD_ENV "_FUSE_COMMFD"
  37. #ifndef HAVE_FORK
  38. #define fork() vfork()
  39. #endif
  40. #ifndef MS_DIRSYNC
  41. #define MS_DIRSYNC 128
  42. #endif
  43. enum {
  44. KEY_KERN_FLAG,
  45. KEY_KERN_OPT,
  46. KEY_FUSERMOUNT_OPT,
  47. KEY_SUBTYPE_OPT,
  48. KEY_MTAB_OPT,
  49. KEY_ALLOW_ROOT,
  50. KEY_RO,
  51. KEY_HELP,
  52. KEY_VERSION,
  53. };
  54. struct mount_opts {
  55. int allow_other;
  56. int allow_root;
  57. int ishelp;
  58. int flags;
  59. int nonempty;
  60. int auto_unmount;
  61. char *fsname;
  62. char *subtype;
  63. char *subtype_opt;
  64. char *mtab_opts;
  65. char *fusermount_opts;
  66. char *kernel_opts;
  67. };
  68. #define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 }
  69. static const struct fuse_opt fuse_mount_opts[] = {
  70. FUSE_MOUNT_OPT("allow_other", allow_other),
  71. FUSE_MOUNT_OPT("allow_root", allow_root),
  72. FUSE_MOUNT_OPT("nonempty", nonempty),
  73. FUSE_MOUNT_OPT("auto_unmount", auto_unmount),
  74. FUSE_MOUNT_OPT("fsname=%s", fsname),
  75. FUSE_MOUNT_OPT("subtype=%s", subtype),
  76. FUSE_OPT_KEY("allow_other", KEY_KERN_OPT),
  77. FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT),
  78. FUSE_OPT_KEY("nonempty", KEY_FUSERMOUNT_OPT),
  79. FUSE_OPT_KEY("auto_unmount", KEY_FUSERMOUNT_OPT),
  80. FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT),
  81. FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT),
  82. FUSE_OPT_KEY("large_read", KEY_KERN_OPT),
  83. FUSE_OPT_KEY("blksize=", KEY_KERN_OPT),
  84. FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT),
  85. FUSE_OPT_KEY("context=", KEY_KERN_OPT),
  86. FUSE_OPT_KEY("fscontext=", KEY_KERN_OPT),
  87. FUSE_OPT_KEY("defcontext=", KEY_KERN_OPT),
  88. FUSE_OPT_KEY("rootcontext=", KEY_KERN_OPT),
  89. FUSE_OPT_KEY("max_read=", KEY_KERN_OPT),
  90. FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP),
  91. FUSE_OPT_KEY("user=", KEY_MTAB_OPT),
  92. FUSE_OPT_KEY("-r", KEY_RO),
  93. FUSE_OPT_KEY("ro", KEY_KERN_FLAG),
  94. FUSE_OPT_KEY("rw", KEY_KERN_FLAG),
  95. FUSE_OPT_KEY("suid", KEY_KERN_FLAG),
  96. FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG),
  97. FUSE_OPT_KEY("dev", KEY_KERN_FLAG),
  98. FUSE_OPT_KEY("nodev", KEY_KERN_FLAG),
  99. FUSE_OPT_KEY("exec", KEY_KERN_FLAG),
  100. FUSE_OPT_KEY("noexec", KEY_KERN_FLAG),
  101. FUSE_OPT_KEY("async", KEY_KERN_FLAG),
  102. FUSE_OPT_KEY("sync", KEY_KERN_FLAG),
  103. FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG),
  104. FUSE_OPT_KEY("atime", KEY_KERN_FLAG),
  105. FUSE_OPT_KEY("noatime", KEY_KERN_FLAG),
  106. FUSE_OPT_KEY("-h", KEY_HELP),
  107. FUSE_OPT_KEY("--help", KEY_HELP),
  108. FUSE_OPT_KEY("-V", KEY_VERSION),
  109. FUSE_OPT_KEY("--version", KEY_VERSION),
  110. FUSE_OPT_END
  111. };
  112. static void mount_help(void)
  113. {
  114. fprintf(stderr,
  115. " -o allow_other allow access to other users\n"
  116. " -o allow_root allow access to root\n"
  117. " -o auto_unmount auto unmount on process termination\n"
  118. " -o nonempty allow mounts over non-empty file/dir\n"
  119. " -o default_permissions enable permission checking by kernel\n"
  120. " -o fsname=NAME set filesystem name\n"
  121. " -o subtype=NAME set filesystem type\n"
  122. " -o large_read issue large read requests (2.4 only)\n"
  123. " -o max_read=N set maximum size of read requests\n"
  124. "\n");
  125. }
  126. static void exec_fusermount(const char *argv[])
  127. {
  128. execv(FUSERMOUNT_DIR "/mergerfs-" FUSERMOUNT_PROG, (char **) argv);
  129. execvp("mergerfs-" FUSERMOUNT_PROG, (char **) argv);
  130. execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv);
  131. execvp(FUSERMOUNT_PROG, (char **) argv);
  132. }
  133. static void mount_version(void)
  134. {
  135. int pid = fork();
  136. if (!pid) {
  137. const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL };
  138. exec_fusermount(argv);
  139. _exit(1);
  140. } else if (pid != -1)
  141. waitpid(pid, NULL, 0);
  142. }
  143. struct mount_flags {
  144. const char *opt;
  145. unsigned long flag;
  146. int on;
  147. };
  148. static const struct mount_flags mount_flags[] = {
  149. {"rw", MS_RDONLY, 0},
  150. {"ro", MS_RDONLY, 1},
  151. {"suid", MS_NOSUID, 0},
  152. {"nosuid", MS_NOSUID, 1},
  153. {"dev", MS_NODEV, 0},
  154. {"nodev", MS_NODEV, 1},
  155. {"exec", MS_NOEXEC, 0},
  156. {"noexec", MS_NOEXEC, 1},
  157. {"async", MS_SYNCHRONOUS, 0},
  158. {"sync", MS_SYNCHRONOUS, 1},
  159. {"atime", MS_NOATIME, 0},
  160. {"noatime", MS_NOATIME, 1},
  161. #ifndef __NetBSD__
  162. {"dirsync", MS_DIRSYNC, 1},
  163. #endif
  164. {NULL, 0, 0}
  165. };
  166. static void set_mount_flag(const char *s, int *flags)
  167. {
  168. int i;
  169. for (i = 0; mount_flags[i].opt != NULL; i++) {
  170. const char *opt = mount_flags[i].opt;
  171. if (strcmp(opt, s) == 0) {
  172. if (mount_flags[i].on)
  173. *flags |= mount_flags[i].flag;
  174. else
  175. *flags &= ~mount_flags[i].flag;
  176. return;
  177. }
  178. }
  179. fprintf(stderr, "fuse: internal error, can't find mount flag\n");
  180. abort();
  181. }
  182. static int fuse_mount_opt_proc(void *data, const char *arg, int key,
  183. struct fuse_args *outargs)
  184. {
  185. struct mount_opts *mo = data;
  186. switch (key) {
  187. case KEY_ALLOW_ROOT:
  188. if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 ||
  189. fuse_opt_add_arg(outargs, "-oallow_root") == -1)
  190. return -1;
  191. return 0;
  192. case KEY_RO:
  193. arg = "ro";
  194. /* fall through */
  195. case KEY_KERN_FLAG:
  196. set_mount_flag(arg, &mo->flags);
  197. return 0;
  198. case KEY_KERN_OPT:
  199. return fuse_opt_add_opt(&mo->kernel_opts, arg);
  200. case KEY_FUSERMOUNT_OPT:
  201. return fuse_opt_add_opt_escaped(&mo->fusermount_opts, arg);
  202. case KEY_SUBTYPE_OPT:
  203. return fuse_opt_add_opt(&mo->subtype_opt, arg);
  204. case KEY_MTAB_OPT:
  205. return fuse_opt_add_opt(&mo->mtab_opts, arg);
  206. case KEY_HELP:
  207. mount_help();
  208. mo->ishelp = 1;
  209. break;
  210. case KEY_VERSION:
  211. mount_version();
  212. mo->ishelp = 1;
  213. break;
  214. }
  215. return 1;
  216. }
  217. /* return value:
  218. * >= 0 => fd
  219. * -1 => error
  220. */
  221. static int receive_fd(int fd)
  222. {
  223. struct msghdr msg;
  224. struct iovec iov;
  225. char buf[1];
  226. int rv;
  227. size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)];
  228. struct cmsghdr *cmsg;
  229. iov.iov_base = buf;
  230. iov.iov_len = 1;
  231. memset(&msg, 0, sizeof(msg));
  232. msg.msg_name = 0;
  233. msg.msg_namelen = 0;
  234. msg.msg_iov = &iov;
  235. msg.msg_iovlen = 1;
  236. /* old BSD implementations should use msg_accrights instead of
  237. * msg_control; the interface is different. */
  238. msg.msg_control = ccmsg;
  239. msg.msg_controllen = sizeof(ccmsg);
  240. while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
  241. if (rv == -1) {
  242. perror("recvmsg");
  243. return -1;
  244. }
  245. if(!rv) {
  246. /* EOF */
  247. return -1;
  248. }
  249. cmsg = CMSG_FIRSTHDR(&msg);
  250. if (cmsg->cmsg_type != SCM_RIGHTS) {
  251. fprintf(stderr, "got control message of unknown type %d\n",
  252. cmsg->cmsg_type);
  253. return -1;
  254. }
  255. return *(int*)CMSG_DATA(cmsg);
  256. }
  257. void fuse_kern_unmount(const char *mountpoint, int fd)
  258. {
  259. int res;
  260. int pid;
  261. if (!mountpoint)
  262. return;
  263. if (fd != -1) {
  264. struct pollfd pfd;
  265. pfd.fd = fd;
  266. pfd.events = 0;
  267. res = poll(&pfd, 1, 0);
  268. /* Need to close file descriptor, otherwise synchronous umount
  269. would recurse into filesystem, and deadlock.
  270. Caller expects fuse_kern_unmount to close the fd, so close it
  271. anyway. */
  272. close(fd);
  273. /* If file poll returns POLLERR on the device file descriptor,
  274. then the filesystem is already unmounted */
  275. if (res == 1 && (pfd.revents & POLLERR))
  276. return;
  277. }
  278. if (geteuid() == 0) {
  279. fuse_mnt_umount("fuse", mountpoint, mountpoint, 1);
  280. return;
  281. }
  282. res = umount2(mountpoint, 2);
  283. if (res == 0)
  284. return;
  285. pid = fork();
  286. if(pid == -1)
  287. return;
  288. if(pid == 0) {
  289. const char *argv[] = { FUSERMOUNT_PROG, "-u", "-q", "-z",
  290. "--", mountpoint, NULL };
  291. exec_fusermount(argv);
  292. _exit(1);
  293. }
  294. waitpid(pid, NULL, 0);
  295. }
  296. void fuse_unmount_compat22(const char *mountpoint)
  297. {
  298. fuse_kern_unmount(mountpoint, -1);
  299. }
  300. static int fuse_mount_fusermount(const char *mountpoint, struct mount_opts *mo,
  301. const char *opts, int quiet)
  302. {
  303. int fds[2], pid;
  304. int res;
  305. int rv;
  306. if (!mountpoint) {
  307. fprintf(stderr, "fuse: missing mountpoint parameter\n");
  308. return -1;
  309. }
  310. res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
  311. if(res == -1) {
  312. perror("fuse: socketpair() failed");
  313. return -1;
  314. }
  315. pid = fork();
  316. if(pid == -1) {
  317. perror("fuse: fork() failed");
  318. close(fds[0]);
  319. close(fds[1]);
  320. return -1;
  321. }
  322. if(pid == 0) {
  323. char env[10];
  324. const char *argv[32];
  325. int a = 0;
  326. if (quiet) {
  327. int fd = open("/dev/null", O_RDONLY);
  328. if (fd != -1) {
  329. dup2(fd, 1);
  330. dup2(fd, 2);
  331. }
  332. }
  333. argv[a++] = FUSERMOUNT_PROG;
  334. if (opts) {
  335. argv[a++] = "-o";
  336. argv[a++] = opts;
  337. }
  338. argv[a++] = "--";
  339. argv[a++] = mountpoint;
  340. argv[a++] = NULL;
  341. close(fds[1]);
  342. fcntl(fds[0], F_SETFD, 0);
  343. snprintf(env, sizeof(env), "%i", fds[0]);
  344. setenv(FUSE_COMMFD_ENV, env, 1);
  345. exec_fusermount(argv);
  346. perror("fuse: failed to exec fusermount");
  347. _exit(1);
  348. }
  349. close(fds[0]);
  350. rv = receive_fd(fds[1]);
  351. if (!mo->auto_unmount) {
  352. /* with auto_unmount option fusermount will not exit until
  353. this socket is closed */
  354. close(fds[1]);
  355. waitpid(pid, NULL, 0); /* bury zombie */
  356. }
  357. return rv;
  358. }
  359. int fuse_mount_compat22(const char *mountpoint, const char *opts)
  360. {
  361. struct mount_opts mo;
  362. memset(&mo, 0, sizeof(mo));
  363. mo.flags = MS_NOSUID | MS_NODEV;
  364. return fuse_mount_fusermount(mountpoint, &mo, opts, 0);
  365. }
  366. static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
  367. const char *mnt_opts)
  368. {
  369. char tmp[128];
  370. const char *devname = "/dev/fuse";
  371. char *source = NULL;
  372. char *type = NULL;
  373. struct stat stbuf;
  374. int fd;
  375. int res;
  376. if (!mnt) {
  377. fprintf(stderr, "fuse: missing mountpoint parameter\n");
  378. return -1;
  379. }
  380. res = stat(mnt, &stbuf);
  381. if (res == -1) {
  382. fprintf(stderr ,"fuse: failed to access mountpoint %s: %s\n",
  383. mnt, strerror(errno));
  384. return -1;
  385. }
  386. if (!mo->nonempty) {
  387. res = fuse_mnt_check_empty("fuse", mnt, stbuf.st_mode,
  388. stbuf.st_size);
  389. if (res == -1)
  390. return -1;
  391. }
  392. if (mo->auto_unmount) {
  393. /* Tell the caller to fallback to fusermount because
  394. auto-unmount does not work otherwise. */
  395. return -2;
  396. }
  397. fd = open(devname, O_RDWR);
  398. if (fd == -1) {
  399. if (errno == ENODEV || errno == ENOENT)
  400. fprintf(stderr, "fuse: device not found, try 'modprobe fuse' first\n");
  401. else
  402. fprintf(stderr, "fuse: failed to open %s: %s\n",
  403. devname, strerror(errno));
  404. return -1;
  405. }
  406. snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%u,group_id=%u",
  407. fd, stbuf.st_mode & S_IFMT, getuid(), getgid());
  408. res = fuse_opt_add_opt(&mo->kernel_opts, tmp);
  409. if (res == -1)
  410. goto out_close;
  411. source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
  412. (mo->subtype ? strlen(mo->subtype) : 0) +
  413. strlen(devname) + 32);
  414. type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
  415. if (!type || !source) {
  416. fprintf(stderr, "fuse: failed to allocate memory\n");
  417. goto out_close;
  418. }
  419. strcpy(type,"fuse");
  420. if (mo->subtype) {
  421. strcat(type, ".");
  422. strcat(type, mo->subtype);
  423. }
  424. strcpy(source,
  425. mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
  426. res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
  427. if (res == -1 && errno == ENODEV && mo->subtype) {
  428. /* Probably missing subtype support */
  429. strcpy(type,"fuse");
  430. if (mo->fsname) {
  431. sprintf(source, "%s#%s", mo->subtype, mo->fsname);
  432. } else {
  433. strcpy(source, type);
  434. }
  435. res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
  436. }
  437. if (res == -1) {
  438. /*
  439. * Maybe kernel doesn't support unprivileged mounts, in this
  440. * case try falling back to fusermount
  441. */
  442. if (errno == EPERM) {
  443. res = -2;
  444. } else {
  445. int errno_save = errno;
  446. fprintf(stderr,
  447. "fuse: mount failed: %s\n",
  448. strerror(errno_save));
  449. }
  450. goto out_close;
  451. }
  452. #ifndef __NetBSD__
  453. #ifndef IGNORE_MTAB
  454. if (geteuid() == 0) {
  455. char *newmnt = fuse_mnt_resolve_path("fuse", mnt);
  456. res = -1;
  457. if (!newmnt)
  458. goto out_umount;
  459. res = fuse_mnt_add_mount("fuse", source, newmnt, type,
  460. mnt_opts);
  461. free(newmnt);
  462. if (res == -1)
  463. goto out_umount;
  464. }
  465. #endif /* IGNORE_MTAB */
  466. #endif /* __NetBSD__ */
  467. free(type);
  468. free(source);
  469. return fd;
  470. out_umount:
  471. umount2(mnt, 2); /* lazy umount */
  472. out_close:
  473. free(type);
  474. free(source);
  475. close(fd);
  476. return res;
  477. }
  478. static int get_mnt_flag_opts(char **mnt_optsp, int flags)
  479. {
  480. int i;
  481. if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1)
  482. return -1;
  483. for (i = 0; mount_flags[i].opt != NULL; i++) {
  484. if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
  485. fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1)
  486. return -1;
  487. }
  488. return 0;
  489. }
  490. int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
  491. {
  492. struct mount_opts mo;
  493. int res = -1;
  494. char *mnt_opts = NULL;
  495. memset(&mo, 0, sizeof(mo));
  496. mo.flags = MS_NOSUID | MS_NODEV;
  497. if (args &&
  498. fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
  499. return -1;
  500. if (mo.allow_other && mo.allow_root) {
  501. fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");
  502. goto out;
  503. }
  504. res = 0;
  505. if (mo.ishelp)
  506. goto out;
  507. res = -1;
  508. if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1)
  509. goto out;
  510. if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1)
  511. goto out;
  512. if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1)
  513. goto out;
  514. res = fuse_mount_sys(mountpoint, &mo, mnt_opts);
  515. if (res == -2) {
  516. if (mo.fusermount_opts &&
  517. fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1)
  518. goto out;
  519. if (mo.subtype) {
  520. char *tmp_opts = NULL;
  521. res = -1;
  522. if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 ||
  523. fuse_opt_add_opt(&tmp_opts, mo.subtype_opt) == -1) {
  524. free(tmp_opts);
  525. goto out;
  526. }
  527. res = fuse_mount_fusermount(mountpoint, &mo, tmp_opts, 1);
  528. free(tmp_opts);
  529. if (res == -1)
  530. res = fuse_mount_fusermount(mountpoint, &mo,
  531. mnt_opts, 0);
  532. } else {
  533. res = fuse_mount_fusermount(mountpoint, &mo, mnt_opts, 0);
  534. }
  535. }
  536. out:
  537. free(mnt_opts);
  538. free(mo.fsname);
  539. free(mo.subtype);
  540. free(mo.fusermount_opts);
  541. free(mo.subtype_opt);
  542. free(mo.kernel_opts);
  543. free(mo.mtab_opts);
  544. return res;
  545. }
  546. FUSE_SYMVER(".symver fuse_mount_compat22,fuse_mount@FUSE_2.2");
  547. FUSE_SYMVER(".symver fuse_unmount_compat22,fuse_unmount@FUSE_2.2");