• R/O
  • HTTP
  • SSH
  • HTTPS

提交

標籤
無標籤

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

system/corennnnn


Commit MetaInfo

修訂f77c1188341bf0d89221c65be3c42db47c1beaa2 (tree)
時間2016-07-27 03:49:13
作者Jianxun Zhang <jianxun.zhang@inte...>
CommiterJaap Jan Meijer

Log Message

add modprobe-like capability and automatic ueventd loading

Author: Jianxun Zhang <jianxun.zhang@intel.com>
Author: Daniel Leung <daniel.leung@intel.com>
Author: Andrew Boie <andrew.p.boie@intel.com>

- insmod_by_dep() added to libcutils; loads a module into kernel.
Modules the target module depends on will be loaded first. Loading
will be stopped when an error occurs.

- rmmod_by_dep() added to libcutils; removes a module from kernel.
It also tries to remove other modules the target module depends
on until an error occurs.

- Implement wildcard matching for ueventd rules.
The PCI and USB addresses for devices can change from devices
from devices for a particular class of peripheral, for example,
bluetooth. The ueventd rules created with these addresses are
then device-specific.

This changes the way ueventd rules with wildcard are handled.
Instead of matching just the prefix with a trailing wildcard,
now these rules can have wildcard anywhere in the rule.
The wildcard matching is implemented using fnmatch(), where
its matching is simliar to shell pathname expansion. It suits
this particular usage model well.

For example, instead of creating a rule to match:

/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/bluetooth/hci0/rfkill*

, this would suffice:

/sys/devices/*/bluetooth/hci0/rfkill*

- Let ueventd auto-load kernel modules. Implements the functionality
for ueventd to auto-load kernel modules when uevents are triggered.
Since /system may not be mounted when uevents are fired,
a deferred loading mechanism is implemented. Once mapping of
module and alias is available, these modules are then loaded.
Modules can also be blacklisted so they will not be loaded
automatically. One example would be the Wifi driver, as
Android's has to control its loading and unloading.

- add 'probemod' builtin command. This command accepts the name of a
kernel module plus a set of command line arguments. The module will
be loaded, along with all its dependencies, using the libcutils
insmod_by_dep() API.

- Drivers in kernel can request modules by launching a program in
user space, the program's path by default is "/sbin/modprobe".
Because Android system has no modprobe and ueventd is the only
program handling the module aliases so far, This patch provides a
cheap approach to handle kernel's requests in ueventd executable.

- Add new builtin init command "coldboot". The main purpose is to
provide an approach in init.*.rc files to fire uevents for devices
under the path which is passed as the the argument. This should be
called after /system is mounted so any queued events that need to
load a module can be fired.

Change Summary

差異

--- /dev/null
+++ b/include/cutils/probe_module.h
@@ -0,0 +1,83 @@
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+/* insmod_by_dep() - load a kernel module (target) with its dependency
25+ * The module's dependency must be described in the provided dependency file.
26+ * other modules in the dependency chain will be loaded prior to the target.
27+ *
28+ * module_name: Name of the target module. e.g. name "MyModule" is for
29+ * module file MyModule.ko.
30+ *
31+ * args : A string of target module's parameters. NOTE: we only
32+ * support parameters of the target module.
33+ *
34+ * dep_name : Name of dependency file. If it is NULL, we will look
35+ * up /system/lib/modules/modules.dep by default.
36+ *
37+ * strip : Non-zero values remove paths of modules in dependency.
38+ * before loading them. The final path of a module will be
39+ * base/MyModule.ko. This is for devices which put every
40+ * modules into a single directory.
41+ *
42+ * Passing 0 to strip keeps module paths in dependency file.
43+ * e.g. "kernel/drivers/.../MyModule.ko" in dep file will
44+ * be loaded as base/kernel/drivers/.../MyModule.ko .
45+ *
46+ * base : Base dir, a prefix to be added to module's path prior to
47+ * loading. The last character prior to base string's terminator
48+ * must be a '/'. If it is NULL, we will take
49+ * /system/lib/modules/modules.dep by default.
50+ *
51+ * return : 0 for success; non-zero for any errors.
52+ *
53+ * Note:
54+ * When loading modules, function will not fail for any modules which are
55+ * already in kernel. The module parameters passed to function will not be
56+ * effective in this case if target module is already loaded into kernel.
57+ */
58+extern int insmod_by_dep(
59+ const char *module_name,
60+ const char *args,
61+ const char *dep_name,
62+ int strip,
63+ const char * base);
64+
65+/* rmmod_by_dep() - remove a module (target) from kernel with its dependency
66+ * The module's dependency must be described in the provided dependency file.
67+ * This function will try to remove other modules in the dependency chain too
68+ *
69+ * module_name: Name of the target module. e.g. name "MyModule" is for
70+ * module file MyModule.ko.
71+ *
72+ * dep_name : Name of dependency file. If it is NULL, we will look
73+ * up /system/lib/modules/modules.dep by default.
74+ *
75+ * return : 0 for success; non-zero for any errors.
76+ */
77+extern int rmmod_by_dep(const char *module_name, const char *dep_name);
78+
79+#ifdef __cplusplus
80+}
81+#endif
82+
83+#endif /*_LIBS_CUTILS_PROBEMODULE_H*/
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -37,10 +37,13 @@
3737 #include <selinux/label.h>
3838
3939 #include <fs_mgr.h>
40+#include <dirent.h>
41+#include <fnmatch.h>
4042 #include <base/stringprintf.h>
4143 #include <cutils/partition_utils.h>
4244 #include <cutils/android_reboot.h>
4345 #include <logwrap/logwrap.h>
46+#include <cutils/probe_module.h>
4447 #include <private/android_filesystem_config.h>
4548
4649 #include "init.h"
@@ -286,6 +289,40 @@ int do_insmod(int nargs, char **args)
286289 return do_insmod_inner(nargs, args, size);
287290 }
288291
292+static int do_probemod_inner(int nargs, char **args, int opt_len)
293+{
294+ char options[opt_len + 1];
295+ int i;
296+ int ret;
297+
298+ options[0] = '\0';
299+ if (nargs > 2) {
300+ strcpy(options, args[2]);
301+ for (i = 3; i < nargs; ++i) {
302+ strcat(options, " ");
303+ strcat(options, args[i]);
304+ }
305+ }
306+
307+ ret = insmod_by_dep(args[1], options, NULL, 1, NULL);
308+ if (ret)
309+ ERROR("Couldn't probe module '%s'\n", args[1]);
310+ return ret;
311+}
312+
313+int do_probemod(int nargs, char **args)
314+{
315+ int i;
316+ int size = 0;
317+
318+ if (nargs > 2) {
319+ for (i = 2; i < nargs; ++i)
320+ size += strlen(args[i]) + 1;
321+ }
322+
323+ return do_probemod_inner(nargs, args, size);
324+}
325+
289326 int do_mkdir(int nargs, char **args)
290327 {
291328 mode_t mode = 0755;
@@ -582,6 +619,16 @@ int do_swapon_all(int nargs, char **args)
582619 return ret;
583620 }
584621
622+int do_builtin_coldboot(int nargs, char **args)
623+{
624+ if (nargs != 2 || !args[1] || *args[1] == '\0')
625+ return -1;
626+
627+ coldboot(args[1]);
628+
629+ return 0;
630+}
631+
585632 int do_setprop(int nargs, char **args)
586633 {
587634 const char *name = args[1];
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -41,6 +41,7 @@
4141 #include <sys/wait.h>
4242
4343 #include <cutils/list.h>
44+#include <cutils/probe_module.h>
4445 #include <cutils/uevent.h>
4546
4647 #include "devices.h"
@@ -49,12 +50,18 @@
4950 #include "log.h"
5051 #include "property_service.h"
5152 #include <zlib.h>
53+#include "parser.h"
5254
5355 #define SYSFS_PREFIX "/sys"
5456 static const char *firmware_dirs[] = { "/etc/firmware",
5557 "/vendor/firmware",
5658 "/firmware/image" };
5759
60+#define MODULES_ALIAS "/system/lib/modules/modules.alias"
61+#define MODULES_BLKLST "/system/etc/modules.blacklist"
62+#define READ_MODULES_ALIAS 1
63+#define READ_MODULES_BLKLST 2
64+
5865 extern struct selabel_handle *sehandle;
5966
6067 extern char boot_device[PROP_VALUE_MAX];
@@ -68,6 +75,7 @@ struct uevent {
6875 const char *firmware;
6976 const char *partition_name;
7077 const char *device_name;
78+ const char *modalias;
7179 int partition_num;
7280 int major;
7381 int minor;
@@ -95,9 +103,26 @@ struct platform_node {
95103 struct listnode list;
96104 };
97105
106+struct module_alias_node {
107+ char *name;
108+ char *pattern;
109+ struct listnode list;
110+};
111+
112+struct module_blacklist_node {
113+ char *name;
114+ struct listnode list;
115+};
116+
98117 static list_declare(sys_perms);
99118 static list_declare(dev_perms);
100119 static list_declare(platform_names);
120+static list_declare(modules_aliases_map);
121+static list_declare(modules_blacklist);
122+static list_declare(deferred_module_loading_list);
123+
124+static int read_modules_aliases();
125+static int read_modules_blacklist();
101126
102127 int add_dev_perms(const char *name, const char *attr,
103128 mode_t perm, unsigned int uid, unsigned int gid,
@@ -398,6 +423,7 @@ static void parse_event(const char *msg, struct uevent *uevent)
398423 uevent->partition_name = NULL;
399424 uevent->partition_num = -1;
400425 uevent->device_name = NULL;
426+ uevent->modalias = NULL;
401427
402428 /* currently ignoring SEQNUM */
403429 while(*msg) {
@@ -428,6 +454,9 @@ static void parse_event(const char *msg, struct uevent *uevent)
428454 } else if(!strncmp(msg, "DEVNAME=", 8)) {
429455 msg += 8;
430456 uevent->device_name = msg;
457+ } else if(!strncmp(msg, "MODALIAS=", 9)) {
458+ msg += 9;
459+ uevent->modalias = msg;
431460 }
432461
433462 /* advance to after the next \0 */
@@ -819,8 +848,148 @@ static void handle_generic_device_event(struct uevent *uevent)
819848 uevent->major, uevent->minor, links);
820849 }
821850
851+static int is_module_blacklisted(const char *name)
852+{
853+ struct listnode *blklst_node;
854+ struct module_blacklist_node *blacklist;
855+ int ret = 0;
856+
857+ if (!name) goto out;
858+
859+ /* See if module is blacklisted, skip if it is */
860+ list_for_each(blklst_node, &modules_blacklist) {
861+ blacklist = node_to_item(blklst_node,
862+ struct module_blacklist_node,
863+ list);
864+ if (!strcmp(name, blacklist->name)) {
865+ INFO("modules %s is blacklisted\n", name);
866+ ret = 1;
867+ goto out;
868+ }
869+ }
870+
871+out:
872+ return ret;
873+}
874+
875+static int load_module_by_device_modalias(const char *id)
876+{
877+ struct listnode *alias_node;
878+ struct module_alias_node *alias;
879+ int ret = -1;
880+
881+ if (!id) goto out;
882+
883+ list_for_each(alias_node, &modules_aliases_map) {
884+ alias = node_to_item(alias_node, struct module_alias_node, list);
885+
886+ if (alias && alias->name && alias->pattern) {
887+ if (fnmatch(alias->pattern, id, 0) == 0) {
888+ INFO("trying to load module %s due to uevents\n", alias->name);
889+
890+ if (!is_module_blacklisted(alias->name)) {
891+ if (insmod_by_dep(alias->name, "", NULL, 1, NULL)) {
892+ /* cannot load module. try another one since
893+ * there may be another match.
894+ */
895+ INFO("cannot load module %s due to uevents\n",
896+ alias->name);
897+ } else {
898+ /* loading was successful */
899+ INFO("loaded module %s due to uevents\n", alias->name);
900+ ret = 0;
901+ goto out;
902+ }
903+ }
904+ }
905+ }
906+ }
907+
908+out:
909+ return ret;
910+}
911+
912+static void handle_deferred_module_loading()
913+{
914+ struct listnode *node = NULL;
915+ struct listnode *next = NULL;
916+ struct module_alias_node *alias = NULL;
917+
918+ /* try to read the module alias mapping if map is empty
919+ * if succeed, loading all the modules in the queue
920+ */
921+ if (!list_empty(&modules_aliases_map)) {
922+ list_for_each_safe(node, next, &deferred_module_loading_list) {
923+ alias = node_to_item(node, struct module_alias_node, list);
924+
925+ if (alias && alias->pattern) {
926+ INFO("deferred loading of module for %s\n", alias->pattern);
927+ load_module_by_device_modalias(alias->pattern);
928+ free(alias->pattern);
929+ list_remove(node);
930+ free(alias);
931+ }
932+ }
933+ }
934+}
935+
936+int module_probe(const char *modalias)
937+{
938+ if (list_empty(&modules_aliases_map)) {
939+ if (read_modules_aliases() == 0)
940+ read_modules_blacklist();
941+ else
942+ return -1;
943+ }
944+
945+ return load_module_by_device_modalias(modalias);
946+}
947+
948+static void handle_module_loading(const char *modalias)
949+{
950+ struct module_alias_node *node;
951+
952+ /* once modules.alias can be read,
953+ * we load all the deferred ones
954+ */
955+ if (list_empty(&modules_aliases_map)) {
956+ if (read_modules_aliases() == 0) {
957+ read_modules_blacklist();
958+ handle_deferred_module_loading();
959+ }
960+ }
961+
962+ if (!modalias) return;
963+
964+ if (list_empty(&modules_aliases_map)) {
965+ /* if module alias mapping is empty,
966+ * queue it for loading later
967+ */
968+ node = (module_alias_node *) calloc(1, sizeof(*node));
969+ if (node) {
970+ node->pattern = strdup(modalias);
971+ if (!node->pattern) {
972+ free(node);
973+ } else {
974+ list_add_tail(&deferred_module_loading_list, &node->list);
975+ INFO("add to queue for deferred module loading: %s",
976+ node->pattern);
977+ }
978+ } else {
979+ ERROR("failed to allocate memory to store device id for deferred module loading.\n");
980+ }
981+ } else {
982+ load_module_by_device_modalias(modalias);
983+ }
984+
985+}
986+
822987 static void handle_device_event(struct uevent *uevent)
823988 {
989+ if (!strcmp(uevent->action,"add")) {
990+ handle_module_loading(uevent->modalias);
991+ }
992+
824993 if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change") || !strcmp(uevent->action, "online"))
825994 fixup_sys_perms(uevent->path);
826995
@@ -998,6 +1167,148 @@ static void handle_firmware_event(struct uevent *uevent)
9981167 }
9991168 }
10001169
1170+static void parse_line_module_alias(struct parse_state *state, int nargs, char **args)
1171+{
1172+ struct module_alias_node *node;
1173+
1174+ if (!args ||
1175+ (nargs != 3) ||
1176+ !args[0] || !args[1] || !args[2]) {
1177+ /* empty line or not enough arguments */
1178+ return;
1179+ }
1180+
1181+ node = (module_alias_node *) calloc(1, sizeof(*node));
1182+ if (!node) return;
1183+
1184+ node->name = strdup(args[2]);
1185+ if (!node->name) {
1186+ free(node);
1187+ return;
1188+ }
1189+
1190+ node->pattern = strdup(args[1]);
1191+ if (!node->pattern) {
1192+ free(node->name);
1193+ free(node);
1194+ return;
1195+ }
1196+
1197+ list_add_tail(&modules_aliases_map, &node->list);
1198+}
1199+
1200+static void parse_line_module_blacklist(struct parse_state *state, int nargs, char **args)
1201+{
1202+ struct module_blacklist_node *node;
1203+
1204+ if (!args ||
1205+ (nargs != 2) ||
1206+ !args[0] || !args[1]) {
1207+ /* empty line or not enough arguments */
1208+ return;
1209+ }
1210+
1211+ /* this line does not being with "blacklist" */
1212+ if (strncmp(args[0], "blacklist", 9)) return;
1213+
1214+ node = (module_blacklist_node *) calloc(1, sizeof(*node));
1215+ if (!node) return;
1216+
1217+ node->name = strdup(args[1]);
1218+ if (!node->name) {
1219+ free(node);
1220+ return;
1221+ }
1222+
1223+ list_add_tail(&modules_blacklist, &node->list);
1224+}
1225+
1226+static int __read_modules_desc_file(int mode)
1227+{
1228+ struct parse_state state;
1229+ char *args[3];
1230+ int nargs;
1231+ char *fn;
1232+ int fd = -1;
1233+ int ret = -1;
1234+ int args_to_read = 0;
1235+ std::string data;
1236+
1237+ if (mode == READ_MODULES_ALIAS) {
1238+ /* read modules.alias */
1239+ if (asprintf(&fn, "%s", MODULES_ALIAS) <= 0) {
1240+ goto out;
1241+ }
1242+ } else if (mode == READ_MODULES_BLKLST) {
1243+ /* read modules.blacklist */
1244+ if (asprintf(&fn, "%s", MODULES_BLKLST) <= 0) {
1245+ goto out;
1246+ }
1247+ } else {
1248+ /* unknown mode */
1249+ goto out;
1250+ }
1251+
1252+ fd = open(fn, O_RDONLY);
1253+ if (fd == -1) {
1254+ goto out;
1255+ }
1256+
1257+ /* read the whole file */
1258+ if (!read_file(fn, &data)) {
1259+ goto out;
1260+ }
1261+
1262+ /* invoke tokenizer */
1263+ nargs = 0;
1264+ state.filename = fn;
1265+ state.line = 1;
1266+ state.ptr = const_cast<char *>(data.c_str());
1267+ state.nexttoken = 0;
1268+ if (mode == READ_MODULES_ALIAS) {
1269+ state.parse_line = parse_line_module_alias;
1270+ args_to_read = 3;
1271+ } else if (mode == READ_MODULES_BLKLST) {
1272+ state.parse_line = parse_line_module_blacklist;
1273+ args_to_read = 2;
1274+ }
1275+ for (;;) {
1276+ int token = next_token(&state);
1277+ switch (token) {
1278+ case T_EOF:
1279+ state.parse_line(&state, 0, 0);
1280+ ret = 0;
1281+ goto out;
1282+ case T_NEWLINE:
1283+ if (nargs) {
1284+ state.parse_line(&state, nargs, args);
1285+ nargs = 0;
1286+ }
1287+ break;
1288+ case T_TEXT:
1289+ if (nargs < args_to_read) {
1290+ args[nargs++] = state.text;
1291+ }
1292+ break;
1293+ }
1294+ }
1295+ ret = 0;
1296+
1297+out:
1298+ if (fd != -1) {
1299+ close(fd);
1300+ }
1301+ return ret;
1302+}
1303+
1304+static int read_modules_aliases() {
1305+ return __read_modules_desc_file(READ_MODULES_ALIAS);
1306+}
1307+
1308+static int read_modules_blacklist() {
1309+ return __read_modules_desc_file(READ_MODULES_BLKLST);
1310+}
1311+
10011312 #define UEVENT_MSG_LEN 2048
10021313 void handle_device_fd()
10031314 {
@@ -1070,7 +1381,7 @@ static void do_coldboot(DIR *d)
10701381 }
10711382 }
10721383
1073-static void coldboot(const char *path)
1384+void coldboot(const char *path)
10741385 {
10751386 DIR *d = opendir(path);
10761387 if(d) {
--- a/init/devices.h
+++ b/init/devices.h
@@ -21,10 +21,12 @@
2121
2222 extern void handle_device_fd();
2323 extern void device_init(void);
24+extern int module_probe(const char *alias);
2425 extern int add_dev_perms(const char *name, const char *attr,
2526 mode_t perm, unsigned int uid,
2627 unsigned int gid, unsigned short prefix,
2728 unsigned short wildcard);
2829 int get_device_fd();
2930
31+void coldboot(const char *path);
3032 #endif /* _INIT_DEVICES_H */
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -129,6 +129,7 @@ static int lookup_keyword(const char *s)
129129 if (!strcmp(s, "onsole")) return K_console;
130130 if (!strcmp(s, "hown")) return K_chown;
131131 if (!strcmp(s, "hmod")) return K_chmod;
132+ if (!strcmp(s, "oldboot")) return K_coldboot;
132133 if (!strcmp(s, "ritical")) return K_critical;
133134 break;
134135 case 'd':
@@ -173,6 +174,7 @@ static int lookup_keyword(const char *s)
173174 break;
174175 case 'p':
175176 if (!strcmp(s, "owerctl")) return K_powerctl;
177+ if (!strcmp(s, "robemod")) return K_probemod;
176178 break;
177179 case 'r':
178180 if (!strcmp(s, "estart")) return K_restart;
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -1,5 +1,6 @@
11 #ifndef KEYWORD
22 int do_bootchart_init(int nargs, char **args);
3+int do_builtin_coldboot(int nargs, char **args);
34 int do_class_start(int nargs, char **args);
45 int do_class_stop(int nargs, char **args);
56 int do_class_reset(int nargs, char **args);
@@ -15,6 +16,7 @@ int do_mkdir(int nargs, char **args);
1516 int do_mount_all(int nargs, char **args);
1617 int do_mount(int nargs, char **args);
1718 int do_powerctl(int nargs, char **args);
19+int do_probemod(int nargs, char **args);
1820 int do_restart(int nargs, char **args);
1921 int do_restorecon(int nargs, char **args);
2022 int do_restorecon_recursive(int nargs, char **args);
@@ -51,6 +53,7 @@ enum {
5153 KEYWORD(class_reset, COMMAND, 1, do_class_reset)
5254 KEYWORD(class_start, COMMAND, 1, do_class_start)
5355 KEYWORD(class_stop, COMMAND, 1, do_class_stop)
56+ KEYWORD(coldboot, COMMAND, 1, do_builtin_coldboot)
5457 KEYWORD(console, OPTION, 0, 0)
5558 KEYWORD(copy, COMMAND, 2, do_copy)
5659 KEYWORD(critical, OPTION, 0, 0)
@@ -77,6 +80,7 @@ enum {
7780 KEYWORD(onrestart, OPTION, 0, 0)
7881 KEYWORD(on, SECTION, 0, 0)
7982 KEYWORD(powerctl, COMMAND, 1, do_powerctl)
83+ KEYWORD(probemod, COMMAND, 1, do_probemod)
8084 KEYWORD(restart, COMMAND, 1, do_restart)
8185 KEYWORD(restorecon, COMMAND, 1, do_restorecon)
8286 KEYWORD(restorecon_recursive, COMMAND, 1, do_restorecon_recursive)
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -31,6 +31,7 @@ commonSources := \
3131 threads.c \
3232 sched_policy.c \
3333 iosched_policy.c \
34+ probe_module.c \
3435 str_parms.c \
3536 fs_config.c
3637
--- /dev/null
+++ b/libcutils/probe_module.c
@@ -0,0 +1,456 @@
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 <errno.h>
21+#include <fcntl.h>
22+#include <cutils/misc.h>
23+
24+#define LOG_TAG "ProbeModule"
25+#include <cutils/log.h>
26+
27+
28+#define LDM_DEFAULT_DEP_FILE "/system/lib/modules/modules.dep"
29+#define LDM_DEFAULT_MOD_PATH "/system/lib/modules/"
30+#define LDM_INIT_DEP_NUM 10
31+
32+extern int init_module(void *, unsigned long, const char *);
33+extern int delete_module(const char *, unsigned int);
34+
35+static void dump_dep(char **dep)
36+{
37+ int d;
38+
39+ for (d = 0; dep[d]; d++)
40+ ALOGD("DUMP DEP: %s\n", dep[d]);
41+}
42+
43+static char * strip_path(const char * const str)
44+{
45+ char *ptr;
46+ int i;
47+
48+ /* initialize pos to terminator */
49+ for (i = strlen(str); i > 0; i--)
50+ if (str[i - 1] == '/')
51+ break;
52+
53+ return (char *)&str[i];
54+}
55+
56+static void hyphen_to_underscore(char *str)
57+{
58+ while (str && *str != '\0') {
59+ if (*str == '-')
60+ *str = '_';
61+ str++;
62+ }
63+}
64+
65+/* Compare module names, but don't differentiate '_' and '-'.
66+ * return: 0 when s1 is matched to s2 or size is zero.
67+ * non-zero in any other cases.
68+ */
69+static int match_name(const char *s1, const char *s2, const size_t size)
70+{
71+ size_t i;
72+
73+ if (!size)
74+ return 0;
75+
76+ for (i = 0; i < size; i++, s1++, s2++) {
77+
78+ if ((*s1 == '_' || *s1 == '-') && (*s2 == '_' || *s2 == '-'))
79+ continue;
80+
81+ if (*s1 != *s2)
82+ return -1;
83+
84+ if (*s1 == '\0')
85+ return 0;
86+ }
87+
88+ return 0;
89+}
90+
91+/* check if a line in dep file is target module's dependency.
92+ * return 1 when it is, otherwise 0 in any other cases.
93+ */
94+static int is_target_module(char *line, const char *target)
95+{
96+ char *token;
97+ char *name;
98+ size_t name_len;
99+ const char *suffix = ".ko";
100+ const char *delimiter = ":";
101+ int ret = 0;
102+
103+ /* search token */
104+ token = strstr(line, delimiter);
105+
106+ if (!token) {
107+ ALOGE("invalid line: no token\n");
108+ return 0;
109+ }
110+
111+ /* only take stuff before the token */
112+ *token = '\0';
113+
114+ /* use "module.ko" in comparision */
115+ name_len = strlen(suffix) + strlen(target) + 1;
116+
117+ name = malloc(sizeof(char) * name_len);
118+
119+ if (!name) {
120+ ALOGE("cannot alloc ram for comparision\n");
121+ return 0;
122+ }
123+
124+ snprintf(name, name_len, "%s%s", target, suffix);
125+
126+ ret = !match_name(strip_path(line), name, name_len);
127+
128+ /* restore [single] token, keep line unchanged until we parse it later */
129+ *token = *delimiter;
130+
131+ free(name);
132+
133+ return ret;
134+
135+}
136+
137+/* turn a single string into an array of dependency.
138+ *
139+ * return: dependency array's address if it succeeded. Caller
140+ * is responsible to free the array's memory.
141+ * NULL when any error happens.
142+ */
143+static char** setup_dep(char *line)
144+{
145+ char *tmp;
146+ char *brk;
147+ int dep_num = LDM_INIT_DEP_NUM;
148+ char **new;
149+ int i;
150+ char **dep = NULL;
151+
152+ dep = malloc(sizeof(char *) * dep_num);
153+
154+ if (!dep) {
155+ ALOGE("cannot alloc dep array\n");
156+ return dep;
157+ }
158+
159+ for (i = 0, tmp = strtok_r(line, ": ", &brk);
160+ tmp;
161+ tmp = strtok_r(NULL, ": ", &brk), i++) {
162+
163+ /* check if we need enlarge dep array */
164+ if (!(i < dep_num - 1)) {
165+
166+ dep_num += LDM_INIT_DEP_NUM;
167+
168+ new = realloc(dep, dep_num);
169+
170+ if (!new) {
171+ ALOGE("failed to enlarge dep buffer\n");
172+ free(dep);
173+ return NULL;
174+ }
175+ else
176+ dep = new;
177+ }
178+
179+ dep[i] = tmp;
180+
181+ }
182+ /* terminate array with a null pointer */
183+ dep[i] = NULL;
184+
185+ return dep;
186+}
187+
188+static int insmod(const char *path_name, const char *args)
189+{
190+ void *data;
191+ unsigned int len;
192+ int ret;
193+
194+ data = load_file(path_name, &len);
195+
196+ if (!data) {
197+ ALOGE("%s: Failed to load module file [%s]\n", __FUNCTION__, path_name);
198+ return -1;
199+ }
200+
201+ ret = init_module(data, len, args);
202+
203+ if (ret != 0 && errno != EEXIST) {
204+ ALOGE("%s: Failed to insmod [%s] with args [%s] error: %s ret: %d\n",
205+ __FUNCTION__, path_name, args, strerror(errno), ret);
206+ ret = -1;
207+ }
208+ else
209+ ret = 0; /* if module is already in kernel, return success. */
210+
211+ free(data);
212+
213+ return ret;
214+}
215+
216+/* install all modules in the dependency chain
217+ * deps : A array of module file names, must be terminated by a NULL pointer
218+ * args : The module parameters for target module.
219+ * strip : Non-zero to strip out path info in the file name;
220+ * 0 to keep path info when loading modules.
221+ * base : a prefix to module path, it will NOT be affected by strip flag.
222+ * return : 0 for success or nothing to do; non-zero when any error occurs.
223+ */
224+static int insmod_s(char *dep[], const char *args, int strip, const char *base)
225+{
226+ char *name;
227+ char *path_name;
228+ int cnt;
229+ size_t len;
230+ int ret = 0;
231+ const char * base_dir = LDM_DEFAULT_MOD_PATH;
232+
233+ if (base && strlen(base))
234+ base_dir = base;
235+
236+ /* load modules in reversed order */
237+ for (cnt = 0; dep[cnt]; cnt++)
238+ ;
239+
240+ while (cnt--) {
241+
242+ name = strip ? strip_path(dep[cnt]) : dep[cnt];
243+
244+ len = strlen(base_dir) + strlen(name) + 1;
245+
246+ path_name = malloc(sizeof(char) * len);
247+
248+ if (!path_name) {
249+ ALOGE("alloc module [%s] path failed\n", path_name);
250+ return -1;
251+ }
252+
253+ snprintf(path_name, len, "%s%s", base_dir, name);
254+
255+ if (cnt)
256+ ret = insmod(path_name, "");
257+ else
258+ ret = insmod(path_name, args);
259+
260+ free(path_name);
261+
262+ if (ret)
263+ break;
264+ }
265+
266+ return ret;
267+}
268+
269+static int rmmod(const char *mod_name, unsigned int flags)
270+{
271+ return delete_module(mod_name, flags);
272+}
273+
274+/* remove all modules in a dependency chain
275+ * NOTE: We assume module name in kernel is same as the file name without .ko
276+ */
277+static int rmmod_s(char *dep[], unsigned int flags)
278+{
279+ int i;
280+ int ret = 0;
281+ char * mod_name;
282+
283+ for (i = 0; dep[i]; i++) {
284+ size_t len;
285+ mod_name = strip_path(dep[i]);
286+ len = strlen(mod_name);
287+
288+ if (len > strlen(".ko")
289+ && mod_name[len - 1] == 'o'
290+ && mod_name[len - 2] == 'k'
291+ && mod_name[len - 3] == '.') {
292+
293+ mod_name[len - 3] = '\0';
294+
295+ hyphen_to_underscore(mod_name);
296+
297+ ret = rmmod(mod_name, flags);
298+
299+ if (ret) {
300+ ALOGE("%s: Failed to remove module [%s] error (%s)\n",
301+ __FUNCTION__, mod_name, strerror(errno));
302+ break;
303+
304+ }
305+ }
306+ }
307+
308+ return ret;
309+}
310+
311+/* look_up_dep() find and setup target module's dependency in modules.dep
312+ *
313+ * dep_file: a pointer to module's dep file loaded in memory, its content
314+ * will be CHANGED during parsing.
315+ *
316+ * return: a pointer to an array which holds the dependency strings and
317+ * terminated by a NULL pointer. Caller is responsible to free the
318+ * array's memory.
319+ *
320+ * non-zero in any other cases. Content of dep array is invalid.
321+ */
322+static char ** look_up_dep(const char *module_name, void *dep_file)
323+{
324+
325+ char *line;
326+ char *saved_pos;
327+ char *start;
328+ int ret = -1;
329+ char **dep = NULL;
330+
331+ if (!dep_file || !module_name || *module_name == '\0')
332+ return NULL;
333+
334+ start = (char *)dep_file;
335+
336+ /* We expect modules.dep file has a new line char before EOF. */
337+ while ((line = strtok_r(start, "\n", &saved_pos)) != NULL) {
338+
339+ start = NULL;
340+
341+ if (is_target_module(line, module_name)) {
342+
343+ dep = setup_dep(line);
344+ /* job done */
345+ break;
346+ }
347+ }
348+
349+ return dep;
350+}
351+
352+/* load_dep_file() load a dep file (usually it is modules.dep)
353+ * into memory. Caller is responsible to free the memory.
354+ *
355+ * file_name: dep file's name, if it is NULL or an empty string,
356+ * This function will try to load a dep file in the
357+ * default path defined in LDM_DEFAULT_DEP_FILE
358+ *
359+ * return: a pointer to the allocated mem which holds all
360+ * content of the depfile. a zero pointer will be
361+ * returned for any errors.
362+ * */
363+static void *load_dep_file(const char *file_name)
364+{
365+ const char *dep_file_name = LDM_DEFAULT_DEP_FILE;
366+ unsigned int len;
367+
368+ if (file_name && *file_name != '\0')
369+ dep_file_name = file_name;
370+
371+ return load_file(dep_file_name, &len);
372+}
373+
374+/* insmod_by_dep() interface to outside,
375+ * refer to its description in probe_module.h
376+ */
377+int insmod_by_dep(const char *module_name,
378+ const char *args,
379+ const char *dep_name,
380+ int strip,
381+ const char *base)
382+{
383+ void *dep_file;
384+ char **dep = NULL;
385+ int ret = -1;
386+
387+ if (!module_name || *module_name == '\0') {
388+ ALOGE("need valid module name\n");
389+ return ret;
390+ }
391+
392+ dep_file = load_dep_file(dep_name);
393+
394+ if (!dep_file) {
395+ ALOGE("cannot load dep file : %s\n", dep_name);
396+ return ret;
397+ }
398+
399+ dep = look_up_dep(module_name, dep_file);
400+
401+ if (!dep) {
402+ ALOGE("%s: cannot load module: [%s]\n", __FUNCTION__, module_name);
403+ goto free_file;
404+ }
405+
406+ ret = insmod_s(dep, args, strip, base);
407+
408+ free(dep);
409+
410+free_file:
411+ free(dep_file);
412+
413+ return ret;
414+
415+}
416+
417+/* rmmod_by_dep() interface to outside,
418+ * refer to its description in probe_module.h
419+ */
420+int rmmod_by_dep(const char *module_name,
421+ const char *dep_name)
422+{
423+ void *dep_file;
424+ char **dep = NULL;
425+ int ret = -1;
426+
427+ if (!module_name || *module_name == '\0') {
428+ ALOGE("need valid module name\n");
429+ return ret;
430+ }
431+
432+ dep_file = load_dep_file(dep_name);
433+
434+ if (!dep_file) {
435+ ALOGE("cannot load dep file : %s\n", dep_name);
436+ return ret;
437+ }
438+
439+ dep = look_up_dep(module_name, dep_file);
440+
441+ if (!dep) {
442+ ALOGE("%s: cannot remove module: [%s]\n", __FUNCTION__, module_name);
443+ goto free_file;
444+ }
445+
446+ ret = rmmod_s(dep, O_NONBLOCK);
447+
448+ free(dep);
449+
450+free_file:
451+ free(dep_file);
452+
453+ return ret;
454+}
455+
456+/* end of file */