Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 13856a0

Browse files
Tom CherryGerrit Code Review
authored andcommitted
Merge "Reland: "init: chroot from recovery to /first_stage_ramdisk""
2 parents adfe8c4 + 866c08c commit 13856a0

File tree

3 files changed

+91
-71
lines changed

3 files changed

+91
-71
lines changed

init/first_stage_mount.cpp

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "first_stage_mount.h"
1818

1919
#include <stdlib.h>
20+
#include <sys/mount.h>
2021
#include <unistd.h>
2122

2223
#include <chrono>
@@ -123,18 +124,8 @@ static inline bool IsDtVbmetaCompatible() {
123124
return is_android_dt_value_expected("vbmeta/compatible", "android,vbmeta");
124125
}
125126

126-
static bool ForceNormalBoot() {
127-
static bool force_normal_boot = []() {
128-
std::string cmdline;
129-
android::base::ReadFileToString("/proc/cmdline", &cmdline);
130-
return cmdline.find("androidboot.force_normal_boot=1") != std::string::npos;
131-
}();
132-
133-
return force_normal_boot;
134-
}
135-
136127
static bool IsRecoveryMode() {
137-
return !ForceNormalBoot() && access("/system/bin/recovery", F_OK) == 0;
128+
return access("/system/bin/recovery", F_OK) == 0;
138129
}
139130

140131
// Class Definitions
@@ -403,11 +394,6 @@ bool FirstStageMount::MountPartitions() {
403394
[](const auto& rec) { return rec->mount_point == "/system"s; });
404395

405396
if (system_partition != mount_fstab_recs_.end()) {
406-
if (ForceNormalBoot()) {
407-
free((*system_partition)->mount_point);
408-
(*system_partition)->mount_point = strdup("/system_recovery_mount");
409-
}
410-
411397
if (!MountPartition(*system_partition)) {
412398
return false;
413399
}

init/init_first_stage.cpp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
* limitations under the License.
1515
*/
1616

17+
#include <dirent.h>
18+
#include <fcntl.h>
1719
#include <paths.h>
1820
#include <stdlib.h>
1921
#include <sys/mount.h>
@@ -26,19 +28,72 @@
2628
#include <vector>
2729

2830
#include <android-base/chrono_utils.h>
31+
#include <android-base/file.h>
2932
#include <android-base/logging.h>
3033
#include <cutils/android_reboot.h>
3134
#include <private/android_filesystem_config.h>
3235

3336
#include "first_stage_mount.h"
3437
#include "reboot_utils.h"
38+
#include "switch_root.h"
3539
#include "util.h"
3640

3741
using android::base::boot_clock;
3842

43+
using namespace std::literals;
44+
3945
namespace android {
4046
namespace init {
4147

48+
namespace {
49+
50+
void FreeRamdisk(DIR* dir, dev_t dev) {
51+
int dfd = dirfd(dir);
52+
53+
dirent* de;
54+
while ((de = readdir(dir)) != nullptr) {
55+
if (de->d_name == "."s || de->d_name == ".."s) {
56+
continue;
57+
}
58+
59+
bool is_dir = false;
60+
61+
if (de->d_type == DT_DIR || de->d_type == DT_UNKNOWN) {
62+
struct stat info;
63+
if (fstatat(dfd, de->d_name, &info, AT_SYMLINK_NOFOLLOW) != 0) {
64+
continue;
65+
}
66+
67+
if (info.st_dev != dev) {
68+
continue;
69+
}
70+
71+
if (S_ISDIR(info.st_mode)) {
72+
is_dir = true;
73+
auto fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
74+
if (fd >= 0) {
75+
auto subdir =
76+
std::unique_ptr<DIR, decltype(&closedir)>{fdopendir(fd), closedir};
77+
if (subdir) {
78+
FreeRamdisk(subdir.get(), dev);
79+
} else {
80+
close(fd);
81+
}
82+
}
83+
}
84+
}
85+
unlinkat(dfd, de->d_name, is_dir ? AT_REMOVEDIR : 0);
86+
}
87+
}
88+
89+
bool ForceNormalBoot() {
90+
std::string cmdline;
91+
android::base::ReadFileToString("/proc/cmdline", &cmdline);
92+
return cmdline.find("androidboot.force_normal_boot=1") != std::string::npos;
93+
}
94+
95+
} // namespace
96+
4297
int main(int argc, char** argv) {
4398
if (REBOOT_BOOTLOADER_ON_PANIC) {
4499
InstallRebootSignalHandlers();
@@ -117,10 +172,41 @@ int main(int argc, char** argv) {
117172

118173
LOG(INFO) << "init first stage started!";
119174

175+
auto old_root_dir = std::unique_ptr<DIR, decltype(&closedir)>{opendir("/"), closedir};
176+
if (!old_root_dir) {
177+
PLOG(ERROR) << "Could not opendir(\"/\"), not freeing ramdisk";
178+
}
179+
180+
struct stat old_root_info;
181+
if (stat("/", &old_root_info) != 0) {
182+
PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
183+
old_root_dir.reset();
184+
}
185+
186+
if (ForceNormalBoot()) {
187+
mkdir("/first_stage_ramdisk", 0755);
188+
// SwitchRoot() must be called with a mount point as the target, so we bind mount the
189+
// target directory to itself here.
190+
if (mount("/first_stage_ramdisk", "/first_stage_ramdisk", nullptr, MS_BIND, nullptr) != 0) {
191+
LOG(FATAL) << "Could not bind mount /first_stage_ramdisk to itself";
192+
}
193+
SwitchRoot("/first_stage_ramdisk");
194+
}
195+
120196
if (!DoFirstStageMount()) {
121197
LOG(FATAL) << "Failed to mount required partitions early ...";
122198
}
123199

200+
struct stat new_root_info;
201+
if (stat("/", &new_root_info) != 0) {
202+
PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
203+
old_root_dir.reset();
204+
}
205+
206+
if (old_root_dir && old_root_info.st_dev != new_root_info.st_dev) {
207+
FreeRamdisk(old_root_dir.get(), old_root_info.st_dev);
208+
}
209+
124210
SetInitAvbVersionInRecovery();
125211

126212
static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;

init/switch_root.cpp

Lines changed: 3 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
#include "switch_root.h"
1818

19-
#include <dirent.h>
2019
#include <fcntl.h>
2120
#include <mntent.h>
2221
#include <sys/mount.h>
@@ -35,45 +34,6 @@ namespace init {
3534

3635
namespace {
3736

38-
void FreeRamdisk(DIR* dir, dev_t dev) {
39-
int dfd = dirfd(dir);
40-
41-
dirent* de;
42-
while ((de = readdir(dir)) != nullptr) {
43-
if (de->d_name == "."s || de->d_name == ".."s) {
44-
continue;
45-
}
46-
47-
bool is_dir = false;
48-
49-
if (de->d_type == DT_DIR || de->d_type == DT_UNKNOWN) {
50-
struct stat info;
51-
if (fstatat(dfd, de->d_name, &info, AT_SYMLINK_NOFOLLOW) != 0) {
52-
continue;
53-
}
54-
55-
if (info.st_dev != dev) {
56-
continue;
57-
}
58-
59-
if (S_ISDIR(info.st_mode)) {
60-
is_dir = true;
61-
auto fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
62-
if (fd >= 0) {
63-
auto subdir =
64-
std::unique_ptr<DIR, decltype(&closedir)>{fdopendir(fd), closedir};
65-
if (subdir) {
66-
FreeRamdisk(subdir.get(), dev);
67-
} else {
68-
close(fd);
69-
}
70-
}
71-
}
72-
}
73-
unlinkat(dfd, de->d_name, is_dir ? AT_REMOVEDIR : 0);
74-
}
75-
}
76-
7737
std::vector<std::string> GetMounts(const std::string& new_root) {
7838
auto fp = std::unique_ptr<std::FILE, decltype(&endmntent)>{setmntent("/proc/mounts", "re"),
7939
endmntent};
@@ -112,24 +72,16 @@ std::vector<std::string> GetMounts(const std::string& new_root) {
11272
void SwitchRoot(const std::string& new_root) {
11373
auto mounts = GetMounts(new_root);
11474

75+
LOG(INFO) << "Switching root to '" << new_root << "'";
76+
11577
for (const auto& mount_path : mounts) {
11678
auto new_mount_path = new_root + mount_path;
79+
mkdir(new_mount_path.c_str(), 0755);
11780
if (mount(mount_path.c_str(), new_mount_path.c_str(), nullptr, MS_MOVE, nullptr) != 0) {
11881
PLOG(FATAL) << "Unable to move mount at '" << mount_path << "'";
11982
}
12083
}
12184

122-
auto old_root_dir = std::unique_ptr<DIR, decltype(&closedir)>{opendir("/"), closedir};
123-
if (!old_root_dir) {
124-
PLOG(ERROR) << "Could not opendir(\"/\"), not freeing ramdisk";
125-
}
126-
127-
struct stat old_root_info;
128-
if (stat("/", &old_root_info) != 0) {
129-
PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
130-
old_root_dir.reset();
131-
}
132-
13385
if (chdir(new_root.c_str()) != 0) {
13486
PLOG(FATAL) << "Could not chdir to new_root, '" << new_root << "'";
13587
}
@@ -141,10 +93,6 @@ void SwitchRoot(const std::string& new_root) {
14193
if (chroot(".") != 0) {
14294
PLOG(FATAL) << "Unable to chroot to new root";
14395
}
144-
145-
if (old_root_dir) {
146-
FreeRamdisk(old_root_dir.get(), old_root_info.st_dev);
147-
}
14896
}
14997

15098
} // namespace init

0 commit comments

Comments
 (0)