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