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

Commit b02f9b54 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes from topic "toolbox-modprobe"

* changes:
  toolbox: add modprobe
  libmodprobe: add verbose mode
  libmodprobe: add GetAllDependencies
  libmodprobe: add support to list modules
  libmodprobe: add support for a blacklist
  libmodprobe: support parameters in LoadWithAliases
  libmodprobe: add support to remove modules
  libmodprobe: make name canonical in LoadWithAliases
  libmodprobe: make available in vendor
parents 0d061b25 64a55345
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -3,6 +3,7 @@ cc_library_static {
    cflags: [
    cflags: [
        "-Werror",
        "-Werror",
    ],
    ],
    vendor_available: true,
    recovery_available: true,
    recovery_available: true,
    srcs: [
    srcs: [
        "libmodprobe.cpp",
        "libmodprobe.cpp",
+16 −3
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@


#pragma once
#pragma once


#include <set>
#include <string>
#include <string>
#include <unordered_map>
#include <unordered_map>
#include <vector>
#include <vector>
@@ -25,12 +26,21 @@ class Modprobe {
    Modprobe(const std::vector<std::string>&);
    Modprobe(const std::vector<std::string>&);


    bool LoadListedModules();
    bool LoadListedModules();
    bool LoadWithAliases(const std::string& module_name, bool strict);
    bool LoadWithAliases(const std::string& module_name, bool strict,
                         const std::string& parameters = "");
    bool Remove(const std::string& module_name);
    std::vector<std::string> ListModules(const std::string& pattern);
    bool GetAllDependencies(const std::string& module, std::vector<std::string>* pre_dependencies,
                            std::vector<std::string>* dependencies,
                            std::vector<std::string>* post_dependencies);
    void EnableBlacklist(bool enable);
    void EnableVerbose(bool enable);


  private:
  private:
    std::string MakeCanonical(const std::string& module_path);
    std::string MakeCanonical(const std::string& module_path);
    bool InsmodWithDeps(const std::string& module_name);
    bool InsmodWithDeps(const std::string& module_name, const std::string& parameters);
    bool Insmod(const std::string& path_name);
    bool Insmod(const std::string& path_name, const std::string& parameters);
    bool Rmmod(const std::string& module_name);
    std::vector<std::string> GetDependencies(const std::string& module);
    std::vector<std::string> GetDependencies(const std::string& module);
    bool ModuleExists(const std::string& module_name);
    bool ModuleExists(const std::string& module_name);


@@ -39,6 +49,7 @@ class Modprobe {
    bool ParseSoftdepCallback(const std::vector<std::string>& args);
    bool ParseSoftdepCallback(const std::vector<std::string>& args);
    bool ParseLoadCallback(const std::vector<std::string>& args);
    bool ParseLoadCallback(const std::vector<std::string>& args);
    bool ParseOptionsCallback(const std::vector<std::string>& args);
    bool ParseOptionsCallback(const std::vector<std::string>& args);
    bool ParseBlacklistCallback(const std::vector<std::string>& args);
    void ParseCfg(const std::string& cfg, std::function<bool(const std::vector<std::string>&)> f);
    void ParseCfg(const std::string& cfg, std::function<bool(const std::vector<std::string>&)> f);


    std::vector<std::pair<std::string, std::string>> module_aliases_;
    std::vector<std::pair<std::string, std::string>> module_aliases_;
@@ -47,4 +58,6 @@ class Modprobe {
    std::vector<std::pair<std::string, std::string>> module_post_softdep_;
    std::vector<std::pair<std::string, std::string>> module_post_softdep_;
    std::vector<std::string> module_load_;
    std::vector<std::string> module_load_;
    std::unordered_map<std::string, std::string> module_options_;
    std::unordered_map<std::string, std::string> module_options_;
    std::set<std::string> module_blacklist_;
    bool blacklist_enabled = false;
};
};
+115 −11
Original line number Original line Diff line number Diff line
@@ -194,6 +194,31 @@ bool Modprobe::ParseOptionsCallback(const std::vector<std::string>& args) {
    return true;
    return true;
}
}


bool Modprobe::ParseBlacklistCallback(const std::vector<std::string>& args) {
    auto it = args.begin();
    const std::string& type = *it++;

    if (type != "blacklist") {
        LOG(ERROR) << "non-blacklist line encountered in modules.blacklist";
        return false;
    }

    if (args.size() != 2) {
        LOG(ERROR) << "lines in modules.blacklist must have exactly 2 entries, not " << args.size();
        return false;
    }

    const std::string& module = *it++;

    const std::string& canonical_name = MakeCanonical(module);
    if (canonical_name.empty()) {
        return false;
    }
    this->module_blacklist_.emplace(canonical_name);

    return true;
}

void Modprobe::ParseCfg(const std::string& cfg,
void Modprobe::ParseCfg(const std::string& cfg,
                        std::function<bool(const std::vector<std::string>&)> f) {
                        std::function<bool(const std::vector<std::string>&)> f) {
    std::string cfg_contents;
    std::string cfg_contents;
@@ -231,6 +256,23 @@ Modprobe::Modprobe(const std::vector<std::string>& base_paths) {


        auto options_callback = std::bind(&Modprobe::ParseOptionsCallback, this, _1);
        auto options_callback = std::bind(&Modprobe::ParseOptionsCallback, this, _1);
        ParseCfg(base_path + "/modules.options", options_callback);
        ParseCfg(base_path + "/modules.options", options_callback);

        auto blacklist_callback = std::bind(&Modprobe::ParseBlacklistCallback, this, _1);
        ParseCfg(base_path + "/modules.blacklist", blacklist_callback);
    }

    android::base::SetMinimumLogSeverity(android::base::INFO);
}

void Modprobe::EnableBlacklist(bool enable) {
    blacklist_enabled = enable;
}

void Modprobe::EnableVerbose(bool enable) {
    if (enable) {
        android::base::SetMinimumLogSeverity(android::base::VERBOSE);
    } else {
        android::base::SetMinimumLogSeverity(android::base::INFO);
    }
    }
}
}


@@ -242,7 +284,7 @@ std::vector<std::string> Modprobe::GetDependencies(const std::string& module) {
    return it->second;
    return it->second;
}
}


bool Modprobe::InsmodWithDeps(const std::string& module_name) {
bool Modprobe::InsmodWithDeps(const std::string& module_name, const std::string& parameters) {
    if (module_name.empty()) {
    if (module_name.empty()) {
        LOG(ERROR) << "Need valid module name, given: " << module_name;
        LOG(ERROR) << "Need valid module name, given: " << module_name;
        return false;
        return false;
@@ -256,11 +298,8 @@ bool Modprobe::InsmodWithDeps(const std::string& module_name) {


    // load module dependencies in reverse order
    // load module dependencies in reverse order
    for (auto dep = dependencies.rbegin(); dep != dependencies.rend() - 1; ++dep) {
    for (auto dep = dependencies.rbegin(); dep != dependencies.rend() - 1; ++dep) {
        const std::string& canonical_name = MakeCanonical(*dep);
        LOG(VERBOSE) << "Loading hard dep for '" << module_name << "': " << *dep;
        if (canonical_name.empty()) {
        if (!LoadWithAliases(*dep, true)) {
            return false;
        }
        if (!LoadWithAliases(canonical_name, true)) {
            return false;
            return false;
        }
        }
    }
    }
@@ -268,18 +307,20 @@ bool Modprobe::InsmodWithDeps(const std::string& module_name) {
    // try to load soft pre-dependencies
    // try to load soft pre-dependencies
    for (const auto& [module, softdep] : module_pre_softdep_) {
    for (const auto& [module, softdep] : module_pre_softdep_) {
        if (module_name == module) {
        if (module_name == module) {
            LOG(VERBOSE) << "Loading soft pre-dep for '" << module << "': " << softdep;
            LoadWithAliases(softdep, false);
            LoadWithAliases(softdep, false);
        }
        }
    }
    }


    // load target module itself with args
    // load target module itself with args
    if (!Insmod(dependencies[0])) {
    if (!Insmod(dependencies[0], parameters)) {
        return false;
        return false;
    }
    }


    // try to load soft post-dependencies
    // try to load soft post-dependencies
    for (const auto& [module, softdep] : module_post_softdep_) {
    for (const auto& [module, softdep] : module_post_softdep_) {
        if (module_name == module) {
        if (module_name == module) {
            LOG(VERBOSE) << "Loading soft post-dep for '" << module << "': " << softdep;
            LoadWithAliases(softdep, false);
            LoadWithAliases(softdep, false);
        }
        }
    }
    }
@@ -287,25 +328,27 @@ bool Modprobe::InsmodWithDeps(const std::string& module_name) {
    return true;
    return true;
}
}


bool Modprobe::LoadWithAliases(const std::string& module_name, bool strict) {
bool Modprobe::LoadWithAliases(const std::string& module_name, bool strict,
    std::set<std::string> modules_to_load = {module_name};
                               const std::string& parameters) {
    std::set<std::string> modules_to_load = {MakeCanonical(module_name)};
    bool module_loaded = false;
    bool module_loaded = false;


    // use aliases to expand list of modules to load (multiple modules
    // use aliases to expand list of modules to load (multiple modules
    // may alias themselves to the requested name)
    // may alias themselves to the requested name)
    for (const auto& [alias, aliased_module] : module_aliases_) {
    for (const auto& [alias, aliased_module] : module_aliases_) {
        if (fnmatch(alias.c_str(), module_name.c_str(), 0) != 0) continue;
        if (fnmatch(alias.c_str(), module_name.c_str(), 0) != 0) continue;
        LOG(VERBOSE) << "Found alias for '" << module_name << "': '" << aliased_module;
        modules_to_load.emplace(aliased_module);
        modules_to_load.emplace(aliased_module);
    }
    }


    // attempt to load all modules aliased to this name
    // attempt to load all modules aliased to this name
    for (const auto& module : modules_to_load) {
    for (const auto& module : modules_to_load) {
        if (!ModuleExists(module)) continue;
        if (!ModuleExists(module)) continue;
        if (InsmodWithDeps(module)) module_loaded = true;
        if (InsmodWithDeps(module, parameters)) module_loaded = true;
    }
    }


    if (strict && !module_loaded) {
    if (strict && !module_loaded) {
        LOG(ERROR) << "LoadWithAliases did not find a module for " << module_name;
        LOG(ERROR) << "LoadWithAliases was unable to load " << module_name;
        return false;
        return false;
    }
    }
    return true;
    return true;
@@ -319,3 +362,64 @@ bool Modprobe::LoadListedModules() {
    }
    }
    return true;
    return true;
}
}

bool Modprobe::Remove(const std::string& module_name) {
    auto dependencies = GetDependencies(MakeCanonical(module_name));
    if (dependencies.empty()) {
        LOG(ERROR) << "Empty dependencies for module " << module_name;
        return false;
    }
    if (!Rmmod(dependencies[0])) {
        return false;
    }
    for (auto dep = dependencies.begin() + 1; dep != dependencies.end(); ++dep) {
        Rmmod(*dep);
    }
    return true;
}

std::vector<std::string> Modprobe::ListModules(const std::string& pattern) {
    std::vector<std::string> rv;
    for (const auto& [module, deps] : module_deps_) {
        // Attempt to match both the canonical module name and the module filename.
        if (!fnmatch(pattern.c_str(), module.c_str(), 0)) {
            rv.emplace_back(module);
        } else if (!fnmatch(pattern.c_str(), basename(deps[0].c_str()), 0)) {
            rv.emplace_back(deps[0]);
        }
    }
    return rv;
}

bool Modprobe::GetAllDependencies(const std::string& module,
                                  std::vector<std::string>* pre_dependencies,
                                  std::vector<std::string>* dependencies,
                                  std::vector<std::string>* post_dependencies) {
    std::string canonical_name = MakeCanonical(module);
    if (pre_dependencies) {
        pre_dependencies->clear();
        for (const auto& [it_module, it_softdep] : module_pre_softdep_) {
            if (canonical_name == it_module) {
                pre_dependencies->emplace_back(it_softdep);
            }
        }
    }
    if (dependencies) {
        dependencies->clear();
        auto hard_deps = GetDependencies(canonical_name);
        if (hard_deps.empty()) {
            return false;
        }
        for (auto dep = hard_deps.rbegin(); dep != hard_deps.rend(); dep++) {
            dependencies->emplace_back(*dep);
        }
    }
    if (post_dependencies) {
        for (const auto& [it_module, it_softdep] : module_post_softdep_) {
            if (canonical_name == it_module) {
                post_dependencies->emplace_back(it_softdep);
            }
        }
    }
    return true;
}
+19 −1
Original line number Original line Diff line number Diff line
@@ -22,7 +22,7 @@


#include <modprobe/modprobe.h>
#include <modprobe/modprobe.h>


bool Modprobe::Insmod(const std::string& path_name) {
bool Modprobe::Insmod(const std::string& path_name, const std::string& parameters) {
    android::base::unique_fd fd(
    android::base::unique_fd fd(
            TEMP_FAILURE_RETRY(open(path_name.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
            TEMP_FAILURE_RETRY(open(path_name.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
    if (fd == -1) {
    if (fd == -1) {
@@ -35,6 +35,9 @@ bool Modprobe::Insmod(const std::string& path_name) {
    if (options_iter != module_options_.end()) {
    if (options_iter != module_options_.end()) {
        options = options_iter->second;
        options = options_iter->second;
    }
    }
    if (!parameters.empty()) {
        options = options + " " + parameters;
    }


    LOG(INFO) << "Loading module " << path_name << " with args \"" << options << "\"";
    LOG(INFO) << "Loading module " << path_name << " with args \"" << options << "\"";
    int ret = syscall(__NR_finit_module, fd.get(), options.c_str(), 0);
    int ret = syscall(__NR_finit_module, fd.get(), options.c_str(), 0);
@@ -51,17 +54,32 @@ bool Modprobe::Insmod(const std::string& path_name) {
    return true;
    return true;
}
}


bool Modprobe::Rmmod(const std::string& module_name) {
    int ret = syscall(__NR_delete_module, MakeCanonical(module_name).c_str(), O_NONBLOCK);
    if (ret != 0) {
        PLOG(ERROR) << "Failed to remove module '" << module_name << "'";
        return false;
    }
    return true;
}

bool Modprobe::ModuleExists(const std::string& module_name) {
bool Modprobe::ModuleExists(const std::string& module_name) {
    struct stat fileStat;
    struct stat fileStat;
    if (blacklist_enabled && module_blacklist_.count(module_name)) {
        LOG(INFO) << "module " << module_name << " is blacklisted";
        return false;
    }
    auto deps = GetDependencies(module_name);
    auto deps = GetDependencies(module_name);
    if (deps.empty()) {
    if (deps.empty()) {
        // missing deps can happen in the case of an alias
        // missing deps can happen in the case of an alias
        return false;
        return false;
    }
    }
    if (stat(deps.front().c_str(), &fileStat)) {
    if (stat(deps.front().c_str(), &fileStat)) {
        LOG(INFO) << "module " << module_name << " does not exist";
        return false;
        return false;
    }
    }
    if (!S_ISREG(fileStat.st_mode)) {
    if (!S_ISREG(fileStat.st_mode)) {
        LOG(INFO) << "module " << module_name << " is not a regular file";
        return false;
        return false;
    }
    }
    return true;
    return true;
+18 −1
Original line number Original line Diff line number Diff line
@@ -29,7 +29,7 @@


#include "libmodprobe_test.h"
#include "libmodprobe_test.h"


bool Modprobe::Insmod(const std::string& path_name) {
bool Modprobe::Insmod(const std::string& path_name, const std::string& parameters) {
    auto deps = GetDependencies(MakeCanonical(path_name));
    auto deps = GetDependencies(MakeCanonical(path_name));
    if (deps.empty()) {
    if (deps.empty()) {
        return false;
        return false;
@@ -47,12 +47,29 @@ bool Modprobe::Insmod(const std::string& path_name) {
    if (options_iter != module_options_.end()) {
    if (options_iter != module_options_.end()) {
        options = " " + options_iter->second;
        options = " " + options_iter->second;
    }
    }
    if (!parameters.empty()) {
        options = options + " " + parameters;
    }

    modules_loaded.emplace_back(path_name + options);
    modules_loaded.emplace_back(path_name + options);
    return true;
    return true;
}
}


bool Modprobe::Rmmod(const std::string& module_name) {
    for (auto it = modules_loaded.begin(); it != modules_loaded.end(); it++) {
        if (*it == module_name) {
            modules_loaded.erase(it);
            return true;
        }
    }
    return false;
}

bool Modprobe::ModuleExists(const std::string& module_name) {
bool Modprobe::ModuleExists(const std::string& module_name) {
    auto deps = GetDependencies(module_name);
    auto deps = GetDependencies(module_name);
    if (blacklist_enabled && module_blacklist_.count(module_name)) {
        return false;
    }
    if (deps.empty()) {
    if (deps.empty()) {
        // missing deps can happen in the case of an alias
        // missing deps can happen in the case of an alias
        return false;
        return false;
Loading