Android-x86
Fork
Donation

  • R/O
  • HTTP
  • SSH
  • HTTPS

system-core: Commit

system/core


Commit MetaInfo

Revision5b54942749913341f7a76d61def6ddefcb45ca16 (tree)
Time2019-03-28 19:36:05
AuthorChih-Wei Huang <cwhuang@linu...>
CommiterChih-Wei Huang

Log Message

ueventd: auto load modules on uevents (pie-x86)

This is an almost rewritten patch which implements the auto modules
loading function for pie-x86.

The commits from nougat-x86 and oreo-x86 are squashed:

* ueventd: defer modules loading if explicitly listed

* ueventd: auto load modules on uevents

* init: add modprobe

* ueventd: load modules in the main process only

* modprobe: handle module options correctly

* modprobe: fix return value

Change Summary

Incremental Difference

--- a/init/Android.mk
+++ b/init/Android.mk
@@ -87,6 +87,7 @@ LOCAL_REQUIRED_MODULES := \
8787
8888 # Create symlinks.
8989 LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
90+ ln -sf ../init $(TARGET_ROOT_OUT)/sbin/modprobe; \
9091 ln -sf ../init $(TARGET_ROOT_OUT)/sbin/ueventd; \
9192 ln -sf ../init $(TARGET_ROOT_OUT)/sbin/watchdogd
9293
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -33,7 +33,6 @@
3333 #include <sys/resource.h>
3434 #include <sys/socket.h>
3535 #include <sys/stat.h>
36-#include <sys/syscall.h>
3736 #include <sys/system_properties.h>
3837 #include <sys/time.h>
3938 #include <sys/types.h>
@@ -50,6 +49,7 @@
5049 #include <android-base/unique_fd.h>
5150 #include <bootloader_message/bootloader_message.h>
5251 #include <cutils/android_reboot.h>
52+#include <cutils/probe_module.h>
5353 #include <ext4_utils/ext4_crypt.h>
5454 #include <ext4_utils/ext4_crypt_init_extensions.h>
5555 #include <fs_mgr.h>
@@ -231,10 +231,7 @@ static Result<Success> do_insmod(const BuiltinArguments& args) {
231231 std::string filename = *it++;
232232 std::string options = android::base::Join(std::vector<std::string>(it, args.end()), ' ');
233233
234- unique_fd fd(TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
235- if (fd == -1) return ErrnoError() << "open(\"" << filename << "\") failed";
236-
237- int rc = syscall(__NR_finit_module, fd.get(), options.c_str(), flags);
234+ int rc = insmod(filename.c_str(), options.c_str(), flags);
238235 if (rc == -1) return ErrnoError() << "finit_module for \"" << filename << "\" failed";
239236
240237 return Success();
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -22,6 +22,8 @@
2222 #include <unistd.h>
2323
2424 #include <memory>
25+#include <set>
26+#include <thread>
2527
2628 #include <android-base/logging.h>
2729 #include <android-base/stringprintf.h>
@@ -29,10 +31,13 @@
2931 #include <private/android_filesystem_config.h>
3032 #include <selinux/android.h>
3133 #include <selinux/selinux.h>
34+#include <cutils/klog.h>
35+#include <cutils/probe_module.h>
3236
3337 #include "selinux.h"
3438 #include "ueventd.h"
3539 #include "util.h"
40+#include "parser.h"
3641
3742 #ifdef _INIT_INIT_H
3843 #error "Do not include init.h in files used by ueventd or watchdogd; it will expose init's globals"
@@ -419,6 +424,91 @@ void DeviceHandler::HandleDeviceEvent(const Uevent& uevent) {
419424 HandleDevice(uevent.action, devpath, block, uevent.major, uevent.minor, links);
420425 }
421426
427+void DeviceHandler::HandleModuleEvent(const Uevent& uevent, std::vector<std::string>* mod_queue)
428+{
429+ if (!uevent.modalias.empty() && uevent.action == "add") {
430+ if (mod_aliases_.empty()) {
431+ ReadModulesDescFiles();
432+ }
433+ bool deferred = false;
434+ if (mod_queue) {
435+ for (auto& entry : deferred_mod_aliases_) {
436+ if (!fnmatch(entry.first.c_str(), uevent.modalias.c_str(), 0)) {
437+ mod_queue->emplace_back(entry.second);
438+ deferred = true;
439+ }
440+ }
441+ }
442+ if (!deferred) {
443+ LoadModule(uevent);
444+ }
445+ }
446+}
447+
448+bool DeviceHandler::LoadModule(const Uevent& uevent) const
449+{
450+ bool ret = false;
451+ for (auto& entry : mod_aliases_) {
452+ if (!fnmatch(entry.first.c_str(), uevent.modalias.c_str(), 0)) {
453+ ret |= LoadModule(entry.second);
454+ }
455+ }
456+ return ret;
457+}
458+
459+bool DeviceHandler::LoadModule(const std::string& mod, const char* options) const
460+{
461+ bool ret = !insmod_by_dep(mod.c_str(), options, NULL, 0, NULL);
462+ if (!ret) {
463+ PLOG(WARNING) << "failed to load " << mod;
464+ }
465+ return ret;
466+}
467+
468+void DeviceHandler::ReadModulesDescFiles()
469+{
470+ auto line_parser = [] (auto args, std::set<std::string>* set_) -> Result<Success> {
471+ if (args.size() < 2) {
472+ return Error() << "must have 2 entries";
473+ }
474+
475+ set_->emplace(args[1]);
476+ return Success();
477+ };
478+ using namespace std::placeholders;
479+ std::set<std::string> blacklist, deferred;
480+
481+ Parser parser;
482+ parser.AddSingleLineParser("blacklist", std::bind(line_parser, _1, &blacklist));
483+ parser.AddSingleLineParser("deferred", std::bind(line_parser, _1, &deferred));
484+
485+ // wait until the file is ready
486+ while (!parser.ParseConfig("/system/etc/modules.blacklist")) {
487+ std::this_thread::sleep_for(100ms);
488+ }
489+
490+ parser.AddSingleLineParser("alias", [&] (auto args) -> Result<Success> {
491+ if (args.size() < 3) {
492+ return Error() << "must have 3 entries";
493+ }
494+ if (deferred.find(args[2]) != deferred.end()) {
495+ deferred_mod_aliases_.emplace(args[1], args[2]);
496+ } else if (blacklist.find(args[2]) == blacklist.end()) {
497+ mod_aliases_.emplace(args[1], args[2]);
498+ }
499+ return Success();
500+ });
501+ char alias[PATH_MAX];
502+ strlcat(get_default_mod_path(alias), "modules.alias", PATH_MAX);
503+ parser.ParseConfig(alias);
504+}
505+
506+void DeviceHandler::OnColdBootDone()
507+{
508+ mod_aliases_.insert(deferred_mod_aliases_.begin(), deferred_mod_aliases_.end());
509+ deferred_mod_aliases_.clear();
510+}
511+
422512 DeviceHandler::DeviceHandler(std::vector<Permissions> dev_permissions,
423513 std::vector<SysfsPermissions> sysfs_permissions,
424514 std::vector<Subsystem> subsystems, std::set<std::string> boot_devices,
@@ -434,5 +524,40 @@ DeviceHandler::DeviceHandler()
434524 : DeviceHandler(std::vector<Permissions>{}, std::vector<SysfsPermissions>{},
435525 std::vector<Subsystem>{}, std::set<std::string>{}, false) {}
436526
527+int modprobe_main(int argc, char **argv)
528+{
529+ // We only accept requests from root user (kernel)
530+ if (getuid()) return -EPERM;
531+
532+ // Kernel will launch a user space program specified by
533+ // /proc/sys/kernel/modprobe to load modules.
534+ // No deferred loading in this case.
535+ while (argc > 1 && (!strcmp(argv[1], "-q") || !strcmp(argv[1], "--"))) {
536+ klog_set_level(KLOG_NOTICE_LEVEL);
537+ argc--, argv++;
538+ }
539+
540+ if (argc < 2) {
541+ // it is called without enough arguments
542+ return -EINVAL;
543+ }
544+
545+ std::string options;
546+ if (argc > 2) {
547+ options = argv[2];
548+ for (int i = 3; i < argc; ++i) {
549+ options += ' ';
550+ options += argv[i];
551+ }
552+ }
553+ KLOG_NOTICE("modprobe", "%s %s", argv[1], options.c_str());
554+
555+ Uevent uevent = { .modalias = argv[1] };
556+ DeviceHandler dh;
557+ dh.ReadModulesDescFiles();
558+ dh.OnColdBootDone();
559+ exit(!dh.LoadModule(uevent) && !dh.LoadModule(uevent.modalias, options.c_str()));
560+}
561+
437562 } // namespace init
438563 } // namespace android
--- a/init/devices.h
+++ b/init/devices.h
@@ -23,6 +23,7 @@
2323 #include <algorithm>
2424 #include <set>
2525 #include <string>
26+#include <map>
2627 #include <vector>
2728
2829 #include <android-base/file.h>
@@ -109,6 +110,11 @@ class DeviceHandler {
109110 ~DeviceHandler(){};
110111
111112 void HandleDeviceEvent(const Uevent& uevent);
113+ void HandleModuleEvent(const Uevent& uevent, std::vector<std::string>* mod_queue = nullptr);
114+ bool LoadModule(const Uevent& uevent) const;
115+ bool LoadModule(const std::string& mod, const char* options = "") const;
116+ void ReadModulesDescFiles();
117+ void OnColdBootDone();
112118
113119 std::vector<std::string> GetBlockDeviceSymlinks(const Uevent& uevent) const;
114120 void set_skip_restorecon(bool value) { skip_restorecon_ = value; }
@@ -127,6 +133,8 @@ class DeviceHandler {
127133 std::vector<SysfsPermissions> sysfs_permissions_;
128134 std::vector<Subsystem> subsystems_;
129135 std::set<std::string> boot_devices_;
136+ std::multimap<std::string, std::string> mod_aliases_;
137+ std::multimap<std::string, std::string> deferred_mod_aliases_;
130138 bool skip_restorecon_;
131139 std::string sysfs_mount_point_;
132140 };
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -549,6 +549,10 @@ static void InstallSigtermHandler() {
549549 }
550550
551551 int main(int argc, char** argv) {
552+ if (!strcmp(basename(argv[0]), "modprobe")) {
553+ return modprobe_main(argc, argv);
554+ }
555+
552556 if (!strcmp(basename(argv[0]), "ueventd")) {
553557 return ueventd_main(argc, argv);
554558 }
--- a/init/uevent.h
+++ b/init/uevent.h
@@ -29,6 +29,7 @@ struct Uevent {
2929 std::string firmware;
3030 std::string partition_name;
3131 std::string device_name;
32+ std::string modalias;
3233 int partition_num;
3334 int major;
3435 int minor;
--- a/init/uevent_listener.cpp
+++ b/init/uevent_listener.cpp
@@ -39,6 +39,7 @@ static void ParseEvent(const char* msg, Uevent* uevent) {
3939 uevent->firmware.clear();
4040 uevent->partition_name.clear();
4141 uevent->device_name.clear();
42+ uevent->modalias.clear();
4243 // currently ignoring SEQNUM
4344 while (*msg) {
4445 if (!strncmp(msg, "ACTION=", 7)) {
@@ -68,6 +69,9 @@ static void ParseEvent(const char* msg, Uevent* uevent) {
6869 } else if (!strncmp(msg, "DEVNAME=", 8)) {
6970 msg += 8;
7071 uevent->device_name = msg;
72+ } else if (!strncmp(msg, "MODALIAS=", 9)) {
73+ msg += 9;
74+ uevent->modalias = msg;
7175 }
7276
7377 // advance to after the next \0
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -127,6 +127,7 @@ class ColdBoot {
127127
128128 unsigned int num_handler_subprocesses_;
129129 std::vector<Uevent> uevent_queue_;
130+ std::vector<std::string> mod_queue_;
130131
131132 std::set<pid_t> subprocess_pids_;
132133 };
@@ -142,7 +143,7 @@ void ColdBoot::UeventHandlerMain(unsigned int process_num, unsigned int total_pr
142143 void ColdBoot::RegenerateUevents() {
143144 uevent_listener_.RegenerateUevents([this](const Uevent& uevent) {
144145 HandleFirmwareEvent(uevent);
145-
146+ device_handler_.HandleModuleEvent(uevent, &mod_queue_);
146147 uevent_queue_.emplace_back(std::move(uevent));
147148 return ListenerAction::kContinue;
148149 });
@@ -212,6 +213,11 @@ void ColdBoot::Run() {
212213
213214 WaitForSubProcesses();
214215
216+ device_handler_.OnColdBootDone();
217+ for (auto& mod : mod_queue_) {
218+ device_handler_.LoadModule(mod);
219+ }
220+
215221 close(open(COLDBOOT_DONE, O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
216222 KLOG_INFO("Coldboot", "took %f seconds", cold_boot_timer.duration().count() / 1000.0f);
217223 }
@@ -281,6 +287,7 @@ int ueventd_main(int argc, char** argv) {
281287
282288 uevent_listener.Poll([&device_handler](const Uevent& uevent) {
283289 HandleFirmwareEvent(uevent);
290+ device_handler.HandleModuleEvent(uevent);
284291 device_handler.HandleDeviceEvent(uevent);
285292 return ListenerAction::kContinue;
286293 });
--- a/init/ueventd.h
+++ b/init/ueventd.h
@@ -21,6 +21,7 @@ namespace android {
2121 namespace init {
2222
2323 int ueventd_main(int argc, char** argv);
24+int modprobe_main(int argc, char **argv);
2425
2526 } // namespace init
2627 } // namespace android
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -105,6 +105,7 @@ cc_library {
105105 "ashmem-dev.cpp",
106106 "klog.cpp",
107107 "partition_utils.cpp",
108+ "probe_module.c",
108109 "properties.cpp",
109110 "qtaguid.cpp",
110111 "trace-dev.cpp",
--- /dev/null
+++ b/libcutils/include/cutils/probe_module.h
@@ -0,0 +1,106 @@
1+/*
2+ * Copyright (C) 2012 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+#ifndef _LIBS_CUTILS_PROBEMODULE_H
18+#define _LIBS_CUTILS_PROBEMODULE_H
19+
20+#ifdef __cplusplus
21+extern "C" {
22+#endif
23+
24+/* get_default_mod_path() - get the default modules path
25+ * It checks /system/lib/modules/$(uname -r)/ first. If it doesn't exist,
26+ * fall back to /system/lib/modules/.
27+ *
28+ * def_mod_path: The buffer to be filled
29+ *
30+ * return : def_mod_path
31+ */
32+extern char *get_default_mod_path(char *def_mod_path);
33+
34+/* insmod() - load a kernel module (target) from a file
35+ *
36+ * filename : Filename of the target module.
37+ *
38+ * args : A string of target module's parameters. NOTE: we only
39+ * support parameters of the target module.
40+ *
41+ * flags : MODULE_INIT_* flags defined in module.h
42+ *
43+ * return : 0 for success; -1 indicates an error
44+ */
45+extern int insmod(const char *filename, const char *options, int flags);
46+
47+/* insmod_by_dep() - load a kernel module (target) with its dependency
48+ * The module's dependency must be described in the provided dependency file.
49+ * other modules in the dependency chain will be loaded prior to the target.
50+ *
51+ * module_name: Name of the target module. e.g. name "MyModule" is for
52+ * module file MyModule.ko.
53+ *
54+ * args : A string of target module's parameters. NOTE: we only
55+ * support parameters of the target module.
56+ *
57+ * dep_name : Name of dependency file. If it is NULL, we will look
58+ * up /system/lib/modules/modules.dep by default.
59+ *
60+ * strip : Non-zero values remove paths of modules in dependency.
61+ * before loading them. The final path of a module will be
62+ * base/MyModule.ko. This is for devices which put every
63+ * modules into a single directory.
64+ *
65+ * Passing 0 to strip keeps module paths in dependency file.
66+ * e.g. "kernel/drivers/.../MyModule.ko" in dep file will
67+ * be loaded as base/kernel/drivers/.../MyModule.ko .
68+ *
69+ * base : Base dir, a prefix to be added to module's path prior to
70+ * loading. The last character prior to base string's terminator
71+ * must be a '/'. If it is NULL, we will take
72+ * /system/lib/modules/modules.dep by default.
73+ *
74+ * return : 0 for success; non-zero for any errors.
75+ *
76+ * Note:
77+ * When loading modules, function will not fail for any modules which are
78+ * already in kernel. The module parameters passed to function will not be
79+ * effective in this case if target module is already loaded into kernel.
80+ */
81+extern int insmod_by_dep(
82+ const char *module_name,
83+ const char *args,
84+ const char *dep_name,
85+ int strip,
86+ const char * base);
87+
88+/* rmmod_by_dep() - remove a module (target) from kernel with its dependency
89+ * The module's dependency must be described in the provided dependency file.
90+ * This function will try to remove other modules in the dependency chain too
91+ *
92+ * module_name: Name of the target module. e.g. name "MyModule" is for
93+ * module file MyModule.ko.
94+ *
95+ * dep_name : Name of dependency file. If it is NULL, we will look
96+ * up /system/lib/modules/modules.dep by default.
97+ *
98+ * return : 0 for success; non-zero for any errors.
99+ */
100+extern int rmmod_by_dep(const char *module_name, const char *dep_name);
101+
102+#ifdef __cplusplus
103+}
104+#endif
105+
106+#endif /*_LIBS_CUTILS_PROBEMODULE_H*/
--- /dev/null
+++ b/libcutils/probe_module.c
@@ -0,0 +1,386 @@
1+/*
2+ * Copyright (C) 2012 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 <stdio.h>
18+#include <stdlib.h>
19+#include <string.h>
20+#include <limits.h>
21+#include <errno.h>
22+#include <fcntl.h>
23+#include <cutils/misc.h>
24+#include <sys/syscall.h>
25+#include <sys/utsname.h>
26+
27+#define LOG_TAG "ProbeModule"
28+#include <cutils/log.h>
29+
30+#define LDM_DEFAULT_MOD_PATH "/system/lib/modules/"
31+
32+extern int delete_module(const char *, unsigned int);
33+
34+/* get_default_mod_path() interface to outside,
35+ * refer to its description in probe_module.h
36+ */
37+char *get_default_mod_path(char *def_mod_path)
38+{
39+ int len;
40+ struct utsname buf;
41+ uname(&buf);
42+ len = snprintf(def_mod_path, PATH_MAX, "%s", LDM_DEFAULT_MOD_PATH);
43+ strcpy(def_mod_path + len, buf.release);
44+ if (access(def_mod_path, F_OK))
45+ def_mod_path[len] = '\0';
46+ else
47+ strcat(def_mod_path, "/");
48+ return def_mod_path;
49+}
50+
51+int insmod(const char *filename, const char *options, int flags)
52+{
53+ int fd = open(filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
54+ if (fd == -1) {
55+ ALOGE("insmod: open(\"%s\") failed: %s", filename, strerror(errno));
56+ return -1;
57+ }
58+ int rc = syscall(__NR_finit_module, fd, options, flags);
59+ if (rc == -1) {
60+ if (errno == EEXIST) {
61+ rc = 0;
62+ } else {
63+ ALOGE("finit_module for \"%s\" failed: %s", filename, strerror(errno));
64+ }
65+ }
66+ close(fd);
67+ return rc;
68+}
69+
70+static char *strip_path(char *str)
71+{
72+ char *ptr = strrchr(str, '/');
73+ return ptr ? ptr + 1 : str;
74+}
75+
76+static void hyphen_to_underscore(char *str)
77+{
78+ while (str && *str != '\0') {
79+ if (*str == '-')
80+ *str = '_';
81+ str++;
82+ }
83+}
84+
85+/* Compare module names, but don't differentiate '_' and '-'.
86+ * return: 0 when s1 is matched to s2 or size is zero.
87+ * non-zero in any other cases.
88+ */
89+static int match_name(const char *s1, const char *s2, const size_t size)
90+{
91+ size_t i;
92+
93+ if (!size)
94+ return 0;
95+
96+ for (i = 0; i < size; i++, s1++, s2++) {
97+
98+ if ((*s1 == '_' || *s1 == '-') && (*s2 == '_' || *s2 == '-'))
99+ continue;
100+
101+ if (*s1 != *s2)
102+ return -1;
103+
104+ if (*s1 == '\0')
105+ return 0;
106+ }
107+
108+ return 0;
109+}
110+
111+/* check if a line in dep file is target module's dependency.
112+ * return 1 when it is, otherwise 0 in any other cases.
113+ */
114+static int is_target_module(char *line, const char *target)
115+{
116+ char *token;
117+ char name[PATH_MAX];
118+ const char *delimiter = ":";
119+ int ret = 0;
120+
121+ /* search token */
122+ token = strstr(line, delimiter);
123+
124+ if (!token) {
125+ ALOGE("invalid line: no token");
126+ return 0;
127+ }
128+
129+ /* only take stuff before the token */
130+ *token = '\0';
131+
132+ /* use "module.ko" in comparision */
133+ strcat(strcpy(name, target), ".ko");
134+
135+ ret = !match_name(strip_path(line), name, strlen(name));
136+
137+ /* restore [single] token, keep line unchanged until we parse it later */
138+ *token = *delimiter;
139+
140+ return ret;
141+
142+}
143+
144+/* turn a single string into an array of dependency.
145+ *
146+ * return: dependency array's address if it succeeded. Caller
147+ * is responsible to free the array's memory.
148+ * NULL when any error happens.
149+ */
150+static char **setup_dep(char *line)
151+{
152+ char *tmp = line;
153+ char *brk;
154+ int i;
155+ char **dep;
156+
157+ for (i = 2; (tmp = strchr(tmp, ' ')); i++)
158+ tmp++;
159+
160+ dep = malloc(sizeof(char *) * i);
161+ if (dep) {
162+ i = 0;
163+ do {
164+ tmp = strtok_r(i ? NULL : line, ": ", &brk);
165+ } while ((dep[i++] = tmp));
166+ }
167+
168+ return dep;
169+}
170+
171+/* install all modules in the dependency chain
172+ * deps : A array of module file names, must be terminated by a NULL pointer
173+ * args : The module parameters for target module.
174+ * strip : Non-zero to strip out path info in the file name;
175+ * 0 to keep path info when loading modules.
176+ * base : a prefix to module path, it will NOT be affected by strip flag.
177+ * return : 0 for success or nothing to do; non-zero when any error occurs.
178+ */
179+static int insmod_s(char *dep[], const char *args, int strip, const char *base)
180+{
181+ char *name;
182+ int cnt;
183+ size_t len;
184+ int ret = 0;
185+ char path_name[PATH_MAX];
186+ char def_mod_path[PATH_MAX];
187+ const char *base_dir;
188+
189+ if (base && strlen(base))
190+ base_dir = base;
191+ else
192+ base_dir = get_default_mod_path(def_mod_path);
193+
194+ /* load modules in reversed order */
195+ for (cnt = 0; dep[cnt]; cnt++)
196+ ;
197+
198+ len = strlen(strcpy(path_name, base_dir));
199+
200+ while (!ret && cnt--) {
201+
202+ name = strip ? strip_path(dep[cnt]) : dep[cnt];
203+
204+ strcpy(path_name + len, name);
205+
206+ ret = insmod(path_name, cnt ? "" : args, 0);
207+ }
208+
209+ return ret;
210+}
211+
212+/* remove all modules in a dependency chain
213+ * NOTE: We assume module name in kernel is same as the file name without .ko
214+ */
215+static int rmmod_s(char *dep[], int flags)
216+{
217+ int i;
218+ int ret = 0;
219+
220+ for (i = 0; dep[i]; i++) {
221+ char *mod_name = strip_path(dep[i]);
222+ size_t len = strlen(mod_name);
223+
224+ if (len > 3 && strstr(mod_name, ".ko") == (mod_name + len - 3)) {
225+ mod_name[len - 3] = '\0';
226+
227+ hyphen_to_underscore(mod_name);
228+
229+ ret = delete_module(mod_name, flags);
230+
231+ if (ret) {
232+ ALOGE("%s: Failed to remove module [%s] error (%s)",
233+ __FUNCTION__, mod_name, strerror(errno));
234+ break;
235+
236+ }
237+ }
238+ }
239+
240+ return ret;
241+}
242+
243+/* look_up_dep() find and setup target module's dependency in modules.dep
244+ *
245+ * dep_file: a pointer to module's dep file loaded in memory, its content
246+ * will be CHANGED during parsing.
247+ *
248+ * return: a pointer to an array which holds the dependency strings and
249+ * terminated by a NULL pointer. Caller is responsible to free the
250+ * array's memory.
251+ *
252+ * non-zero in any other cases. Content of dep array is invalid.
253+ */
254+static char **look_up_dep(const char *module_name, void *dep_file)
255+{
256+ char *line;
257+ char *saved_pos;
258+ char *start;
259+ char **dep = NULL;
260+
261+ if (!dep_file || !module_name || *module_name == '\0')
262+ return NULL;
263+
264+ start = (char *)dep_file;
265+
266+ /* We expect modules.dep file has a new line char before EOF. */
267+ while ((line = strtok_r(start, "\n", &saved_pos)) != NULL) {
268+
269+ start = NULL;
270+
271+ if (is_target_module(line, module_name)) {
272+
273+ dep = setup_dep(line);
274+ /* job done */
275+ break;
276+ }
277+ }
278+
279+ return dep;
280+}
281+
282+/* load_dep_file() load a dep file (usually it is modules.dep)
283+ * into memory. Caller is responsible to free the memory.
284+ *
285+ * file_name: dep file's name, if it is NULL or an empty string,
286+ * This function will try to load a dep file in the
287+ * default path defined in LDM_DEFAULT_DEP_FILE
288+ *
289+ * return: a pointer to the allocated mem which holds all
290+ * content of the depfile. a zero pointer will be
291+ * returned for any errors.
292+ * */
293+static void *load_dep_file(const char *file_name)
294+{
295+ unsigned int len;
296+ char def_mod_path[PATH_MAX];
297+ if (!file_name || *file_name == '\0') {
298+ file_name = get_default_mod_path(def_mod_path);
299+ strcat(def_mod_path, "modules.dep");
300+ }
301+
302+ return load_file(file_name, &len);
303+}
304+
305+/* insmod_by_dep() interface to outside,
306+ * refer to its description in probe_module.h
307+ */
308+int insmod_by_dep(const char *module_name,
309+ const char *args,
310+ const char *dep_name,
311+ int strip,
312+ const char *base)
313+{
314+ void *dep_file;
315+ char **dep = NULL;
316+ int ret = -1;
317+
318+ if (!module_name || *module_name == '\0') {
319+ ALOGE("need valid module name");
320+ return ret;
321+ }
322+
323+ dep_file = load_dep_file(dep_name);
324+
325+ if (!dep_file) {
326+ ALOGE("cannot load dep file : %s", dep_name);
327+ return ret;
328+ }
329+
330+ dep = look_up_dep(module_name, dep_file);
331+
332+ if (!dep) {
333+ ALOGE("%s: cannot load module: [%s]", __FUNCTION__, module_name);
334+ goto free_file;
335+ }
336+
337+ ret = insmod_s(dep, args, strip, base);
338+
339+ free(dep);
340+
341+free_file:
342+ free(dep_file);
343+
344+ return ret;
345+
346+}
347+
348+/* rmmod_by_dep() interface to outside,
349+ * refer to its description in probe_module.h
350+ */
351+int rmmod_by_dep(const char *module_name, const char *dep_name)
352+{
353+ void *dep_file;
354+ char **dep = NULL;
355+ int ret = -1;
356+
357+ if (!module_name || *module_name == '\0') {
358+ ALOGE("need valid module name");
359+ return ret;
360+ }
361+
362+ dep_file = load_dep_file(dep_name);
363+
364+ if (!dep_file) {
365+ ALOGE("cannot load dep file : %s", dep_name);
366+ return ret;
367+ }
368+
369+ dep = look_up_dep(module_name, dep_file);
370+
371+ if (!dep) {
372+ ALOGE("%s: cannot remove module: [%s]", __FUNCTION__, module_name);
373+ goto free_file;
374+ }
375+
376+ ret = rmmod_s(dep, O_NONBLOCK);
377+
378+ free(dep);
379+
380+free_file:
381+ free(dep_file);
382+
383+ return ret;
384+}
385+
386+/* end of file */
Show on old repository browser