Merge "Build libbase with _FILE_OFFSET_BITS=64."
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index ac138a3..824511e 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -40,6 +40,7 @@
"fs_mgr_verity.cpp",
"fs_mgr_dm_linear.cpp",
"fs_mgr_overlayfs.cpp",
+ "fs_mgr_roots.cpp",
"fs_mgr_vendor_overlay.cpp",
],
shared_libs: [
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 88f7a2c..943fe10 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -1179,11 +1179,12 @@
// wrapper to __mount() and expects a fully prepared fstab_rec,
// unlike fs_mgr_do_mount which does more things with avb / verity etc.
-int fs_mgr_do_mount_one(const FstabEntry& entry) {
+int fs_mgr_do_mount_one(const FstabEntry& entry, const std::string& mount_point) {
// Run fsck if needed
prepare_fs_for_mount(entry.blk_device, entry);
- int ret = __mount(entry.blk_device, entry.mount_point, entry);
+ int ret =
+ __mount(entry.blk_device, mount_point.empty() ? entry.mount_point : mount_point, entry);
if (ret) {
ret = (errno == EBUSY) ? FS_MGR_DOMNT_BUSY : FS_MGR_DOMNT_FAILED;
}
diff --git a/fs_mgr/fs_mgr_boot_config.cpp b/fs_mgr/fs_mgr_boot_config.cpp
index 733ad55..abece4d 100644
--- a/fs_mgr/fs_mgr_boot_config.cpp
+++ b/fs_mgr/fs_mgr_boot_config.cpp
@@ -81,6 +81,9 @@
bool fs_mgr_get_boot_config_from_kernel_cmdline(const std::string& key, std::string* out_val) {
std::string cmdline;
if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) return false;
+ if (!cmdline.empty() && cmdline.back() == '\n') {
+ cmdline.pop_back();
+ }
return fs_mgr_get_boot_config_from_kernel(cmdline, key, out_val);
}
diff --git a/fs_mgr/fs_mgr_roots.cpp b/fs_mgr/fs_mgr_roots.cpp
new file mode 100644
index 0000000..f44ff41
--- /dev/null
+++ b/fs_mgr/fs_mgr_roots.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2018 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 "fs_mgr/roots.h"
+
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <string>
+
+#include "fs_mgr.h"
+#include "fs_mgr_dm_linear.h"
+#include "fs_mgr_priv.h"
+
+namespace android {
+namespace fs_mgr {
+
+static constexpr const char* kSystemRoot = "/system";
+
+static bool gDidMapLogicalPartitions = false;
+
+FstabEntry* GetEntryForPath(Fstab* fstab, const std::string& path) {
+ if (path.empty()) return nullptr;
+ std::string str(path);
+ while (true) {
+ auto it = std::find_if(fstab->begin(), fstab->end(),
+ [&str](const auto& entry) { return entry.mount_point == str; });
+ if (it != fstab->end()) return &*it;
+ if (str == "/") break;
+ auto slash = str.find_last_of('/');
+ if (slash == std::string::npos) break;
+ if (slash == 0) {
+ str = "/";
+ } else {
+ str = str.substr(0, slash);
+ }
+ }
+ return nullptr;
+}
+
+enum class MountState {
+ ERROR = -1,
+ NOT_MOUNTED = 0,
+ MOUNTED = 1,
+};
+
+static MountState GetMountState(const std::string& mount_point) {
+ Fstab mounted_fstab;
+ if (!ReadFstabFromFile("/proc/mounts", &mounted_fstab)) {
+ LERROR << "Failed to scan mounted volumes";
+ return MountState::ERROR;
+ }
+
+ auto mv = std::find_if(
+ mounted_fstab.begin(), mounted_fstab.end(),
+ [&mount_point](const auto& entry) { return entry.mount_point == mount_point; });
+ if (mv != mounted_fstab.end()) {
+ return MountState::MOUNTED;
+ }
+ return MountState::NOT_MOUNTED;
+}
+
+bool EnsurePathMounted(Fstab* fstab, const std::string& path, const std::string& mount_pt) {
+ auto rec = GetEntryForPath(fstab, path);
+ if (rec == nullptr) {
+ LERROR << "unknown volume for path [" << path << "]";
+ return false;
+ }
+ if (rec->fs_type == "ramdisk") {
+ // The ramdisk is always mounted.
+ return true;
+ }
+
+ // If we can't acquire the block device for a logical partition, it likely
+ // was never created. In that case we try to create it.
+ if (rec->fs_mgr_flags.logical && !fs_mgr_update_logical_partition(rec)) {
+ if (gDidMapLogicalPartitions) {
+ LERROR << "Failed to find block device for partition";
+ return false;
+ }
+ std::string super_name = fs_mgr_get_super_partition_name();
+ if (!android::fs_mgr::CreateLogicalPartitions("/dev/block/by-name/" + super_name)) {
+ LERROR << "Failed to create logical partitions";
+ return false;
+ }
+ gDidMapLogicalPartitions = true;
+ if (!fs_mgr_update_logical_partition(rec)) {
+ LERROR << "Failed to find block device for partition";
+ return false;
+ }
+ }
+
+ auto mounted = GetMountState(rec->mount_point);
+ if (mounted == MountState::ERROR) {
+ return false;
+ }
+ if (mounted == MountState::MOUNTED) {
+ return true;
+ }
+
+ const std::string mount_point = mount_pt.empty() ? rec->mount_point : mount_pt;
+
+ static const std::vector<std::string> supported_fs{"ext4", "squashfs", "vfat", "f2fs"};
+ if (std::find(supported_fs.begin(), supported_fs.end(), rec->fs_type) == supported_fs.end()) {
+ LERROR << "unknown fs_type \"" << rec->fs_type << "\" for " << mount_point;
+ return false;
+ }
+
+ int result = fs_mgr_do_mount_one(*rec, mount_point);
+ if (result == -1 && rec->fs_mgr_flags.formattable) {
+ PERROR << "Failed to mount " << mount_point << "; formatting";
+ bool crypt_footer = rec->is_encryptable() && rec->key_loc == "footer";
+ if (fs_mgr_do_format(*rec, crypt_footer) != 0) {
+ PERROR << "Failed to format " << mount_point;
+ return false;
+ }
+ result = fs_mgr_do_mount_one(*rec, mount_point);
+ }
+
+ if (result == -1) {
+ PERROR << "Failed to mount " << mount_point;
+ return false;
+ }
+ return true;
+}
+
+bool EnsurePathUnmounted(Fstab* fstab, const std::string& path) {
+ auto rec = GetEntryForPath(fstab, path);
+ if (rec == nullptr) {
+ LERROR << "unknown volume for path [" << path << "]";
+ return false;
+ }
+ if (rec->fs_type == "ramdisk") {
+ // The ramdisk is always mounted; you can't unmount it.
+ return false;
+ }
+
+ Fstab mounted_fstab;
+ if (!ReadFstabFromFile("/proc/mounts", &mounted_fstab)) {
+ LERROR << "Failed to scan mounted volumes";
+ return false;
+ }
+
+ auto mounted = GetMountState(rec->mount_point);
+ if (mounted == MountState::ERROR) {
+ return false;
+ }
+ if (mounted == MountState::NOT_MOUNTED) {
+ return true;
+ }
+
+ int result = umount(rec->mount_point.c_str());
+ if (result == -1) {
+ PWARNING << "Failed to umount " << rec->mount_point;
+ return false;
+ }
+ return true;
+}
+
+std::string GetSystemRoot() {
+ Fstab fstab;
+ if (!ReadDefaultFstab(&fstab)) {
+ LERROR << "Failed to read default fstab";
+ return "";
+ }
+
+ auto it = std::find_if(fstab.begin(), fstab.end(),
+ [](const auto& entry) { return entry.mount_point == kSystemRoot; });
+ if (it == fstab.end()) {
+ return "/";
+ }
+
+ return kSystemRoot;
+}
+
+bool LogicalPartitionsMapped() {
+ return gDidMapLogicalPartitions;
+}
+
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 814ba46..e87332f 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -69,7 +69,7 @@
int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point);
int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point,
bool need_cp);
-int fs_mgr_do_mount_one(const FstabEntry& entry);
+int fs_mgr_do_mount_one(const FstabEntry& entry, const std::string& mount_point = "");
int fs_mgr_do_mount_one(fstab_rec* rec);
int fs_mgr_do_tmpfs_mount(const char *n_name);
fstab_rec const* fs_mgr_get_crypt_entry(fstab const* fstab);
diff --git a/fs_mgr/include/fs_mgr/roots.h b/fs_mgr/include/fs_mgr/roots.h
new file mode 100644
index 0000000..65c59cf
--- /dev/null
+++ b/fs_mgr/include/fs_mgr/roots.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <fs_mgr.h>
+
+namespace android {
+namespace fs_mgr {
+
+// 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.
+FstabEntry* GetEntryForPath(Fstab* fstab, const std::string& path);
+
+// Make sure that the volume 'path' is on is mounted.
+// * If 'mount_point' is nullptr, use mount point in fstab. Caller can call
+// fs_mgr_ensure_path_unmounted() with the same 'path' argument to unmount.
+// * If 'mount_point' is not nullptr, the mount point is overridden. Caller can
+// call umount(mount_point) to unmount.
+// Returns true on success (volume is mounted).
+bool EnsurePathMounted(Fstab* fstab, const std::string& path, const std::string& mount_point = "");
+
+// Make sure that the volume 'path' is on is unmounted. Returns true on
+// success (volume is unmounted).
+bool EnsurePathUnmounted(Fstab* fstab, const std::string& path);
+
+// Return "/system" if it is in default fstab, otherwise "/".
+std::string GetSystemRoot();
+
+// Return true iff logical partitions are mapped when partitions are mounted via ensure_path_mounted
+// functions.
+bool LogicalPartitionsMapped();
+
+} // namespace fs_mgr
+} // namespace android