mount.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. * Copyright (C) 2014 John Crispin <blogic@openwrt.org>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU Lesser General Public License version 2.1
  6. * as published by the Free Software Foundation
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. */
  13. #include <sys/types.h>
  14. #include <sys/stat.h>
  15. #include <sys/mount.h>
  16. #include <sys/wait.h>
  17. #include <errno.h>
  18. #include <stdio.h>
  19. #include <unistd.h>
  20. #include <string.h>
  21. #include "libfstools.h"
  22. /* this is a raw syscall - man 2 pivot_root */
  23. extern int pivot_root(const char *new_root, const char *put_old);
  24. /**
  25. * mount_move - move mounted point to the new location
  26. *
  27. * @oldroot: directory that is current location of mount point
  28. * @newroot: new directory for the mount point
  29. */
  30. int
  31. mount_move(const char *oldroot, const char *newroot, const char *dir)
  32. {
  33. #ifndef MS_MOVE
  34. #define MS_MOVE (1 << 13)
  35. #endif
  36. struct stat s;
  37. char olddir[64];
  38. char newdir[64];
  39. int ret;
  40. snprintf(olddir, sizeof(olddir), "%s%s", oldroot, dir);
  41. snprintf(newdir, sizeof(newdir), "%s%s", newroot, dir);
  42. if (stat(olddir, &s) || !S_ISDIR(s.st_mode))
  43. return -1;
  44. if (stat(newdir, &s) || !S_ISDIR(s.st_mode))
  45. return -1;
  46. ret = mount(olddir, newdir, NULL, MS_NOATIME | MS_MOVE, NULL);
  47. /* if (ret)
  48. ULOG_ERR("failed %s %s: %m\n", olddir, newdir);*/
  49. return ret;
  50. }
  51. int
  52. pivot(char *new, char *old)
  53. {
  54. char pivotdir[64];
  55. int ret;
  56. if (mount_move("", new, "/proc"))
  57. return -1;
  58. snprintf(pivotdir, sizeof(pivotdir), "%s%s", new, old);
  59. ret = pivot_root(new, pivotdir);
  60. if (ret < 0) {
  61. ULOG_ERR("pivot_root failed %s %s: %m\n", new, pivotdir);
  62. return -1;
  63. }
  64. mount_move(old, "", "/dev");
  65. mount_move(old, "", "/tmp");
  66. mount_move(old, "", "/sys");
  67. mount_move(old, "", "/overlay");
  68. return 0;
  69. }
  70. void
  71. selinux_restorecon(char *overlaydir)
  72. {
  73. struct stat s;
  74. pid_t restorecon_pid;
  75. int status;
  76. /* on non-SELinux system we don't have /sbin/restorecon, return */
  77. if (stat("/sbin/restorecon", &s))
  78. return;
  79. restorecon_pid = fork();
  80. if (!restorecon_pid)
  81. exit(execl("/sbin/restorecon", "restorecon", overlaydir, (char *) NULL));
  82. else if (restorecon_pid > 0)
  83. waitpid(restorecon_pid, &status, 0);
  84. }
  85. /**
  86. * fopivot - switch to overlay using passed dir as upper one
  87. *
  88. * @rw_root: writable directory that will be used as upper dir
  89. * @ro_root: directory where old root will be put
  90. */
  91. int
  92. fopivot(char *rw_root, char *ro_root)
  93. {
  94. char overlay[64], mount_options[64], upperdir[64], workdir[64], upgrade[64], upgrade_dest[64];
  95. struct stat st;
  96. if (find_filesystem("overlay")) {
  97. ULOG_ERR("BUG: no suitable fs found\n");
  98. return -1;
  99. }
  100. snprintf(overlay, sizeof(overlay), "overlayfs:%s", rw_root);
  101. snprintf(upperdir, sizeof(upperdir), "%s/upper", rw_root);
  102. snprintf(workdir, sizeof(workdir), "%s/work", rw_root);
  103. snprintf(upgrade, sizeof(upgrade), "%s/sysupgrade.tgz", rw_root);
  104. snprintf(upgrade_dest, sizeof(upgrade_dest), "%s/sysupgrade.tgz", upperdir);
  105. snprintf(mount_options, sizeof(mount_options), "lowerdir=/,upperdir=%s,workdir=%s",
  106. upperdir, workdir);
  107. /*
  108. * Initialize SELinux security label on newly created overlay
  109. * filesystem where /upper doesn't yet exist
  110. */
  111. if (stat(upperdir, &st))
  112. selinux_restorecon(rw_root);
  113. /*
  114. * Overlay FS v23 and later requires both a upper and
  115. * a work directory, both on the same filesystem, but
  116. * not part of the same subtree.
  117. * We can't really deal with these constraints without
  118. * creating two new subdirectories in /overlay.
  119. */
  120. if (mkdir(upperdir, 0755) == -1 && errno != EEXIST)
  121. return -1;
  122. if (mkdir(workdir, 0755) == -1 && errno != EEXIST)
  123. return -1;
  124. if (stat(upgrade, &st) == 0)
  125. rename(upgrade, upgrade_dest);
  126. if (mount(overlay, "/mnt", "overlay", MS_NOATIME, mount_options)) {
  127. ULOG_ERR("mount failed: %m, options %s\n", mount_options);
  128. return -1;
  129. }
  130. return pivot("/mnt", ro_root);
  131. }
  132. /**
  133. * ramoverlay - use RAM to store filesystem changes on top of RO root
  134. */
  135. int
  136. ramoverlay(void)
  137. {
  138. mkdir("/tmp/root", 0755);
  139. mount("tmpfs", "/tmp/root", "tmpfs", MS_NOATIME, "mode=0755");
  140. return fopivot("/tmp/root", "/rom");
  141. }