2019-07-30 20:53:15 +02:00
|
|
|
/*
|
|
|
|
* 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>
|
2020-06-22 17:49:14 +02:00
|
|
|
#include <errno.h>
|
2019-07-30 20:53:15 +02:00
|
|
|
#include <getopt.h>
|
|
|
|
#include <stdlib.h>
|
2020-06-22 17:49:14 +02:00
|
|
|
#include <string.h>
|
2020-06-22 17:49:14 +02:00
|
|
|
|
2019-07-30 20:53:15 +02:00
|
|
|
#include <iostream>
|
2020-06-22 17:49:14 +02:00
|
|
|
#include <string>
|
2019-07-30 20:53:15 +02:00
|
|
|
|
2020-06-22 17:49:14 +02:00
|
|
|
#include <android-base/file.h>
|
2019-07-30 20:53:15 +02:00
|
|
|
#include <android-base/strings.h>
|
|
|
|
#include <modprobe/modprobe.h>
|
|
|
|
|
2020-06-22 17:49:14 +02:00
|
|
|
namespace {
|
|
|
|
|
2019-07-30 20:53:15 +02:00
|
|
|
enum modprobe_mode {
|
|
|
|
AddModulesMode,
|
|
|
|
RemoveModulesMode,
|
|
|
|
ListModulesMode,
|
|
|
|
ShowDependenciesMode,
|
|
|
|
};
|
|
|
|
|
2020-06-22 17:49:14 +02:00
|
|
|
void print_usage(void) {
|
2019-07-30 20:53:15 +02:00
|
|
|
std::cerr << "Usage:" << std::endl;
|
|
|
|
std::cerr << std::endl;
|
2020-06-22 17:49:14 +02:00
|
|
|
// -d option is required on Android
|
2020-06-22 17:49:14 +02:00
|
|
|
std::cerr << " modprobe [options] -d DIR [--all=FILE|MODULE]..." << std::endl;
|
2020-06-22 17:49:14 +02:00
|
|
|
std::cerr << " modprobe [options] -d DIR MODULE [symbol=value]..." << std::endl;
|
2019-07-30 20:53:15 +02:00
|
|
|
std::cerr << std::endl;
|
|
|
|
std::cerr << "Options:" << std::endl;
|
2020-06-22 17:49:14 +02:00
|
|
|
std::cerr << " --all=FILE: FILE to acquire module names from" << std::endl;
|
2020-06-22 17:49:14 +02:00
|
|
|
std::cerr << " -b, --use-blocklist: Apply blocklist to module names too" << std::endl;
|
|
|
|
std::cerr << " -d, --dirname=DIR: Load modules from DIR, option may be used multiple times"
|
|
|
|
<< std::endl;
|
|
|
|
std::cerr << " -D, --show-depends: Print dependencies for modules only, do not load"
|
|
|
|
<< std::endl;
|
|
|
|
std::cerr << " -h, --help: Print this help" << std::endl;
|
|
|
|
std::cerr << " -l, --list: List modules matching pattern" << std::endl;
|
|
|
|
std::cerr << " -r, --remove: Remove MODULE (multiple modules may be specified)" << std::endl;
|
|
|
|
std::cerr << " -q, --quiet: disable messages" << std::endl;
|
|
|
|
std::cerr << " -v, --verbose: enable more messages" << std::endl;
|
2019-07-30 20:53:15 +02:00
|
|
|
std::cerr << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define check_mode() \
|
|
|
|
if (mode != AddModulesMode) { \
|
|
|
|
std::cerr << "Error, multiple mode flags specified" << std::endl; \
|
|
|
|
print_usage(); \
|
|
|
|
return EXIT_FAILURE; \
|
|
|
|
}
|
|
|
|
|
2020-06-22 17:49:14 +02:00
|
|
|
std::string stripComments(const std::string& str) {
|
|
|
|
for (std::string rv = str;;) {
|
|
|
|
auto comment = rv.find('#');
|
|
|
|
if (comment == std::string::npos) return rv;
|
|
|
|
auto end = rv.find('\n', comment);
|
|
|
|
if (end != std::string::npos) end = end - comment;
|
|
|
|
rv.erase(comment, end);
|
|
|
|
}
|
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
|
|
|
|
2020-06-22 17:49:14 +02:00
|
|
|
} // anonymous namespace
|
|
|
|
|
2019-07-30 20:53:15 +02:00
|
|
|
extern "C" int modprobe_main(int argc, char** argv) {
|
|
|
|
std::vector<std::string> modules;
|
|
|
|
std::string module_parameters;
|
2020-06-22 17:49:14 +02:00
|
|
|
std::string mods;
|
2019-07-30 20:53:15 +02:00
|
|
|
std::vector<std::string> mod_dirs;
|
|
|
|
modprobe_mode mode = AddModulesMode;
|
2020-06-15 20:51:59 +02:00
|
|
|
bool blocklist = false;
|
2019-07-30 20:53:15 +02:00
|
|
|
bool verbose = false;
|
|
|
|
int rv = EXIT_SUCCESS;
|
|
|
|
|
|
|
|
int opt;
|
2020-06-22 17:49:14 +02:00
|
|
|
int option_index = 0;
|
|
|
|
// NB: We have non-standard short options -l and -D to make it easier for
|
|
|
|
// OEMs to transition from toybox.
|
|
|
|
// clang-format off
|
|
|
|
static struct option long_options[] = {
|
2020-06-22 17:49:14 +02:00
|
|
|
{ "all", optional_argument, 0, 'a' },
|
2020-06-22 17:49:14 +02:00
|
|
|
{ "use-blocklist", no_argument, 0, 'b' },
|
|
|
|
{ "dirname", required_argument, 0, 'd' },
|
|
|
|
{ "show-depends", no_argument, 0, 'D' },
|
|
|
|
{ "help", no_argument, 0, 'h' },
|
|
|
|
{ "list", no_argument, 0, 'l' },
|
|
|
|
{ "quiet", no_argument, 0, 'q' },
|
|
|
|
{ "remove", no_argument, 0, 'r' },
|
|
|
|
{ "verbose", no_argument, 0, 'v' },
|
|
|
|
};
|
|
|
|
// clang-format on
|
2020-06-22 17:49:14 +02:00
|
|
|
while ((opt = getopt_long(argc, argv, "a::bd:Dhlqrv", long_options, &option_index)) != -1) {
|
2019-07-30 20:53:15 +02:00
|
|
|
switch (opt) {
|
|
|
|
case 'a':
|
|
|
|
// toybox modprobe supported -a to load multiple modules, this
|
2020-06-22 17:49:14 +02:00
|
|
|
// is supported here by default, ignore flag if no argument.
|
2019-07-30 20:53:15 +02:00
|
|
|
check_mode();
|
2020-06-22 17:49:14 +02:00
|
|
|
if (optarg == NULL) break;
|
|
|
|
if (!android::base::ReadFileToString(optarg, &mods)) {
|
|
|
|
std::cerr << "Failed to open " << optarg << ": " << strerror(errno)
|
|
|
|
<< std::endl;
|
|
|
|
rv = EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
for (auto mod : android::base::Split(stripComments(mods), "\n")) {
|
|
|
|
mod = android::base::Trim(mod);
|
|
|
|
if (mod == "") continue;
|
|
|
|
if (std::find(modules.begin(), modules.end(), mod) != modules.end()) continue;
|
|
|
|
modules.emplace_back(mod);
|
|
|
|
}
|
2019-07-30 20:53:15 +02:00
|
|
|
break;
|
|
|
|
case 'b':
|
2020-06-15 20:51:59 +02:00
|
|
|
blocklist = true;
|
2019-07-30 20:53:15 +02:00
|
|
|
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;
|
2020-06-22 17:49:14 +02:00
|
|
|
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, " ")
|
2019-07-30 20:53:15 +02:00
|
|
|
<< 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);
|
2020-06-15 20:51:59 +02:00
|
|
|
if (blocklist) {
|
|
|
|
m.EnableBlocklist(true);
|
2019-07-30 20:53:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto& module : modules) {
|
|
|
|
switch (mode) {
|
|
|
|
case AddModulesMode:
|
|
|
|
if (!m.LoadWithAliases(module, true, module_parameters)) {
|
2020-06-22 17:49:14 +02:00
|
|
|
std::cerr << "Failed to load module " << module << std::endl;
|
2019-07-30 20:53:15 +02:00
|
|
|
rv = EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RemoveModulesMode:
|
|
|
|
if (!m.Remove(module)) {
|
2020-06-22 17:49:14 +02:00
|
|
|
std::cerr << "Failed to remove module " << module << std::endl;
|
2019-07-30 20:53:15 +02:00
|
|
|
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:
|
2020-06-22 17:49:14 +02:00
|
|
|
std::cerr << "Bad mode" << std::endl;
|
2019-07-30 20:53:15 +02:00
|
|
|
rv = EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|