From 3ad274be1558ab190f35df1126b42512a8d05762 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Mon, 22 Jun 2020 08:49:14 -0700 Subject: [PATCH] modprobe: switch to getopt_long for argument parsing Add support for long options, and fit existing options to upstream behaviors and extensions. Fix some missing std::endl and android::base::Join() usage. Bug: 159424228 Bug: 151950334 Test: manually test long options work Change-Id: Id792d87d4407628e706aeccecb6e2bce22bcad10 --- toolbox/modprobe.cpp | 61 +++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/toolbox/modprobe.cpp b/toolbox/modprobe.cpp index 3ffa74ecd..0033b65fd 100644 --- a/toolbox/modprobe.cpp +++ b/toolbox/modprobe.cpp @@ -17,11 +17,15 @@ #include #include #include + #include +#include #include #include +namespace { + enum modprobe_mode { AddModulesMode, RemoveModulesMode, @@ -29,21 +33,24 @@ enum modprobe_mode { ShowDependenciesMode, }; -static void print_usage(void) { +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; + // -d option is required on Android + std::cerr << " modprobe [options] -d DIR MODULE..." << std::endl; + std::cerr << " modprobe [options] -d DIR MODULE [symbol=value]..." << std::endl; std::cerr << std::endl; std::cerr << "Options:" << std::endl; - std::cerr << " -b: Apply blocklist 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 << " -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; std::cerr << std::endl; } @@ -54,6 +61,8 @@ static void print_usage(void) { return EXIT_FAILURE; \ } +} // anonymous namespace + extern "C" int modprobe_main(int argc, char** argv) { std::vector modules; std::string module_parameters; @@ -64,7 +73,23 @@ extern "C" int modprobe_main(int argc, char** argv) { int rv = EXIT_SUCCESS; int opt; - while ((opt = getopt(argc, argv, "abd:Dhlqrv")) != -1) { + 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[] = { + { "all", no_argument, 0, 'a' }, + { "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 + while ((opt = getopt_long(argc, argv, "abd:Dhlqrv", long_options, &option_index)) != -1) { switch (opt) { case 'a': // toybox modprobe supported -a to load multiple modules, this @@ -121,9 +146,9 @@ extern "C" int modprobe_main(int argc, char** argv) { 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::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; } @@ -159,13 +184,13 @@ extern "C" int modprobe_main(int argc, char** argv) { switch (mode) { case AddModulesMode: if (!m.LoadWithAliases(module, true, module_parameters)) { - std::cerr << "Failed to load module " << module; + std::cerr << "Failed to load module " << module << std::endl; rv = EXIT_FAILURE; } break; case RemoveModulesMode: if (!m.Remove(module)) { - std::cerr << "Failed to remove module " << module; + std::cerr << "Failed to remove module " << module << std::endl; rv = EXIT_FAILURE; } break; @@ -192,7 +217,7 @@ extern "C" int modprobe_main(int argc, char** argv) { break; } default: - std::cerr << "Bad mode"; + std::cerr << "Bad mode" << std::endl; rv = EXIT_FAILURE; } }