Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bf80e7dd authored by Yifan Hong's avatar Yifan Hong
Browse files

Move parts of roots.cpp from librecovery

Move some mounting functionalities from librecovery so that
other modules can also mount logical partitions correctly.

- Also, refactor to use C++ Fstab struct.
- Also, fixed CreateLogicalPartitions() to take full path of
super device.

Test: run recovery tests
Test: vintf_object_recovery_test

Bug: 118634720
Bug: 113182233
Bug: 62292478
Change-Id: Ie02c3a941ed801fdae5818099faf5f3863444296
parent 0cd2d5f0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ cc_library {
        "fs_mgr_verity.cpp",
        "fs_mgr_dm_linear.cpp",
        "fs_mgr_overlayfs.cpp",
        "fs_mgr_roots.cpp",
        "fs_mgr_vendor_overlay.cpp",
    ],
    shared_libs: [
+195 −0
Original line number Diff line number Diff line
/*
 * 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
+52 −0
Original line number Diff line number Diff line
/*
 * 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