blob: 0033b65fd9f785accd4aea3c7c95c3ee7541120c [file] [log] [blame]
Steve Muckle64a55342019-07-30 11:53:15 -07001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <ctype.h>
18#include <getopt.h>
19#include <stdlib.h>
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070020
Steve Muckle64a55342019-07-30 11:53:15 -070021#include <iostream>
22
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070023#include <android-base/file.h>
Steve Muckle64a55342019-07-30 11:53:15 -070024#include <android-base/strings.h>
25#include <modprobe/modprobe.h>
26
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070027namespace {
28
Steve Muckle64a55342019-07-30 11:53:15 -070029enum modprobe_mode {
30 AddModulesMode,
31 RemoveModulesMode,
32 ListModulesMode,
33 ShowDependenciesMode,
34};
35
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070036void print_usage(void) {
Steve Muckle64a55342019-07-30 11:53:15 -070037 std::cerr << "Usage:" << std::endl;
38 std::cerr << std::endl;
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070039 // -d option is required on Android
40 std::cerr << " modprobe [options] -d DIR MODULE..." << std::endl;
41 std::cerr << " modprobe [options] -d DIR MODULE [symbol=value]..." << std::endl;
Steve Muckle64a55342019-07-30 11:53:15 -070042 std::cerr << std::endl;
43 std::cerr << "Options:" << std::endl;
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070044 std::cerr << " -b, --use-blocklist: Apply blocklist to module names too" << std::endl;
45 std::cerr << " -d, --dirname=DIR: Load modules from DIR, option may be used multiple times"
46 << std::endl;
47 std::cerr << " -D, --show-depends: Print dependencies for modules only, do not load"
48 << std::endl;
49 std::cerr << " -h, --help: Print this help" << std::endl;
50 std::cerr << " -l, --list: List modules matching pattern" << std::endl;
51 std::cerr << " -r, --remove: Remove MODULE (multiple modules may be specified)" << std::endl;
52 std::cerr << " -q, --quiet: disable messages" << std::endl;
53 std::cerr << " -v, --verbose: enable more messages" << std::endl;
Steve Muckle64a55342019-07-30 11:53:15 -070054 std::cerr << std::endl;
55}
56
57#define check_mode() \
58 if (mode != AddModulesMode) { \
59 std::cerr << "Error, multiple mode flags specified" << std::endl; \
60 print_usage(); \
61 return EXIT_FAILURE; \
62 }
63
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070064} // anonymous namespace
65
Steve Muckle64a55342019-07-30 11:53:15 -070066extern "C" int modprobe_main(int argc, char** argv) {
67 std::vector<std::string> modules;
68 std::string module_parameters;
69 std::vector<std::string> mod_dirs;
70 modprobe_mode mode = AddModulesMode;
Mark Salyzyn703fb742020-06-15 11:51:59 -070071 bool blocklist = false;
Steve Muckle64a55342019-07-30 11:53:15 -070072 bool verbose = false;
73 int rv = EXIT_SUCCESS;
74
75 int opt;
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070076 int option_index = 0;
77 // NB: We have non-standard short options -l and -D to make it easier for
78 // OEMs to transition from toybox.
79 // clang-format off
80 static struct option long_options[] = {
81 { "all", no_argument, 0, 'a' },
82 { "use-blocklist", no_argument, 0, 'b' },
83 { "dirname", required_argument, 0, 'd' },
84 { "show-depends", no_argument, 0, 'D' },
85 { "help", no_argument, 0, 'h' },
86 { "list", no_argument, 0, 'l' },
87 { "quiet", no_argument, 0, 'q' },
88 { "remove", no_argument, 0, 'r' },
89 { "verbose", no_argument, 0, 'v' },
90 };
91 // clang-format on
92 while ((opt = getopt_long(argc, argv, "abd:Dhlqrv", long_options, &option_index)) != -1) {
Steve Muckle64a55342019-07-30 11:53:15 -070093 switch (opt) {
94 case 'a':
95 // toybox modprobe supported -a to load multiple modules, this
96 // is supported here by default, ignore flag
97 check_mode();
98 break;
99 case 'b':
Mark Salyzyn703fb742020-06-15 11:51:59 -0700100 blocklist = true;
Steve Muckle64a55342019-07-30 11:53:15 -0700101 break;
102 case 'd':
103 mod_dirs.emplace_back(optarg);
104 break;
105 case 'D':
106 check_mode();
107 mode = ShowDependenciesMode;
108 break;
109 case 'h':
110 print_usage();
111 return EXIT_SUCCESS;
112 case 'l':
113 check_mode();
114 mode = ListModulesMode;
115 break;
116 case 'q':
117 verbose = false;
118 break;
119 case 'r':
120 check_mode();
121 mode = RemoveModulesMode;
122 break;
123 case 'v':
124 verbose = true;
125 break;
126 default:
127 std::cerr << "Unrecognized option: " << opt << std::endl;
128 return EXIT_FAILURE;
129 }
130 }
131
132 int parameter_count = 0;
133 for (opt = optind; opt < argc; opt++) {
134 if (!strchr(argv[opt], '=')) {
135 modules.emplace_back(argv[opt]);
136 } else {
137 parameter_count++;
138 if (module_parameters.empty()) {
139 module_parameters = argv[opt];
140 } else {
141 module_parameters = module_parameters + " " + argv[opt];
142 }
143 }
144 }
145
146 if (verbose) {
147 std::cout << "mode is " << mode << std::endl;
148 std::cout << "verbose is " << verbose << std::endl;
Mark Salyzyn3ad274b2020-06-22 08:49:14 -0700149 std::cout << "mod_dirs is: " << android::base::Join(mod_dirs, " ") << std::endl;
150 std::cout << "modules is: " << android::base::Join(modules, " ") << std::endl;
151 std::cout << "module parameters is: " << android::base::Join(module_parameters, " ")
Steve Muckle64a55342019-07-30 11:53:15 -0700152 << std::endl;
153 }
154
155 if (modules.empty()) {
156 if (mode == ListModulesMode) {
157 // emulate toybox modprobe list with no pattern (list all)
158 modules.emplace_back("*");
159 } else {
160 std::cerr << "No modules given." << std::endl;
161 print_usage();
162 return EXIT_FAILURE;
163 }
164 }
165 if (mod_dirs.empty()) {
166 std::cerr << "No module configuration directories given." << std::endl;
167 print_usage();
168 return EXIT_FAILURE;
169 }
170 if (parameter_count && modules.size() > 1) {
171 std::cerr << "Only one module may be loaded when specifying module parameters."
172 << std::endl;
173 print_usage();
174 return EXIT_FAILURE;
175 }
176
177 Modprobe m(mod_dirs);
178 m.EnableVerbose(verbose);
Mark Salyzyn703fb742020-06-15 11:51:59 -0700179 if (blocklist) {
180 m.EnableBlocklist(true);
Steve Muckle64a55342019-07-30 11:53:15 -0700181 }
182
183 for (const auto& module : modules) {
184 switch (mode) {
185 case AddModulesMode:
186 if (!m.LoadWithAliases(module, true, module_parameters)) {
Mark Salyzyn3ad274b2020-06-22 08:49:14 -0700187 std::cerr << "Failed to load module " << module << std::endl;
Steve Muckle64a55342019-07-30 11:53:15 -0700188 rv = EXIT_FAILURE;
189 }
190 break;
191 case RemoveModulesMode:
192 if (!m.Remove(module)) {
Mark Salyzyn3ad274b2020-06-22 08:49:14 -0700193 std::cerr << "Failed to remove module " << module << std::endl;
Steve Muckle64a55342019-07-30 11:53:15 -0700194 rv = EXIT_FAILURE;
195 }
196 break;
197 case ListModulesMode: {
198 std::vector<std::string> list = m.ListModules(module);
199 std::cout << android::base::Join(list, "\n") << std::endl;
200 break;
201 }
202 case ShowDependenciesMode: {
203 std::vector<std::string> pre_deps;
204 std::vector<std::string> deps;
205 std::vector<std::string> post_deps;
206 if (!m.GetAllDependencies(module, &pre_deps, &deps, &post_deps)) {
207 rv = EXIT_FAILURE;
208 break;
209 }
210 std::cout << "Dependencies for " << module << ":" << std::endl;
211 std::cout << "Soft pre-dependencies:" << std::endl;
212 std::cout << android::base::Join(pre_deps, "\n") << std::endl;
213 std::cout << "Hard dependencies:" << std::endl;
214 std::cout << android::base::Join(deps, "\n") << std::endl;
215 std::cout << "Soft post-dependencies:" << std::endl;
216 std::cout << android::base::Join(post_deps, "\n") << std::endl;
217 break;
218 }
219 default:
Mark Salyzyn3ad274b2020-06-22 08:49:14 -0700220 std::cerr << "Bad mode" << std::endl;
Steve Muckle64a55342019-07-30 11:53:15 -0700221 rv = EXIT_FAILURE;
222 }
223 }
224
225 return rv;
226}