blob: 73f84dce39c390ecbd59937c252828fd6ba09861 [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>
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -070018#include <errno.h>
Steve Muckle64a55342019-07-30 11:53:15 -070019#include <getopt.h>
20#include <stdlib.h>
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -070021#include <string.h>
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070022
Steve Muckle64a55342019-07-30 11:53:15 -070023#include <iostream>
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -070024#include <string>
Steve Muckle64a55342019-07-30 11:53:15 -070025
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070026#include <android-base/file.h>
Steve Muckle64a55342019-07-30 11:53:15 -070027#include <android-base/strings.h>
28#include <modprobe/modprobe.h>
29
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070030namespace {
31
Steve Muckle64a55342019-07-30 11:53:15 -070032enum modprobe_mode {
33 AddModulesMode,
34 RemoveModulesMode,
35 ListModulesMode,
36 ShowDependenciesMode,
37};
38
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070039void print_usage(void) {
Steve Muckle64a55342019-07-30 11:53:15 -070040 std::cerr << "Usage:" << std::endl;
41 std::cerr << std::endl;
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070042 // -d option is required on Android
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -070043 std::cerr << " modprobe [options] -d DIR [--all=FILE|MODULE]..." << std::endl;
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070044 std::cerr << " modprobe [options] -d DIR MODULE [symbol=value]..." << std::endl;
Steve Muckle64a55342019-07-30 11:53:15 -070045 std::cerr << std::endl;
46 std::cerr << "Options:" << std::endl;
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -070047 std::cerr << " --all=FILE: FILE to acquire module names from" << std::endl;
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070048 std::cerr << " -b, --use-blocklist: Apply blocklist to module names too" << std::endl;
49 std::cerr << " -d, --dirname=DIR: Load modules from DIR, option may be used multiple times"
50 << std::endl;
51 std::cerr << " -D, --show-depends: Print dependencies for modules only, do not load"
52 << std::endl;
53 std::cerr << " -h, --help: Print this help" << std::endl;
54 std::cerr << " -l, --list: List modules matching pattern" << std::endl;
55 std::cerr << " -r, --remove: Remove MODULE (multiple modules may be specified)" << std::endl;
56 std::cerr << " -q, --quiet: disable messages" << std::endl;
57 std::cerr << " -v, --verbose: enable more messages" << std::endl;
Steve Muckle64a55342019-07-30 11:53:15 -070058 std::cerr << std::endl;
59}
60
61#define check_mode() \
62 if (mode != AddModulesMode) { \
63 std::cerr << "Error, multiple mode flags specified" << std::endl; \
64 print_usage(); \
65 return EXIT_FAILURE; \
66 }
67
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -070068std::string stripComments(const std::string& str) {
69 for (std::string rv = str;;) {
70 auto comment = rv.find('#');
71 if (comment == std::string::npos) return rv;
72 auto end = rv.find('\n', comment);
73 if (end != std::string::npos) end = end - comment;
74 rv.erase(comment, end);
75 }
76 /* NOTREACHED */
77}
78
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070079} // anonymous namespace
80
Steve Muckle64a55342019-07-30 11:53:15 -070081extern "C" int modprobe_main(int argc, char** argv) {
82 std::vector<std::string> modules;
83 std::string module_parameters;
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -070084 std::string mods;
Steve Muckle64a55342019-07-30 11:53:15 -070085 std::vector<std::string> mod_dirs;
86 modprobe_mode mode = AddModulesMode;
Mark Salyzyn703fb742020-06-15 11:51:59 -070087 bool blocklist = false;
Steve Muckle64a55342019-07-30 11:53:15 -070088 bool verbose = false;
89 int rv = EXIT_SUCCESS;
90
91 int opt;
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070092 int option_index = 0;
93 // NB: We have non-standard short options -l and -D to make it easier for
94 // OEMs to transition from toybox.
95 // clang-format off
96 static struct option long_options[] = {
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -070097 { "all", optional_argument, 0, 'a' },
Mark Salyzyn3ad274b2020-06-22 08:49:14 -070098 { "use-blocklist", no_argument, 0, 'b' },
99 { "dirname", required_argument, 0, 'd' },
100 { "show-depends", no_argument, 0, 'D' },
101 { "help", no_argument, 0, 'h' },
102 { "list", no_argument, 0, 'l' },
103 { "quiet", no_argument, 0, 'q' },
104 { "remove", no_argument, 0, 'r' },
105 { "verbose", no_argument, 0, 'v' },
106 };
107 // clang-format on
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -0700108 while ((opt = getopt_long(argc, argv, "a::bd:Dhlqrv", long_options, &option_index)) != -1) {
Steve Muckle64a55342019-07-30 11:53:15 -0700109 switch (opt) {
110 case 'a':
111 // toybox modprobe supported -a to load multiple modules, this
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -0700112 // is supported here by default, ignore flag if no argument.
Steve Muckle64a55342019-07-30 11:53:15 -0700113 check_mode();
Mark Salyzyn6c9a1e42020-06-22 08:49:14 -0700114 if (optarg == NULL) break;
115 if (!android::base::ReadFileToString(optarg, &mods)) {
116 std::cerr << "Failed to open " << optarg << ": " << strerror(errno)
117 << std::endl;
118 rv = EXIT_FAILURE;
119 }
120 for (auto mod : android::base::Split(stripComments(mods), "\n")) {
121 mod = android::base::Trim(mod);
122 if (mod == "") continue;
123 if (std::find(modules.begin(), modules.end(), mod) != modules.end()) continue;
124 modules.emplace_back(mod);
125 }
Steve Muckle64a55342019-07-30 11:53:15 -0700126 break;
127 case 'b':
Mark Salyzyn703fb742020-06-15 11:51:59 -0700128 blocklist = true;
Steve Muckle64a55342019-07-30 11:53:15 -0700129 break;
130 case 'd':
131 mod_dirs.emplace_back(optarg);
132 break;
133 case 'D':
134 check_mode();
135 mode = ShowDependenciesMode;
136 break;
137 case 'h':
138 print_usage();
139 return EXIT_SUCCESS;
140 case 'l':
141 check_mode();
142 mode = ListModulesMode;
143 break;
144 case 'q':
145 verbose = false;
146 break;
147 case 'r':
148 check_mode();
149 mode = RemoveModulesMode;
150 break;
151 case 'v':
152 verbose = true;
153 break;
154 default:
155 std::cerr << "Unrecognized option: " << opt << std::endl;
156 return EXIT_FAILURE;
157 }
158 }
159
160 int parameter_count = 0;
161 for (opt = optind; opt < argc; opt++) {
162 if (!strchr(argv[opt], '=')) {
163 modules.emplace_back(argv[opt]);
164 } else {
165 parameter_count++;
166 if (module_parameters.empty()) {
167 module_parameters = argv[opt];
168 } else {
169 module_parameters = module_parameters + " " + argv[opt];
170 }
171 }
172 }
173
174 if (verbose) {
175 std::cout << "mode is " << mode << std::endl;
176 std::cout << "verbose is " << verbose << std::endl;
Mark Salyzyn3ad274b2020-06-22 08:49:14 -0700177 std::cout << "mod_dirs is: " << android::base::Join(mod_dirs, " ") << std::endl;
178 std::cout << "modules is: " << android::base::Join(modules, " ") << std::endl;
179 std::cout << "module parameters is: " << android::base::Join(module_parameters, " ")
Steve Muckle64a55342019-07-30 11:53:15 -0700180 << std::endl;
181 }
182
183 if (modules.empty()) {
184 if (mode == ListModulesMode) {
185 // emulate toybox modprobe list with no pattern (list all)
186 modules.emplace_back("*");
187 } else {
188 std::cerr << "No modules given." << std::endl;
189 print_usage();
190 return EXIT_FAILURE;
191 }
192 }
193 if (mod_dirs.empty()) {
194 std::cerr << "No module configuration directories given." << std::endl;
195 print_usage();
196 return EXIT_FAILURE;
197 }
198 if (parameter_count && modules.size() > 1) {
199 std::cerr << "Only one module may be loaded when specifying module parameters."
200 << std::endl;
201 print_usage();
202 return EXIT_FAILURE;
203 }
204
205 Modprobe m(mod_dirs);
206 m.EnableVerbose(verbose);
Mark Salyzyn703fb742020-06-15 11:51:59 -0700207 if (blocklist) {
208 m.EnableBlocklist(true);
Steve Muckle64a55342019-07-30 11:53:15 -0700209 }
210
211 for (const auto& module : modules) {
212 switch (mode) {
213 case AddModulesMode:
214 if (!m.LoadWithAliases(module, true, module_parameters)) {
Mark Salyzyn3ad274b2020-06-22 08:49:14 -0700215 std::cerr << "Failed to load module " << module << std::endl;
Steve Muckle64a55342019-07-30 11:53:15 -0700216 rv = EXIT_FAILURE;
217 }
218 break;
219 case RemoveModulesMode:
220 if (!m.Remove(module)) {
Mark Salyzyn3ad274b2020-06-22 08:49:14 -0700221 std::cerr << "Failed to remove module " << module << std::endl;
Steve Muckle64a55342019-07-30 11:53:15 -0700222 rv = EXIT_FAILURE;
223 }
224 break;
225 case ListModulesMode: {
226 std::vector<std::string> list = m.ListModules(module);
227 std::cout << android::base::Join(list, "\n") << std::endl;
228 break;
229 }
230 case ShowDependenciesMode: {
231 std::vector<std::string> pre_deps;
232 std::vector<std::string> deps;
233 std::vector<std::string> post_deps;
234 if (!m.GetAllDependencies(module, &pre_deps, &deps, &post_deps)) {
235 rv = EXIT_FAILURE;
236 break;
237 }
238 std::cout << "Dependencies for " << module << ":" << std::endl;
239 std::cout << "Soft pre-dependencies:" << std::endl;
240 std::cout << android::base::Join(pre_deps, "\n") << std::endl;
241 std::cout << "Hard dependencies:" << std::endl;
242 std::cout << android::base::Join(deps, "\n") << std::endl;
243 std::cout << "Soft post-dependencies:" << std::endl;
244 std::cout << android::base::Join(post_deps, "\n") << std::endl;
245 break;
246 }
247 default:
Mark Salyzyn3ad274b2020-06-22 08:49:14 -0700248 std::cerr << "Bad mode" << std::endl;
Steve Muckle64a55342019-07-30 11:53:15 -0700249 rv = EXIT_FAILURE;
250 }
251 }
252
253 return rv;
254}