blob: e761e56d4155cfffb5560059410915904e038183 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <unistd.h>
#include <algorithm>
#include <utility>
#include <vector>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include "fs_mgr_priv.h"
using android::base::StartsWith;
const std::string kDefaultAndroidDtDir("/proc/device-tree/firmware/android");
struct fs_mgr_flag_values {
std::string key_loc;
std::string key_dir;
std::string verity_loc;
std::string sysfs_path;
off64_t part_length = 0;
std::string label;
int partnum = -1;
int swap_prio = -1;
int max_comp_streams = 0;
off64_t zram_size = 0;
off64_t reserved_size = 0;
int file_contents_mode = 0;
int file_names_mode = 0;
off64_t erase_blk_size = 0;
off64_t logical_blk_size = 0;
std::string vbmeta_partition;
};
struct flag_list {
const char *name;
unsigned int flag;
};
static struct flag_list mount_flags[] = {
{ "noatime", MS_NOATIME },
{ "noexec", MS_NOEXEC },
{ "nosuid", MS_NOSUID },
{ "nodev", MS_NODEV },
{ "nodiratime", MS_NODIRATIME },
{ "ro", MS_RDONLY },
{ "rw", 0 },
{ "remount", MS_REMOUNT },
{ "bind", MS_BIND },
{ "rec", MS_REC },
{ "unbindable", MS_UNBINDABLE },
{ "private", MS_PRIVATE },
{ "slave", MS_SLAVE },
{ "shared", MS_SHARED },
{ "defaults", 0 },
{ 0, 0 },
};
static struct flag_list fs_mgr_flags[] = {
{"wait", MF_WAIT},
{"check", MF_CHECK},
{"encryptable=", MF_CRYPT},
{"forceencrypt=", MF_FORCECRYPT},
{"fileencryption=", MF_FILEENCRYPTION},
{"forcefdeorfbe=", MF_FORCEFDEORFBE},
{"keydirectory=", MF_KEYDIRECTORY},
{"nonremovable", MF_NONREMOVABLE},
{"voldmanaged=", MF_VOLDMANAGED},
{"length=", MF_LENGTH},
{"recoveryonly", MF_RECOVERYONLY},
{"swapprio=", MF_SWAPPRIO},
{"zramsize=", MF_ZRAMSIZE},
{"max_comp_streams=", MF_MAX_COMP_STREAMS},
{"verifyatboot", MF_VERIFYATBOOT},
{"verify", MF_VERIFY},
{"avb", MF_AVB},
{"avb=", MF_AVB},
{"noemulatedsd", MF_NOEMULATEDSD},
{"notrim", MF_NOTRIM},
{"formattable", MF_FORMATTABLE},
{"slotselect", MF_SLOTSELECT},
{"nofail", MF_NOFAIL},
{"first_stage_mount", MF_FIRST_STAGE_MOUNT},
{"latemount", MF_LATEMOUNT},
{"reservedsize=", MF_RESERVEDSIZE},
{"quota", MF_QUOTA},
{"eraseblk=", MF_ERASEBLKSIZE},
{"logicalblk=", MF_LOGICALBLKSIZE},
{"sysfs_path=", MF_SYSFS},
{"defaults", 0},
{"logical", MF_LOGICAL},
{"checkpoint=block", MF_CHECKPOINT_BLK},
{"checkpoint=fs", MF_CHECKPOINT_FS},
{0, 0},
};
#define EM_AES_256_XTS 1
#define EM_ICE 2
#define EM_AES_256_CTS 3
#define EM_AES_256_HEH 4
#define EM_ADIANTUM 5
static const struct flag_list file_contents_encryption_modes[] = {
{"aes-256-xts", EM_AES_256_XTS},
{"adiantum", EM_ADIANTUM},
{"software", EM_AES_256_XTS}, /* alias for backwards compatibility */
{"ice", EM_ICE}, /* hardware-specific inline cryptographic engine */
{0, 0},
};
static const struct flag_list file_names_encryption_modes[] = {
{"aes-256-cts", EM_AES_256_CTS},
{"aes-256-heh", EM_AES_256_HEH},
{"adiantum", EM_ADIANTUM},
{0, 0},
};
static int encryption_mode_to_flag(const struct flag_list* list, const char* mode,
const char* type) {
const struct flag_list *j;
for (j = list; j->name; ++j) {
if (!strcmp(mode, j->name)) {
return j->flag;
}
}
LERROR << "Unknown " << type << " encryption mode: " << mode;
return 0;
}
static const char* flag_to_encryption_mode(const struct flag_list* list, int flag) {
const struct flag_list *j;
for (j = list; j->name; ++j) {
if (flag == j->flag) {
return j->name;
}
}
return nullptr;
}
static off64_t calculate_zram_size(unsigned int percentage) {
off64_t total;
total = sysconf(_SC_PHYS_PAGES);
total *= percentage;
total /= 100;
total *= sysconf(_SC_PAGESIZE);
return total;
}
static off64_t parse_size(const char* arg) {
char *endptr;
off64_t size = strtoll(arg, &endptr, 10);
if (*endptr == 'k' || *endptr == 'K')
size *= 1024LL;
else if (*endptr == 'm' || *endptr == 'M')
size *= 1024LL * 1024LL;
else if (*endptr == 'g' || *endptr == 'G')
size *= 1024LL * 1024LL * 1024LL;
return size;
}
/* fills 'dt_value' with the underlying device tree value string without
* the trailing '\0'. Returns true if 'dt_value' has a valid string, 'false'
* otherwise.
*/
static bool read_dt_file(const std::string& file_name, std::string* dt_value)
{
if (android::base::ReadFileToString(file_name, dt_value)) {
if (!dt_value->empty()) {
// trim the trailing '\0' out, otherwise the comparison
// will produce false-negatives.
dt_value->resize(dt_value->size() - 1);
return true;
}
}
return false;
}
static int parse_flags(char *flags, struct flag_list *fl,
struct fs_mgr_flag_values *flag_vals,
char *fs_options, int fs_options_len)
{
int f = 0;
int i;
char *p;
char *savep;
/* initialize fs_options to the null string */
if (fs_options && (fs_options_len > 0)) {
fs_options[0] = '\0';
}
p = strtok_r(flags, ",", &savep);
while (p) {
/* Look for the flag "p" in the flag list "fl"
* If not found, the loop exits with fl[i].name being null.
*/
for (i = 0; fl[i].name; i++) {
auto name = fl[i].name;
auto len = strlen(name);
auto end = len;
if (name[end - 1] == '=') --end;
if (!strncmp(p, name, len) && (p[end] == name[end])) {
f |= fl[i].flag;
if (!flag_vals) break;
if (p[end] != '=') break;
char* arg = p + end + 1;
auto flag = fl[i].flag;
if (flag == MF_CRYPT) {
/* The encryptable flag is followed by an = and the
* location of the keys. Get it and return it.
*/
flag_vals->key_loc = arg;
} else if (flag == MF_VERIFY) {
/* If the verify flag is followed by an = and the
* location for the verity state, get it and return it.
*/
flag_vals->verity_loc = arg;
} else if (flag == MF_FORCECRYPT) {
/* The forceencrypt flag is followed by an = and the
* location of the keys. Get it and return it.
*/
flag_vals->key_loc = arg;
} else if (flag == MF_FORCEFDEORFBE) {
/* The forcefdeorfbe flag is followed by an = and the
* location of the keys. Get it and return it.
*/
flag_vals->key_loc = arg;
flag_vals->file_contents_mode = EM_AES_256_XTS;
flag_vals->file_names_mode = EM_AES_256_CTS;
} else if (flag == MF_FILEENCRYPTION) {
/* The fileencryption flag is followed by an = and
* the mode of contents encryption, then optionally a
* : and the mode of filenames encryption (defaults
* to aes-256-cts). Get it and return it.
*/
auto mode = arg;
auto colon = strchr(mode, ':');
if (colon) {
*colon = '\0';
}
flag_vals->file_contents_mode =
encryption_mode_to_flag(file_contents_encryption_modes,
mode, "file contents");
if (colon) {
flag_vals->file_names_mode =
encryption_mode_to_flag(file_names_encryption_modes,
colon + 1, "file names");
} else if (flag_vals->file_contents_mode == EM_ADIANTUM) {
flag_vals->file_names_mode = EM_ADIANTUM;
} else {
flag_vals->file_names_mode = EM_AES_256_CTS;
}
} else if (flag == MF_KEYDIRECTORY) {
/* The metadata flag is followed by an = and the
* directory for the keys. Get it and return it.
*/
flag_vals->key_dir = arg;
} else if (flag == MF_LENGTH) {
/* The length flag is followed by an = and the
* size of the partition. Get it and return it.
*/
flag_vals->part_length = strtoll(arg, NULL, 0);
} else if (flag == MF_VOLDMANAGED) {
/* The voldmanaged flag is followed by an = and the
* label, a colon and the partition number or the
* word "auto", e.g.
* voldmanaged=sdcard:3
* Get and return them.
*/
auto label_start = arg;
auto label_end = strchr(label_start, ':');
if (label_end) {
flag_vals->label = std::string(label_start, (int)(label_end - label_start));
auto part_start = label_end + 1;
if (!strcmp(part_start, "auto")) {
flag_vals->partnum = -1;
} else {
flag_vals->partnum = strtol(part_start, NULL, 0);
}
} else {
LERROR << "Warning: voldmanaged= flag malformed";
}
} else if (flag == MF_SWAPPRIO) {
flag_vals->swap_prio = strtoll(arg, NULL, 0);
} else if (flag == MF_MAX_COMP_STREAMS) {
flag_vals->max_comp_streams = strtoll(arg, NULL, 0);
} else if (flag == MF_AVB) {
flag_vals->vbmeta_partition = arg;
} else if (flag == MF_ZRAMSIZE) {
auto is_percent = !!strrchr(arg, '%');
auto val = strtoll(arg, NULL, 0);
if (is_percent)
flag_vals->zram_size = calculate_zram_size(val);
else
flag_vals->zram_size = val;
} else if (flag == MF_RESERVEDSIZE) {
/* The reserved flag is followed by an = and the
* reserved size of the partition. Get it and return it.
*/
flag_vals->reserved_size = parse_size(arg);
} else if (flag == MF_ERASEBLKSIZE) {
/* The erase block size flag is followed by an = and the flash
* erase block size. Get it, check that it is a power of 2 and
* at least 4096, and return it.
*/
auto val = strtoll(arg, nullptr, 0);
if (val >= 4096 && (val & (val - 1)) == 0)
flag_vals->erase_blk_size = val;
} else if (flag == MF_LOGICALBLKSIZE) {
/* The logical block size flag is followed by an = and the flash
* logical block size. Get it, check that it is a power of 2 and
* at least 4096, and return it.
*/
auto val = strtoll(arg, nullptr, 0);
if (val >= 4096 && (val & (val - 1)) == 0)
flag_vals->logical_blk_size = val;
} else if (flag == MF_SYSFS) {
/* The path to trigger device gc by idle-maint of vold. */
flag_vals->sysfs_path = arg;
}
break;
}
}
if (!fl[i].name) {
if (fs_options) {
/* It's not a known flag, so it must be a filesystem specific
* option. Add it to fs_options if it was passed in.
*/
strlcat(fs_options, p, fs_options_len);
strlcat(fs_options, ",", fs_options_len);
} else {
/* fs_options was not passed in, so if the flag is unknown
* it's an error.
*/
LERROR << "Warning: unknown flag " << p;
}
}
p = strtok_r(NULL, ",", &savep);
}
if (fs_options && fs_options[0]) {
/* remove the last trailing comma from the list of options */
fs_options[strlen(fs_options) - 1] = '\0';
}
return f;
}
static std::string init_android_dt_dir() {
std::string android_dt_dir;
// The platform may specify a custom Android DT path in kernel cmdline
if (!fs_mgr_get_boot_config_from_kernel_cmdline("android_dt_dir", &android_dt_dir)) {
// Fall back to the standard procfs-based path
android_dt_dir = kDefaultAndroidDtDir;
}
return android_dt_dir;
}
// FIXME: The same logic is duplicated in system/core/init/
const std::string& get_android_dt_dir() {
// Set once and saves time for subsequent calls to this function
static const std::string kAndroidDtDir = init_android_dt_dir();
return kAndroidDtDir;
}
static bool is_dt_fstab_compatible() {
std::string dt_value;
std::string file_name = get_android_dt_dir() + "/fstab/compatible";
if (read_dt_file(file_name, &dt_value) && dt_value == "android,fstab") {
// If there's no status property or its set to "ok" or "okay", then we use the DT fstab.
std::string status_value;
std::string status_file_name = get_android_dt_dir() + "/fstab/status";
return !read_dt_file(status_file_name, &status_value) || status_value == "ok" ||
status_value == "okay";
}
return false;
}
static std::string read_fstab_from_dt() {
if (!is_dt_compatible() || !is_dt_fstab_compatible()) {
return {};
}
std::string fstabdir_name = get_android_dt_dir() + "/fstab";
std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
if (!fstabdir) return {};
dirent* dp;
// Each element in fstab_dt_entries is <mount point, the line format in fstab file>.
std::vector<std::pair<std::string, std::string>> fstab_dt_entries;
while ((dp = readdir(fstabdir.get())) != NULL) {
// skip over name, compatible and .
if (dp->d_type != DT_DIR || dp->d_name[0] == '.') continue;
// create <dev> <mnt_point> <type> <mnt_flags> <fsmgr_flags>\n
std::vector<std::string> fstab_entry;
std::string file_name;
std::string value;
// skip a partition entry if the status property is present and not set to ok
file_name = android::base::StringPrintf("%s/%s/status", fstabdir_name.c_str(), dp->d_name);
if (read_dt_file(file_name, &value)) {
if (value != "okay" && value != "ok") {
LINFO << "dt_fstab: Skip disabled entry for partition " << dp->d_name;
continue;
}
}
file_name = android::base::StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
if (!read_dt_file(file_name, &value)) {
LERROR << "dt_fstab: Failed to find device for partition " << dp->d_name;
return {};
}
fstab_entry.push_back(value);
std::string mount_point;
file_name =
android::base::StringPrintf("%s/%s/mnt_point", fstabdir_name.c_str(), dp->d_name);
if (read_dt_file(file_name, &value)) {
LINFO << "dt_fstab: Using a specified mount point " << value << " for " << dp->d_name;
mount_point = value;
} else {
mount_point = android::base::StringPrintf("/%s", dp->d_name);
}
fstab_entry.push_back(mount_point);
file_name = android::base::StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
if (!read_dt_file(file_name, &value)) {
LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
return {};
}
fstab_entry.push_back(value);
file_name = android::base::StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
if (!read_dt_file(file_name, &value)) {
LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
return {};
}
fstab_entry.push_back(value);
file_name = android::base::StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
if (!read_dt_file(file_name, &value)) {
LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
return {};
}
fstab_entry.push_back(value);
// Adds a fstab_entry to fstab_dt_entries, to be sorted by mount_point later.
fstab_dt_entries.emplace_back(mount_point, android::base::Join(fstab_entry, " "));
}
// Sort fstab_dt entries, to ensure /vendor is mounted before /vendor/abc is attempted.
std::sort(fstab_dt_entries.begin(), fstab_dt_entries.end(),
[](const auto& a, const auto& b) { return a.first < b.first; });
std::string fstab_result;
for (const auto& [_, dt_entry] : fstab_dt_entries) {
fstab_result += dt_entry + "\n";
}
return fstab_result;
}
bool is_dt_compatible() {
std::string file_name = get_android_dt_dir() + "/compatible";
std::string dt_value;
if (read_dt_file(file_name, &dt_value)) {
if (dt_value == "android,firmware") {
return true;
}
}
return false;
}
static bool fs_mgr_read_fstab_file(FILE* fstab_file, bool proc_mounts, Fstab* fstab_out) {
ssize_t len;
size_t alloc_len = 0;
char *line = NULL;
const char *delim = " \t";
char *save_ptr, *p;
Fstab fstab;
struct fs_mgr_flag_values flag_vals;
#define FS_OPTIONS_LEN 1024
char tmp_fs_options[FS_OPTIONS_LEN];
while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
/* if the last character is a newline, shorten the string by 1 byte */
if (line[len - 1] == '\n') {
line[len - 1] = '\0';
}
/* Skip any leading whitespace */
p = line;
while (isspace(*p)) {
p++;
}
/* ignore comments or empty lines */
if (*p == '#' || *p == '\0')
continue;
FstabEntry entry;
if (!(p = strtok_r(line, delim, &save_ptr))) {
LERROR << "Error parsing mount source";
goto err;
}
entry.blk_device = p;
if (!(p = strtok_r(NULL, delim, &save_ptr))) {
LERROR << "Error parsing mount_point";
goto err;
}
entry.mount_point = p;
if (!(p = strtok_r(NULL, delim, &save_ptr))) {
LERROR << "Error parsing fs_type";
goto err;
}
entry.fs_type = p;
if (!(p = strtok_r(NULL, delim, &save_ptr))) {
LERROR << "Error parsing mount_flags";
goto err;
}
tmp_fs_options[0] = '\0';
entry.flags = parse_flags(p, mount_flags, NULL, tmp_fs_options, FS_OPTIONS_LEN);
/* fs_options are optional */
if (tmp_fs_options[0]) {
entry.fs_options = tmp_fs_options;
}
// For /proc/mounts, ignore everything after mnt_freq and mnt_passno
if (proc_mounts) {
p += strlen(p);
} else if (!(p = strtok_r(NULL, delim, &save_ptr))) {
LERROR << "Error parsing fs_mgr_options";
goto err;
}
entry.fs_mgr_flags.val = parse_flags(p, fs_mgr_flags, &flag_vals, NULL, 0);
entry.key_loc = std::move(flag_vals.key_loc);
entry.key_dir = std::move(flag_vals.key_dir);
entry.verity_loc = std::move(flag_vals.verity_loc);
entry.length = flag_vals.part_length;
entry.label = std::move(flag_vals.label);
entry.partnum = flag_vals.partnum;
entry.swap_prio = flag_vals.swap_prio;
entry.max_comp_streams = flag_vals.max_comp_streams;
entry.zram_size = flag_vals.zram_size;
entry.reserved_size = flag_vals.reserved_size;
entry.file_contents_mode = flag_vals.file_contents_mode;
entry.file_names_mode = flag_vals.file_names_mode;
entry.erase_blk_size = flag_vals.erase_blk_size;
entry.logical_blk_size = flag_vals.logical_blk_size;
entry.sysfs_path = std::move(flag_vals.sysfs_path);
entry.vbmeta_partition = std::move(flag_vals.vbmeta_partition);
if (entry.fs_mgr_flags.logical) {
entry.logical_partition_name = entry.blk_device;
}
fstab.emplace_back(std::move(entry));
}
if (fstab.empty()) {
LERROR << "No entries found in fstab";
goto err;
}
/* If an A/B partition, modify block device to be the real block device */
if (!fs_mgr_update_for_slotselect(&fstab)) {
LERROR << "Error updating for slotselect";
goto err;
}
free(line);
*fstab_out = std::move(fstab);
return true;
err:
free(line);
return false;
}
/* Extracts <device>s from the by-name symlinks specified in a fstab:
* /dev/block/<type>/<device>/by-name/<partition>
*
* <type> can be: platform, pci or vbd.
*
* For example, given the following entries in the input fstab:
* /dev/block/platform/soc/1da4000.ufshc/by-name/system
* /dev/block/pci/soc.0/f9824900.sdhci/by-name/vendor
* it returns a set { "soc/1da4000.ufshc", "soc.0/f9824900.sdhci" }.
*/
static std::set<std::string> extract_boot_devices(const Fstab& fstab) {
std::set<std::string> boot_devices;
for (const auto& entry : fstab) {
std::string blk_device = entry.blk_device;
// Skips blk_device that doesn't conform to the format.
if (!android::base::StartsWith(blk_device, "/dev/block") ||
android::base::StartsWith(blk_device, "/dev/block/by-name") ||
android::base::StartsWith(blk_device, "/dev/block/bootdevice/by-name")) {
continue;
}
// Skips non-by_name blk_device.
// /dev/block/<type>/<device>/by-name/<partition>
// ^ slash_by_name
auto slash_by_name = blk_device.find("/by-name");
if (slash_by_name == std::string::npos) continue;
blk_device.erase(slash_by_name); // erases /by-name/<partition>
// Erases /dev/block/, now we have <type>/<device>
blk_device.erase(0, std::string("/dev/block/").size());
// <type>/<device>
// ^ first_slash
auto first_slash = blk_device.find('/');
if (first_slash == std::string::npos) continue;
auto boot_device = blk_device.substr(first_slash + 1);
if (!boot_device.empty()) boot_devices.insert(std::move(boot_device));
}
return boot_devices;
}
bool ReadFstabFromFile(const std::string& path, Fstab* fstab) {
auto fstab_file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
if (!fstab_file) {
PERROR << __FUNCTION__ << "(): cannot open file: '" << path << "'";
return false;
}
if (!fs_mgr_read_fstab_file(fstab_file.get(), path == "/proc/mounts", fstab)) {
LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << path << "'";
return false;
}
return true;
}
struct fstab* fs_mgr_read_fstab(const char* fstab_path) {
Fstab fstab;
if (!ReadFstabFromFile(fstab_path, &fstab)) {
return nullptr;
}
return FstabToLegacyFstab(fstab);
}
// Returns fstab entries parsed from the device tree if they exist
bool ReadFstabFromDt(Fstab* fstab) {
std::string fstab_buf = read_fstab_from_dt();
if (fstab_buf.empty()) {
LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
return false;
}
std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
fmemopen(static_cast<void*>(const_cast<char*>(fstab_buf.c_str())),
fstab_buf.length(), "r"), fclose);
if (!fstab_file) {
PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
return false;
}
if (!fs_mgr_read_fstab_file(fstab_file.get(), false, fstab)) {
LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:"
<< std::endl << fstab_buf;
return false;
}
return true;
}
struct fstab* fs_mgr_read_fstab_dt() {
Fstab fstab;
if (!ReadFstabFromDt(&fstab)) {
return nullptr;
}
return FstabToLegacyFstab(fstab);
}
/*
* Identify path to fstab file. Lookup is based on pattern
* fstab.<hardware>, fstab.<hardware.platform> in folders
/odm/etc, vendor/etc, or /.
*/
static std::string get_fstab_path()
{
for (const char* prop : {"hardware", "hardware.platform"}) {
std::string hw;
if (!fs_mgr_get_boot_config(prop, &hw)) continue;
for (const char* prefix : {"/odm/etc/fstab.", "/vendor/etc/fstab.", "/fstab."}) {
std::string fstab_path = prefix + hw;
if (access(fstab_path.c_str(), F_OK) == 0) {
return fstab_path;
}
}
}
return std::string();
}
// Loads the fstab file and combines with fstab entries passed in from device tree.
bool ReadDefaultFstab(Fstab* fstab) {
Fstab dt_fstab;
ReadFstabFromDt(&dt_fstab);
*fstab = std::move(dt_fstab);
std::string default_fstab_path;
// Use different fstab paths for normal boot and recovery boot, respectively
if (access("/system/bin/recovery", F_OK) == 0) {
default_fstab_path = "/etc/recovery.fstab";
} else { // normal boot
default_fstab_path = get_fstab_path();
}
Fstab default_fstab;
if (!default_fstab_path.empty()) {
ReadFstabFromFile(default_fstab_path, &default_fstab);
} else {
LINFO << __FUNCTION__ << "(): failed to find device default fstab";
}
for (auto&& entry : default_fstab) {
fstab->emplace_back(std::move(entry));
}
return !fstab->empty();
}
struct fstab* fs_mgr_read_fstab_default() {
Fstab fstab;
if (!ReadDefaultFstab(&fstab)) {
return nullptr;
}
return FstabToLegacyFstab(fstab);
}
void fs_mgr_free_fstab(struct fstab *fstab)
{
int i;
if (!fstab) {
return;
}
for (i = 0; i < fstab->num_entries; i++) {
/* Free the pointers return by strdup(3) */
free(fstab->recs[i].blk_device);
free(fstab->recs[i].logical_partition_name);
free(fstab->recs[i].mount_point);
free(fstab->recs[i].fs_type);
free(fstab->recs[i].fs_options);
free(fstab->recs[i].key_loc);
free(fstab->recs[i].key_dir);
free(fstab->recs[i].label);
free(fstab->recs[i].sysfs_path);
}
/* Free the fstab_recs array created by calloc(3) */
free(fstab->recs);
/* Free fstab */
free(fstab);
}
/* Add an entry to the fstab, and return 0 on success or -1 on error */
int fs_mgr_add_entry(struct fstab *fstab,
const char *mount_point, const char *fs_type,
const char *blk_device)
{
struct fstab_rec *new_fstab_recs;
int n = fstab->num_entries;
new_fstab_recs = (struct fstab_rec *)
realloc(fstab->recs, sizeof(struct fstab_rec) * (n + 1));
if (!new_fstab_recs) {
return -1;
}
/* A new entry was added, so initialize it */
memset(&new_fstab_recs[n], 0, sizeof(struct fstab_rec));
new_fstab_recs[n].mount_point = strdup(mount_point);
new_fstab_recs[n].fs_type = strdup(fs_type);
new_fstab_recs[n].blk_device = strdup(blk_device);
new_fstab_recs[n].length = 0;
/* Update the fstab struct */
fstab->recs = new_fstab_recs;
fstab->num_entries++;
return 0;
}
/*
* Returns the fstab_rec* whose mount_point is path.
* Returns nullptr if not found.
*/
struct fstab_rec* fs_mgr_get_entry_for_mount_point(struct fstab* fstab, const std::string& path) {
if (!fstab) {
return nullptr;
}
for (int i = 0; i < fstab->num_entries; i++) {
if (fstab->recs[i].mount_point && path == fstab->recs[i].mount_point) {
return &fstab->recs[i];
}
}
return nullptr;
}
std::set<std::string> fs_mgr_get_boot_devices() {
// boot_devices can be specified in device tree.
std::string dt_value;
std::string file_name = get_android_dt_dir() + "/boot_devices";
if (read_dt_file(file_name, &dt_value)) {
auto boot_devices = android::base::Split(dt_value, ",");
return std::set<std::string>(boot_devices.begin(), boot_devices.end());
}
// Fallback to extract boot devices from fstab.
Fstab fstab;
if (!ReadDefaultFstab(&fstab)) {
return {};
}
return extract_boot_devices(fstab);
}
FstabEntry FstabRecToFstabEntry(const fstab_rec* fstab_rec) {
FstabEntry entry;
entry.blk_device = fstab_rec->blk_device;
entry.logical_partition_name = fstab_rec->logical_partition_name;
entry.mount_point = fstab_rec->mount_point;
entry.fs_type = fstab_rec->fs_type;
entry.flags = fstab_rec->flags;
entry.fs_options = fstab_rec->fs_options;
entry.fs_mgr_flags.val = fstab_rec->fs_mgr_flags;
entry.key_loc = fstab_rec->key_loc;
entry.key_dir = fstab_rec->key_dir;
entry.verity_loc = fstab_rec->verity_loc;
entry.length = fstab_rec->length;
entry.label = fstab_rec->label;
entry.partnum = fstab_rec->partnum;
entry.swap_prio = fstab_rec->swap_prio;
entry.max_comp_streams = fstab_rec->max_comp_streams;
entry.zram_size = fstab_rec->zram_size;
entry.reserved_size = fstab_rec->reserved_size;
entry.file_contents_mode = fstab_rec->file_contents_mode;
entry.file_names_mode = fstab_rec->file_names_mode;
entry.erase_blk_size = fstab_rec->erase_blk_size;
entry.logical_blk_size = fstab_rec->logical_blk_size;
entry.sysfs_path = fstab_rec->sysfs_path;
return entry;
}
Fstab LegacyFstabToFstab(const struct fstab* legacy_fstab) {
Fstab fstab;
for (int i = 0; i < legacy_fstab->num_entries; i++) {
fstab.emplace_back(FstabRecToFstabEntry(&legacy_fstab->recs[i]));
}
return fstab;
}
fstab* FstabToLegacyFstab(const Fstab& fstab) {
struct fstab* legacy_fstab = static_cast<struct fstab*>(calloc(1, sizeof(struct fstab)));
legacy_fstab->num_entries = fstab.size();
legacy_fstab->recs =
static_cast<fstab_rec*>(calloc(legacy_fstab->num_entries, sizeof(fstab_rec)));
for (int i = 0; i < legacy_fstab->num_entries; i++) {
legacy_fstab->recs[i].blk_device = strdup(fstab[i].blk_device.c_str());
legacy_fstab->recs[i].logical_partition_name =
strdup(fstab[i].logical_partition_name.c_str());
legacy_fstab->recs[i].mount_point = strdup(fstab[i].mount_point.c_str());
legacy_fstab->recs[i].fs_type = strdup(fstab[i].fs_type.c_str());
legacy_fstab->recs[i].flags = fstab[i].flags;
legacy_fstab->recs[i].fs_options = strdup(fstab[i].fs_options.c_str());
legacy_fstab->recs[i].fs_mgr_flags = fstab[i].fs_mgr_flags.val;
legacy_fstab->recs[i].key_loc = strdup(fstab[i].key_loc.c_str());
legacy_fstab->recs[i].key_dir = strdup(fstab[i].key_dir.c_str());
legacy_fstab->recs[i].verity_loc = strdup(fstab[i].verity_loc.c_str());
legacy_fstab->recs[i].length = fstab[i].length;
legacy_fstab->recs[i].label = strdup(fstab[i].label.c_str());
legacy_fstab->recs[i].partnum = fstab[i].partnum;
legacy_fstab->recs[i].swap_prio = fstab[i].swap_prio;
legacy_fstab->recs[i].max_comp_streams = fstab[i].max_comp_streams;
legacy_fstab->recs[i].zram_size = fstab[i].zram_size;
legacy_fstab->recs[i].reserved_size = fstab[i].reserved_size;
legacy_fstab->recs[i].file_contents_mode = fstab[i].file_contents_mode;
legacy_fstab->recs[i].file_names_mode = fstab[i].file_names_mode;
legacy_fstab->recs[i].erase_blk_size = fstab[i].erase_blk_size;
legacy_fstab->recs[i].logical_blk_size = fstab[i].logical_blk_size;
legacy_fstab->recs[i].sysfs_path = strdup(fstab[i].sysfs_path.c_str());
}
return legacy_fstab;
}
int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_VOLDMANAGED;
}
int fs_mgr_is_nonremovable(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_NONREMOVABLE;
}
int fs_mgr_is_verified(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_VERIFY;
}
int fs_mgr_is_avb(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_AVB;
}
int fs_mgr_is_verifyatboot(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_VERIFYATBOOT;
}
int fs_mgr_is_encryptable(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE);
}
int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_FILEENCRYPTION;
}
void fs_mgr_get_file_encryption_modes(const struct fstab_rec *fstab,
const char **contents_mode_ret,
const char **filenames_mode_ret)
{
*contents_mode_ret = flag_to_encryption_mode(file_contents_encryption_modes,
fstab->file_contents_mode);
*filenames_mode_ret = flag_to_encryption_mode(file_names_encryption_modes,
fstab->file_names_mode);
}
int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_FORCEFDEORFBE;
}
int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
}
int fs_mgr_is_notrim(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & MF_NOTRIM;
}
int fs_mgr_is_formattable(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & (MF_FORMATTABLE);
}
int fs_mgr_is_slotselect(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & MF_SLOTSELECT;
}
int fs_mgr_is_nofail(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & MF_NOFAIL;
}
int fs_mgr_is_first_stage_mount(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & MF_FIRST_STAGE_MOUNT;
}
int fs_mgr_is_latemount(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & MF_LATEMOUNT;
}
int fs_mgr_is_quota(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & MF_QUOTA;
}
int fs_mgr_has_sysfs_path(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_SYSFS;
}
int fs_mgr_is_logical(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & MF_LOGICAL;
}
int fs_mgr_is_checkpoint(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & (MF_CHECKPOINT_FS | MF_CHECKPOINT_BLK);
}
int fs_mgr_is_checkpoint_fs(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & MF_CHECKPOINT_FS;
}
int fs_mgr_is_checkpoint_blk(const struct fstab_rec* fstab) {
return fstab->fs_mgr_flags & MF_CHECKPOINT_BLK;
}