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

Commit 373a3cad authored by Steve Muckle's avatar Steve Muckle
Browse files

libmodprobe: parse kernel command line for module options

Bug: 145808811
Test: atest libmodprobe_tests, verify on flame
Change-Id: I0b41b1610fe13ae526d38f029da888f6f0d8a02d
parent ee08c978
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -44,6 +44,9 @@ class Modprobe {
    bool Rmmod(const std::string& module_name);
    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);
    void AddOption(const std::string& module_name, const std::string& option_name,
                   const std::string& value);
    std::string GetKernelCmdline();


    bool ParseDepCallback(const std::string& base_path, const std::vector<std::string>& args);
    bool ParseDepCallback(const std::string& base_path, const std::vector<std::string>& args);
    bool ParseAliasCallback(const std::vector<std::string>& args);
    bool ParseAliasCallback(const std::vector<std::string>& args);
@@ -51,6 +54,7 @@ class Modprobe {
    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);
    bool ParseBlacklistCallback(const std::vector<std::string>& args);
    void ParseKernelCmdlineOptions();
    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_;
+75 −0
Original line number Original line Diff line number Diff line
@@ -238,6 +238,80 @@ void Modprobe::ParseCfg(const std::string& cfg,
    return;
    return;
}
}


void Modprobe::AddOption(const std::string& module_name, const std::string& option_name,
                         const std::string& value) {
    auto canonical_name = MakeCanonical(module_name);
    auto options_iter = module_options_.find(canonical_name);
    auto option_str = option_name + "=" + value;
    if (options_iter != module_options_.end()) {
        options_iter->second = options_iter->second + " " + option_str;
    } else {
        module_options_.emplace(canonical_name, option_str);
    }
}

void Modprobe::ParseKernelCmdlineOptions(void) {
    std::string cmdline = GetKernelCmdline();
    std::string module_name = "";
    std::string option_name = "";
    std::string value = "";
    bool in_module = true;
    bool in_option = false;
    bool in_value = false;
    bool in_quotes = false;
    int start = 0;

    for (int i = 0; i < cmdline.size(); i++) {
        if (cmdline[i] == '"') {
            in_quotes = !in_quotes;
        }

        if (in_quotes) continue;

        if (cmdline[i] == ' ') {
            if (in_value) {
                value = cmdline.substr(start, i - start);
                if (!module_name.empty() && !option_name.empty()) {
                    AddOption(module_name, option_name, value);
                }
            }
            module_name = "";
            option_name = "";
            value = "";
            in_value = false;
            start = i + 1;
            in_module = true;
            continue;
        }

        if (cmdline[i] == '.') {
            if (in_module) {
                module_name = cmdline.substr(start, i - start);
                start = i + 1;
                in_module = false;
            }
            in_option = true;
            continue;
        }

        if (cmdline[i] == '=') {
            if (in_option) {
                option_name = cmdline.substr(start, i - start);
                start = i + 1;
                in_option = false;
            }
            in_value = true;
            continue;
        }
    }
    if (in_value && !in_quotes) {
        value = cmdline.substr(start, cmdline.size() - start);
        if (!module_name.empty() && !option_name.empty()) {
            AddOption(module_name, option_name, value);
        }
    }
}

Modprobe::Modprobe(const std::vector<std::string>& base_paths) {
Modprobe::Modprobe(const std::vector<std::string>& base_paths) {
    using namespace std::placeholders;
    using namespace std::placeholders;


@@ -261,6 +335,7 @@ Modprobe::Modprobe(const std::vector<std::string>& base_paths) {
        ParseCfg(base_path + "/modules.blacklist", blacklist_callback);
        ParseCfg(base_path + "/modules.blacklist", blacklist_callback);
    }
    }


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


+9 −0
Original line number Original line Diff line number Diff line
@@ -17,11 +17,20 @@
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/syscall.h>


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


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


std::string Modprobe::GetKernelCmdline(void) {
    std::string cmdline;
    if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
        return "";
    }
    return cmdline;
}

bool Modprobe::Insmod(const std::string& path_name, const std::string& parameters) {
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)));
+5 −1
Original line number Original line Diff line number Diff line
@@ -29,6 +29,10 @@


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


std::string Modprobe::GetKernelCmdline(void) {
    return kernel_cmdline;
}

bool Modprobe::Insmod(const std::string& path_name, const std::string& parameters) {
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()) {
@@ -57,7 +61,7 @@ bool Modprobe::Insmod(const std::string& path_name, const std::string& parameter


bool Modprobe::Rmmod(const std::string& module_name) {
bool Modprobe::Rmmod(const std::string& module_name) {
    for (auto it = modules_loaded.begin(); it != modules_loaded.end(); it++) {
    for (auto it = modules_loaded.begin(); it != modules_loaded.end(); it++) {
        if (*it == module_name) {
        if (*it == module_name || android::base::StartsWith(*it, module_name + " ")) {
            modules_loaded.erase(it);
            modules_loaded.erase(it);
            return true;
            return true;
        }
        }
+22 −8
Original line number Original line Diff line number Diff line
@@ -31,7 +31,13 @@ std::vector<std::string> test_modules;
// Used by libmodprobe_ext_test to report which modules would have been loaded.
// Used by libmodprobe_ext_test to report which modules would have been loaded.
std::vector<std::string> modules_loaded;
std::vector<std::string> modules_loaded;


// Used by libmodprobe_ext_test to fake a kernel commandline
std::string kernel_cmdline;

TEST(libmodprobe, Test) {
TEST(libmodprobe, Test) {
    kernel_cmdline =
            "flag1 flag2 test1.option1=50 test4.option3=\"set x\" test1.option2=60 "
            "test8. test5.option1= test10.option1=1";
    test_modules = {
    test_modules = {
            "/test1.ko",  "/test2.ko",  "/test3.ko",  "/test4.ko",  "/test5.ko",
            "/test1.ko",  "/test2.ko",  "/test3.ko",  "/test4.ko",  "/test5.ko",
            "/test6.ko",  "/test7.ko",  "/test8.ko",  "/test9.ko",  "/test10.ko",
            "/test6.ko",  "/test7.ko",  "/test8.ko",  "/test9.ko",  "/test10.ko",
@@ -42,25 +48,33 @@ TEST(libmodprobe, Test) {
            "/test14.ko",
            "/test14.ko",
            "/test15.ko",
            "/test15.ko",
            "/test3.ko",
            "/test3.ko",
            "/test4.ko",
            "/test4.ko option3=\"set x\"",
            "/test1.ko",
            "/test1.ko option1=50 option2=60",
            "/test6.ko",
            "/test6.ko",
            "/test2.ko",
            "/test2.ko",
            "/test5.ko",
            "/test5.ko option1=",
            "/test8.ko",
            "/test8.ko",
            "/test7.ko param1=4",
            "/test7.ko param1=4",
            "/test9.ko param_x=1 param_y=2 param_z=3",
            "/test9.ko param_x=1 param_y=2 param_z=3",
            "/test10.ko",
            "/test10.ko option1=1",
            "/test12.ko",
            "/test12.ko",
            "/test11.ko",
            "/test11.ko",
            "/test13.ko",
            "/test13.ko",
    };
    };


    std::vector<std::string> expected_after_remove = {
    std::vector<std::string> expected_after_remove = {
            "/test14.ko", "/test15.ko",         "/test1.ko",
            "/test14.ko",
            "/test6.ko",  "/test2.ko",          "/test5.ko",
            "/test15.ko",
            "/test8.ko",  "/test7.ko param1=4", "/test9.ko param_x=1 param_y=2 param_z=3",
            "/test1.ko option1=50 option2=60",
            "/test10.ko", "/test12.ko",         "/test11.ko",
            "/test6.ko",
            "/test2.ko",
            "/test5.ko option1=",
            "/test8.ko",
            "/test7.ko param1=4",
            "/test9.ko param_x=1 param_y=2 param_z=3",
            "/test10.ko option1=1",
            "/test12.ko",
            "/test11.ko",
            "/test13.ko",
            "/test13.ko",
    };
    };


Loading