blob: 7df7b71a91bbd8c1ea25b10c0b9bcf95068f42c5 [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
218 Modprobe m(mod_dirs);
Mark Salyzyn703fb742020-06-15 11:51:59 -0700219 if (blocklist) {
220 m.EnableBlocklist(true);
Steve Muckle64a55342019-07-30 11:53:15 -0700221 }
222
223 for (const auto& module : modules) {
224 switch (mode) {
225 case AddModulesMode:
226 if (!m.LoadWithAliases(module, true, module_parameters)) {
Mark Salyzyn63368be2020-06-24 03:02:39 -0700227 PLOG(ERROR) << "Failed to load module " << module;
Steve Muckle64a55342019-07-30 11:53:15 -0700228 rv = EXIT_FAILURE;
229 }
230 break;
231 case RemoveModulesMode:
232 if (!m.Remove(module)) {
Mark Salyzyn63368be2020-06-24 03:02:39 -0700233 PLOG(ERROR) << "Failed to remove module " << module;
Steve Muckle64a55342019-07-30 11:53:15 -0700234 rv = EXIT_FAILURE;
235 }
236 break;
237 case ListModulesMode: {
238 std::vector<std::string> list = m.ListModules(module);
Mark Salyzyn63368be2020-06-24 03:02:39 -0700239 LOG(INFO) << android::base::Join(list, "\n");
Steve Muckle64a55342019-07-30 11:53:15 -0700240 break;
241 }
242 case ShowDependenciesMode: {
243 std::vector<std::string> pre_deps;
244 std::vector<std::string> deps;
245 std::vector<std::string> post_deps;
246 if (!m.GetAllDependencies(module, &pre_deps, &deps, &post_deps)) {
247 rv = EXIT_FAILURE;
248 break;
249 }
Mark Salyzyn63368be2020-06-24 03:02:39 -0700250 LOG(INFO) << "Dependencies for " << module << ":";
251 LOG(INFO) << "Soft pre-dependencies:";
252 LOG(INFO) << android::base::Join(pre_deps, "\n");
253 LOG(INFO) << "Hard dependencies:";
254 LOG(INFO) << android::base::Join(deps, "\n");
255 LOG(INFO) << "Soft post-dependencies:";
256 LOG(INFO) << android::base::Join(post_deps, "\n");
Steve Muckle64a55342019-07-30 11:53:15 -0700257 break;
258 }
259 default:
Mark Salyzyn63368be2020-06-24 03:02:39 -0700260 LOG(ERROR) << "Bad mode";
Steve Muckle64a55342019-07-30 11:53:15 -0700261 rv = EXIT_FAILURE;
262 }
263 }
264
265 return rv;
266}