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

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

Merge "create libmodprobe, integrate into first_stage_init"

parents ad0f27fe 18b981ea
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ cc_defaults {
        "libavb",
        "libc++fs",
        "libcgrouprc_format",
        "libmodprobe",
        "libprotobuf-cpp-lite",
        "libpropertyinfoserializer",
        "libpropertyinfoparser",
+1 −0
Original line number Diff line number Diff line
@@ -110,6 +110,7 @@ LOCAL_STATIC_LIBRARIES := \
    libdexfile_support \
    libunwindstack \
    libbacktrace \
    libmodprobe \

LOCAL_SANITIZE := signed-integer-overflow
# First stage init is weird: it may start without stdout/stderr, and no /proc.
+6 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <modprobe/modprobe.h>
#include <private/android_filesystem_config.h>

#include "debug_ramdisk.h"
@@ -192,6 +193,11 @@ int FirstStageMain(int argc, char** argv) {
        old_root_dir.reset();
    }

    Modprobe m({"/lib/modules"});
    if (!m.LoadListedModules()) {
        LOG(FATAL) << "Failed to load kernel modules";
    }

    if (ForceNormalBoot()) {
        mkdir("/first_stage_ramdisk", 0755);
        // SwitchRoot() must be called with a mount point as the target, so we bind mount the
+4 −131
Original line number Diff line number Diff line
@@ -16,147 +16,20 @@

#include "modalias_handler.h"

#include <fnmatch.h>
#include <sys/syscall.h>

#include <algorithm>
#include <functional>
#include <string>
#include <vector>

#include <android-base/chrono_utils.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>

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

namespace android {
namespace init {

Result<void> ModaliasHandler::ParseDepCallback(std::vector<std::string>&& args) {
    std::vector<std::string> deps;

    // Set first item as our modules path
    std::string::size_type pos = args[0].find(':');
    if (pos != std::string::npos) {
        deps.emplace_back(args[0].substr(0, pos));
    } else {
        return Error() << "dependency lines must start with name followed by ':'";
    }

    // Remaining items are dependencies of our module
    for (auto arg = args.begin() + 1; arg != args.end(); ++arg) {
        deps.push_back(*arg);
    }

    // Key is striped module name to match names in alias file
    std::size_t start = args[0].find_last_of('/');
    std::size_t end = args[0].find(".ko:");
    if ((end - start) <= 1) return Error() << "malformed dependency line";
    auto mod_name = args[0].substr(start + 1, (end - start) - 1);
    // module names can have '-', but their file names will have '_'
    std::replace(mod_name.begin(), mod_name.end(), '-', '_');
    this->module_deps_[mod_name] = deps;

    return {};
}

Result<void> ModaliasHandler::ParseAliasCallback(std::vector<std::string>&& args) {
    auto it = args.begin();
    const std::string& type = *it++;

    if (type != "alias") {
        return Error() << "we only handle alias lines, got: " << type;
    }

    if (args.size() != 3) {
        return Error() << "alias lines must have 3 entries";
    }

    std::string& alias = *it++;
    std::string& module_name = *it++;
    this->module_aliases_.emplace_back(alias, module_name);

    return {};
}

ModaliasHandler::ModaliasHandler() {
    using namespace std::placeholders;

    static const std::string base_paths[] = {
            "/vendor/lib/modules/",
            "/lib/modules/",
            "/odm/lib/modules/",
    };

    Parser alias_parser;
    auto alias_callback = std::bind(&ModaliasHandler::ParseAliasCallback, this, _1);
    alias_parser.AddSingleLineParser("alias", alias_callback);
    for (const auto& base_path : base_paths) alias_parser.ParseConfig(base_path + "modules.alias");

    Parser dep_parser;
    auto dep_callback = std::bind(&ModaliasHandler::ParseDepCallback, this, _1);
    dep_parser.AddSingleLineParser("", dep_callback);
    for (const auto& base_path : base_paths) dep_parser.ParseConfig(base_path + "modules.dep");
}

Result<void> ModaliasHandler::Insmod(const std::string& path_name, const std::string& args) {
    base::unique_fd fd(
            TEMP_FAILURE_RETRY(open(path_name.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
    if (fd == -1) return ErrnoError() << "Could not open module '" << path_name << "'";

    int ret = syscall(__NR_finit_module, fd.get(), args.c_str(), 0);
    if (ret != 0) {
        if (errno == EEXIST) {
            // Module already loaded
            return {};
        }
        return ErrnoError() << "Failed to insmod '" << path_name << "' with args '" << args << "'";
    }

    LOG(INFO) << "Loaded kernel module " << path_name;
    return {};
}

Result<void> ModaliasHandler::InsmodWithDeps(const std::string& module_name,
                                             const std::string& args) {
    if (module_name.empty()) {
        return Error() << "Need valid module name";
    }

    auto it = module_deps_.find(module_name);
    if (it == module_deps_.end()) {
        return Error() << "Module '" << module_name << "' not in dependency file";
    }
    auto& dependencies = it->second;

    // load module dependencies in reverse order
    for (auto dep = dependencies.rbegin(); dep != dependencies.rend() - 1; ++dep) {
        if (auto result = Insmod(*dep, ""); !result) return result;
    }

    // load target module itself with args
    return Insmod(dependencies[0], args);
}
ModaliasHandler::ModaliasHandler(const std::vector<std::string>& base_paths)
    : modprobe_(base_paths) {}

void ModaliasHandler::HandleUevent(const Uevent& uevent) {
    if (uevent.modalias.empty()) return;

    for (const auto& [alias, module] : module_aliases_) {
        if (fnmatch(alias.c_str(), uevent.modalias.c_str(), 0) != 0) continue;  // Keep looking

        LOG(DEBUG) << "Loading kernel module '" << module << "' for alias '" << uevent.modalias
                   << "'";

        if (auto result = InsmodWithDeps(module, ""); !result) {
            LOG(ERROR) << "Cannot load module: " << result.error();
            // try another one since there may be another match
            continue;
        }

        // loading was successful
        return;
    }
    modprobe_.LoadWithAliases(uevent.modalias, true);
}

}  // namespace init
+4 −11
Original line number Diff line number Diff line
@@ -17,10 +17,10 @@
#pragma once

#include <string>
#include <unordered_map>
#include <vector>

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

#include "uevent.h"
#include "uevent_handler.h"

@@ -29,20 +29,13 @@ namespace init {

class ModaliasHandler : public UeventHandler {
  public:
    ModaliasHandler();
    ModaliasHandler(const std::vector<std::string>&);
    virtual ~ModaliasHandler() = default;

    void HandleUevent(const Uevent& uevent) override;

  private:
    Result<void> InsmodWithDeps(const std::string& module_name, const std::string& args);
    Result<void> Insmod(const std::string& path_name, const std::string& args);

    Result<void> ParseDepCallback(std::vector<std::string>&& args);
    Result<void> ParseAliasCallback(std::vector<std::string>&& args);

    std::vector<std::pair<std::string, std::string>> module_aliases_;
    std::unordered_map<std::string, std::vector<std::string>> module_deps_;
    Modprobe modprobe_;
};

}  // namespace init
Loading