toolbox: add modprobe
Add an implementation of modprobe based on libmodprobe.
Change-Id: I85ba440766406fe6ca7e90bec204d06632785a66
diff --git a/toolbox/modprobe.cpp b/toolbox/modprobe.cpp
new file mode 100644
index 0000000..1b5f54e
--- /dev/null
+++ b/toolbox/modprobe.cpp
@@ -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;
+}