blob: 17f815697ef31c8c8b83603c5f145c053b779e49 [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
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -070021#include <string>
Steve Muckle64a55342019-07-30 11:53:15 -070022
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070023#include <android-base/file.h>
Mark Salyzyn63368be2020-06-24 03:02:39 -070024#include <android-base/logging.h>
Steve Muckle64a55342019-07-30 11:53:15 -070025#include <android-base/strings.h>
Vincent Donnefort83207782023-01-24 17:39:16 +000026#include <android-base/stringprintf.h>
Steve Muckle64a55342019-07-30 11:53:15 -070027#include <modprobe/modprobe.h>
28
Vincent Donnefort83207782023-01-24 17:39:16 +000029#include <sys/utsname.h>
30
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070031namespace {
32
Steve Muckle64a55342019-07-30 11:53:15 -070033enum modprobe_mode {
34 AddModulesMode,
35 RemoveModulesMode,
36 ListModulesMode,
37 ShowDependenciesMode,
38};
39
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070040void print_usage(void) {
Mark Salyzyn63368be2020-06-24 03:02:39 -070041 LOG(INFO) << "Usage:";
42 LOG(INFO);
Vincent Donnefort83207782023-01-24 17:39:16 +000043 LOG(INFO) << " modprobe [options] [-d DIR] [--all=FILE|MODULE]...";
44 LOG(INFO) << " modprobe [options] [-d DIR] MODULE [symbol=value]...";
Mark Salyzyn63368be2020-06-24 03:02:39 -070045 LOG(INFO);
46 LOG(INFO) << "Options:";
47 LOG(INFO) << " --all=FILE: FILE to acquire module names from";
48 LOG(INFO) << " -b, --use-blocklist: Apply blocklist to module names too";
49 LOG(INFO) << " -d, --dirname=DIR: Load modules from DIR, option may be used multiple times";
50 LOG(INFO) << " -D, --show-depends: Print dependencies for modules only, do not load";
51 LOG(INFO) << " -h, --help: Print this help";
52 LOG(INFO) << " -l, --list: List modules matching pattern";
53 LOG(INFO) << " -r, --remove: Remove MODULE (multiple modules may be specified)";
54 LOG(INFO) << " -s, --syslog: print to syslog also";
55 LOG(INFO) << " -q, --quiet: disable messages";
56 LOG(INFO) << " -v, --verbose: enable more messages, even more with a second -v";
57 LOG(INFO);
Steve Muckle64a55342019-07-30 11:53:15 -070058}
59
Mark Salyzyn63368be2020-06-24 03:02:39 -070060#define check_mode() \
61 if (mode != AddModulesMode) { \
62 LOG(ERROR) << "multiple mode flags specified"; \
63 print_usage(); \
64 return EXIT_FAILURE; \
Steve Muckle64a55342019-07-30 11:53:15 -070065 }
66
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -070067std::string stripComments(const std::string& str) {
68 for (std::string rv = str;;) {
69 auto comment = rv.find('#');
70 if (comment == std::string::npos) return rv;
71 auto end = rv.find('\n', comment);
72 if (end != std::string::npos) end = end - comment;
73 rv.erase(comment, end);
74 }
75 /* NOTREACHED */
76}
77
Mark Salyzyn63368be2020-06-24 03:02:39 -070078auto syslog = false;
79
80void MyLogger(android::base::LogId id, android::base::LogSeverity severity, const char* tag,
81 const char* file, unsigned int line, const char* message) {
82 android::base::StdioLogger(id, severity, tag, file, line, message);
83 if (syslog && message[0]) {
84 android::base::KernelLogger(id, severity, tag, file, line, message);
85 }
86}
87
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070088} // anonymous namespace
89
Steve Muckle64a55342019-07-30 11:53:15 -070090extern "C" int modprobe_main(int argc, char** argv) {
Mark Salyzyn63368be2020-06-24 03:02:39 -070091 android::base::InitLogging(argv, MyLogger);
92 android::base::SetMinimumLogSeverity(android::base::INFO);
93
Steve Muckle64a55342019-07-30 11:53:15 -070094 std::vector<std::string> modules;
95 std::string module_parameters;
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -070096 std::string mods;
Steve Muckle64a55342019-07-30 11:53:15 -070097 std::vector<std::string> mod_dirs;
98 modprobe_mode mode = AddModulesMode;
Mark Salyzyn703fb742020-06-15 11:51:59 -070099 bool blocklist = false;
Steve Muckle64a55342019-07-30 11:53:15 -0700100 int rv = EXIT_SUCCESS;
101
102 int opt;
Mark Salyzyn3ad274b2020-06-22 08:49:14 -0700103 int option_index = 0;
104 // NB: We have non-standard short options -l and -D to make it easier for
105 // OEMs to transition from toybox.
106 // clang-format off
107 static struct option long_options[] = {
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -0700108 { "all", optional_argument, 0, 'a' },
Mark Salyzyn3ad274b2020-06-22 08:49:14 -0700109 { "use-blocklist", no_argument, 0, 'b' },
110 { "dirname", required_argument, 0, 'd' },
111 { "show-depends", no_argument, 0, 'D' },
112 { "help", no_argument, 0, 'h' },
113 { "list", no_argument, 0, 'l' },
114 { "quiet", no_argument, 0, 'q' },
115 { "remove", no_argument, 0, 'r' },
Mark Salyzyn63368be2020-06-24 03:02:39 -0700116 { "syslog", no_argument, 0, 's' },
Mark Salyzyn3ad274b2020-06-22 08:49:14 -0700117 { "verbose", no_argument, 0, 'v' },
118 };
119 // clang-format on
Mark Salyzyn63368be2020-06-24 03:02:39 -0700120 while ((opt = getopt_long(argc, argv, "a::bd:Dhlqrsv", long_options, &option_index)) != -1) {
Steve Muckle64a55342019-07-30 11:53:15 -0700121 switch (opt) {
122 case 'a':
123 // toybox modprobe supported -a to load multiple modules, this
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -0700124 // is supported here by default, ignore flag if no argument.
Steve Muckle64a55342019-07-30 11:53:15 -0700125 check_mode();
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -0700126 if (optarg == NULL) break;
127 if (!android::base::ReadFileToString(optarg, &mods)) {
Mark Salyzyn63368be2020-06-24 03:02:39 -0700128 PLOG(ERROR) << "Failed to open " << optarg;
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -0700129 rv = EXIT_FAILURE;
130 }
131 for (auto mod : android::base::Split(stripComments(mods), "\n")) {
132 mod = android::base::Trim(mod);
133 if (mod == "") continue;
134 if (std::find(modules.begin(), modules.end(), mod) != modules.end()) continue;
135 modules.emplace_back(mod);
136 }
Steve Muckle64a55342019-07-30 11:53:15 -0700137 break;
138 case 'b':
Mark Salyzyn703fb742020-06-15 11:51:59 -0700139 blocklist = true;
Steve Muckle64a55342019-07-30 11:53:15 -0700140 break;
141 case 'd':
142 mod_dirs.emplace_back(optarg);
143 break;
144 case 'D':
145 check_mode();
146 mode = ShowDependenciesMode;
147 break;
148 case 'h':
Mark Salyzyn63368be2020-06-24 03:02:39 -0700149 android::base::SetMinimumLogSeverity(android::base::INFO);
Steve Muckle64a55342019-07-30 11:53:15 -0700150 print_usage();
Mark Salyzyn63368be2020-06-24 03:02:39 -0700151 return rv;
Steve Muckle64a55342019-07-30 11:53:15 -0700152 case 'l':
153 check_mode();
154 mode = ListModulesMode;
155 break;
156 case 'q':
Mark Salyzyn63368be2020-06-24 03:02:39 -0700157 android::base::SetMinimumLogSeverity(android::base::WARNING);
Steve Muckle64a55342019-07-30 11:53:15 -0700158 break;
159 case 'r':
160 check_mode();
161 mode = RemoveModulesMode;
162 break;
Mark Salyzyn63368be2020-06-24 03:02:39 -0700163 case 's':
164 syslog = true;
165 break;
Steve Muckle64a55342019-07-30 11:53:15 -0700166 case 'v':
Mark Salyzyn63368be2020-06-24 03:02:39 -0700167 if (android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
168 android::base::SetMinimumLogSeverity(android::base::VERBOSE);
169 } else {
170 android::base::SetMinimumLogSeverity(android::base::DEBUG);
171 }
Steve Muckle64a55342019-07-30 11:53:15 -0700172 break;
173 default:
Mark Salyzyn63368be2020-06-24 03:02:39 -0700174 LOG(ERROR) << "Unrecognized option: " << opt;
175 print_usage();
Steve Muckle64a55342019-07-30 11:53:15 -0700176 return EXIT_FAILURE;
177 }
178 }
179
180 int parameter_count = 0;
181 for (opt = optind; opt < argc; opt++) {
182 if (!strchr(argv[opt], '=')) {
183 modules.emplace_back(argv[opt]);
184 } else {
185 parameter_count++;
186 if (module_parameters.empty()) {
187 module_parameters = argv[opt];
188 } else {
189 module_parameters = module_parameters + " " + argv[opt];
190 }
191 }
192 }
193
Vincent Donnefort83207782023-01-24 17:39:16 +0000194 if (mod_dirs.empty()) {
195 utsname uts;
196 uname(&uts);
197 mod_dirs.emplace_back(android::base::StringPrintf("/lib/modules/%s", uts.release));
198 }
199
Mark Salyzyn63368be2020-06-24 03:02:39 -0700200 LOG(DEBUG) << "mode is " << mode;
201 LOG(DEBUG) << "mod_dirs is: " << android::base::Join(mod_dirs, " ");
202 LOG(DEBUG) << "modules is: " << android::base::Join(modules, " ");
203 LOG(DEBUG) << "module parameters is: " << android::base::Join(module_parameters, " ");
Steve Muckle64a55342019-07-30 11:53:15 -0700204
205 if (modules.empty()) {
206 if (mode == ListModulesMode) {
207 // emulate toybox modprobe list with no pattern (list all)
208 modules.emplace_back("*");
209 } else {
Mark Salyzyn63368be2020-06-24 03:02:39 -0700210 LOG(ERROR) << "No modules given.";
Steve Muckle64a55342019-07-30 11:53:15 -0700211 print_usage();
212 return EXIT_FAILURE;
213 }
214 }
215 if (mod_dirs.empty()) {
Mark Salyzyn63368be2020-06-24 03:02:39 -0700216 LOG(ERROR) << "No module configuration directories given.";
Steve Muckle64a55342019-07-30 11:53:15 -0700217 print_usage();
218 return EXIT_FAILURE;
219 }
220 if (parameter_count && modules.size() > 1) {
Mark Salyzyn63368be2020-06-24 03:02:39 -0700221 LOG(ERROR) << "Only one module may be loaded when specifying module parameters.";
Steve Muckle64a55342019-07-30 11:53:15 -0700222 print_usage();
223 return EXIT_FAILURE;
224 }
225
Will McVicker87b2ef02021-03-12 11:11:37 -0800226 Modprobe m(mod_dirs, "modules.load", blocklist);
Steve Muckle64a55342019-07-30 11:53:15 -0700227
228 for (const auto& module : modules) {
229 switch (mode) {
230 case AddModulesMode:
231 if (!m.LoadWithAliases(module, true, module_parameters)) {
Mark Salyzyn63368be2020-06-24 03:02:39 -0700232 PLOG(ERROR) << "Failed to load module " << module;
Steve Muckle64a55342019-07-30 11:53:15 -0700233 rv = EXIT_FAILURE;
234 }
235 break;
236 case RemoveModulesMode:
237 if (!m.Remove(module)) {
Mark Salyzyn63368be2020-06-24 03:02:39 -0700238 PLOG(ERROR) << "Failed to remove module " << module;
Steve Muckle64a55342019-07-30 11:53:15 -0700239 rv = EXIT_FAILURE;
240 }
241 break;
242 case ListModulesMode: {
243 std::vector<std::string> list = m.ListModules(module);
Mark Salyzyn63368be2020-06-24 03:02:39 -0700244 LOG(INFO) << android::base::Join(list, "\n");
Steve Muckle64a55342019-07-30 11:53:15 -0700245 break;
246 }
247 case ShowDependenciesMode: {
248 std::vector<std::string> pre_deps;
249 std::vector<std::string> deps;
250 std::vector<std::string> post_deps;
251 if (!m.GetAllDependencies(module, &pre_deps, &deps, &post_deps)) {
252 rv = EXIT_FAILURE;
253 break;
254 }
Mark Salyzyn63368be2020-06-24 03:02:39 -0700255 LOG(INFO) << "Dependencies for " << module << ":";
256 LOG(INFO) << "Soft pre-dependencies:";
257 LOG(INFO) << android::base::Join(pre_deps, "\n");
258 LOG(INFO) << "Hard dependencies:";
259 LOG(INFO) << android::base::Join(deps, "\n");
260 LOG(INFO) << "Soft post-dependencies:";
261 LOG(INFO) << android::base::Join(post_deps, "\n");
Steve Muckle64a55342019-07-30 11:53:15 -0700262 break;
263 }
264 default:
Mark Salyzyn63368be2020-06-24 03:02:39 -0700265 LOG(ERROR) << "Bad mode";
Steve Muckle64a55342019-07-30 11:53:15 -0700266 rv = EXIT_FAILURE;
267 }
268 }
269
270 return rv;
271}