Merge "libmodprobe: parse kernel command line for module options" am: d1e9812217 am: 6d46873127 am: 0019007173
Change-Id: I728a441962ea5f358c48a2b6fa43ce131c1f0eba
diff --git a/libmodprobe/include/modprobe/modprobe.h b/libmodprobe/include/modprobe/modprobe.h
index 333fc55..ee6ae7a 100644
--- a/libmodprobe/include/modprobe/modprobe.h
+++ b/libmodprobe/include/modprobe/modprobe.h
@@ -44,6 +44,9 @@
bool Rmmod(const std::string& module_name);
std::vector<std::string> GetDependencies(const std::string& module);
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 ParseAliasCallback(const std::vector<std::string>& args);
@@ -51,6 +54,7 @@
bool ParseLoadCallback(const std::vector<std::string>& args);
bool ParseOptionsCallback(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);
std::vector<std::pair<std::string, std::string>> module_aliases_;
diff --git a/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp
index 6b9107f..f22bbf1 100644
--- a/libmodprobe/libmodprobe.cpp
+++ b/libmodprobe/libmodprobe.cpp
@@ -238,6 +238,80 @@
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) {
using namespace std::placeholders;
@@ -261,6 +335,7 @@
ParseCfg(base_path + "/modules.blacklist", blacklist_callback);
}
+ ParseKernelCmdlineOptions();
android::base::SetMinimumLogSeverity(android::base::INFO);
}
diff --git a/libmodprobe/libmodprobe_ext.cpp b/libmodprobe/libmodprobe_ext.cpp
index 8bebe4c..99472c1 100644
--- a/libmodprobe/libmodprobe_ext.cpp
+++ b/libmodprobe/libmodprobe_ext.cpp
@@ -17,11 +17,20 @@
#include <sys/stat.h>
#include <sys/syscall.h>
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.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) {
android::base::unique_fd fd(
TEMP_FAILURE_RETRY(open(path_name.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
diff --git a/libmodprobe/libmodprobe_ext_test.cpp b/libmodprobe/libmodprobe_ext_test.cpp
index 7d817b1..057dea3 100644
--- a/libmodprobe/libmodprobe_ext_test.cpp
+++ b/libmodprobe/libmodprobe_ext_test.cpp
@@ -29,6 +29,10 @@
#include "libmodprobe_test.h"
+std::string Modprobe::GetKernelCmdline(void) {
+ return kernel_cmdline;
+}
+
bool Modprobe::Insmod(const std::string& path_name, const std::string& parameters) {
auto deps = GetDependencies(MakeCanonical(path_name));
if (deps.empty()) {
@@ -57,7 +61,7 @@
bool Modprobe::Rmmod(const std::string& module_name) {
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);
return true;
}
diff --git a/libmodprobe/libmodprobe_test.cpp b/libmodprobe/libmodprobe_test.cpp
index a711631..879c7f2 100644
--- a/libmodprobe/libmodprobe_test.cpp
+++ b/libmodprobe/libmodprobe_test.cpp
@@ -31,7 +31,13 @@
// Used by libmodprobe_ext_test to report which modules would have been loaded.
std::vector<std::string> modules_loaded;
+// Used by libmodprobe_ext_test to fake a kernel commandline
+std::string kernel_cmdline;
+
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 = {
"/test1.ko", "/test2.ko", "/test3.ko", "/test4.ko", "/test5.ko",
"/test6.ko", "/test7.ko", "/test8.ko", "/test9.ko", "/test10.ko",
@@ -42,25 +48,33 @@
"/test14.ko",
"/test15.ko",
"/test3.ko",
- "/test4.ko",
- "/test1.ko",
+ "/test4.ko option3=\"set x\"",
+ "/test1.ko option1=50 option2=60",
"/test6.ko",
"/test2.ko",
- "/test5.ko",
+ "/test5.ko option1=",
"/test8.ko",
"/test7.ko param1=4",
"/test9.ko param_x=1 param_y=2 param_z=3",
- "/test10.ko",
+ "/test10.ko option1=1",
"/test12.ko",
"/test11.ko",
"/test13.ko",
};
std::vector<std::string> expected_after_remove = {
- "/test14.ko", "/test15.ko", "/test1.ko",
- "/test6.ko", "/test2.ko", "/test5.ko",
- "/test8.ko", "/test7.ko param1=4", "/test9.ko param_x=1 param_y=2 param_z=3",
- "/test10.ko", "/test12.ko", "/test11.ko",
+ "/test14.ko",
+ "/test15.ko",
+ "/test1.ko option1=50 option2=60",
+ "/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",
};
diff --git a/libmodprobe/libmodprobe_test.h b/libmodprobe/libmodprobe_test.h
index a001b69..e7b949f 100644
--- a/libmodprobe/libmodprobe_test.h
+++ b/libmodprobe/libmodprobe_test.h
@@ -19,5 +19,6 @@
#include <string>
#include <vector>
+extern std::string kernel_cmdline;
extern std::vector<std::string> test_modules;
extern std::vector<std::string> modules_loaded;