Loading libmodprobe/include/modprobe/modprobe.h +4 −0 Original line number Original line Diff line number Diff line Loading @@ -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); Loading @@ -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_; Loading libmodprobe/libmodprobe.cpp +75 −0 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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); } } Loading libmodprobe/libmodprobe_ext.cpp +9 −0 Original line number Original line Diff line number Diff line Loading @@ -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))); Loading libmodprobe/libmodprobe_ext_test.cpp +5 −1 Original line number Original line Diff line number Diff line Loading @@ -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()) { Loading Loading @@ -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; } } Loading libmodprobe/libmodprobe_test.cpp +22 −8 Original line number Original line Diff line number Diff line Loading @@ -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", Loading @@ -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 Loading
libmodprobe/include/modprobe/modprobe.h +4 −0 Original line number Original line Diff line number Diff line Loading @@ -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); Loading @@ -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_; Loading
libmodprobe/libmodprobe.cpp +75 −0 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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); } } Loading
libmodprobe/libmodprobe_ext.cpp +9 −0 Original line number Original line Diff line number Diff line Loading @@ -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))); Loading
libmodprobe/libmodprobe_ext_test.cpp +5 −1 Original line number Original line Diff line number Diff line Loading @@ -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()) { Loading Loading @@ -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; } } Loading
libmodprobe/libmodprobe_test.cpp +22 −8 Original line number Original line Diff line number Diff line Loading @@ -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", Loading @@ -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