| /* | |
| * 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 entry = GetEntryForMountPoint(fstab, str); | |
| if (entry != nullptr) return entry; | |
| 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 = GetEntryForMountPoint(&mounted_fstab, mount_point); | |
| if (mv != nullptr) { | |
| 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", "none"}; | |
| 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 entry = GetEntryForMountPoint(&fstab, kSystemRoot); | |
| if (entry == nullptr) { | |
| return "/"; | |
| } | |
| return kSystemRoot; | |
| } | |
| bool LogicalPartitionsMapped() { | |
| return gDidMapLogicalPartitions; | |
| } | |
| } // namespace fs_mgr | |
| } // namespace android |