init: chroot from recovery to /first_stage_ramdisk

When using the recovery image as a trampoline to boot the system,
first chroot from the recovery image to /first_stage_ramdisk, to
minimize differences between these two boot paths.

Primary motivation is due to the fact that the basename of each mount
point is used by device-manager to name its nodes, and the previous
code that created used /system_recovery_mount as the mount point for
system.img broke AVB.  Instead of hacking around that issue, this
change unified mounting for the recovery trampoline and true first
stage ramdisk paths.

Bug: 114062208
Test: AVB works with blueline_mainline
Change-Id: Iffb154962b6e160150917e068f1e7d0bf7cb84e7
diff --git a/init/switch_root.cpp b/init/switch_root.cpp
index 0e59b57..cc75f31 100644
--- a/init/switch_root.cpp
+++ b/init/switch_root.cpp
@@ -16,7 +16,6 @@
 
 #include "switch_root.h"
 
-#include <dirent.h>
 #include <fcntl.h>
 #include <mntent.h>
 #include <sys/mount.h>
@@ -35,45 +34,6 @@
 
 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};
@@ -109,42 +69,32 @@
 
 }  // namespace
 
-void SwitchRoot(const std::string& new_root) {
+void SwitchRoot(const std::string& new_root, bool move_root_mount) {
     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 (mount(new_root.c_str(), "/", nullptr, MS_MOVE, nullptr) != 0) {
-        PLOG(FATAL) << "Unable to move root mount 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