Loading init/first_stage_mount.cpp +17 −3 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ #include "first_stage_mount.h" #include <stdlib.h> #include <sys/mount.h> #include <unistd.h> #include <chrono> Loading Loading @@ -124,8 +123,18 @@ static inline bool IsDtVbmetaCompatible() { return is_android_dt_value_expected("vbmeta/compatible", "android,vbmeta"); } static bool ForceNormalBoot() { static bool force_normal_boot = []() { std::string cmdline; android::base::ReadFileToString("/proc/cmdline", &cmdline); return cmdline.find("androidboot.force_normal_boot=1") != std::string::npos; }(); return force_normal_boot; } static bool IsRecoveryMode() { return access("/system/bin/recovery", F_OK) == 0; return !ForceNormalBoot() && access("/system/bin/recovery", F_OK) == 0; } // Class Definitions Loading Loading @@ -394,11 +403,16 @@ bool FirstStageMount::MountPartitions() { [](const auto& rec) { return rec->mount_point == "/system"s; }); if (system_partition != mount_fstab_recs_.end()) { if (ForceNormalBoot()) { free((*system_partition)->mount_point); (*system_partition)->mount_point = strdup("/system_recovery_mount"); } if (!MountPartition(*system_partition)) { return false; } SwitchRoot((*system_partition)->mount_point, true); SwitchRoot((*system_partition)->mount_point); mount_fstab_recs_.erase(system_partition); } Loading init/init_first_stage.cpp +0 −81 Original line number Diff line number Diff line Loading @@ -14,8 +14,6 @@ * limitations under the License. */ #include <dirent.h> #include <fcntl.h> #include <paths.h> #include <stdlib.h> #include <sys/mount.h> Loading @@ -28,72 +26,19 @@ #include <vector> #include <android-base/chrono_utils.h> #include <android-base/file.h> #include <android-base/logging.h> #include <cutils/android_reboot.h> #include <private/android_filesystem_config.h> #include "first_stage_mount.h" #include "reboot_utils.h" #include "switch_root.h" #include "util.h" using android::base::boot_clock; using namespace std::literals; namespace android { 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); } } bool ForceNormalBoot() { std::string cmdline; android::base::ReadFileToString("/proc/cmdline", &cmdline); return cmdline.find("androidboot.force_normal_boot=1") != std::string::npos; } } // namespace int main(int argc, char** argv) { if (REBOOT_BOOTLOADER_ON_PANIC) { InstallRebootSignalHandlers(); Loading Loading @@ -172,36 +117,10 @@ int main(int argc, char** argv) { LOG(INFO) << "init first stage started!"; 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 (ForceNormalBoot()) { mkdir("/first_stage_ramdisk", 0755); SwitchRoot("/first_stage_ramdisk", false); } if (!DoFirstStageMount()) { LOG(FATAL) << "Failed to mount required partitions early ..."; } struct stat new_root_info; if (stat("/", &new_root_info) != 0) { PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk"; old_root_dir.reset(); } if (old_root_dir && old_root_info.st_dev != new_root_info.st_dev) { FreeRamdisk(old_root_dir.get(), old_root_info.st_dev); } SetInitAvbVersionInRecovery(); static constexpr uint32_t kNanosecondsPerMillisecond = 1e6; Loading init/switch_root.cpp +58 −8 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include "switch_root.h" #include <dirent.h> #include <fcntl.h> #include <mntent.h> #include <sys/mount.h> Loading @@ -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}; Loading Loading @@ -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 (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 Loading init/switch_root.h +1 −1 Original line number Diff line number Diff line Loading @@ -21,7 +21,7 @@ namespace android { namespace init { void SwitchRoot(const std::string& new_root, bool move_root_mount); void SwitchRoot(const std::string& new_root); } // namespace init } // namespace android Loading
init/first_stage_mount.cpp +17 −3 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ #include "first_stage_mount.h" #include <stdlib.h> #include <sys/mount.h> #include <unistd.h> #include <chrono> Loading Loading @@ -124,8 +123,18 @@ static inline bool IsDtVbmetaCompatible() { return is_android_dt_value_expected("vbmeta/compatible", "android,vbmeta"); } static bool ForceNormalBoot() { static bool force_normal_boot = []() { std::string cmdline; android::base::ReadFileToString("/proc/cmdline", &cmdline); return cmdline.find("androidboot.force_normal_boot=1") != std::string::npos; }(); return force_normal_boot; } static bool IsRecoveryMode() { return access("/system/bin/recovery", F_OK) == 0; return !ForceNormalBoot() && access("/system/bin/recovery", F_OK) == 0; } // Class Definitions Loading Loading @@ -394,11 +403,16 @@ bool FirstStageMount::MountPartitions() { [](const auto& rec) { return rec->mount_point == "/system"s; }); if (system_partition != mount_fstab_recs_.end()) { if (ForceNormalBoot()) { free((*system_partition)->mount_point); (*system_partition)->mount_point = strdup("/system_recovery_mount"); } if (!MountPartition(*system_partition)) { return false; } SwitchRoot((*system_partition)->mount_point, true); SwitchRoot((*system_partition)->mount_point); mount_fstab_recs_.erase(system_partition); } Loading
init/init_first_stage.cpp +0 −81 Original line number Diff line number Diff line Loading @@ -14,8 +14,6 @@ * limitations under the License. */ #include <dirent.h> #include <fcntl.h> #include <paths.h> #include <stdlib.h> #include <sys/mount.h> Loading @@ -28,72 +26,19 @@ #include <vector> #include <android-base/chrono_utils.h> #include <android-base/file.h> #include <android-base/logging.h> #include <cutils/android_reboot.h> #include <private/android_filesystem_config.h> #include "first_stage_mount.h" #include "reboot_utils.h" #include "switch_root.h" #include "util.h" using android::base::boot_clock; using namespace std::literals; namespace android { 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); } } bool ForceNormalBoot() { std::string cmdline; android::base::ReadFileToString("/proc/cmdline", &cmdline); return cmdline.find("androidboot.force_normal_boot=1") != std::string::npos; } } // namespace int main(int argc, char** argv) { if (REBOOT_BOOTLOADER_ON_PANIC) { InstallRebootSignalHandlers(); Loading Loading @@ -172,36 +117,10 @@ int main(int argc, char** argv) { LOG(INFO) << "init first stage started!"; 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 (ForceNormalBoot()) { mkdir("/first_stage_ramdisk", 0755); SwitchRoot("/first_stage_ramdisk", false); } if (!DoFirstStageMount()) { LOG(FATAL) << "Failed to mount required partitions early ..."; } struct stat new_root_info; if (stat("/", &new_root_info) != 0) { PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk"; old_root_dir.reset(); } if (old_root_dir && old_root_info.st_dev != new_root_info.st_dev) { FreeRamdisk(old_root_dir.get(), old_root_info.st_dev); } SetInitAvbVersionInRecovery(); static constexpr uint32_t kNanosecondsPerMillisecond = 1e6; Loading
init/switch_root.cpp +58 −8 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include "switch_root.h" #include <dirent.h> #include <fcntl.h> #include <mntent.h> #include <sys/mount.h> Loading @@ -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}; Loading Loading @@ -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 (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 Loading
init/switch_root.h +1 −1 Original line number Diff line number Diff line Loading @@ -21,7 +21,7 @@ namespace android { namespace init { void SwitchRoot(const std::string& new_root, bool move_root_mount); void SwitchRoot(const std::string& new_root); } // namespace init } // namespace android