xref: /aosp_15_r20/system/core/libmodprobe/libmodprobe.cpp (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
1*00c7fec1SAndroid Build Coastguard Worker /*
2*00c7fec1SAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*00c7fec1SAndroid Build Coastguard Worker  *
4*00c7fec1SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*00c7fec1SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*00c7fec1SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*00c7fec1SAndroid Build Coastguard Worker  *
8*00c7fec1SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*00c7fec1SAndroid Build Coastguard Worker  *
10*00c7fec1SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*00c7fec1SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*00c7fec1SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*00c7fec1SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*00c7fec1SAndroid Build Coastguard Worker  * limitations under the License.
15*00c7fec1SAndroid Build Coastguard Worker  */
16*00c7fec1SAndroid Build Coastguard Worker 
17*00c7fec1SAndroid Build Coastguard Worker #include <modprobe/modprobe.h>
18*00c7fec1SAndroid Build Coastguard Worker 
19*00c7fec1SAndroid Build Coastguard Worker #include <fnmatch.h>
20*00c7fec1SAndroid Build Coastguard Worker #include <grp.h>
21*00c7fec1SAndroid Build Coastguard Worker #include <pwd.h>
22*00c7fec1SAndroid Build Coastguard Worker #include <sys/stat.h>
23*00c7fec1SAndroid Build Coastguard Worker #include <sys/syscall.h>
24*00c7fec1SAndroid Build Coastguard Worker #include <sys/wait.h>
25*00c7fec1SAndroid Build Coastguard Worker 
26*00c7fec1SAndroid Build Coastguard Worker #include <algorithm>
27*00c7fec1SAndroid Build Coastguard Worker #include <map>
28*00c7fec1SAndroid Build Coastguard Worker #include <set>
29*00c7fec1SAndroid Build Coastguard Worker #include <string>
30*00c7fec1SAndroid Build Coastguard Worker #include <thread>
31*00c7fec1SAndroid Build Coastguard Worker #include <vector>
32*00c7fec1SAndroid Build Coastguard Worker 
33*00c7fec1SAndroid Build Coastguard Worker #include <android-base/chrono_utils.h>
34*00c7fec1SAndroid Build Coastguard Worker #include <android-base/file.h>
35*00c7fec1SAndroid Build Coastguard Worker #include <android-base/logging.h>
36*00c7fec1SAndroid Build Coastguard Worker #include <android-base/parseint.h>
37*00c7fec1SAndroid Build Coastguard Worker #include <android-base/strings.h>
38*00c7fec1SAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
39*00c7fec1SAndroid Build Coastguard Worker 
40*00c7fec1SAndroid Build Coastguard Worker #include "exthandler/exthandler.h"
41*00c7fec1SAndroid Build Coastguard Worker 
MakeCanonical(const std::string & module_path)42*00c7fec1SAndroid Build Coastguard Worker std::string Modprobe::MakeCanonical(const std::string& module_path) {
43*00c7fec1SAndroid Build Coastguard Worker     auto start = module_path.find_last_of('/');
44*00c7fec1SAndroid Build Coastguard Worker     if (start == std::string::npos) {
45*00c7fec1SAndroid Build Coastguard Worker         start = 0;
46*00c7fec1SAndroid Build Coastguard Worker     } else {
47*00c7fec1SAndroid Build Coastguard Worker         start += 1;
48*00c7fec1SAndroid Build Coastguard Worker     }
49*00c7fec1SAndroid Build Coastguard Worker     auto end = module_path.size();
50*00c7fec1SAndroid Build Coastguard Worker     if (android::base::EndsWith(module_path, ".ko")) {
51*00c7fec1SAndroid Build Coastguard Worker         end -= 3;
52*00c7fec1SAndroid Build Coastguard Worker     }
53*00c7fec1SAndroid Build Coastguard Worker     if ((end - start) <= 1) {
54*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "malformed module name: " << module_path;
55*00c7fec1SAndroid Build Coastguard Worker         return "";
56*00c7fec1SAndroid Build Coastguard Worker     }
57*00c7fec1SAndroid Build Coastguard Worker     std::string module_name = module_path.substr(start, end - start);
58*00c7fec1SAndroid Build Coastguard Worker     // module names can have '-', but their file names will have '_'
59*00c7fec1SAndroid Build Coastguard Worker     std::replace(module_name.begin(), module_name.end(), '-', '_');
60*00c7fec1SAndroid Build Coastguard Worker     return module_name;
61*00c7fec1SAndroid Build Coastguard Worker }
62*00c7fec1SAndroid Build Coastguard Worker 
ParseDepCallback(const std::string & base_path,const std::vector<std::string> & args)63*00c7fec1SAndroid Build Coastguard Worker bool Modprobe::ParseDepCallback(const std::string& base_path,
64*00c7fec1SAndroid Build Coastguard Worker                                 const std::vector<std::string>& args) {
65*00c7fec1SAndroid Build Coastguard Worker     std::vector<std::string> deps;
66*00c7fec1SAndroid Build Coastguard Worker     std::string prefix = "";
67*00c7fec1SAndroid Build Coastguard Worker 
68*00c7fec1SAndroid Build Coastguard Worker     // Set first item as our modules path
69*00c7fec1SAndroid Build Coastguard Worker     std::string::size_type pos = args[0].find(':');
70*00c7fec1SAndroid Build Coastguard Worker     if (args[0][0] != '/') {
71*00c7fec1SAndroid Build Coastguard Worker         prefix = base_path + "/";
72*00c7fec1SAndroid Build Coastguard Worker     }
73*00c7fec1SAndroid Build Coastguard Worker     if (pos != std::string::npos) {
74*00c7fec1SAndroid Build Coastguard Worker         deps.emplace_back(prefix + args[0].substr(0, pos));
75*00c7fec1SAndroid Build Coastguard Worker     } else {
76*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "dependency lines must start with name followed by ':'";
77*00c7fec1SAndroid Build Coastguard Worker         return false;
78*00c7fec1SAndroid Build Coastguard Worker     }
79*00c7fec1SAndroid Build Coastguard Worker 
80*00c7fec1SAndroid Build Coastguard Worker     // Remaining items are dependencies of our module
81*00c7fec1SAndroid Build Coastguard Worker     for (auto arg = args.begin() + 1; arg != args.end(); ++arg) {
82*00c7fec1SAndroid Build Coastguard Worker         if ((*arg)[0] != '/') {
83*00c7fec1SAndroid Build Coastguard Worker             prefix = base_path + "/";
84*00c7fec1SAndroid Build Coastguard Worker         } else {
85*00c7fec1SAndroid Build Coastguard Worker             prefix = "";
86*00c7fec1SAndroid Build Coastguard Worker         }
87*00c7fec1SAndroid Build Coastguard Worker         deps.push_back(prefix + *arg);
88*00c7fec1SAndroid Build Coastguard Worker     }
89*00c7fec1SAndroid Build Coastguard Worker 
90*00c7fec1SAndroid Build Coastguard Worker     std::string canonical_name = MakeCanonical(args[0].substr(0, pos));
91*00c7fec1SAndroid Build Coastguard Worker     if (canonical_name.empty()) {
92*00c7fec1SAndroid Build Coastguard Worker         return false;
93*00c7fec1SAndroid Build Coastguard Worker     }
94*00c7fec1SAndroid Build Coastguard Worker     this->module_deps_[canonical_name] = deps;
95*00c7fec1SAndroid Build Coastguard Worker 
96*00c7fec1SAndroid Build Coastguard Worker     return true;
97*00c7fec1SAndroid Build Coastguard Worker }
98*00c7fec1SAndroid Build Coastguard Worker 
ParseAliasCallback(const std::vector<std::string> & args)99*00c7fec1SAndroid Build Coastguard Worker bool Modprobe::ParseAliasCallback(const std::vector<std::string>& args) {
100*00c7fec1SAndroid Build Coastguard Worker     auto it = args.begin();
101*00c7fec1SAndroid Build Coastguard Worker     const std::string& type = *it++;
102*00c7fec1SAndroid Build Coastguard Worker 
103*00c7fec1SAndroid Build Coastguard Worker     if (type != "alias") {
104*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "non-alias line encountered in modules.alias, found " << type;
105*00c7fec1SAndroid Build Coastguard Worker         return false;
106*00c7fec1SAndroid Build Coastguard Worker     }
107*00c7fec1SAndroid Build Coastguard Worker 
108*00c7fec1SAndroid Build Coastguard Worker     if (args.size() != 3) {
109*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "alias lines in modules.alias must have 3 entries, not " << args.size();
110*00c7fec1SAndroid Build Coastguard Worker         return false;
111*00c7fec1SAndroid Build Coastguard Worker     }
112*00c7fec1SAndroid Build Coastguard Worker 
113*00c7fec1SAndroid Build Coastguard Worker     const std::string& alias = *it++;
114*00c7fec1SAndroid Build Coastguard Worker     const std::string& module_name = *it++;
115*00c7fec1SAndroid Build Coastguard Worker     this->module_aliases_.emplace_back(alias, module_name);
116*00c7fec1SAndroid Build Coastguard Worker 
117*00c7fec1SAndroid Build Coastguard Worker     return true;
118*00c7fec1SAndroid Build Coastguard Worker }
119*00c7fec1SAndroid Build Coastguard Worker 
ParseSoftdepCallback(const std::vector<std::string> & args)120*00c7fec1SAndroid Build Coastguard Worker bool Modprobe::ParseSoftdepCallback(const std::vector<std::string>& args) {
121*00c7fec1SAndroid Build Coastguard Worker     auto it = args.begin();
122*00c7fec1SAndroid Build Coastguard Worker     const std::string& type = *it++;
123*00c7fec1SAndroid Build Coastguard Worker     std::string state = "";
124*00c7fec1SAndroid Build Coastguard Worker 
125*00c7fec1SAndroid Build Coastguard Worker     if (type != "softdep") {
126*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "non-softdep line encountered in modules.softdep, found " << type;
127*00c7fec1SAndroid Build Coastguard Worker         return false;
128*00c7fec1SAndroid Build Coastguard Worker     }
129*00c7fec1SAndroid Build Coastguard Worker 
130*00c7fec1SAndroid Build Coastguard Worker     if (args.size() < 4) {
131*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "softdep lines in modules.softdep must have at least 4 entries";
132*00c7fec1SAndroid Build Coastguard Worker         return false;
133*00c7fec1SAndroid Build Coastguard Worker     }
134*00c7fec1SAndroid Build Coastguard Worker 
135*00c7fec1SAndroid Build Coastguard Worker     const std::string& module = *it++;
136*00c7fec1SAndroid Build Coastguard Worker     while (it != args.end()) {
137*00c7fec1SAndroid Build Coastguard Worker         const std::string& token = *it++;
138*00c7fec1SAndroid Build Coastguard Worker         if (token == "pre:" || token == "post:") {
139*00c7fec1SAndroid Build Coastguard Worker             state = token;
140*00c7fec1SAndroid Build Coastguard Worker             continue;
141*00c7fec1SAndroid Build Coastguard Worker         }
142*00c7fec1SAndroid Build Coastguard Worker         if (state == "") {
143*00c7fec1SAndroid Build Coastguard Worker             LOG(ERROR) << "malformed modules.softdep at token " << token;
144*00c7fec1SAndroid Build Coastguard Worker             return false;
145*00c7fec1SAndroid Build Coastguard Worker         }
146*00c7fec1SAndroid Build Coastguard Worker         if (state == "pre:") {
147*00c7fec1SAndroid Build Coastguard Worker             this->module_pre_softdep_.emplace_back(module, token);
148*00c7fec1SAndroid Build Coastguard Worker         } else {
149*00c7fec1SAndroid Build Coastguard Worker             this->module_post_softdep_.emplace_back(module, token);
150*00c7fec1SAndroid Build Coastguard Worker         }
151*00c7fec1SAndroid Build Coastguard Worker     }
152*00c7fec1SAndroid Build Coastguard Worker 
153*00c7fec1SAndroid Build Coastguard Worker     return true;
154*00c7fec1SAndroid Build Coastguard Worker }
155*00c7fec1SAndroid Build Coastguard Worker 
ParseLoadCallback(const std::vector<std::string> & args)156*00c7fec1SAndroid Build Coastguard Worker bool Modprobe::ParseLoadCallback(const std::vector<std::string>& args) {
157*00c7fec1SAndroid Build Coastguard Worker     auto it = args.begin();
158*00c7fec1SAndroid Build Coastguard Worker     const std::string& module = *it++;
159*00c7fec1SAndroid Build Coastguard Worker 
160*00c7fec1SAndroid Build Coastguard Worker     const std::string& canonical_name = MakeCanonical(module);
161*00c7fec1SAndroid Build Coastguard Worker     if (canonical_name.empty()) {
162*00c7fec1SAndroid Build Coastguard Worker         return false;
163*00c7fec1SAndroid Build Coastguard Worker     }
164*00c7fec1SAndroid Build Coastguard Worker     this->module_load_.emplace_back(canonical_name);
165*00c7fec1SAndroid Build Coastguard Worker 
166*00c7fec1SAndroid Build Coastguard Worker     return true;
167*00c7fec1SAndroid Build Coastguard Worker }
168*00c7fec1SAndroid Build Coastguard Worker 
ParseOptionsCallback(const std::vector<std::string> & args)169*00c7fec1SAndroid Build Coastguard Worker bool Modprobe::ParseOptionsCallback(const std::vector<std::string>& args) {
170*00c7fec1SAndroid Build Coastguard Worker     auto it = args.begin();
171*00c7fec1SAndroid Build Coastguard Worker     const std::string& type = *it++;
172*00c7fec1SAndroid Build Coastguard Worker 
173*00c7fec1SAndroid Build Coastguard Worker     if (type == "dyn_options") {
174*00c7fec1SAndroid Build Coastguard Worker         return ParseDynOptionsCallback(std::vector<std::string>(it, args.end()));
175*00c7fec1SAndroid Build Coastguard Worker     }
176*00c7fec1SAndroid Build Coastguard Worker 
177*00c7fec1SAndroid Build Coastguard Worker     if (type != "options") {
178*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "non-options line encountered in modules.options";
179*00c7fec1SAndroid Build Coastguard Worker         return false;
180*00c7fec1SAndroid Build Coastguard Worker     }
181*00c7fec1SAndroid Build Coastguard Worker 
182*00c7fec1SAndroid Build Coastguard Worker     if (args.size() < 2) {
183*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "lines in modules.options must have at least 2 entries, not " << args.size();
184*00c7fec1SAndroid Build Coastguard Worker         return false;
185*00c7fec1SAndroid Build Coastguard Worker     }
186*00c7fec1SAndroid Build Coastguard Worker 
187*00c7fec1SAndroid Build Coastguard Worker     const std::string& module = *it++;
188*00c7fec1SAndroid Build Coastguard Worker     std::string options = "";
189*00c7fec1SAndroid Build Coastguard Worker 
190*00c7fec1SAndroid Build Coastguard Worker     const std::string& canonical_name = MakeCanonical(module);
191*00c7fec1SAndroid Build Coastguard Worker     if (canonical_name.empty()) {
192*00c7fec1SAndroid Build Coastguard Worker         return false;
193*00c7fec1SAndroid Build Coastguard Worker     }
194*00c7fec1SAndroid Build Coastguard Worker 
195*00c7fec1SAndroid Build Coastguard Worker     while (it != args.end()) {
196*00c7fec1SAndroid Build Coastguard Worker         options += *it++;
197*00c7fec1SAndroid Build Coastguard Worker         if (it != args.end()) {
198*00c7fec1SAndroid Build Coastguard Worker             options += " ";
199*00c7fec1SAndroid Build Coastguard Worker         }
200*00c7fec1SAndroid Build Coastguard Worker     }
201*00c7fec1SAndroid Build Coastguard Worker 
202*00c7fec1SAndroid Build Coastguard Worker     auto [unused, inserted] = this->module_options_.emplace(canonical_name, options);
203*00c7fec1SAndroid Build Coastguard Worker     if (!inserted) {
204*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "multiple options lines present for module " << module;
205*00c7fec1SAndroid Build Coastguard Worker         return false;
206*00c7fec1SAndroid Build Coastguard Worker     }
207*00c7fec1SAndroid Build Coastguard Worker     return true;
208*00c7fec1SAndroid Build Coastguard Worker }
209*00c7fec1SAndroid Build Coastguard Worker 
ParseDynOptionsCallback(const std::vector<std::string> & args)210*00c7fec1SAndroid Build Coastguard Worker bool Modprobe::ParseDynOptionsCallback(const std::vector<std::string>& args) {
211*00c7fec1SAndroid Build Coastguard Worker     auto it = args.begin();
212*00c7fec1SAndroid Build Coastguard Worker     int arg_size = 3;
213*00c7fec1SAndroid Build Coastguard Worker 
214*00c7fec1SAndroid Build Coastguard Worker     if (args.size() < arg_size) {
215*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "dyn_options lines in modules.options must have at least" << arg_size
216*00c7fec1SAndroid Build Coastguard Worker                    << " entries, not " << args.size();
217*00c7fec1SAndroid Build Coastguard Worker         return false;
218*00c7fec1SAndroid Build Coastguard Worker     }
219*00c7fec1SAndroid Build Coastguard Worker 
220*00c7fec1SAndroid Build Coastguard Worker     const std::string& module = *it++;
221*00c7fec1SAndroid Build Coastguard Worker 
222*00c7fec1SAndroid Build Coastguard Worker     const std::string& canonical_name = MakeCanonical(module);
223*00c7fec1SAndroid Build Coastguard Worker     if (canonical_name.empty()) {
224*00c7fec1SAndroid Build Coastguard Worker         return false;
225*00c7fec1SAndroid Build Coastguard Worker     }
226*00c7fec1SAndroid Build Coastguard Worker 
227*00c7fec1SAndroid Build Coastguard Worker     const std::string& pwnam = *it++;
228*00c7fec1SAndroid Build Coastguard Worker     passwd* pwd = getpwnam(pwnam.c_str());
229*00c7fec1SAndroid Build Coastguard Worker     if (!pwd) {
230*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "invalid handler uid'" << pwnam << "'";
231*00c7fec1SAndroid Build Coastguard Worker         return false;
232*00c7fec1SAndroid Build Coastguard Worker     }
233*00c7fec1SAndroid Build Coastguard Worker 
234*00c7fec1SAndroid Build Coastguard Worker     std::string handler_with_args =
235*00c7fec1SAndroid Build Coastguard Worker             android::base::Join(std::vector<std::string>(it, args.end()), ' ');
236*00c7fec1SAndroid Build Coastguard Worker     handler_with_args.erase(std::remove(handler_with_args.begin(), handler_with_args.end(), '\"'),
237*00c7fec1SAndroid Build Coastguard Worker                             handler_with_args.end());
238*00c7fec1SAndroid Build Coastguard Worker 
239*00c7fec1SAndroid Build Coastguard Worker     LOG(DEBUG) << "Launching external module options handler: '" << handler_with_args
240*00c7fec1SAndroid Build Coastguard Worker                << " for module: " << module;
241*00c7fec1SAndroid Build Coastguard Worker 
242*00c7fec1SAndroid Build Coastguard Worker     // There is no need to set envs for external module options handler - pass
243*00c7fec1SAndroid Build Coastguard Worker     // empty map.
244*00c7fec1SAndroid Build Coastguard Worker     std::unordered_map<std::string, std::string> envs_map;
245*00c7fec1SAndroid Build Coastguard Worker     auto result = RunExternalHandler(handler_with_args, pwd->pw_uid, 0, envs_map);
246*00c7fec1SAndroid Build Coastguard Worker     if (!result.ok()) {
247*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "External module handler failed: " << result.error();
248*00c7fec1SAndroid Build Coastguard Worker         return false;
249*00c7fec1SAndroid Build Coastguard Worker     }
250*00c7fec1SAndroid Build Coastguard Worker 
251*00c7fec1SAndroid Build Coastguard Worker     LOG(INFO) << "Dynamic options for module: " << module << " are '" << *result << "'";
252*00c7fec1SAndroid Build Coastguard Worker 
253*00c7fec1SAndroid Build Coastguard Worker     auto [unused, inserted] = this->module_options_.emplace(canonical_name, *result);
254*00c7fec1SAndroid Build Coastguard Worker     if (!inserted) {
255*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "multiple options lines present for module " << module;
256*00c7fec1SAndroid Build Coastguard Worker         return false;
257*00c7fec1SAndroid Build Coastguard Worker     }
258*00c7fec1SAndroid Build Coastguard Worker     return true;
259*00c7fec1SAndroid Build Coastguard Worker }
260*00c7fec1SAndroid Build Coastguard Worker 
ParseBlocklistCallback(const std::vector<std::string> & args)261*00c7fec1SAndroid Build Coastguard Worker bool Modprobe::ParseBlocklistCallback(const std::vector<std::string>& args) {
262*00c7fec1SAndroid Build Coastguard Worker     auto it = args.begin();
263*00c7fec1SAndroid Build Coastguard Worker     const std::string& type = *it++;
264*00c7fec1SAndroid Build Coastguard Worker 
265*00c7fec1SAndroid Build Coastguard Worker     if (type != "blocklist") {
266*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "non-blocklist line encountered in modules.blocklist";
267*00c7fec1SAndroid Build Coastguard Worker         return false;
268*00c7fec1SAndroid Build Coastguard Worker     }
269*00c7fec1SAndroid Build Coastguard Worker 
270*00c7fec1SAndroid Build Coastguard Worker     if (args.size() != 2) {
271*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "lines in modules.blocklist must have exactly 2 entries, not " << args.size();
272*00c7fec1SAndroid Build Coastguard Worker         return false;
273*00c7fec1SAndroid Build Coastguard Worker     }
274*00c7fec1SAndroid Build Coastguard Worker 
275*00c7fec1SAndroid Build Coastguard Worker     const std::string& module = *it++;
276*00c7fec1SAndroid Build Coastguard Worker 
277*00c7fec1SAndroid Build Coastguard Worker     const std::string& canonical_name = MakeCanonical(module);
278*00c7fec1SAndroid Build Coastguard Worker     if (canonical_name.empty()) {
279*00c7fec1SAndroid Build Coastguard Worker         return false;
280*00c7fec1SAndroid Build Coastguard Worker     }
281*00c7fec1SAndroid Build Coastguard Worker     this->module_blocklist_.emplace(canonical_name);
282*00c7fec1SAndroid Build Coastguard Worker 
283*00c7fec1SAndroid Build Coastguard Worker     return true;
284*00c7fec1SAndroid Build Coastguard Worker }
285*00c7fec1SAndroid Build Coastguard Worker 
ParseCfg(const std::string & cfg,std::function<bool (const std::vector<std::string> &)> f)286*00c7fec1SAndroid Build Coastguard Worker void Modprobe::ParseCfg(const std::string& cfg,
287*00c7fec1SAndroid Build Coastguard Worker                         std::function<bool(const std::vector<std::string>&)> f) {
288*00c7fec1SAndroid Build Coastguard Worker     std::string cfg_contents;
289*00c7fec1SAndroid Build Coastguard Worker     if (!android::base::ReadFileToString(cfg, &cfg_contents, false)) {
290*00c7fec1SAndroid Build Coastguard Worker         return;
291*00c7fec1SAndroid Build Coastguard Worker     }
292*00c7fec1SAndroid Build Coastguard Worker 
293*00c7fec1SAndroid Build Coastguard Worker     std::vector<std::string> lines = android::base::Split(cfg_contents, "\n");
294*00c7fec1SAndroid Build Coastguard Worker     for (const auto& line : lines) {
295*00c7fec1SAndroid Build Coastguard Worker         if (line.empty() || line[0] == '#') {
296*00c7fec1SAndroid Build Coastguard Worker             continue;
297*00c7fec1SAndroid Build Coastguard Worker         }
298*00c7fec1SAndroid Build Coastguard Worker         const std::vector<std::string> args = android::base::Split(line, " ");
299*00c7fec1SAndroid Build Coastguard Worker         if (args.empty()) continue;
300*00c7fec1SAndroid Build Coastguard Worker         f(args);
301*00c7fec1SAndroid Build Coastguard Worker     }
302*00c7fec1SAndroid Build Coastguard Worker     return;
303*00c7fec1SAndroid Build Coastguard Worker }
304*00c7fec1SAndroid Build Coastguard Worker 
AddOption(const std::string & module_name,const std::string & option_name,const std::string & value)305*00c7fec1SAndroid Build Coastguard Worker void Modprobe::AddOption(const std::string& module_name, const std::string& option_name,
306*00c7fec1SAndroid Build Coastguard Worker                          const std::string& value) {
307*00c7fec1SAndroid Build Coastguard Worker     auto canonical_name = MakeCanonical(module_name);
308*00c7fec1SAndroid Build Coastguard Worker     auto options_iter = module_options_.find(canonical_name);
309*00c7fec1SAndroid Build Coastguard Worker     auto option_str = option_name + "=" + value;
310*00c7fec1SAndroid Build Coastguard Worker     if (options_iter != module_options_.end()) {
311*00c7fec1SAndroid Build Coastguard Worker         options_iter->second = options_iter->second + " " + option_str;
312*00c7fec1SAndroid Build Coastguard Worker     } else {
313*00c7fec1SAndroid Build Coastguard Worker         module_options_.emplace(canonical_name, option_str);
314*00c7fec1SAndroid Build Coastguard Worker     }
315*00c7fec1SAndroid Build Coastguard Worker }
316*00c7fec1SAndroid Build Coastguard Worker 
ParseKernelCmdlineOptions(void)317*00c7fec1SAndroid Build Coastguard Worker void Modprobe::ParseKernelCmdlineOptions(void) {
318*00c7fec1SAndroid Build Coastguard Worker     std::string cmdline = GetKernelCmdline();
319*00c7fec1SAndroid Build Coastguard Worker     std::string module_name = "";
320*00c7fec1SAndroid Build Coastguard Worker     std::string option_name = "";
321*00c7fec1SAndroid Build Coastguard Worker     std::string value = "";
322*00c7fec1SAndroid Build Coastguard Worker     bool in_module = true;
323*00c7fec1SAndroid Build Coastguard Worker     bool in_option = false;
324*00c7fec1SAndroid Build Coastguard Worker     bool in_value = false;
325*00c7fec1SAndroid Build Coastguard Worker     bool in_quotes = false;
326*00c7fec1SAndroid Build Coastguard Worker     int start = 0;
327*00c7fec1SAndroid Build Coastguard Worker 
328*00c7fec1SAndroid Build Coastguard Worker     for (int i = 0; i < cmdline.size(); i++) {
329*00c7fec1SAndroid Build Coastguard Worker         if (cmdline[i] == '"') {
330*00c7fec1SAndroid Build Coastguard Worker             in_quotes = !in_quotes;
331*00c7fec1SAndroid Build Coastguard Worker         }
332*00c7fec1SAndroid Build Coastguard Worker 
333*00c7fec1SAndroid Build Coastguard Worker         if (in_quotes) continue;
334*00c7fec1SAndroid Build Coastguard Worker 
335*00c7fec1SAndroid Build Coastguard Worker         if (cmdline[i] == ' ') {
336*00c7fec1SAndroid Build Coastguard Worker             if (in_value) {
337*00c7fec1SAndroid Build Coastguard Worker                 value = cmdline.substr(start, i - start);
338*00c7fec1SAndroid Build Coastguard Worker                 if (!module_name.empty() && !option_name.empty()) {
339*00c7fec1SAndroid Build Coastguard Worker                     AddOption(module_name, option_name, value);
340*00c7fec1SAndroid Build Coastguard Worker                 }
341*00c7fec1SAndroid Build Coastguard Worker             }
342*00c7fec1SAndroid Build Coastguard Worker             module_name = "";
343*00c7fec1SAndroid Build Coastguard Worker             option_name = "";
344*00c7fec1SAndroid Build Coastguard Worker             value = "";
345*00c7fec1SAndroid Build Coastguard Worker             in_value = false;
346*00c7fec1SAndroid Build Coastguard Worker             start = i + 1;
347*00c7fec1SAndroid Build Coastguard Worker             in_module = true;
348*00c7fec1SAndroid Build Coastguard Worker             continue;
349*00c7fec1SAndroid Build Coastguard Worker         }
350*00c7fec1SAndroid Build Coastguard Worker 
351*00c7fec1SAndroid Build Coastguard Worker         if (cmdline[i] == '.') {
352*00c7fec1SAndroid Build Coastguard Worker             if (in_module) {
353*00c7fec1SAndroid Build Coastguard Worker                 module_name = cmdline.substr(start, i - start);
354*00c7fec1SAndroid Build Coastguard Worker                 start = i + 1;
355*00c7fec1SAndroid Build Coastguard Worker                 in_module = false;
356*00c7fec1SAndroid Build Coastguard Worker             }
357*00c7fec1SAndroid Build Coastguard Worker             in_option = true;
358*00c7fec1SAndroid Build Coastguard Worker             continue;
359*00c7fec1SAndroid Build Coastguard Worker         }
360*00c7fec1SAndroid Build Coastguard Worker 
361*00c7fec1SAndroid Build Coastguard Worker         if (cmdline[i] == '=') {
362*00c7fec1SAndroid Build Coastguard Worker             if (in_option) {
363*00c7fec1SAndroid Build Coastguard Worker                 option_name = cmdline.substr(start, i - start);
364*00c7fec1SAndroid Build Coastguard Worker                 start = i + 1;
365*00c7fec1SAndroid Build Coastguard Worker                 in_option = false;
366*00c7fec1SAndroid Build Coastguard Worker             }
367*00c7fec1SAndroid Build Coastguard Worker             in_value = true;
368*00c7fec1SAndroid Build Coastguard Worker             continue;
369*00c7fec1SAndroid Build Coastguard Worker         }
370*00c7fec1SAndroid Build Coastguard Worker     }
371*00c7fec1SAndroid Build Coastguard Worker     if (in_value && !in_quotes) {
372*00c7fec1SAndroid Build Coastguard Worker         value = cmdline.substr(start, cmdline.size() - start);
373*00c7fec1SAndroid Build Coastguard Worker         if (!module_name.empty() && !option_name.empty()) {
374*00c7fec1SAndroid Build Coastguard Worker             AddOption(module_name, option_name, value);
375*00c7fec1SAndroid Build Coastguard Worker         }
376*00c7fec1SAndroid Build Coastguard Worker     }
377*00c7fec1SAndroid Build Coastguard Worker }
378*00c7fec1SAndroid Build Coastguard Worker 
Modprobe(const std::vector<std::string> & base_paths,const std::string load_file,bool use_blocklist)379*00c7fec1SAndroid Build Coastguard Worker Modprobe::Modprobe(const std::vector<std::string>& base_paths, const std::string load_file,
380*00c7fec1SAndroid Build Coastguard Worker                    bool use_blocklist)
381*00c7fec1SAndroid Build Coastguard Worker     : blocklist_enabled(use_blocklist) {
382*00c7fec1SAndroid Build Coastguard Worker     using namespace std::placeholders;
383*00c7fec1SAndroid Build Coastguard Worker 
384*00c7fec1SAndroid Build Coastguard Worker     for (const auto& base_path : base_paths) {
385*00c7fec1SAndroid Build Coastguard Worker         auto alias_callback = std::bind(&Modprobe::ParseAliasCallback, this, _1);
386*00c7fec1SAndroid Build Coastguard Worker         ParseCfg(base_path + "/modules.alias", alias_callback);
387*00c7fec1SAndroid Build Coastguard Worker 
388*00c7fec1SAndroid Build Coastguard Worker         auto dep_callback = std::bind(&Modprobe::ParseDepCallback, this, base_path, _1);
389*00c7fec1SAndroid Build Coastguard Worker         ParseCfg(base_path + "/modules.dep", dep_callback);
390*00c7fec1SAndroid Build Coastguard Worker 
391*00c7fec1SAndroid Build Coastguard Worker         auto softdep_callback = std::bind(&Modprobe::ParseSoftdepCallback, this, _1);
392*00c7fec1SAndroid Build Coastguard Worker         ParseCfg(base_path + "/modules.softdep", softdep_callback);
393*00c7fec1SAndroid Build Coastguard Worker 
394*00c7fec1SAndroid Build Coastguard Worker         auto load_callback = std::bind(&Modprobe::ParseLoadCallback, this, _1);
395*00c7fec1SAndroid Build Coastguard Worker         ParseCfg(base_path + "/" + load_file, load_callback);
396*00c7fec1SAndroid Build Coastguard Worker 
397*00c7fec1SAndroid Build Coastguard Worker         auto options_callback = std::bind(&Modprobe::ParseOptionsCallback, this, _1);
398*00c7fec1SAndroid Build Coastguard Worker         ParseCfg(base_path + "/modules.options", options_callback);
399*00c7fec1SAndroid Build Coastguard Worker 
400*00c7fec1SAndroid Build Coastguard Worker         auto blocklist_callback = std::bind(&Modprobe::ParseBlocklistCallback, this, _1);
401*00c7fec1SAndroid Build Coastguard Worker         ParseCfg(base_path + "/modules.blocklist", blocklist_callback);
402*00c7fec1SAndroid Build Coastguard Worker     }
403*00c7fec1SAndroid Build Coastguard Worker 
404*00c7fec1SAndroid Build Coastguard Worker     ParseKernelCmdlineOptions();
405*00c7fec1SAndroid Build Coastguard Worker }
406*00c7fec1SAndroid Build Coastguard Worker 
GetDependencies(const std::string & module)407*00c7fec1SAndroid Build Coastguard Worker std::vector<std::string> Modprobe::GetDependencies(const std::string& module) {
408*00c7fec1SAndroid Build Coastguard Worker     auto it = module_deps_.find(module);
409*00c7fec1SAndroid Build Coastguard Worker     if (it == module_deps_.end()) {
410*00c7fec1SAndroid Build Coastguard Worker         return {};
411*00c7fec1SAndroid Build Coastguard Worker     }
412*00c7fec1SAndroid Build Coastguard Worker     return it->second;
413*00c7fec1SAndroid Build Coastguard Worker }
414*00c7fec1SAndroid Build Coastguard Worker 
InsmodWithDeps(const std::string & module_name,const std::string & parameters)415*00c7fec1SAndroid Build Coastguard Worker bool Modprobe::InsmodWithDeps(const std::string& module_name, const std::string& parameters) {
416*00c7fec1SAndroid Build Coastguard Worker     if (module_name.empty()) {
417*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "Need valid module name, given: " << module_name;
418*00c7fec1SAndroid Build Coastguard Worker         return false;
419*00c7fec1SAndroid Build Coastguard Worker     }
420*00c7fec1SAndroid Build Coastguard Worker 
421*00c7fec1SAndroid Build Coastguard Worker     auto dependencies = GetDependencies(module_name);
422*00c7fec1SAndroid Build Coastguard Worker     if (dependencies.empty()) {
423*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "Module " << module_name << " not in dependency file";
424*00c7fec1SAndroid Build Coastguard Worker         return false;
425*00c7fec1SAndroid Build Coastguard Worker     }
426*00c7fec1SAndroid Build Coastguard Worker 
427*00c7fec1SAndroid Build Coastguard Worker     // load module dependencies in reverse order
428*00c7fec1SAndroid Build Coastguard Worker     for (auto dep = dependencies.rbegin(); dep != dependencies.rend() - 1; ++dep) {
429*00c7fec1SAndroid Build Coastguard Worker         LOG(VERBOSE) << "Loading hard dep for '" << module_name << "': " << *dep;
430*00c7fec1SAndroid Build Coastguard Worker         if (!LoadWithAliases(*dep, true)) {
431*00c7fec1SAndroid Build Coastguard Worker             return false;
432*00c7fec1SAndroid Build Coastguard Worker         }
433*00c7fec1SAndroid Build Coastguard Worker     }
434*00c7fec1SAndroid Build Coastguard Worker 
435*00c7fec1SAndroid Build Coastguard Worker     // try to load soft pre-dependencies
436*00c7fec1SAndroid Build Coastguard Worker     for (const auto& [module, softdep] : module_pre_softdep_) {
437*00c7fec1SAndroid Build Coastguard Worker         if (module_name == module) {
438*00c7fec1SAndroid Build Coastguard Worker             LOG(VERBOSE) << "Loading soft pre-dep for '" << module << "': " << softdep;
439*00c7fec1SAndroid Build Coastguard Worker             LoadWithAliases(softdep, false);
440*00c7fec1SAndroid Build Coastguard Worker         }
441*00c7fec1SAndroid Build Coastguard Worker     }
442*00c7fec1SAndroid Build Coastguard Worker 
443*00c7fec1SAndroid Build Coastguard Worker     // load target module itself with args
444*00c7fec1SAndroid Build Coastguard Worker     if (!Insmod(dependencies[0], parameters)) {
445*00c7fec1SAndroid Build Coastguard Worker         return false;
446*00c7fec1SAndroid Build Coastguard Worker     }
447*00c7fec1SAndroid Build Coastguard Worker 
448*00c7fec1SAndroid Build Coastguard Worker     // try to load soft post-dependencies
449*00c7fec1SAndroid Build Coastguard Worker     for (const auto& [module, softdep] : module_post_softdep_) {
450*00c7fec1SAndroid Build Coastguard Worker         if (module_name == module) {
451*00c7fec1SAndroid Build Coastguard Worker             LOG(VERBOSE) << "Loading soft post-dep for '" << module << "': " << softdep;
452*00c7fec1SAndroid Build Coastguard Worker             LoadWithAliases(softdep, false);
453*00c7fec1SAndroid Build Coastguard Worker         }
454*00c7fec1SAndroid Build Coastguard Worker     }
455*00c7fec1SAndroid Build Coastguard Worker 
456*00c7fec1SAndroid Build Coastguard Worker     return true;
457*00c7fec1SAndroid Build Coastguard Worker }
458*00c7fec1SAndroid Build Coastguard Worker 
LoadWithAliases(const std::string & module_name,bool strict,const std::string & parameters)459*00c7fec1SAndroid Build Coastguard Worker bool Modprobe::LoadWithAliases(const std::string& module_name, bool strict,
460*00c7fec1SAndroid Build Coastguard Worker                                const std::string& parameters) {
461*00c7fec1SAndroid Build Coastguard Worker     auto canonical_name = MakeCanonical(module_name);
462*00c7fec1SAndroid Build Coastguard Worker     if (module_loaded_.count(canonical_name)) {
463*00c7fec1SAndroid Build Coastguard Worker         return true;
464*00c7fec1SAndroid Build Coastguard Worker     }
465*00c7fec1SAndroid Build Coastguard Worker 
466*00c7fec1SAndroid Build Coastguard Worker     std::set<std::string> modules_to_load = {canonical_name};
467*00c7fec1SAndroid Build Coastguard Worker     bool module_loaded = false;
468*00c7fec1SAndroid Build Coastguard Worker 
469*00c7fec1SAndroid Build Coastguard Worker     // use aliases to expand list of modules to load (multiple modules
470*00c7fec1SAndroid Build Coastguard Worker     // may alias themselves to the requested name)
471*00c7fec1SAndroid Build Coastguard Worker     for (const auto& [alias, aliased_module] : module_aliases_) {
472*00c7fec1SAndroid Build Coastguard Worker         if (fnmatch(alias.c_str(), module_name.c_str(), 0) != 0) continue;
473*00c7fec1SAndroid Build Coastguard Worker         LOG(VERBOSE) << "Found alias for '" << module_name << "': '" << aliased_module;
474*00c7fec1SAndroid Build Coastguard Worker         if (module_loaded_.count(MakeCanonical(aliased_module))) continue;
475*00c7fec1SAndroid Build Coastguard Worker         modules_to_load.emplace(aliased_module);
476*00c7fec1SAndroid Build Coastguard Worker     }
477*00c7fec1SAndroid Build Coastguard Worker 
478*00c7fec1SAndroid Build Coastguard Worker     // attempt to load all modules aliased to this name
479*00c7fec1SAndroid Build Coastguard Worker     for (const auto& module : modules_to_load) {
480*00c7fec1SAndroid Build Coastguard Worker         if (!ModuleExists(module)) continue;
481*00c7fec1SAndroid Build Coastguard Worker         if (InsmodWithDeps(module, parameters)) module_loaded = true;
482*00c7fec1SAndroid Build Coastguard Worker     }
483*00c7fec1SAndroid Build Coastguard Worker 
484*00c7fec1SAndroid Build Coastguard Worker     if (strict && !module_loaded) {
485*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "LoadWithAliases was unable to load " << module_name
486*00c7fec1SAndroid Build Coastguard Worker                    << ", tried: " << android::base::Join(modules_to_load, ", ");
487*00c7fec1SAndroid Build Coastguard Worker         return false;
488*00c7fec1SAndroid Build Coastguard Worker     }
489*00c7fec1SAndroid Build Coastguard Worker     return true;
490*00c7fec1SAndroid Build Coastguard Worker }
491*00c7fec1SAndroid Build Coastguard Worker 
IsBlocklisted(const std::string & module_name)492*00c7fec1SAndroid Build Coastguard Worker bool Modprobe::IsBlocklisted(const std::string& module_name) {
493*00c7fec1SAndroid Build Coastguard Worker     if (!blocklist_enabled) return false;
494*00c7fec1SAndroid Build Coastguard Worker 
495*00c7fec1SAndroid Build Coastguard Worker     auto canonical_name = MakeCanonical(module_name);
496*00c7fec1SAndroid Build Coastguard Worker     auto dependencies = GetDependencies(canonical_name);
497*00c7fec1SAndroid Build Coastguard Worker     for (auto dep = dependencies.begin(); dep != dependencies.end(); ++dep) {
498*00c7fec1SAndroid Build Coastguard Worker         if (module_blocklist_.count(MakeCanonical(*dep))) return true;
499*00c7fec1SAndroid Build Coastguard Worker     }
500*00c7fec1SAndroid Build Coastguard Worker 
501*00c7fec1SAndroid Build Coastguard Worker     return module_blocklist_.count(canonical_name) > 0;
502*00c7fec1SAndroid Build Coastguard Worker }
503*00c7fec1SAndroid Build Coastguard Worker 
504*00c7fec1SAndroid Build Coastguard Worker // Another option to load kernel modules. load independent modules dependencies
505*00c7fec1SAndroid Build Coastguard Worker // in parallel and then update dependency list of other remaining modules,
506*00c7fec1SAndroid Build Coastguard Worker // repeat these steps until all modules are loaded.
507*00c7fec1SAndroid Build Coastguard Worker // Discard all blocklist.
508*00c7fec1SAndroid Build Coastguard Worker // Softdeps are taken care in InsmodWithDeps().
LoadModulesParallel(int num_threads)509*00c7fec1SAndroid Build Coastguard Worker bool Modprobe::LoadModulesParallel(int num_threads) {
510*00c7fec1SAndroid Build Coastguard Worker     bool ret = true;
511*00c7fec1SAndroid Build Coastguard Worker     std::map<std::string, std::vector<std::string>> mod_with_deps;
512*00c7fec1SAndroid Build Coastguard Worker 
513*00c7fec1SAndroid Build Coastguard Worker     // Get dependencies
514*00c7fec1SAndroid Build Coastguard Worker     for (const auto& module : module_load_) {
515*00c7fec1SAndroid Build Coastguard Worker         // Skip blocklist modules
516*00c7fec1SAndroid Build Coastguard Worker         if (IsBlocklisted(module)) {
517*00c7fec1SAndroid Build Coastguard Worker             LOG(VERBOSE) << "LMP: Blocklist: Module " << module << " skipping...";
518*00c7fec1SAndroid Build Coastguard Worker             continue;
519*00c7fec1SAndroid Build Coastguard Worker         }
520*00c7fec1SAndroid Build Coastguard Worker         auto dependencies = GetDependencies(MakeCanonical(module));
521*00c7fec1SAndroid Build Coastguard Worker         if (dependencies.empty()) {
522*00c7fec1SAndroid Build Coastguard Worker             LOG(ERROR) << "LMP: Hard-dep: Module " << module
523*00c7fec1SAndroid Build Coastguard Worker                        << " not in .dep file";
524*00c7fec1SAndroid Build Coastguard Worker             return false;
525*00c7fec1SAndroid Build Coastguard Worker         }
526*00c7fec1SAndroid Build Coastguard Worker         mod_with_deps[MakeCanonical(module)] = dependencies;
527*00c7fec1SAndroid Build Coastguard Worker     }
528*00c7fec1SAndroid Build Coastguard Worker 
529*00c7fec1SAndroid Build Coastguard Worker     while (!mod_with_deps.empty()) {
530*00c7fec1SAndroid Build Coastguard Worker         std::vector<std::thread> threads;
531*00c7fec1SAndroid Build Coastguard Worker         std::vector<std::string> mods_path_to_load;
532*00c7fec1SAndroid Build Coastguard Worker         std::mutex vector_lock;
533*00c7fec1SAndroid Build Coastguard Worker 
534*00c7fec1SAndroid Build Coastguard Worker         // Find independent modules
535*00c7fec1SAndroid Build Coastguard Worker         for (const auto& [it_mod, it_dep] : mod_with_deps) {
536*00c7fec1SAndroid Build Coastguard Worker             auto itd_last = it_dep.rbegin();
537*00c7fec1SAndroid Build Coastguard Worker             if (itd_last == it_dep.rend())
538*00c7fec1SAndroid Build Coastguard Worker                 continue;
539*00c7fec1SAndroid Build Coastguard Worker 
540*00c7fec1SAndroid Build Coastguard Worker             auto cnd_last = MakeCanonical(*itd_last);
541*00c7fec1SAndroid Build Coastguard Worker             // Hard-dependencies cannot be blocklisted
542*00c7fec1SAndroid Build Coastguard Worker             if (IsBlocklisted(cnd_last)) {
543*00c7fec1SAndroid Build Coastguard Worker                 LOG(ERROR) << "LMP: Blocklist: Module-dep " << cnd_last
544*00c7fec1SAndroid Build Coastguard Worker                            << " : failed to load module " << it_mod;
545*00c7fec1SAndroid Build Coastguard Worker                 return false;
546*00c7fec1SAndroid Build Coastguard Worker             }
547*00c7fec1SAndroid Build Coastguard Worker 
548*00c7fec1SAndroid Build Coastguard Worker             std::string str = "load_sequential=1";
549*00c7fec1SAndroid Build Coastguard Worker             auto it = module_options_[cnd_last].find(str);
550*00c7fec1SAndroid Build Coastguard Worker             if (it != std::string::npos) {
551*00c7fec1SAndroid Build Coastguard Worker                 module_options_[cnd_last].erase(it, it + str.size());
552*00c7fec1SAndroid Build Coastguard Worker 
553*00c7fec1SAndroid Build Coastguard Worker                 if (!LoadWithAliases(cnd_last, true)) {
554*00c7fec1SAndroid Build Coastguard Worker                     return false;
555*00c7fec1SAndroid Build Coastguard Worker                 }
556*00c7fec1SAndroid Build Coastguard Worker             } else {
557*00c7fec1SAndroid Build Coastguard Worker                 if (std::find(mods_path_to_load.begin(), mods_path_to_load.end(),
558*00c7fec1SAndroid Build Coastguard Worker                             cnd_last) == mods_path_to_load.end()) {
559*00c7fec1SAndroid Build Coastguard Worker                     mods_path_to_load.emplace_back(cnd_last);
560*00c7fec1SAndroid Build Coastguard Worker                 }
561*00c7fec1SAndroid Build Coastguard Worker             }
562*00c7fec1SAndroid Build Coastguard Worker         }
563*00c7fec1SAndroid Build Coastguard Worker 
564*00c7fec1SAndroid Build Coastguard Worker         // Load independent modules in parallel
565*00c7fec1SAndroid Build Coastguard Worker         auto thread_function = [&] {
566*00c7fec1SAndroid Build Coastguard Worker             std::unique_lock lk(vector_lock);
567*00c7fec1SAndroid Build Coastguard Worker             while (!mods_path_to_load.empty()) {
568*00c7fec1SAndroid Build Coastguard Worker                 auto ret_load = true;
569*00c7fec1SAndroid Build Coastguard Worker                 auto mod_to_load = std::move(mods_path_to_load.back());
570*00c7fec1SAndroid Build Coastguard Worker                 mods_path_to_load.pop_back();
571*00c7fec1SAndroid Build Coastguard Worker 
572*00c7fec1SAndroid Build Coastguard Worker                 lk.unlock();
573*00c7fec1SAndroid Build Coastguard Worker                 ret_load &= LoadWithAliases(mod_to_load, true);
574*00c7fec1SAndroid Build Coastguard Worker                 lk.lock();
575*00c7fec1SAndroid Build Coastguard Worker                 if (!ret_load) {
576*00c7fec1SAndroid Build Coastguard Worker                     ret &= ret_load;
577*00c7fec1SAndroid Build Coastguard Worker                 }
578*00c7fec1SAndroid Build Coastguard Worker             }
579*00c7fec1SAndroid Build Coastguard Worker         };
580*00c7fec1SAndroid Build Coastguard Worker 
581*00c7fec1SAndroid Build Coastguard Worker         std::generate_n(std::back_inserter(threads), num_threads,
582*00c7fec1SAndroid Build Coastguard Worker                         [&] { return std::thread(thread_function); });
583*00c7fec1SAndroid Build Coastguard Worker 
584*00c7fec1SAndroid Build Coastguard Worker         // Wait for the threads.
585*00c7fec1SAndroid Build Coastguard Worker         for (auto& thread : threads) {
586*00c7fec1SAndroid Build Coastguard Worker             thread.join();
587*00c7fec1SAndroid Build Coastguard Worker         }
588*00c7fec1SAndroid Build Coastguard Worker 
589*00c7fec1SAndroid Build Coastguard Worker         if (!ret) return ret;
590*00c7fec1SAndroid Build Coastguard Worker 
591*00c7fec1SAndroid Build Coastguard Worker         std::lock_guard guard(module_loaded_lock_);
592*00c7fec1SAndroid Build Coastguard Worker         // Remove loaded module form mod_with_deps and soft dependencies of other modules
593*00c7fec1SAndroid Build Coastguard Worker         for (const auto& module_loaded : module_loaded_)
594*00c7fec1SAndroid Build Coastguard Worker             mod_with_deps.erase(module_loaded);
595*00c7fec1SAndroid Build Coastguard Worker 
596*00c7fec1SAndroid Build Coastguard Worker         // Remove loaded module form dependencies of other modules which are not loaded yet
597*00c7fec1SAndroid Build Coastguard Worker         for (const auto& module_loaded_path : module_loaded_paths_) {
598*00c7fec1SAndroid Build Coastguard Worker             for (auto& [mod, deps] : mod_with_deps) {
599*00c7fec1SAndroid Build Coastguard Worker                 auto it = std::find(deps.begin(), deps.end(), module_loaded_path);
600*00c7fec1SAndroid Build Coastguard Worker                 if (it != deps.end()) {
601*00c7fec1SAndroid Build Coastguard Worker                     deps.erase(it);
602*00c7fec1SAndroid Build Coastguard Worker                 }
603*00c7fec1SAndroid Build Coastguard Worker             }
604*00c7fec1SAndroid Build Coastguard Worker         }
605*00c7fec1SAndroid Build Coastguard Worker     }
606*00c7fec1SAndroid Build Coastguard Worker 
607*00c7fec1SAndroid Build Coastguard Worker     return ret;
608*00c7fec1SAndroid Build Coastguard Worker }
609*00c7fec1SAndroid Build Coastguard Worker 
LoadListedModules(bool strict)610*00c7fec1SAndroid Build Coastguard Worker bool Modprobe::LoadListedModules(bool strict) {
611*00c7fec1SAndroid Build Coastguard Worker     auto ret = true;
612*00c7fec1SAndroid Build Coastguard Worker     for (const auto& module : module_load_) {
613*00c7fec1SAndroid Build Coastguard Worker         if (!LoadWithAliases(module, true)) {
614*00c7fec1SAndroid Build Coastguard Worker             if (IsBlocklisted(module)) continue;
615*00c7fec1SAndroid Build Coastguard Worker             ret = false;
616*00c7fec1SAndroid Build Coastguard Worker             if (strict) break;
617*00c7fec1SAndroid Build Coastguard Worker         }
618*00c7fec1SAndroid Build Coastguard Worker     }
619*00c7fec1SAndroid Build Coastguard Worker     return ret;
620*00c7fec1SAndroid Build Coastguard Worker }
621*00c7fec1SAndroid Build Coastguard Worker 
Remove(const std::string & module_name)622*00c7fec1SAndroid Build Coastguard Worker bool Modprobe::Remove(const std::string& module_name) {
623*00c7fec1SAndroid Build Coastguard Worker     auto dependencies = GetDependencies(MakeCanonical(module_name));
624*00c7fec1SAndroid Build Coastguard Worker     for (auto dep = dependencies.begin(); dep != dependencies.end(); ++dep) {
625*00c7fec1SAndroid Build Coastguard Worker         Rmmod(*dep);
626*00c7fec1SAndroid Build Coastguard Worker     }
627*00c7fec1SAndroid Build Coastguard Worker     Rmmod(module_name);
628*00c7fec1SAndroid Build Coastguard Worker     return true;
629*00c7fec1SAndroid Build Coastguard Worker }
630*00c7fec1SAndroid Build Coastguard Worker 
ListModules(const std::string & pattern)631*00c7fec1SAndroid Build Coastguard Worker std::vector<std::string> Modprobe::ListModules(const std::string& pattern) {
632*00c7fec1SAndroid Build Coastguard Worker     std::vector<std::string> rv;
633*00c7fec1SAndroid Build Coastguard Worker     for (const auto& [module, deps] : module_deps_) {
634*00c7fec1SAndroid Build Coastguard Worker         // Attempt to match both the canonical module name and the module filename.
635*00c7fec1SAndroid Build Coastguard Worker         if (!fnmatch(pattern.c_str(), module.c_str(), 0)) {
636*00c7fec1SAndroid Build Coastguard Worker             rv.emplace_back(module);
637*00c7fec1SAndroid Build Coastguard Worker         } else if (!fnmatch(pattern.c_str(), android::base::Basename(deps[0]).c_str(), 0)) {
638*00c7fec1SAndroid Build Coastguard Worker             rv.emplace_back(deps[0]);
639*00c7fec1SAndroid Build Coastguard Worker         }
640*00c7fec1SAndroid Build Coastguard Worker     }
641*00c7fec1SAndroid Build Coastguard Worker     return rv;
642*00c7fec1SAndroid Build Coastguard Worker }
643*00c7fec1SAndroid Build Coastguard Worker 
GetAllDependencies(const std::string & module,std::vector<std::string> * pre_dependencies,std::vector<std::string> * dependencies,std::vector<std::string> * post_dependencies)644*00c7fec1SAndroid Build Coastguard Worker bool Modprobe::GetAllDependencies(const std::string& module,
645*00c7fec1SAndroid Build Coastguard Worker                                   std::vector<std::string>* pre_dependencies,
646*00c7fec1SAndroid Build Coastguard Worker                                   std::vector<std::string>* dependencies,
647*00c7fec1SAndroid Build Coastguard Worker                                   std::vector<std::string>* post_dependencies) {
648*00c7fec1SAndroid Build Coastguard Worker     std::string canonical_name = MakeCanonical(module);
649*00c7fec1SAndroid Build Coastguard Worker     if (pre_dependencies) {
650*00c7fec1SAndroid Build Coastguard Worker         pre_dependencies->clear();
651*00c7fec1SAndroid Build Coastguard Worker         for (const auto& [it_module, it_softdep] : module_pre_softdep_) {
652*00c7fec1SAndroid Build Coastguard Worker             if (canonical_name == it_module) {
653*00c7fec1SAndroid Build Coastguard Worker                 pre_dependencies->emplace_back(it_softdep);
654*00c7fec1SAndroid Build Coastguard Worker             }
655*00c7fec1SAndroid Build Coastguard Worker         }
656*00c7fec1SAndroid Build Coastguard Worker     }
657*00c7fec1SAndroid Build Coastguard Worker     if (dependencies) {
658*00c7fec1SAndroid Build Coastguard Worker         dependencies->clear();
659*00c7fec1SAndroid Build Coastguard Worker         auto hard_deps = GetDependencies(canonical_name);
660*00c7fec1SAndroid Build Coastguard Worker         if (hard_deps.empty()) {
661*00c7fec1SAndroid Build Coastguard Worker             return false;
662*00c7fec1SAndroid Build Coastguard Worker         }
663*00c7fec1SAndroid Build Coastguard Worker         for (auto dep = hard_deps.rbegin(); dep != hard_deps.rend(); dep++) {
664*00c7fec1SAndroid Build Coastguard Worker             dependencies->emplace_back(*dep);
665*00c7fec1SAndroid Build Coastguard Worker         }
666*00c7fec1SAndroid Build Coastguard Worker     }
667*00c7fec1SAndroid Build Coastguard Worker     if (post_dependencies) {
668*00c7fec1SAndroid Build Coastguard Worker         for (const auto& [it_module, it_softdep] : module_post_softdep_) {
669*00c7fec1SAndroid Build Coastguard Worker             if (canonical_name == it_module) {
670*00c7fec1SAndroid Build Coastguard Worker                 post_dependencies->emplace_back(it_softdep);
671*00c7fec1SAndroid Build Coastguard Worker             }
672*00c7fec1SAndroid Build Coastguard Worker         }
673*00c7fec1SAndroid Build Coastguard Worker     }
674*00c7fec1SAndroid Build Coastguard Worker     return true;
675*00c7fec1SAndroid Build Coastguard Worker }
676