Revert "init: chroot from recovery to /first_stage_ramdisk"
This reverts commit 56999b41af9c553787a2436ce4067aca04aa2dc6.
Reason for revert: Something is broken here; we're not switching to /system properly.
Change-Id: I777fedcfb545c11275c9cc12f99b99a2423959a0
diff --git a/init/switch_root.cpp b/init/switch_root.cpp
index cc75f31..0e59b57 100644
--- a/init/switch_root.cpp
+++ b/init/switch_root.cpp
@@ -16,6 +16,7 @@
#include "switch_root.h"
+#include <dirent.h>
#include <fcntl.h>
#include <mntent.h>
#include <sys/mount.h>
@@ -34,6 +35,45 @@
namespace {
+void FreeRamdisk(DIR* dir, dev_t dev) {
+ int dfd = dirfd(dir);
+
+ dirent* de;
+ while ((de = readdir(dir)) != nullptr) {
+ if (de->d_name == "."s || de->d_name == ".."s) {
+ continue;
+ }
+
+ bool is_dir = false;
+
+ if (de->d_type == DT_DIR || de->d_type == DT_UNKNOWN) {
+ struct stat info;
+ if (fstatat(dfd, de->d_name, &info, AT_SYMLINK_NOFOLLOW) != 0) {
+ continue;
+ }
+
+ if (info.st_dev != dev) {
+ continue;
+ }
+
+ if (S_ISDIR(info.st_mode)) {
+ is_dir = true;
+ auto fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
+ if (fd >= 0) {
+ auto subdir =
+ std::unique_ptr<DIR, decltype(&closedir)>{fdopendir(fd), closedir};
+ if (subdir) {
+ FreeRamdisk(subdir.get(), dev);
+ } else {
+ close(fd);
+ }
+ }
+ }
+ }
+ unlinkat(dfd, de->d_name, is_dir ? AT_REMOVEDIR : 0);
+ }
+}
+
std::vector<std::string> GetMounts(const std::string& new_root) {
auto fp = std::unique_ptr<std::FILE, decltype(&endmntent)>{setmntent("/proc/mounts", "re"),
endmntent};
@@ -69,32 +109,42 @@
} // namespace
-void SwitchRoot(const std::string& new_root, bool move_root_mount) {
+void SwitchRoot(const std::string& new_root) {
auto mounts = GetMounts(new_root);
- LOG(INFO) << "Switching root to '" << new_root << "'";
-
for (const auto& mount_path : mounts) {
auto new_mount_path = new_root + mount_path;
- mkdir(new_mount_path.c_str(), 0755);
if (mount(mount_path.c_str(), new_mount_path.c_str(), nullptr, MS_MOVE, nullptr) != 0) {
PLOG(FATAL) << "Unable to move mount at '" << mount_path << "'";
}
}
+ auto old_root_dir = std::unique_ptr<DIR, decltype(&closedir)>{opendir("/"), closedir};
+ if (!old_root_dir) {
+ PLOG(ERROR) << "Could not opendir(\"/\"), not freeing ramdisk";
+ }
+
+ struct stat old_root_info;
+ if (stat("/", &old_root_info) != 0) {
+ PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
+ old_root_dir.reset();
+ }
+
if (chdir(new_root.c_str()) != 0) {
PLOG(FATAL) << "Could not chdir to new_root, '" << new_root << "'";
}
- if (move_root_mount) {
- if (mount(new_root.c_str(), "/", nullptr, MS_MOVE, nullptr) != 0) {
- PLOG(FATAL) << "Unable to move root mount to new_root, '" << new_root << "'";
- }
+ if (mount(new_root.c_str(), "/", nullptr, MS_MOVE, nullptr) != 0) {
+ PLOG(FATAL) << "Unable to move root mount to new_root, '" << new_root << "'";
}
if (chroot(".") != 0) {
PLOG(FATAL) << "Unable to chroot to new root";
}
+
+ if (old_root_dir) {
+ FreeRamdisk(old_root_dir.get(), old_root_info.st_dev);
+ }
}
} // namespace init