summaryrefslogtreecommitdiffstats
path: root/roots.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--roots.cpp510
1 files changed, 276 insertions, 234 deletions
diff --git a/roots.cpp b/roots.cpp
index 29f55b96f..184e7992b 100644
--- a/roots.cpp
+++ b/roots.cpp
@@ -16,174 +16,208 @@
#include "roots.h"
-#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdint.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
-#include <ctype.h>
-#include <fcntl.h>
+
+#include <algorithm>
+#include <string>
+#include <vector>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
+#include <cryptfs.h>
#include <ext4_utils/wipe.h>
#include <fs_mgr.h>
-#include "common.h"
#include "mounts.h"
-#include "cryptfs.h"
-static struct fstab *fstab = NULL;
+static struct fstab* fstab = nullptr;
-extern struct selabel_handle *sehandle;
+extern struct selabel_handle* sehandle;
-void load_volume_table()
-{
- int i;
- int ret;
+void load_volume_table() {
+ fstab = fs_mgr_read_fstab_default();
+ if (!fstab) {
+ LOG(ERROR) << "Failed to read default fstab";
+ return;
+ }
- fstab = fs_mgr_read_fstab_default();
- if (!fstab) {
- LOG(ERROR) << "failed to read default fstab";
- return;
- }
+ int ret = fs_mgr_add_entry(fstab, "/tmp", "ramdisk", "ramdisk");
+ if (ret == -1) {
+ LOG(ERROR) << "Failed to add /tmp entry to fstab";
+ fs_mgr_free_fstab(fstab);
+ fstab = nullptr;
+ return;
+ }
- ret = fs_mgr_add_entry(fstab, "/tmp", "ramdisk", "ramdisk");
- if (ret < 0 ) {
- LOG(ERROR) << "failed to add /tmp entry to fstab";
- fs_mgr_free_fstab(fstab);
- fstab = NULL;
- return;
- }
+ printf("recovery filesystem table\n");
+ printf("=========================\n");
+ for (int i = 0; i < fstab->num_entries; ++i) {
+ const Volume* v = &fstab->recs[i];
+ printf(" %d %s %s %s %lld\n", i, v->mount_point, v->fs_type, v->blk_device, v->length);
+ }
+ printf("\n");
+}
- printf("recovery filesystem table\n");
- printf("=========================\n");
- for (i = 0; i < fstab->num_entries; ++i) {
- Volume* v = &fstab->recs[i];
- printf(" %d %s %s %s %lld\n", i, v->mount_point, v->fs_type,
- v->blk_device, v->length);
- }
- printf("\n");
+Volume* volume_for_mount_point(const std::string& mount_point) {
+ return fs_mgr_get_entry_for_mount_point(fstab, mount_point);
}
-Volume* volume_for_path(const char* path) {
- return fs_mgr_get_entry_for_mount_point(fstab, path);
+// Finds the volume specified by the given path. fs_mgr_get_entry_for_mount_point() does exact match
+// only, so it attempts the prefixes recursively (e.g. "/cache/recovery/last_log",
+// "/cache/recovery", "/cache", "/" for a given path of "/cache/recovery/last_log") and returns the
+// first match or nullptr.
+static Volume* volume_for_path(const char* path) {
+ if (path == nullptr || path[0] == '\0') return nullptr;
+ std::string str(path);
+ while (true) {
+ Volume* result = fs_mgr_get_entry_for_mount_point(fstab, str);
+ if (result != nullptr || str == "/") {
+ return result;
+ }
+ size_t slash = str.find_last_of('/');
+ if (slash == std::string::npos) return nullptr;
+ if (slash == 0) {
+ str = "/";
+ } else {
+ str = str.substr(0, slash);
+ }
+ }
+ return nullptr;
}
// Mount the volume specified by path at the given mount_point.
int ensure_path_mounted_at(const char* path, const char* mount_point) {
- Volume* v = volume_for_path(path);
- if (v == NULL) {
- LOG(ERROR) << "unknown volume for path [" << path << "]";
- return -1;
- }
- if (strcmp(v->fs_type, "ramdisk") == 0) {
- // the ramdisk is always mounted.
- return 0;
- }
+ Volume* v = volume_for_path(path);
+ if (v == nullptr) {
+ LOG(ERROR) << "unknown volume for path [" << path << "]";
+ return -1;
+ }
+ if (strcmp(v->fs_type, "ramdisk") == 0) {
+ // The ramdisk is always mounted.
+ return 0;
+ }
- if (!scan_mounted_volumes()) {
- LOG(ERROR) << "failed to scan mounted volumes";
- return -1;
- }
+ if (!scan_mounted_volumes()) {
+ LOG(ERROR) << "Failed to scan mounted volumes";
+ return -1;
+ }
- if (!mount_point) {
- mount_point = v->mount_point;
- }
+ if (!mount_point) {
+ mount_point = v->mount_point;
+ }
+
+ const MountedVolume* mv = find_mounted_volume_by_mount_point(mount_point);
+ if (mv != nullptr) {
+ // Volume is already mounted.
+ return 0;
+ }
- MountedVolume* mv = find_mounted_volume_by_mount_point(mount_point);
- if (mv) {
- // volume is already mounted
- return 0;
+ mkdir(mount_point, 0755); // in case it doesn't already exist
+
+ if (strcmp(v->fs_type, "ext4") == 0 || strcmp(v->fs_type, "squashfs") == 0 ||
+ strcmp(v->fs_type, "vfat") == 0) {
+ int result = mount(v->blk_device, mount_point, v->fs_type, v->flags, v->fs_options);
+ if (result == -1 && fs_mgr_is_formattable(v)) {
+ PLOG(ERROR) << "Failed to mount " << mount_point << "; formatting";
+ bool crypt_footer = fs_mgr_is_encryptable(v) && !strcmp(v->key_loc, "footer");
+ if (fs_mgr_do_format(v, crypt_footer) == 0) {
+ result = mount(v->blk_device, mount_point, v->fs_type, v->flags, v->fs_options);
+ } else {
+ PLOG(ERROR) << "Failed to format " << mount_point;
+ return -1;
+ }
}
- mkdir(mount_point, 0755); // in case it doesn't already exist
-
- if (strcmp(v->fs_type, "ext4") == 0 ||
- strcmp(v->fs_type, "squashfs") == 0 ||
- strcmp(v->fs_type, "vfat") == 0) {
- int result = mount(v->blk_device, mount_point, v->fs_type, v->flags, v->fs_options);
- if (result == -1 && fs_mgr_is_formattable(v)) {
- LOG(ERROR) << "failed to mount " << mount_point << " (" << strerror(errno)
- << ") , formatting.....";
- bool crypt_footer = fs_mgr_is_encryptable(v) && !strcmp(v->key_loc, "footer");
- if (fs_mgr_do_format(v, crypt_footer) == 0) {
- result = mount(v->blk_device, mount_point, v->fs_type, v->flags, v->fs_options);
- } else {
- PLOG(ERROR) << "failed to format " << mount_point;
- return -1;
- }
- }
-
- if (result == -1) {
- PLOG(ERROR) << "failed to mount " << mount_point;
- return -1;
- }
- return 0;
+ if (result == -1) {
+ PLOG(ERROR) << "Failed to mount " << mount_point;
+ return -1;
}
+ return 0;
+ }
- LOG(ERROR) << "unknown fs_type \"" << v->fs_type << "\" for " << mount_point;
- return -1;
+ LOG(ERROR) << "unknown fs_type \"" << v->fs_type << "\" for " << mount_point;
+ return -1;
}
int ensure_path_mounted(const char* path) {
- // Mount at the default mount point.
- return ensure_path_mounted_at(path, nullptr);
+ // Mount at the default mount point.
+ return ensure_path_mounted_at(path, nullptr);
}
int ensure_path_unmounted(const char* path) {
- Volume* v = volume_for_path(path);
- if (v == NULL) {
- LOG(ERROR) << "unknown volume for path [" << path << "]";
- return -1;
- }
- if (strcmp(v->fs_type, "ramdisk") == 0) {
- // the ramdisk is always mounted; you can't unmount it.
- return -1;
- }
+ const Volume* v = volume_for_path(path);
+ if (v == nullptr) {
+ LOG(ERROR) << "unknown volume for path [" << path << "]";
+ return -1;
+ }
+ if (strcmp(v->fs_type, "ramdisk") == 0) {
+ // The ramdisk is always mounted; you can't unmount it.
+ return -1;
+ }
- if (!scan_mounted_volumes()) {
- LOG(ERROR) << "failed to scan mounted volumes";
- return -1;
- }
+ if (!scan_mounted_volumes()) {
+ LOG(ERROR) << "Failed to scan mounted volumes";
+ return -1;
+ }
- MountedVolume* mv = find_mounted_volume_by_mount_point(v->mount_point);
- if (mv == NULL) {
- // volume is already unmounted
- return 0;
- }
+ MountedVolume* mv = find_mounted_volume_by_mount_point(v->mount_point);
+ if (mv == nullptr) {
+ // Volume is already unmounted.
+ return 0;
+ }
- return unmount_mounted_volume(mv);
+ return unmount_mounted_volume(mv);
}
-static int exec_cmd(const char* path, char* const argv[]) {
- int status;
- pid_t child;
- if ((child = vfork()) == 0) {
- execv(path, argv);
- _exit(EXIT_FAILURE);
- }
- waitpid(child, &status, 0);
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
- LOG(ERROR) << path << " failed with status " << WEXITSTATUS(status);
- }
- return WEXITSTATUS(status);
+static int exec_cmd(const std::vector<std::string>& args) {
+ CHECK_NE(static_cast<size_t>(0), args.size());
+
+ std::vector<char*> argv(args.size());
+ std::transform(args.cbegin(), args.cend(), argv.begin(),
+ [](const std::string& arg) { return const_cast<char*>(arg.c_str()); });
+ argv.push_back(nullptr);
+
+ pid_t child;
+ if ((child = fork()) == 0) {
+ execv(argv[0], argv.data());
+ _exit(EXIT_FAILURE);
+ }
+
+ int status;
+ waitpid(child, &status, 0);
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ LOG(ERROR) << args[0] << " failed with status " << WEXITSTATUS(status);
+ }
+ return WEXITSTATUS(status);
}
-static ssize_t get_file_size(int fd, uint64_t reserve_len) {
+static int64_t get_file_size(int fd, uint64_t reserve_len) {
struct stat buf;
int ret = fstat(fd, &buf);
if (ret) return 0;
- ssize_t computed_size;
+ int64_t computed_size;
if (S_ISREG(buf.st_mode)) {
computed_size = buf.st_size - reserve_len;
} else if (S_ISBLK(buf.st_mode)) {
- computed_size = get_block_device_size(fd) - reserve_len;
+ uint64_t block_device_size = get_block_device_size(fd);
+ if (block_device_size < reserve_len ||
+ block_device_size > std::numeric_limits<int64_t>::max()) {
+ computed_size = 0;
+ } else {
+ computed_size = block_device_size - reserve_len;
+ }
} else {
computed_size = 0;
}
@@ -192,136 +226,144 @@ static ssize_t get_file_size(int fd, uint64_t reserve_len) {
}
int format_volume(const char* volume, const char* directory) {
- Volume* v = volume_for_path(volume);
- if (v == NULL) {
- LOG(ERROR) << "unknown volume \"" << volume << "\"";
- return -1;
+ const Volume* v = volume_for_path(volume);
+ if (v == nullptr) {
+ LOG(ERROR) << "unknown volume \"" << volume << "\"";
+ return -1;
+ }
+ if (strcmp(v->fs_type, "ramdisk") == 0) {
+ LOG(ERROR) << "can't format_volume \"" << volume << "\"";
+ return -1;
+ }
+ if (strcmp(v->mount_point, volume) != 0) {
+ LOG(ERROR) << "can't give path \"" << volume << "\" to format_volume";
+ return -1;
+ }
+ if (ensure_path_unmounted(volume) != 0) {
+ LOG(ERROR) << "format_volume: Failed to unmount \"" << v->mount_point << "\"";
+ return -1;
+ }
+ if (strcmp(v->fs_type, "ext4") != 0 && strcmp(v->fs_type, "f2fs") != 0) {
+ LOG(ERROR) << "format_volume: fs_type \"" << v->fs_type << "\" unsupported";
+ return -1;
+ }
+
+ // If there's a key_loc that looks like a path, it should be a block device for storing encryption
+ // metadata. Wipe it too.
+ if (v->key_loc != nullptr && v->key_loc[0] == '/') {
+ LOG(INFO) << "Wiping " << v->key_loc;
+ int fd = open(v->key_loc, O_WRONLY | O_CREAT, 0644);
+ if (fd == -1) {
+ PLOG(ERROR) << "format_volume: Failed to open " << v->key_loc;
+ return -1;
}
- if (strcmp(v->fs_type, "ramdisk") == 0) {
- // you can't format the ramdisk.
- LOG(ERROR) << "can't format_volume \"" << volume << "\"";
- return -1;
+ wipe_block_device(fd, get_file_size(fd));
+ close(fd);
+ }
+
+ int64_t length = 0;
+ if (v->length > 0) {
+ length = v->length;
+ } else if (v->length < 0 ||
+ (v->key_loc != nullptr && strcmp(v->key_loc, "footer") == 0)) {
+ android::base::unique_fd fd(open(v->blk_device, O_RDONLY));
+ if (fd == -1) {
+ PLOG(ERROR) << "format_volume: failed to open " << v->blk_device;
+ return -1;
}
- if (strcmp(v->mount_point, volume) != 0) {
- LOG(ERROR) << "can't give path \"" << volume << "\" to format_volume";
- return -1;
+ length =
+ get_file_size(fd.get(), v->length ? -v->length : CRYPT_FOOTER_OFFSET);
+ if (length <= 0) {
+ LOG(ERROR) << "get_file_size: invalid size " << length << " for "
+ << v->blk_device;
+ return -1;
}
+ }
- if (ensure_path_unmounted(volume) != 0) {
- LOG(ERROR) << "format_volume failed to unmount \"" << v->mount_point << "\"";
- return -1;
+ if (strcmp(v->fs_type, "ext4") == 0) {
+ static constexpr int kBlockSize = 4096;
+ std::vector<std::string> mke2fs_args = {
+ "/sbin/mke2fs_static", "-F", "-t", "ext4", "-b", std::to_string(kBlockSize),
+ };
+
+ int raid_stride = v->logical_blk_size / kBlockSize;
+ int raid_stripe_width = v->erase_blk_size / kBlockSize;
+ // stride should be the max of 8KB and logical block size
+ if (v->logical_blk_size != 0 && v->logical_blk_size < 8192) {
+ raid_stride = 8192 / kBlockSize;
+ }
+ if (v->erase_blk_size != 0 && v->logical_blk_size != 0) {
+ mke2fs_args.push_back("-E");
+ mke2fs_args.push_back(
+ android::base::StringPrintf("stride=%d,stripe-width=%d", raid_stride, raid_stripe_width));
+ }
+ mke2fs_args.push_back(v->blk_device);
+ if (length != 0) {
+ mke2fs_args.push_back(std::to_string(length / kBlockSize));
}
- if (strcmp(v->fs_type, "ext4") == 0 || strcmp(v->fs_type, "f2fs") == 0) {
- // if there's a key_loc that looks like a path, it should be a
- // block device for storing encryption metadata. wipe it too.
- if (v->key_loc != NULL && v->key_loc[0] == '/') {
- LOG(INFO) << "wiping " << v->key_loc;
- int fd = open(v->key_loc, O_WRONLY | O_CREAT, 0644);
- if (fd < 0) {
- LOG(ERROR) << "format_volume: failed to open " << v->key_loc;
- return -1;
- }
- wipe_block_device(fd, get_file_size(fd));
- close(fd);
- }
-
- ssize_t length = 0;
- if (v->length != 0) {
- length = v->length;
- } else if (v->key_loc != NULL && strcmp(v->key_loc, "footer") == 0) {
- android::base::unique_fd fd(open(v->blk_device, O_RDONLY));
- if (fd < 0) {
- PLOG(ERROR) << "get_file_size: failed to open " << v->blk_device;
- return -1;
- }
- length = get_file_size(fd.get(), CRYPT_FOOTER_OFFSET);
- if (length <= 0) {
- LOG(ERROR) << "get_file_size: invalid size " << length << " for " << v->blk_device;
- return -1;
- }
- }
- int result;
- if (strcmp(v->fs_type, "ext4") == 0) {
- static constexpr int block_size = 4096;
- int raid_stride = v->logical_blk_size / block_size;
- int raid_stripe_width = v->erase_blk_size / block_size;
-
- // stride should be the max of 8kb and logical block size
- if (v->logical_blk_size != 0 && v->logical_blk_size < 8192) {
- raid_stride = 8192 / block_size;
- }
-
- const char* mke2fs_argv[] = { "/sbin/mke2fs_static",
- "-F",
- "-t",
- "ext4",
- "-b",
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr,
- nullptr };
-
- int i = 5;
- std::string block_size_str = std::to_string(block_size);
- mke2fs_argv[i++] = block_size_str.c_str();
-
- std::string ext_args;
- if (v->erase_blk_size != 0 && v->logical_blk_size != 0) {
- ext_args = android::base::StringPrintf("stride=%d,stripe-width=%d", raid_stride,
- raid_stripe_width);
- mke2fs_argv[i++] = "-E";
- mke2fs_argv[i++] = ext_args.c_str();
- }
-
- mke2fs_argv[i++] = v->blk_device;
-
- std::string size_str = std::to_string(length / block_size);
- if (length != 0) {
- mke2fs_argv[i++] = size_str.c_str();
- }
-
- result = exec_cmd(mke2fs_argv[0], const_cast<char**>(mke2fs_argv));
- if (result == 0 && directory != nullptr) {
- const char* e2fsdroid_argv[] = { "/sbin/e2fsdroid_static",
- "-e",
- "-f",
- directory,
- "-a",
- volume,
- v->blk_device,
- nullptr };
-
- result = exec_cmd(e2fsdroid_argv[0], const_cast<char**>(e2fsdroid_argv));
- }
- } else { /* Has to be f2fs because we checked earlier. */
- char *num_sectors = nullptr;
- if (length >= 512 && asprintf(&num_sectors, "%zd", length / 512) <= 0) {
- LOG(ERROR) << "format_volume: failed to create " << v->fs_type
- << " command for " << v->blk_device;
- return -1;
- }
- const char *f2fs_path = "/sbin/mkfs.f2fs";
- const char* const f2fs_argv[] = {"mkfs.f2fs", "-t", "-d1", v->blk_device, num_sectors, nullptr};
-
- result = exec_cmd(f2fs_path, (char* const*)f2fs_argv);
- free(num_sectors);
- }
- if (result != 0) {
- PLOG(ERROR) << "format_volume: make " << v->fs_type << " failed on " << v->blk_device;
- return -1;
- }
- return 0;
+ int result = exec_cmd(mke2fs_args);
+ if (result == 0 && directory != nullptr) {
+ std::vector<std::string> e2fsdroid_args = {
+ "/sbin/e2fsdroid_static",
+ "-e",
+ "-f",
+ directory,
+ "-a",
+ volume,
+ v->blk_device,
+ };
+ result = exec_cmd(e2fsdroid_args);
}
- LOG(ERROR) << "format_volume: fs_type \"" << v->fs_type << "\" unsupported";
+ if (result != 0) {
+ PLOG(ERROR) << "format_volume: Failed to make ext4 on " << v->blk_device;
+ return -1;
+ }
+ return 0;
+ }
+
+ // Has to be f2fs because we checked earlier.
+ static constexpr int kSectorSize = 4096;
+ std::string cmd("/sbin/mkfs.f2fs");
+ // clang-format off
+ std::vector<std::string> make_f2fs_cmd = {
+ cmd,
+ "-d1",
+ "-f",
+ "-O", "encrypt",
+ "-O", "quota",
+ "-O", "verity",
+ "-w", std::to_string(kSectorSize),
+ v->blk_device,
+ };
+ // clang-format on
+ if (length >= kSectorSize) {
+ make_f2fs_cmd.push_back(std::to_string(length / kSectorSize));
+ }
+
+ int result = exec_cmd(make_f2fs_cmd);
+ if (result == 0 && directory != nullptr) {
+ cmd = "/sbin/sload.f2fs";
+ // clang-format off
+ std::vector<std::string> sload_f2fs_cmd = {
+ cmd,
+ "-f", directory,
+ "-t", volume,
+ v->blk_device,
+ };
+ // clang-format on
+ result = exec_cmd(sload_f2fs_cmd);
+ }
+ if (result != 0) {
+ PLOG(ERROR) << "format_volume: Failed " << cmd << " on " << v->blk_device;
return -1;
+ }
+ return 0;
}
int format_volume(const char* volume) {
- return format_volume(volume, NULL);
+ return format_volume(volume, nullptr);
}
int setup_install_mounts() {
@@ -339,12 +381,12 @@ int setup_install_mounts() {
if (strcmp(v->mount_point, "/tmp") == 0 || strcmp(v->mount_point, "/cache") == 0) {
if (ensure_path_mounted(v->mount_point) != 0) {
- LOG(ERROR) << "failed to mount " << v->mount_point;
+ LOG(ERROR) << "Failed to mount " << v->mount_point;
return -1;
}
} else {
if (ensure_path_unmounted(v->mount_point) != 0) {
- LOG(ERROR) << "failed to unmount " << v->mount_point;
+ LOG(ERROR) << "Failed to unmount " << v->mount_point;
return -1;
}
}