diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp index a4ded922f..eb86eb087 100644 --- a/init/first_stage_mount.cpp +++ b/init/first_stage_mount.cpp @@ -17,7 +17,6 @@ #include "first_stage_mount.h" #include -#include #include #include @@ -123,8 +122,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 @@ -362,11 +371,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); } diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp index 4ab18021b..d81ca5c35 100644 --- a/init/init_first_stage.cpp +++ b/init/init_first_stage.cpp @@ -14,8 +14,6 @@ * limitations under the License. */ -#include -#include #include #include #include @@ -28,72 +26,19 @@ #include #include -#include #include #include #include #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{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(); @@ -172,36 +117,10 @@ int main(int argc, char** argv) { LOG(INFO) << "init first stage started!"; - auto old_root_dir = std::unique_ptr{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; 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 #include #include #include @@ -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{fdopendir(fd), closedir}; + if (subdir) { + FreeRamdisk(subdir.get(), dev); + } else { + close(fd); + } + } + } + } + unlinkat(dfd, de->d_name, is_dir ? AT_REMOVEDIR : 0); + } +} + std::vector GetMounts(const std::string& new_root) { auto fp = std::unique_ptr{setmntent("/proc/mounts", "re"), endmntent}; @@ -69,32 +109,42 @@ std::vector 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{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 diff --git a/init/switch_root.h b/init/switch_root.h index e12ccee48..d515e5dd7 100644 --- a/init/switch_root.h +++ b/init/switch_root.h @@ -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