blob: 3ffa74ecd4283e4a84f0261dcc9be3b10f0b6fe8 [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>
20#include <iostream>
21
22#include <android-base/strings.h>
23#include <modprobe/modprobe.h>
24
25enum modprobe_mode {
26 AddModulesMode,
27 RemoveModulesMode,
28 ListModulesMode,
29 ShowDependenciesMode,
30};
31
32static void print_usage(void) {
33 std::cerr << "Usage:" << std::endl;
34 std::cerr << std::endl;
35 std::cerr << " modprobe [-alrqvsDb] [-d DIR] [MODULE]+" << std::endl;
36 std::cerr << " modprobe [-alrqvsDb] [-d DIR] MODULE [symbol=value][...]" << std::endl;
37 std::cerr << std::endl;
38 std::cerr << "Options:" << std::endl;
Mark Salyzyn703fb742020-06-15 11:51:59 -070039 std::cerr << " -b: Apply blocklist to module names too" << std::endl;
Steve Muckle64a55342019-07-30 11:53:15 -070040 std::cerr << " -d: Load modules from DIR, option may be used multiple times" << std::endl;
41 std::cerr << " -D: Print dependencies for modules only, do not load";
42 std::cerr << " -h: Print this help" << std::endl;
43 std::cerr << " -l: List modules matching pattern" << std::endl;
44 std::cerr << " -r: Remove MODULE (multiple modules may be specified)" << std::endl;
45 std::cerr << " -q: Quiet" << std::endl;
46 std::cerr << " -v: Verbose" << std::endl;
47 std::cerr << std::endl;
48}
49
50#define check_mode() \
51 if (mode != AddModulesMode) { \
52 std::cerr << "Error, multiple mode flags specified" << std::endl; \
53 print_usage(); \
54 return EXIT_FAILURE; \
55 }
56
57extern "C" int modprobe_main(int argc, char** argv) {
58 std::vector<std::string> modules;
59 std::string module_parameters;
60 std::vector<std::string> mod_dirs;
61 modprobe_mode mode = AddModulesMode;
Mark Salyzyn703fb742020-06-15 11:51:59 -070062 bool blocklist = false;
Steve Muckle64a55342019-07-30 11:53:15 -070063 bool verbose = false;
64 int rv = EXIT_SUCCESS;
65
66 int opt;
67 while ((opt = getopt(argc, argv, "abd:Dhlqrv")) != -1) {
68 switch (opt) {
69 case 'a':
70 // toybox modprobe supported -a to load multiple modules, this
71 // is supported here by default, ignore flag
72 check_mode();
73 break;
74 case 'b':
Mark Salyzyn703fb742020-06-15 11:51:59 -070075 blocklist = true;
Steve Muckle64a55342019-07-30 11:53:15 -070076 break;
77 case 'd':
78 mod_dirs.emplace_back(optarg);
79 break;
80 case 'D':
81 check_mode();
82 mode = ShowDependenciesMode;
83 break;
84 case 'h':
85 print_usage();
86 return EXIT_SUCCESS;
87 case 'l':
88 check_mode();
89 mode = ListModulesMode;
90 break;
91 case 'q':
92 verbose = false;
93 break;
94 case 'r':
95 check_mode();
96 mode = RemoveModulesMode;
97 break;
98 case 'v':
99 verbose = true;
100 break;
101 default:
102 std::cerr << "Unrecognized option: " << opt << std::endl;
103 return EXIT_FAILURE;
104 }
105 }
106
107 int parameter_count = 0;
108 for (opt = optind; opt < argc; opt++) {
109 if (!strchr(argv[opt], '=')) {
110 modules.emplace_back(argv[opt]);
111 } else {
112 parameter_count++;
113 if (module_parameters.empty()) {
114 module_parameters = argv[opt];
115 } else {
116 module_parameters = module_parameters + " " + argv[opt];
117 }
118 }
119 }
120
121 if (verbose) {
122 std::cout << "mode is " << mode << std::endl;
123 std::cout << "verbose is " << verbose << std::endl;
124 std::cout << "mod_dirs is: " << android::base::Join(mod_dirs, "") << std::endl;
125 std::cout << "modules is: " << android::base::Join(modules, "") << std::endl;
126 std::cout << "module parameters is: " << android::base::Join(module_parameters, "")
127 << std::endl;
128 }
129
130 if (modules.empty()) {
131 if (mode == ListModulesMode) {
132 // emulate toybox modprobe list with no pattern (list all)
133 modules.emplace_back("*");
134 } else {
135 std::cerr << "No modules given." << std::endl;
136 print_usage();
137 return EXIT_FAILURE;
138 }
139 }
140 if (mod_dirs.empty()) {
141 std::cerr << "No module configuration directories given." << std::endl;
142 print_usage();
143 return EXIT_FAILURE;
144 }
145 if (parameter_count && modules.size() > 1) {
146 std::cerr << "Only one module may be loaded when specifying module parameters."
147 << std::endl;
148 print_usage();
149 return EXIT_FAILURE;
150 }
151
152 Modprobe m(mod_dirs);
153 m.EnableVerbose(verbose);
Mark Salyzyn703fb742020-06-15 11:51:59 -0700154 if (blocklist) {
155 m.EnableBlocklist(true);
Steve Muckle64a55342019-07-30 11:53:15 -0700156 }
157
158 for (const auto& module : modules) {
159 switch (mode) {
160 case AddModulesMode:
161 if (!m.LoadWithAliases(module, true, module_parameters)) {
162 std::cerr << "Failed to load module " << module;
163 rv = EXIT_FAILURE;
164 }
165 break;
166 case RemoveModulesMode:
167 if (!m.Remove(module)) {
168 std::cerr << "Failed to remove module " << module;
169 rv = EXIT_FAILURE;
170 }
171 break;
172 case ListModulesMode: {
173 std::vector<std::string> list = m.ListModules(module);
174 std::cout << android::base::Join(list, "\n") << std::endl;
175 break;
176 }
177 case ShowDependenciesMode: {
178 std::vector<std::string> pre_deps;
179 std::vector<std::string> deps;
180 std::vector<std::string> post_deps;
181 if (!m.GetAllDependencies(module, &pre_deps, &deps, &post_deps)) {
182 rv = EXIT_FAILURE;
183 break;
184 }
185 std::cout << "Dependencies for " << module << ":" << std::endl;
186 std::cout << "Soft pre-dependencies:" << std::endl;
187 std::cout << android::base::Join(pre_deps, "\n") << std::endl;
188 std::cout << "Hard dependencies:" << std::endl;
189 std::cout << android::base::Join(deps, "\n") << std::endl;
190 std::cout << "Soft post-dependencies:" << std::endl;
191 std::cout << android::base::Join(post_deps, "\n") << std::endl;
192 break;
193 }
194 default:
195 std::cerr << "Bad mode";
196 rv = EXIT_FAILURE;
197 }
198 }
199
200 return rv;
201}