blob: 711586a9844fb3453f3efa5500b6f140780575e4 [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>
26#include <modprobe/modprobe.h>
27
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070028namespace {
29
Steve Muckle64a55342019-07-30 11:53:15 -070030enum modprobe_mode {
31 AddModulesMode,
32 RemoveModulesMode,
33 ListModulesMode,
34 ShowDependenciesMode,
35};
36
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070037void print_usage(void) {
Mark Salyzyn63368be2020-06-24 03:02:39 -070038 LOG(INFO) << "Usage:";
39 LOG(INFO);
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070040 // -d option is required on Android
Mark Salyzyn63368be2020-06-24 03:02:39 -070041 LOG(INFO) << " modprobe [options] -d DIR [--all=FILE|MODULE]...";
42 LOG(INFO) << " modprobe [options] -d DIR MODULE [symbol=value]...";
43 LOG(INFO);
44 LOG(INFO) << "Options:";
45 LOG(INFO) << " --all=FILE: FILE to acquire module names from";
46 LOG(INFO) << " -b, --use-blocklist: Apply blocklist to module names too";
47 LOG(INFO) << " -d, --dirname=DIR: Load modules from DIR, option may be used multiple times";
48 LOG(INFO) << " -D, --show-depends: Print dependencies for modules only, do not load";
49 LOG(INFO) << " -h, --help: Print this help";
50 LOG(INFO) << " -l, --list: List modules matching pattern";
51 LOG(INFO) << " -r, --remove: Remove MODULE (multiple modules may be specified)";
52 LOG(INFO) << " -s, --syslog: print to syslog also";
53 LOG(INFO) << " -q, --quiet: disable messages";
54 LOG(INFO) << " -v, --verbose: enable more messages, even more with a second -v";
55 LOG(INFO);
Steve Muckle64a55342019-07-30 11:53:15 -070056}
57
Mark Salyzyn63368be2020-06-24 03:02:39 -070058#define check_mode() \
59 if (mode != AddModulesMode) { \
60 LOG(ERROR) << "multiple mode flags specified"; \
61 print_usage(); \
62 return EXIT_FAILURE; \
Steve Muckle64a55342019-07-30 11:53:15 -070063 }
64
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -070065std::string stripComments(const std::string& str) {
66 for (std::string rv = str;;) {
67 auto comment = rv.find('#');
68 if (comment == std::string::npos) return rv;
69 auto end = rv.find('\n', comment);
70 if (end != std::string::npos) end = end - comment;
71 rv.erase(comment, end);
72 }
73 /* NOTREACHED */
74}
75
Mark Salyzyn63368be2020-06-24 03:02:39 -070076auto syslog = false;
77
78void MyLogger(android::base::LogId id, android::base::LogSeverity severity, const char* tag,
79 const char* file, unsigned int line, const char* message) {
80 android::base::StdioLogger(id, severity, tag, file, line, message);
81 if (syslog && message[0]) {
82 android::base::KernelLogger(id, severity, tag, file, line, message);
83 }
84}
85
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070086} // anonymous namespace
87
Steve Muckle64a55342019-07-30 11:53:15 -070088extern "C" int modprobe_main(int argc, char** argv) {
Mark Salyzyn63368be2020-06-24 03:02:39 -070089 android::base::InitLogging(argv, MyLogger);
90 android::base::SetMinimumLogSeverity(android::base::INFO);
91
Steve Muckle64a55342019-07-30 11:53:15 -070092 std::vector<std::string> modules;
93 std::string module_parameters;
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -070094 std::string mods;
Steve Muckle64a55342019-07-30 11:53:15 -070095 std::vector<std::string> mod_dirs;
96 modprobe_mode mode = AddModulesMode;
Mark Salyzyn703fb742020-06-15 11:51:59 -070097 bool blocklist = false;
Steve Muckle64a55342019-07-30 11:53:15 -070098 int rv = EXIT_SUCCESS;
99
100 int opt;
Mark Salyzyn3ad274b2020-06-22 08:49:14 -0700101 int option_index = 0;
102 // NB: We have non-standard short options -l and -D to make it easier for
103 // OEMs to transition from toybox.
104 // clang-format off
105 static struct option long_options[] = {
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -0700106 { "all", optional_argument, 0, 'a' },
Mark Salyzyn3ad274b2020-06-22 08:49:14 -0700107 { "use-blocklist", no_argument, 0, 'b' },
108 { "dirname", required_argument, 0, 'd' },
109 { "show-depends", no_argument, 0, 'D' },
110 { "help", no_argument, 0, 'h' },
111 { "list", no_argument, 0, 'l' },
112 { "quiet", no_argument, 0, 'q' },
113 { "remove", no_argument, 0, 'r' },
Mark Salyzyn63368be2020-06-24 03:02:39 -0700114 { "syslog", no_argument, 0, 's' },
Mark Salyzyn3ad274b2020-06-22 08:49:14 -0700115 { "verbose", no_argument, 0, 'v' },
116 };
117 // clang-format on
Mark Salyzyn63368be2020-06-24 03:02:39 -0700118 while ((opt = getopt_long(argc, argv, "a::bd:Dhlqrsv", long_options, &option_index)) != -1) {
Steve Muckle64a55342019-07-30 11:53:15 -0700119 switch (opt) {
120 case 'a':
121 // toybox modprobe supported -a to load multiple modules, this
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -0700122 // is supported here by default, ignore flag if no argument.
Steve Muckle64a55342019-07-30 11:53:15 -0700123 check_mode();
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -0700124 if (optarg == NULL) break;
125 if (!android::base::ReadFileToString(optarg, &mods)) {
Mark Salyzyn63368be2020-06-24 03:02:39 -0700126 PLOG(ERROR) << "Failed to open " << optarg;
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -0700127 rv = EXIT_FAILURE;
128 }
129 for (auto mod : android::base::Split(stripComments(mods), "\n")) {
130 mod = android::base::Trim(mod);
131 if (mod == "") continue;
132 if (std::find(modules.begin(), modules.end(), mod) != modules.end()) continue;
133 modules.emplace_back(mod);
134 }
Steve Muckle64a55342019-07-30 11:53:15 -0700135 break;
136 case 'b':
Mark Salyzyn703fb742020-06-15 11:51:59 -0700137 blocklist = true;
Steve Muckle64a55342019-07-30 11:53:15 -0700138 break;
139 case 'd':
140 mod_dirs.emplace_back(optarg);
141 break;
142 case 'D':
143 check_mode();
144 mode = ShowDependenciesMode;
145 break;
146 case 'h':
Mark Salyzyn63368be2020-06-24 03:02:39 -0700147 android::base::SetMinimumLogSeverity(android::base::INFO);
Steve Muckle64a55342019-07-30 11:53:15 -0700148 print_usage();
Mark Salyzyn63368be2020-06-24 03:02:39 -0700149 return rv;
Steve Muckle64a55342019-07-30 11:53:15 -0700150 case 'l':
151 check_mode();
152 mode = ListModulesMode;
153 break;
154 case 'q':
Mark Salyzyn63368be2020-06-24 03:02:39 -0700155 android::base::SetMinimumLogSeverity(android::base::WARNING);
Steve Muckle64a55342019-07-30 11:53:15 -0700156 break;
157 case 'r':
158 check_mode();
159 mode = RemoveModulesMode;
160 break;
Mark Salyzyn63368be2020-06-24 03:02:39 -0700161 case 's':
162 syslog = true;
163 break;
Steve Muckle64a55342019-07-30 11:53:15 -0700164 case 'v':
Mark Salyzyn63368be2020-06-24 03:02:39 -0700165 if (android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
166 android::base::SetMinimumLogSeverity(android::base::VERBOSE);
167 } else {
168 android::base::SetMinimumLogSeverity(android::base::DEBUG);
169 }
Steve Muckle64a55342019-07-30 11:53:15 -0700170 break;
171 default:
Mark Salyzyn63368be2020-06-24 03:02:39 -0700172 LOG(ERROR) << "Unrecognized option: " << opt;
173 print_usage();
Steve Muckle64a55342019-07-30 11:53:15 -0700174 return EXIT_FAILURE;
175 }
176 }
177
178 int parameter_count = 0;
179 for (opt = optind; opt < argc; opt++) {
180 if (!strchr(argv[opt], '=')) {
181 modules.emplace_back(argv[opt]);
182 } else {
183 parameter_count++;
184 if (module_parameters.empty()) {
185 module_parameters = argv[opt];
186 } else {
187 module_parameters = module_parameters + " " + argv[opt];
188 }
189 }
190 }
191
Mark Salyzyn63368be2020-06-24 03:02:39 -0700192 LOG(DEBUG) << "mode is " << mode;
193 LOG(DEBUG) << "mod_dirs is: " << android::base::Join(mod_dirs, " ");
194 LOG(DEBUG) << "modules is: " << android::base::Join(modules, " ");
195 LOG(DEBUG) << "module parameters is: " << android::base::Join(module_parameters, " ");
Steve Muckle64a55342019-07-30 11:53:15 -0700196
197 if (modules.empty()) {
198 if (mode == ListModulesMode) {
199 // emulate toybox modprobe list with no pattern (list all)
200 modules.emplace_back("*");
201 } else {
Mark Salyzyn63368be2020-06-24 03:02:39 -0700202 LOG(ERROR) << "No modules given.";
Steve Muckle64a55342019-07-30 11:53:15 -0700203 print_usage();
204 return EXIT_FAILURE;
205 }
206 }
207 if (mod_dirs.empty()) {
Mark Salyzyn63368be2020-06-24 03:02:39 -0700208 LOG(ERROR) << "No module configuration directories given.";
Steve Muckle64a55342019-07-30 11:53:15 -0700209 print_usage();
210 return EXIT_FAILURE;
211 }
212 if (parameter_count && modules.size() > 1) {
Mark Salyzyn63368be2020-06-24 03:02:39 -0700213 LOG(ERROR) << "Only one module may be loaded when specifying module parameters.";
Steve Muckle64a55342019-07-30 11:53:15 -0700214 print_usage();
215 return EXIT_FAILURE;
216 }
217
Will McVicker87b2ef02021-03-12 11:11:37 -0800218 Modprobe m(mod_dirs, "modules.load", blocklist);
Steve Muckle64a55342019-07-30 11:53:15 -0700219
220 for (const auto& module : modules) {
221 switch (mode) {
222 case AddModulesMode:
223 if (!m.LoadWithAliases(module, true, module_parameters)) {
Mark Salyzyn63368be2020-06-24 03:02:39 -0700224 PLOG(ERROR) << "Failed to load module " << module;
Steve Muckle64a55342019-07-30 11:53:15 -0700225 rv = EXIT_FAILURE;
226 }
227 break;
228 case RemoveModulesMode:
229 if (!m.Remove(module)) {
Mark Salyzyn63368be2020-06-24 03:02:39 -0700230 PLOG(ERROR) << "Failed to remove module " << module;
Steve Muckle64a55342019-07-30 11:53:15 -0700231 rv = EXIT_FAILURE;
232 }
233 break;
234 case ListModulesMode: {
235 std::vector<std::string> list = m.ListModules(module);
Mark Salyzyn63368be2020-06-24 03:02:39 -0700236 LOG(INFO) << android::base::Join(list, "\n");
Steve Muckle64a55342019-07-30 11:53:15 -0700237 break;
238 }
239 case ShowDependenciesMode: {
240 std::vector<std::string> pre_deps;
241 std::vector<std::string> deps;
242 std::vector<std::string> post_deps;
243 if (!m.GetAllDependencies(module, &pre_deps, &deps, &post_deps)) {
244 rv = EXIT_FAILURE;
245 break;
246 }
Mark Salyzyn63368be2020-06-24 03:02:39 -0700247 LOG(INFO) << "Dependencies for " << module << ":";
248 LOG(INFO) << "Soft pre-dependencies:";
249 LOG(INFO) << android::base::Join(pre_deps, "\n");
250 LOG(INFO) << "Hard dependencies:";
251 LOG(INFO) << android::base::Join(deps, "\n");
252 LOG(INFO) << "Soft post-dependencies:";
253 LOG(INFO) << android::base::Join(post_deps, "\n");
Steve Muckle64a55342019-07-30 11:53:15 -0700254 break;
255 }
256 default:
Mark Salyzyn63368be2020-06-24 03:02:39 -0700257 LOG(ERROR) << "Bad mode";
Steve Muckle64a55342019-07-30 11:53:15 -0700258 rv = EXIT_FAILURE;
259 }
260 }
261
262 return rv;
263}