diff options
author | Tom Cherry <tomcherry@google.com> | 2018-11-09 18:47:26 +0000 |
---|---|---|
committer | Tom Cherry <tomcherry@google.com> | 2018-11-09 18:47:26 +0000 |
commit | e087a6a3bbfc8abe73a0a64fc54909d9f769e8b8 (patch) | |
tree | 063156742ec8caf52a31b2791ae70f0314ca28d1 /init/switch_root.cpp | |
parent | 56999b41af9c553787a2436ce4067aca04aa2dc6 (diff) |
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
Diffstat (limited to 'init/switch_root.cpp')
-rw-r--r-- | init/switch_root.cpp | 66 |
1 files changed, 58 insertions, 8 deletions
diff --git a/init/switch_root.cpp b/init/switch_root.cpp index cc75f312e..0e59b576b 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 init { 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 @@ std::vector<std::string> GetMounts(const std::string& new_root) { } // 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 |