| /* | 
 |  * 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; | 
 | } |