Merge changes from topic "toolbox-modprobe"
* changes: toolbox: add modprobe libmodprobe: add verbose mode libmodprobe: add GetAllDependencies libmodprobe: add support to list modules libmodprobe: add support for a blacklist libmodprobe: support parameters in LoadWithAliases libmodprobe: add support to remove modules libmodprobe: make name canonical in LoadWithAliases libmodprobe: make available in vendor
This commit is contained in:
commit
b02f9b549c
9 changed files with 419 additions and 27 deletions
|
@ -3,6 +3,7 @@ cc_library_static {
|
|||
cflags: [
|
||||
"-Werror",
|
||||
],
|
||||
vendor_available: true,
|
||||
recovery_available: true,
|
||||
srcs: [
|
||||
"libmodprobe.cpp",
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
@ -25,12 +26,21 @@ class Modprobe {
|
|||
Modprobe(const std::vector<std::string>&);
|
||||
|
||||
bool LoadListedModules();
|
||||
bool LoadWithAliases(const std::string& module_name, bool strict);
|
||||
bool LoadWithAliases(const std::string& module_name, bool strict,
|
||||
const std::string& parameters = "");
|
||||
bool Remove(const std::string& module_name);
|
||||
std::vector<std::string> ListModules(const std::string& pattern);
|
||||
bool GetAllDependencies(const std::string& module, std::vector<std::string>* pre_dependencies,
|
||||
std::vector<std::string>* dependencies,
|
||||
std::vector<std::string>* post_dependencies);
|
||||
void EnableBlacklist(bool enable);
|
||||
void EnableVerbose(bool enable);
|
||||
|
||||
private:
|
||||
std::string MakeCanonical(const std::string& module_path);
|
||||
bool InsmodWithDeps(const std::string& module_name);
|
||||
bool Insmod(const std::string& path_name);
|
||||
bool InsmodWithDeps(const std::string& module_name, const std::string& parameters);
|
||||
bool Insmod(const std::string& path_name, const std::string& parameters);
|
||||
bool Rmmod(const std::string& module_name);
|
||||
std::vector<std::string> GetDependencies(const std::string& module);
|
||||
bool ModuleExists(const std::string& module_name);
|
||||
|
||||
|
@ -39,6 +49,7 @@ class Modprobe {
|
|||
bool ParseSoftdepCallback(const std::vector<std::string>& args);
|
||||
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 ParseCfg(const std::string& cfg, std::function<bool(const std::vector<std::string>&)> f);
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> module_aliases_;
|
||||
|
@ -47,4 +58,6 @@ class Modprobe {
|
|||
std::vector<std::pair<std::string, std::string>> module_post_softdep_;
|
||||
std::vector<std::string> module_load_;
|
||||
std::unordered_map<std::string, std::string> module_options_;
|
||||
std::set<std::string> module_blacklist_;
|
||||
bool blacklist_enabled = false;
|
||||
};
|
||||
|
|
|
@ -194,6 +194,31 @@ bool Modprobe::ParseOptionsCallback(const std::vector<std::string>& args) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Modprobe::ParseBlacklistCallback(const std::vector<std::string>& args) {
|
||||
auto it = args.begin();
|
||||
const std::string& type = *it++;
|
||||
|
||||
if (type != "blacklist") {
|
||||
LOG(ERROR) << "non-blacklist line encountered in modules.blacklist";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (args.size() != 2) {
|
||||
LOG(ERROR) << "lines in modules.blacklist must have exactly 2 entries, not " << args.size();
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string& module = *it++;
|
||||
|
||||
const std::string& canonical_name = MakeCanonical(module);
|
||||
if (canonical_name.empty()) {
|
||||
return false;
|
||||
}
|
||||
this->module_blacklist_.emplace(canonical_name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Modprobe::ParseCfg(const std::string& cfg,
|
||||
std::function<bool(const std::vector<std::string>&)> f) {
|
||||
std::string cfg_contents;
|
||||
|
@ -231,6 +256,23 @@ Modprobe::Modprobe(const std::vector<std::string>& base_paths) {
|
|||
|
||||
auto options_callback = std::bind(&Modprobe::ParseOptionsCallback, this, _1);
|
||||
ParseCfg(base_path + "/modules.options", options_callback);
|
||||
|
||||
auto blacklist_callback = std::bind(&Modprobe::ParseBlacklistCallback, this, _1);
|
||||
ParseCfg(base_path + "/modules.blacklist", blacklist_callback);
|
||||
}
|
||||
|
||||
android::base::SetMinimumLogSeverity(android::base::INFO);
|
||||
}
|
||||
|
||||
void Modprobe::EnableBlacklist(bool enable) {
|
||||
blacklist_enabled = enable;
|
||||
}
|
||||
|
||||
void Modprobe::EnableVerbose(bool enable) {
|
||||
if (enable) {
|
||||
android::base::SetMinimumLogSeverity(android::base::VERBOSE);
|
||||
} else {
|
||||
android::base::SetMinimumLogSeverity(android::base::INFO);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -242,7 +284,7 @@ std::vector<std::string> Modprobe::GetDependencies(const std::string& module) {
|
|||
return it->second;
|
||||
}
|
||||
|
||||
bool Modprobe::InsmodWithDeps(const std::string& module_name) {
|
||||
bool Modprobe::InsmodWithDeps(const std::string& module_name, const std::string& parameters) {
|
||||
if (module_name.empty()) {
|
||||
LOG(ERROR) << "Need valid module name, given: " << module_name;
|
||||
return false;
|
||||
|
@ -256,11 +298,8 @@ bool Modprobe::InsmodWithDeps(const std::string& module_name) {
|
|||
|
||||
// load module dependencies in reverse order
|
||||
for (auto dep = dependencies.rbegin(); dep != dependencies.rend() - 1; ++dep) {
|
||||
const std::string& canonical_name = MakeCanonical(*dep);
|
||||
if (canonical_name.empty()) {
|
||||
return false;
|
||||
}
|
||||
if (!LoadWithAliases(canonical_name, true)) {
|
||||
LOG(VERBOSE) << "Loading hard dep for '" << module_name << "': " << *dep;
|
||||
if (!LoadWithAliases(*dep, true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -268,18 +307,20 @@ bool Modprobe::InsmodWithDeps(const std::string& module_name) {
|
|||
// try to load soft pre-dependencies
|
||||
for (const auto& [module, softdep] : module_pre_softdep_) {
|
||||
if (module_name == module) {
|
||||
LOG(VERBOSE) << "Loading soft pre-dep for '" << module << "': " << softdep;
|
||||
LoadWithAliases(softdep, false);
|
||||
}
|
||||
}
|
||||
|
||||
// load target module itself with args
|
||||
if (!Insmod(dependencies[0])) {
|
||||
if (!Insmod(dependencies[0], parameters)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// try to load soft post-dependencies
|
||||
for (const auto& [module, softdep] : module_post_softdep_) {
|
||||
if (module_name == module) {
|
||||
LOG(VERBOSE) << "Loading soft post-dep for '" << module << "': " << softdep;
|
||||
LoadWithAliases(softdep, false);
|
||||
}
|
||||
}
|
||||
|
@ -287,25 +328,27 @@ bool Modprobe::InsmodWithDeps(const std::string& module_name) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Modprobe::LoadWithAliases(const std::string& module_name, bool strict) {
|
||||
std::set<std::string> modules_to_load = {module_name};
|
||||
bool Modprobe::LoadWithAliases(const std::string& module_name, bool strict,
|
||||
const std::string& parameters) {
|
||||
std::set<std::string> modules_to_load = {MakeCanonical(module_name)};
|
||||
bool module_loaded = false;
|
||||
|
||||
// use aliases to expand list of modules to load (multiple modules
|
||||
// may alias themselves to the requested name)
|
||||
for (const auto& [alias, aliased_module] : module_aliases_) {
|
||||
if (fnmatch(alias.c_str(), module_name.c_str(), 0) != 0) continue;
|
||||
LOG(VERBOSE) << "Found alias for '" << module_name << "': '" << aliased_module;
|
||||
modules_to_load.emplace(aliased_module);
|
||||
}
|
||||
|
||||
// attempt to load all modules aliased to this name
|
||||
for (const auto& module : modules_to_load) {
|
||||
if (!ModuleExists(module)) continue;
|
||||
if (InsmodWithDeps(module)) module_loaded = true;
|
||||
if (InsmodWithDeps(module, parameters)) module_loaded = true;
|
||||
}
|
||||
|
||||
if (strict && !module_loaded) {
|
||||
LOG(ERROR) << "LoadWithAliases did not find a module for " << module_name;
|
||||
LOG(ERROR) << "LoadWithAliases was unable to load " << module_name;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -319,3 +362,64 @@ bool Modprobe::LoadListedModules() {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Modprobe::Remove(const std::string& module_name) {
|
||||
auto dependencies = GetDependencies(MakeCanonical(module_name));
|
||||
if (dependencies.empty()) {
|
||||
LOG(ERROR) << "Empty dependencies for module " << module_name;
|
||||
return false;
|
||||
}
|
||||
if (!Rmmod(dependencies[0])) {
|
||||
return false;
|
||||
}
|
||||
for (auto dep = dependencies.begin() + 1; dep != dependencies.end(); ++dep) {
|
||||
Rmmod(*dep);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::string> Modprobe::ListModules(const std::string& pattern) {
|
||||
std::vector<std::string> rv;
|
||||
for (const auto& [module, deps] : module_deps_) {
|
||||
// Attempt to match both the canonical module name and the module filename.
|
||||
if (!fnmatch(pattern.c_str(), module.c_str(), 0)) {
|
||||
rv.emplace_back(module);
|
||||
} else if (!fnmatch(pattern.c_str(), basename(deps[0].c_str()), 0)) {
|
||||
rv.emplace_back(deps[0]);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool Modprobe::GetAllDependencies(const std::string& module,
|
||||
std::vector<std::string>* pre_dependencies,
|
||||
std::vector<std::string>* dependencies,
|
||||
std::vector<std::string>* post_dependencies) {
|
||||
std::string canonical_name = MakeCanonical(module);
|
||||
if (pre_dependencies) {
|
||||
pre_dependencies->clear();
|
||||
for (const auto& [it_module, it_softdep] : module_pre_softdep_) {
|
||||
if (canonical_name == it_module) {
|
||||
pre_dependencies->emplace_back(it_softdep);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dependencies) {
|
||||
dependencies->clear();
|
||||
auto hard_deps = GetDependencies(canonical_name);
|
||||
if (hard_deps.empty()) {
|
||||
return false;
|
||||
}
|
||||
for (auto dep = hard_deps.rbegin(); dep != hard_deps.rend(); dep++) {
|
||||
dependencies->emplace_back(*dep);
|
||||
}
|
||||
}
|
||||
if (post_dependencies) {
|
||||
for (const auto& [it_module, it_softdep] : module_post_softdep_) {
|
||||
if (canonical_name == it_module) {
|
||||
post_dependencies->emplace_back(it_softdep);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#include <modprobe/modprobe.h>
|
||||
|
||||
bool Modprobe::Insmod(const std::string& path_name) {
|
||||
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)));
|
||||
if (fd == -1) {
|
||||
|
@ -35,6 +35,9 @@ bool Modprobe::Insmod(const std::string& path_name) {
|
|||
if (options_iter != module_options_.end()) {
|
||||
options = options_iter->second;
|
||||
}
|
||||
if (!parameters.empty()) {
|
||||
options = options + " " + parameters;
|
||||
}
|
||||
|
||||
LOG(INFO) << "Loading module " << path_name << " with args \"" << options << "\"";
|
||||
int ret = syscall(__NR_finit_module, fd.get(), options.c_str(), 0);
|
||||
|
@ -51,17 +54,32 @@ bool Modprobe::Insmod(const std::string& path_name) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Modprobe::Rmmod(const std::string& module_name) {
|
||||
int ret = syscall(__NR_delete_module, MakeCanonical(module_name).c_str(), O_NONBLOCK);
|
||||
if (ret != 0) {
|
||||
PLOG(ERROR) << "Failed to remove module '" << module_name << "'";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Modprobe::ModuleExists(const std::string& module_name) {
|
||||
struct stat fileStat;
|
||||
if (blacklist_enabled && module_blacklist_.count(module_name)) {
|
||||
LOG(INFO) << "module " << module_name << " is blacklisted";
|
||||
return false;
|
||||
}
|
||||
auto deps = GetDependencies(module_name);
|
||||
if (deps.empty()) {
|
||||
// missing deps can happen in the case of an alias
|
||||
return false;
|
||||
}
|
||||
if (stat(deps.front().c_str(), &fileStat)) {
|
||||
LOG(INFO) << "module " << module_name << " does not exist";
|
||||
return false;
|
||||
}
|
||||
if (!S_ISREG(fileStat.st_mode)) {
|
||||
LOG(INFO) << "module " << module_name << " is not a regular file";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
#include "libmodprobe_test.h"
|
||||
|
||||
bool Modprobe::Insmod(const std::string& path_name) {
|
||||
bool Modprobe::Insmod(const std::string& path_name, const std::string& parameters) {
|
||||
auto deps = GetDependencies(MakeCanonical(path_name));
|
||||
if (deps.empty()) {
|
||||
return false;
|
||||
|
@ -47,12 +47,29 @@ bool Modprobe::Insmod(const std::string& path_name) {
|
|||
if (options_iter != module_options_.end()) {
|
||||
options = " " + options_iter->second;
|
||||
}
|
||||
if (!parameters.empty()) {
|
||||
options = options + " " + parameters;
|
||||
}
|
||||
|
||||
modules_loaded.emplace_back(path_name + options);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Modprobe::Rmmod(const std::string& module_name) {
|
||||
for (auto it = modules_loaded.begin(); it != modules_loaded.end(); it++) {
|
||||
if (*it == module_name) {
|
||||
modules_loaded.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Modprobe::ModuleExists(const std::string& module_name) {
|
||||
auto deps = GetDependencies(module_name);
|
||||
if (blacklist_enabled && module_blacklist_.count(module_name)) {
|
||||
return false;
|
||||
}
|
||||
if (deps.empty()) {
|
||||
// missing deps can happen in the case of an alias
|
||||
return false;
|
||||
|
|
|
@ -56,6 +56,14 @@ TEST(libmodprobe, Test) {
|
|||
"/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",
|
||||
"/test13.ko",
|
||||
};
|
||||
|
||||
const std::string modules_dep =
|
||||
"test1.ko:\n"
|
||||
"test2.ko:\n"
|
||||
|
@ -91,6 +99,10 @@ TEST(libmodprobe, Test) {
|
|||
"options test9.ko param_x=1 param_y=2 param_z=3\n"
|
||||
"options test100.ko param_1=1\n";
|
||||
|
||||
const std::string modules_blacklist =
|
||||
"blacklist test9.ko\n"
|
||||
"blacklist test3.ko\n";
|
||||
|
||||
const std::string modules_load =
|
||||
"test4.ko\n"
|
||||
"test1.ko\n"
|
||||
|
@ -101,17 +113,20 @@ TEST(libmodprobe, Test) {
|
|||
"test11.ko\n";
|
||||
|
||||
TemporaryDir dir;
|
||||
ASSERT_TRUE(android::base::WriteStringToFile(
|
||||
modules_alias, std::string(dir.path) + "/modules.alias", 0600, getuid(), getgid()));
|
||||
auto dir_path = std::string(dir.path);
|
||||
ASSERT_TRUE(android::base::WriteStringToFile(modules_alias, dir_path + "/modules.alias", 0600,
|
||||
getuid(), getgid()));
|
||||
|
||||
ASSERT_TRUE(android::base::WriteStringToFile(
|
||||
modules_dep, std::string(dir.path) + "/modules.dep", 0600, getuid(), getgid()));
|
||||
ASSERT_TRUE(android::base::WriteStringToFile(
|
||||
modules_softdep, std::string(dir.path) + "/modules.softdep", 0600, getuid(), getgid()));
|
||||
ASSERT_TRUE(android::base::WriteStringToFile(
|
||||
modules_options, std::string(dir.path) + "/modules.options", 0600, getuid(), getgid()));
|
||||
ASSERT_TRUE(android::base::WriteStringToFile(
|
||||
modules_load, std::string(dir.path) + "/modules.load", 0600, getuid(), getgid()));
|
||||
ASSERT_TRUE(android::base::WriteStringToFile(modules_dep, dir_path + "/modules.dep", 0600,
|
||||
getuid(), getgid()));
|
||||
ASSERT_TRUE(android::base::WriteStringToFile(modules_softdep, dir_path + "/modules.softdep",
|
||||
0600, getuid(), getgid()));
|
||||
ASSERT_TRUE(android::base::WriteStringToFile(modules_options, dir_path + "/modules.options",
|
||||
0600, getuid(), getgid()));
|
||||
ASSERT_TRUE(android::base::WriteStringToFile(modules_load, dir_path + "/modules.load", 0600,
|
||||
getuid(), getgid()));
|
||||
ASSERT_TRUE(android::base::WriteStringToFile(modules_blacklist, dir_path + "/modules.blacklist",
|
||||
0600, getuid(), getgid()));
|
||||
|
||||
for (auto i = test_modules.begin(); i != test_modules.end(); ++i) {
|
||||
*i = dir.path + *i;
|
||||
|
@ -131,4 +146,21 @@ TEST(libmodprobe, Test) {
|
|||
}
|
||||
|
||||
EXPECT_TRUE(modules_loaded == expected_modules_loaded);
|
||||
|
||||
EXPECT_TRUE(m.Remove("test4"));
|
||||
|
||||
GTEST_LOG_(INFO) << "Expected modules loaded after removing test4 (in order):";
|
||||
for (auto i = expected_after_remove.begin(); i != expected_after_remove.end(); ++i) {
|
||||
*i = dir.path + *i;
|
||||
GTEST_LOG_(INFO) << "\"" << *i << "\"";
|
||||
}
|
||||
GTEST_LOG_(INFO) << "Actual modules loaded after removing test4 (in order):";
|
||||
for (auto i = modules_loaded.begin(); i != modules_loaded.end(); ++i) {
|
||||
GTEST_LOG_(INFO) << "\"" << *i << "\"";
|
||||
}
|
||||
|
||||
EXPECT_TRUE(modules_loaded == expected_after_remove);
|
||||
|
||||
m.EnableBlacklist(true);
|
||||
EXPECT_FALSE(m.LoadWithAliases("test4", true));
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ cc_defaults {
|
|||
"toolbox.c",
|
||||
"getevent.c",
|
||||
"getprop.cpp",
|
||||
"modprobe.cpp",
|
||||
"setprop.cpp",
|
||||
"start.cpp",
|
||||
],
|
||||
|
@ -33,11 +34,15 @@ cc_defaults {
|
|||
shared_libs: [
|
||||
"libbase",
|
||||
],
|
||||
static_libs: ["libpropertyinfoparser"],
|
||||
static_libs: [
|
||||
"libmodprobe",
|
||||
"libpropertyinfoparser",
|
||||
],
|
||||
|
||||
symlinks: [
|
||||
"getevent",
|
||||
"getprop",
|
||||
"modprobe",
|
||||
"setprop",
|
||||
"start",
|
||||
"stop",
|
||||
|
|
201
toolbox/modprobe.cpp
Normal file
201
toolbox/modprobe.cpp
Normal file
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
|
||||
#include <android-base/strings.h>
|
||||
#include <modprobe/modprobe.h>
|
||||
|
||||
enum modprobe_mode {
|
||||
AddModulesMode,
|
||||
RemoveModulesMode,
|
||||
ListModulesMode,
|
||||
ShowDependenciesMode,
|
||||
};
|
||||
|
||||
static void print_usage(void) {
|
||||
std::cerr << "Usage:" << std::endl;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << " modprobe [-alrqvsDb] [-d DIR] [MODULE]+" << std::endl;
|
||||
std::cerr << " modprobe [-alrqvsDb] [-d DIR] MODULE [symbol=value][...]" << std::endl;
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "Options:" << std::endl;
|
||||
std::cerr << " -b: Apply blacklist to module names too" << std::endl;
|
||||
std::cerr << " -d: Load modules from DIR, option may be used multiple times" << std::endl;
|
||||
std::cerr << " -D: Print dependencies for modules only, do not load";
|
||||
std::cerr << " -h: Print this help" << std::endl;
|
||||
std::cerr << " -l: List modules matching pattern" << std::endl;
|
||||
std::cerr << " -r: Remove MODULE (multiple modules may be specified)" << std::endl;
|
||||
std::cerr << " -q: Quiet" << std::endl;
|
||||
std::cerr << " -v: Verbose" << std::endl;
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
#define check_mode() \
|
||||
if (mode != AddModulesMode) { \
|
||||
std::cerr << "Error, multiple mode flags specified" << std::endl; \
|
||||
print_usage(); \
|
||||
return EXIT_FAILURE; \
|
||||
}
|
||||
|
||||
extern "C" int modprobe_main(int argc, char** argv) {
|
||||
std::vector<std::string> modules;
|
||||
std::string module_parameters;
|
||||
std::vector<std::string> mod_dirs;
|
||||
modprobe_mode mode = AddModulesMode;
|
||||
bool blacklist = false;
|
||||
bool verbose = false;
|
||||
int rv = EXIT_SUCCESS;
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "abd:Dhlqrv")) != -1) {
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
// toybox modprobe supported -a to load multiple modules, this
|
||||
// is supported here by default, ignore flag
|
||||
check_mode();
|
||||
break;
|
||||
case 'b':
|
||||
blacklist = true;
|
||||
break;
|
||||
case 'd':
|
||||
mod_dirs.emplace_back(optarg);
|
||||
break;
|
||||
case 'D':
|
||||
check_mode();
|
||||
mode = ShowDependenciesMode;
|
||||
break;
|
||||
case 'h':
|
||||
print_usage();
|
||||
return EXIT_SUCCESS;
|
||||
case 'l':
|
||||
check_mode();
|
||||
mode = ListModulesMode;
|
||||
break;
|
||||
case 'q':
|
||||
verbose = false;
|
||||
break;
|
||||
case 'r':
|
||||
check_mode();
|
||||
mode = RemoveModulesMode;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
default:
|
||||
std::cerr << "Unrecognized option: " << opt << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
int parameter_count = 0;
|
||||
for (opt = optind; opt < argc; opt++) {
|
||||
if (!strchr(argv[opt], '=')) {
|
||||
modules.emplace_back(argv[opt]);
|
||||
} else {
|
||||
parameter_count++;
|
||||
if (module_parameters.empty()) {
|
||||
module_parameters = argv[opt];
|
||||
} else {
|
||||
module_parameters = module_parameters + " " + argv[opt];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
std::cout << "mode is " << mode << std::endl;
|
||||
std::cout << "verbose is " << verbose << std::endl;
|
||||
std::cout << "mod_dirs is: " << android::base::Join(mod_dirs, "") << std::endl;
|
||||
std::cout << "modules is: " << android::base::Join(modules, "") << std::endl;
|
||||
std::cout << "module parameters is: " << android::base::Join(module_parameters, "")
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
if (modules.empty()) {
|
||||
if (mode == ListModulesMode) {
|
||||
// emulate toybox modprobe list with no pattern (list all)
|
||||
modules.emplace_back("*");
|
||||
} else {
|
||||
std::cerr << "No modules given." << std::endl;
|
||||
print_usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
if (mod_dirs.empty()) {
|
||||
std::cerr << "No module configuration directories given." << std::endl;
|
||||
print_usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (parameter_count && modules.size() > 1) {
|
||||
std::cerr << "Only one module may be loaded when specifying module parameters."
|
||||
<< std::endl;
|
||||
print_usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
Modprobe m(mod_dirs);
|
||||
m.EnableVerbose(verbose);
|
||||
if (blacklist) {
|
||||
m.EnableBlacklist(true);
|
||||
}
|
||||
|
||||
for (const auto& module : modules) {
|
||||
switch (mode) {
|
||||
case AddModulesMode:
|
||||
if (!m.LoadWithAliases(module, true, module_parameters)) {
|
||||
std::cerr << "Failed to load module " << module;
|
||||
rv = EXIT_FAILURE;
|
||||
}
|
||||
break;
|
||||
case RemoveModulesMode:
|
||||
if (!m.Remove(module)) {
|
||||
std::cerr << "Failed to remove module " << module;
|
||||
rv = EXIT_FAILURE;
|
||||
}
|
||||
break;
|
||||
case ListModulesMode: {
|
||||
std::vector<std::string> list = m.ListModules(module);
|
||||
std::cout << android::base::Join(list, "\n") << std::endl;
|
||||
break;
|
||||
}
|
||||
case ShowDependenciesMode: {
|
||||
std::vector<std::string> pre_deps;
|
||||
std::vector<std::string> deps;
|
||||
std::vector<std::string> post_deps;
|
||||
if (!m.GetAllDependencies(module, &pre_deps, &deps, &post_deps)) {
|
||||
rv = EXIT_FAILURE;
|
||||
break;
|
||||
}
|
||||
std::cout << "Dependencies for " << module << ":" << std::endl;
|
||||
std::cout << "Soft pre-dependencies:" << std::endl;
|
||||
std::cout << android::base::Join(pre_deps, "\n") << std::endl;
|
||||
std::cout << "Hard dependencies:" << std::endl;
|
||||
std::cout << android::base::Join(deps, "\n") << std::endl;
|
||||
std::cout << "Soft post-dependencies:" << std::endl;
|
||||
std::cout << android::base::Join(post_deps, "\n") << std::endl;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
std::cerr << "Bad mode";
|
||||
rv = EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
TOOL(getevent)
|
||||
TOOL(getprop)
|
||||
TOOL(modprobe)
|
||||
TOOL(setprop)
|
||||
TOOL(start)
|
||||
TOOL(stop)
|
||||
|
|
Loading…
Reference in a new issue