libmodprobe: parse kernel command line for module options
Bug: 145808811 Test: atest libmodprobe_tests, verify on flame Change-Id: I0b41b1610fe13ae526d38f029da888f6f0d8a02d
This commit is contained in:
parent
ee08c978d2
commit
373a3cadd7
6 changed files with 116 additions and 9 deletions
|
@ -44,6 +44,9 @@ class Modprobe {
|
|||
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 @@ class Modprobe {
|
|||
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_;
|
||||
|
|
|
@ -238,6 +238,80 @@ void Modprobe::ParseCfg(const std::string& cfg,
|
|||
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 @@ Modprobe::Modprobe(const std::vector<std::string>& base_paths) {
|
|||
ParseCfg(base_path + "/modules.blacklist", blacklist_callback);
|
||||
}
|
||||
|
||||
ParseKernelCmdlineOptions();
|
||||
android::base::SetMinimumLogSeverity(android::base::INFO);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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::Insmod(const std::string& path_name, const std::string& parameter
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,13 @@ std::vector<std::string> test_modules;
|
|||
// 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 @@ TEST(libmodprobe, Test) {
|
|||
"/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",
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue