system/corennnnn
Revisão | 6806855b011933ae7d8e1007eabda00e4d774e1b (tree) |
---|---|
Hora | 2016-12-09 16:22:10 |
Autor | Chih-Wei Huang <cwhuang@linu...> |
Commiter | Chih-Wei Huang |
ueventd: auto load modules on uevents
This is a squashed and refactory patch of the following commits
from marshmallow-x86:
@@ -0,0 +1,103 @@ | ||
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 | + */ | |
42 | +extern int insmod(const char *filename, const char *args); | |
43 | + | |
44 | +/* insmod_by_dep() - load a kernel module (target) with its dependency | |
45 | + * The module's dependency must be described in the provided dependency file. | |
46 | + * other modules in the dependency chain will be loaded prior to the target. | |
47 | + * | |
48 | + * module_name: Name of the target module. e.g. name "MyModule" is for | |
49 | + * module file MyModule.ko. | |
50 | + * | |
51 | + * args : A string of target module's parameters. NOTE: we only | |
52 | + * support parameters of the target module. | |
53 | + * | |
54 | + * dep_name : Name of dependency file. If it is NULL, we will look | |
55 | + * up /system/lib/modules/modules.dep by default. | |
56 | + * | |
57 | + * strip : Non-zero values remove paths of modules in dependency. | |
58 | + * before loading them. The final path of a module will be | |
59 | + * base/MyModule.ko. This is for devices which put every | |
60 | + * modules into a single directory. | |
61 | + * | |
62 | + * Passing 0 to strip keeps module paths in dependency file. | |
63 | + * e.g. "kernel/drivers/.../MyModule.ko" in dep file will | |
64 | + * be loaded as base/kernel/drivers/.../MyModule.ko . | |
65 | + * | |
66 | + * base : Base dir, a prefix to be added to module's path prior to | |
67 | + * loading. The last character prior to base string's terminator | |
68 | + * must be a '/'. If it is NULL, we will take | |
69 | + * /system/lib/modules/modules.dep by default. | |
70 | + * | |
71 | + * return : 0 for success; non-zero for any errors. | |
72 | + * | |
73 | + * Note: | |
74 | + * When loading modules, function will not fail for any modules which are | |
75 | + * already in kernel. The module parameters passed to function will not be | |
76 | + * effective in this case if target module is already loaded into kernel. | |
77 | + */ | |
78 | +extern int insmod_by_dep( | |
79 | + const char *module_name, | |
80 | + const char *args, | |
81 | + const char *dep_name, | |
82 | + int strip, | |
83 | + const char * base); | |
84 | + | |
85 | +/* rmmod_by_dep() - remove a module (target) from kernel with its dependency | |
86 | + * The module's dependency must be described in the provided dependency file. | |
87 | + * This function will try to remove other modules in the dependency chain too | |
88 | + * | |
89 | + * module_name: Name of the target module. e.g. name "MyModule" is for | |
90 | + * module file MyModule.ko. | |
91 | + * | |
92 | + * dep_name : Name of dependency file. If it is NULL, we will look | |
93 | + * up /system/lib/modules/modules.dep by default. | |
94 | + * | |
95 | + * return : 0 for success; non-zero for any errors. | |
96 | + */ | |
97 | +extern int rmmod_by_dep(const char *module_name, const char *dep_name); | |
98 | + | |
99 | +#ifdef __cplusplus | |
100 | +} | |
101 | +#endif | |
102 | + | |
103 | +#endif /*_LIBS_CUTILS_PROBEMODULE_H*/ |
@@ -105,6 +105,7 @@ LOCAL_STATIC_LIBRARIES := \ | ||
105 | 105 | |
106 | 106 | # Create symlinks |
107 | 107 | LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \ |
108 | + ln -sf ../init $(TARGET_ROOT_OUT)/sbin/modprobe; \ | |
108 | 109 | ln -sf ../init $(TARGET_ROOT_OUT)/sbin/ueventd; \ |
109 | 110 | ln -sf ../init $(TARGET_ROOT_OUT)/sbin/watchdogd |
110 | 111 |
@@ -29,7 +29,6 @@ | ||
29 | 29 | #include <sys/socket.h> |
30 | 30 | #include <sys/mount.h> |
31 | 31 | #include <sys/resource.h> |
32 | -#include <sys/syscall.h> | |
33 | 32 | #include <sys/time.h> |
34 | 33 | #include <sys/types.h> |
35 | 34 | #include <sys/stat.h> |
@@ -49,6 +48,7 @@ | ||
49 | 48 | #include <bootloader_message/bootloader_message.h> |
50 | 49 | #include <cutils/partition_utils.h> |
51 | 50 | #include <cutils/android_reboot.h> |
51 | +#include <cutils/probe_module.h> | |
52 | 52 | #include <logwrap/logwrap.h> |
53 | 53 | #include <private/android_filesystem_config.h> |
54 | 54 |
@@ -69,20 +69,6 @@ | ||
69 | 69 | |
70 | 70 | static const int kTerminateServiceDelayMicroSeconds = 50000; |
71 | 71 | |
72 | -static int insmod(const char *filename, const char *options) { | |
73 | - int fd = open(filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC); | |
74 | - if (fd == -1) { | |
75 | - ERROR("insmod: open(\"%s\") failed: %s", filename, strerror(errno)); | |
76 | - return -1; | |
77 | - } | |
78 | - int rc = syscall(__NR_finit_module, fd, options, 0); | |
79 | - if (rc == -1) { | |
80 | - ERROR("finit_module for \"%s\" failed: %s", filename, strerror(errno)); | |
81 | - } | |
82 | - close(fd); | |
83 | - return rc; | |
84 | -} | |
85 | - | |
86 | 72 | static int __ifupdown(const char *interface, int up) { |
87 | 73 | struct ifreq ifr; |
88 | 74 | int s, ret; |
@@ -42,12 +42,14 @@ | ||
42 | 42 | |
43 | 43 | #include <android-base/file.h> |
44 | 44 | #include <cutils/list.h> |
45 | +#include <cutils/probe_module.h> | |
45 | 46 | #include <cutils/uevent.h> |
46 | 47 | |
47 | 48 | #include "devices.h" |
48 | 49 | #include "ueventd_parser.h" |
49 | 50 | #include "util.h" |
50 | 51 | #include "log.h" |
52 | +#include "parser.h" | |
51 | 53 | |
52 | 54 | #define SYSFS_PREFIX "/sys" |
53 | 55 | #if defined(__i386__) || defined(__x86_64__) |
@@ -58,6 +60,10 @@ static const char *firmware_dirs[] = { "/etc/firmware", | ||
58 | 60 | "/firmware/image" }; |
59 | 61 | #endif |
60 | 62 | |
63 | +#define MODULES_BLKLST "/system/etc/modules.blacklist" | |
64 | +#define READ_MODULES_ALIAS 1 | |
65 | +#define READ_MODULES_BLKLST 2 | |
66 | + | |
61 | 67 | extern struct selabel_handle *sehandle; |
62 | 68 | |
63 | 69 | static int device_fd = -1; |
@@ -69,6 +75,7 @@ struct uevent { | ||
69 | 75 | const char *firmware; |
70 | 76 | const char *partition_name; |
71 | 77 | const char *device_name; |
78 | + const char *modalias; | |
72 | 79 | int partition_num; |
73 | 80 | int major; |
74 | 81 | int minor; |
@@ -96,9 +103,26 @@ struct platform_node { | ||
96 | 103 | struct listnode list; |
97 | 104 | }; |
98 | 105 | |
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 | + | |
99 | 117 | static list_declare(sys_perms); |
100 | 118 | static list_declare(dev_perms); |
101 | 119 | 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(); | |
102 | 126 | |
103 | 127 | int add_dev_perms(const char *name, const char *attr, |
104 | 128 | mode_t perm, unsigned int uid, unsigned int gid, |
@@ -377,6 +401,7 @@ static void parse_event(const char *msg, struct uevent *uevent) | ||
377 | 401 | uevent->partition_name = NULL; |
378 | 402 | uevent->partition_num = -1; |
379 | 403 | uevent->device_name = NULL; |
404 | + uevent->modalias = NULL; | |
380 | 405 | |
381 | 406 | /* currently ignoring SEQNUM */ |
382 | 407 | while(*msg) { |
@@ -407,6 +432,9 @@ static void parse_event(const char *msg, struct uevent *uevent) | ||
407 | 432 | } else if(!strncmp(msg, "DEVNAME=", 8)) { |
408 | 433 | msg += 8; |
409 | 434 | uevent->device_name = msg; |
435 | + } else if(!strncmp(msg, "MODALIAS=", 9)) { | |
436 | + msg += 9; | |
437 | + uevent->modalias = msg; | |
410 | 438 | } |
411 | 439 | |
412 | 440 | /* advance to after the next \0 */ |
@@ -746,8 +774,182 @@ static void handle_generic_device_event(struct uevent *uevent) | ||
746 | 774 | uevent->major, uevent->minor, links); |
747 | 775 | } |
748 | 776 | |
777 | +static int is_module_blacklisted(const char *name) | |
778 | +{ | |
779 | + struct listnode *blklst_node; | |
780 | + struct module_blacklist_node *blacklist; | |
781 | + int ret = 0; | |
782 | + | |
783 | + if (!name) goto out; | |
784 | + | |
785 | + /* See if module is blacklisted, skip if it is */ | |
786 | + list_for_each(blklst_node, &modules_blacklist) { | |
787 | + blacklist = node_to_item(blklst_node, | |
788 | + struct module_blacklist_node, | |
789 | + list); | |
790 | + if (!strcmp(name, blacklist->name)) { | |
791 | + INFO("modules %s is blacklisted\n", name); | |
792 | + ret = 1; | |
793 | + goto out; | |
794 | + } | |
795 | + } | |
796 | + | |
797 | +out: | |
798 | + return ret; | |
799 | +} | |
800 | + | |
801 | +static int load_module_by_device_modalias(const char *id) | |
802 | +{ | |
803 | + struct listnode *alias_node; | |
804 | + struct module_alias_node *alias; | |
805 | + int ret = -1; | |
806 | + | |
807 | + list_for_each(alias_node, &modules_aliases_map) { | |
808 | + alias = node_to_item(alias_node, struct module_alias_node, list); | |
809 | + | |
810 | + if (alias && alias->name && alias->pattern) { | |
811 | + if (fnmatch(alias->pattern, id, 0) == 0) { | |
812 | + INFO("trying to load module %s due to uevents\n", alias->name); | |
813 | + | |
814 | + if (!is_module_blacklisted(alias->name)) { | |
815 | + if (insmod_by_dep(alias->name, "", NULL, 0, NULL)) { | |
816 | + /* cannot load module. try another one since | |
817 | + * there may be another match. | |
818 | + */ | |
819 | + NOTICE("failed to load %s for modalias %s\n", | |
820 | + alias->name, id); | |
821 | + } else { | |
822 | + /* loading was successful */ | |
823 | + INFO("loaded module %s due to uevents\n", alias->name); | |
824 | + ret = 0; | |
825 | + } | |
826 | + } | |
827 | + } | |
828 | + } | |
829 | + } | |
830 | + | |
831 | + return ret; | |
832 | +} | |
833 | + | |
834 | +static void handle_deferred_module_loading() | |
835 | +{ | |
836 | + /* try to read the module alias mapping if map is empty | |
837 | + * if succeed, loading all the modules in the queue | |
838 | + */ | |
839 | + if (!list_empty(&modules_aliases_map)) { | |
840 | + struct listnode *node = NULL; | |
841 | + struct listnode *next = NULL; | |
842 | + struct module_alias_node *alias = NULL; | |
843 | + | |
844 | + list_for_each_safe(node, next, &deferred_module_loading_list) { | |
845 | + alias = node_to_item(node, struct module_alias_node, list); | |
846 | + | |
847 | + if (alias && alias->pattern) { | |
848 | + INFO("deferred loading of module for %s\n", alias->pattern); | |
849 | + load_module_by_device_modalias(alias->pattern); | |
850 | + free(alias->pattern); | |
851 | + list_remove(node); | |
852 | + free(alias); | |
853 | + } | |
854 | + } | |
855 | + } | |
856 | +} | |
857 | + | |
858 | +static int module_probe(int argc, char **argv) | |
859 | +{ | |
860 | + if (list_empty(&modules_aliases_map)) { | |
861 | + read_modules_aliases(); | |
862 | + read_modules_blacklist(); | |
863 | + } | |
864 | + | |
865 | + // is it a modalias? | |
866 | + int ret = load_module_by_device_modalias(argv[1]); | |
867 | + if (ret) { | |
868 | + // treat it as a module name | |
869 | + std::string options; | |
870 | + if (argc > 2) { | |
871 | + options = argv[2]; | |
872 | + for (int i = 3; i < argc; ++i) { | |
873 | + options += ' '; | |
874 | + options += argv[i]; | |
875 | + } | |
876 | + } | |
877 | + ret = insmod_by_dep(argv[1], options.c_str(), NULL, 0, NULL); | |
878 | + } | |
879 | + return ret; | |
880 | +} | |
881 | + | |
882 | +int modprobe_main(int argc, char **argv) | |
883 | +{ | |
884 | + const char *prog = argv[0]; | |
885 | + | |
886 | + /* We only accept requests from root user (kernel) */ | |
887 | + if (getuid()) | |
888 | + return -EPERM; | |
889 | + | |
890 | + /* Kernel will launch a user space program specified by | |
891 | + * /proc/sys/kernel/modprobe to load modules. | |
892 | + * No deferred loading in this case. | |
893 | + */ | |
894 | + while (argc > 1 && (!strcmp(argv[1], "-q") || !strcmp(argv[1], "--"))) { | |
895 | + klog_set_level(KLOG_NOTICE_LEVEL); | |
896 | + argc--, argv++; | |
897 | + } | |
898 | + | |
899 | + if (argc < 2) { | |
900 | + /* it is called without enough arguments */ | |
901 | + return -EINVAL; | |
902 | + } | |
903 | + | |
904 | + NOTICE("%s %s\n", prog, argv[1]); | |
905 | + return module_probe(argc, argv); | |
906 | +} | |
907 | + | |
908 | +static void handle_module_loading(const char *modalias) | |
909 | +{ | |
910 | + struct module_alias_node *node; | |
911 | + | |
912 | + /* once modules.alias can be read, | |
913 | + * we load all the deferred ones | |
914 | + */ | |
915 | + if (list_empty(&modules_aliases_map)) { | |
916 | + if (read_modules_aliases() == 0) { | |
917 | + read_modules_blacklist(); | |
918 | + handle_deferred_module_loading(); | |
919 | + } | |
920 | + } | |
921 | + | |
922 | + if (!modalias) return; | |
923 | + | |
924 | + if (list_empty(&modules_aliases_map)) { | |
925 | + /* if module alias mapping is empty, | |
926 | + * queue it for loading later | |
927 | + */ | |
928 | + node = (module_alias_node *) calloc(1, sizeof(*node)); | |
929 | + if (node) { | |
930 | + node->pattern = strdup(modalias); | |
931 | + if (!node->pattern) { | |
932 | + free(node); | |
933 | + } else { | |
934 | + list_add_tail(&deferred_module_loading_list, &node->list); | |
935 | + INFO("add to queue for deferred module loading: %s", | |
936 | + node->pattern); | |
937 | + } | |
938 | + } else { | |
939 | + ERROR("failed to allocate memory to store device id for deferred module loading.\n"); | |
940 | + } | |
941 | + } else { | |
942 | + load_module_by_device_modalias(modalias); | |
943 | + } | |
944 | + | |
945 | +} | |
946 | + | |
749 | 947 | static void handle_device_event(struct uevent *uevent) |
750 | 948 | { |
949 | + if (!strcmp(uevent->action,"add")) { | |
950 | + handle_module_loading(uevent->modalias); | |
951 | + } | |
952 | + | |
751 | 953 | if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change") || !strcmp(uevent->action, "online")) |
752 | 954 | fixup_sys_perms(uevent->path); |
753 | 955 |
@@ -810,7 +1012,7 @@ static void process_firmware_event(struct uevent *uevent) | ||
810 | 1012 | size_t i; |
811 | 1013 | int booting = is_booting(); |
812 | 1014 | |
813 | - INFO("firmware: loading '%s' for '%s'\n", | |
1015 | + NOTICE("firmware: loading '%s' for '%s'\n", | |
814 | 1016 | uevent->firmware, uevent->path); |
815 | 1017 | |
816 | 1018 | l = asprintf(&root, SYSFS_PREFIX"%s/", uevent->path); |
@@ -878,26 +1080,155 @@ root_free_out: | ||
878 | 1080 | |
879 | 1081 | static void handle_firmware_event(struct uevent *uevent) |
880 | 1082 | { |
881 | - pid_t pid; | |
882 | - | |
883 | 1083 | if(strcmp(uevent->subsystem, "firmware")) |
884 | 1084 | return; |
885 | 1085 | |
886 | 1086 | if(strcmp(uevent->action, "add")) |
887 | 1087 | return; |
888 | 1088 | |
889 | - /* we fork, to avoid making large memory allocations in init proper */ | |
890 | - pid = fork(); | |
891 | - if (!pid) { | |
892 | - process_firmware_event(uevent); | |
893 | - _exit(EXIT_SUCCESS); | |
894 | - } else if (pid < 0) { | |
895 | - ERROR("could not fork to process firmware event: %s\n", strerror(errno)); | |
1089 | + process_firmware_event(uevent); | |
1090 | +} | |
1091 | + | |
1092 | +static void parse_line_module_alias(struct parse_state *state, int nargs, char **args) | |
1093 | +{ | |
1094 | + struct module_alias_node *node; | |
1095 | + | |
1096 | + if (!args || | |
1097 | + (nargs != 3) || | |
1098 | + !args[0] || !args[1] || !args[2]) { | |
1099 | + /* empty line or not enough arguments */ | |
1100 | + return; | |
1101 | + } | |
1102 | + | |
1103 | + node = (module_alias_node *) calloc(1, sizeof(*node)); | |
1104 | + if (!node) return; | |
1105 | + | |
1106 | + node->name = strdup(args[2]); | |
1107 | + if (!node->name) { | |
1108 | + free(node); | |
1109 | + return; | |
1110 | + } | |
1111 | + | |
1112 | + node->pattern = strdup(args[1]); | |
1113 | + if (!node->pattern) { | |
1114 | + free(node->name); | |
1115 | + free(node); | |
1116 | + return; | |
896 | 1117 | } |
1118 | + | |
1119 | + list_add_tail(&modules_aliases_map, &node->list); | |
1120 | +} | |
1121 | + | |
1122 | +static void parse_line_module_blacklist(struct parse_state *state, int nargs, char **args) | |
1123 | +{ | |
1124 | + struct module_blacklist_node *node; | |
1125 | + | |
1126 | + if (!args || | |
1127 | + (nargs != 2) || | |
1128 | + !args[0] || !args[1]) { | |
1129 | + /* empty line or not enough arguments */ | |
1130 | + return; | |
1131 | + } | |
1132 | + | |
1133 | + /* this line does not being with "blacklist" */ | |
1134 | + if (strncmp(args[0], "blacklist", 9)) return; | |
1135 | + | |
1136 | + node = (module_blacklist_node *) calloc(1, sizeof(*node)); | |
1137 | + if (!node) return; | |
1138 | + | |
1139 | + node->name = strdup(args[1]); | |
1140 | + if (!node->name) { | |
1141 | + free(node); | |
1142 | + return; | |
1143 | + } | |
1144 | + | |
1145 | + list_add_tail(&modules_blacklist, &node->list); | |
1146 | +} | |
1147 | + | |
1148 | +static int __read_modules_desc_file(int mode) | |
1149 | +{ | |
1150 | + struct parse_state state; | |
1151 | + char *args[3]; | |
1152 | + int nargs; | |
1153 | + char fn[PATH_MAX]; | |
1154 | + int fd = -1; | |
1155 | + int ret = -1; | |
1156 | + int args_to_read = 0; | |
1157 | + std::string data; | |
1158 | + | |
1159 | + if (mode == READ_MODULES_ALIAS) { | |
1160 | + /* read modules.alias */ | |
1161 | + strcat(get_default_mod_path(fn), "modules.alias"); | |
1162 | + } else if (mode == READ_MODULES_BLKLST) { | |
1163 | + /* read modules.blacklist */ | |
1164 | + strcpy(fn, MODULES_BLKLST); | |
1165 | + } else { | |
1166 | + /* unknown mode */ | |
1167 | + goto out; | |
1168 | + } | |
1169 | + | |
1170 | + fd = open(fn, O_RDONLY); | |
1171 | + if (fd == -1) { | |
1172 | + goto out; | |
1173 | + } | |
1174 | + | |
1175 | + /* read the whole file */ | |
1176 | + if (!read_file(fn, &data)) { | |
1177 | + goto out; | |
1178 | + } | |
1179 | + | |
1180 | + /* invoke tokenizer */ | |
1181 | + nargs = 0; | |
1182 | + state.filename = fn; | |
1183 | + state.line = 1; | |
1184 | + state.ptr = &data[0]; | |
1185 | + state.nexttoken = 0; | |
1186 | + if (mode == READ_MODULES_ALIAS) { | |
1187 | + state.parse_line = parse_line_module_alias; | |
1188 | + args_to_read = 3; | |
1189 | + } else if (mode == READ_MODULES_BLKLST) { | |
1190 | + state.parse_line = parse_line_module_blacklist; | |
1191 | + args_to_read = 2; | |
1192 | + } | |
1193 | + for (;;) { | |
1194 | + int token = next_token(&state); | |
1195 | + switch (token) { | |
1196 | + case T_EOF: | |
1197 | + state.parse_line(&state, 0, 0); | |
1198 | + ret = 0; | |
1199 | + goto out; | |
1200 | + case T_NEWLINE: | |
1201 | + if (nargs) { | |
1202 | + state.parse_line(&state, nargs, args); | |
1203 | + nargs = 0; | |
1204 | + } | |
1205 | + break; | |
1206 | + case T_TEXT: | |
1207 | + if (nargs < args_to_read) { | |
1208 | + args[nargs++] = state.text; | |
1209 | + } | |
1210 | + break; | |
1211 | + } | |
1212 | + } | |
1213 | + ret = 0; | |
1214 | + | |
1215 | +out: | |
1216 | + if (fd != -1) { | |
1217 | + close(fd); | |
1218 | + } | |
1219 | + return ret; | |
1220 | +} | |
1221 | + | |
1222 | +static int read_modules_aliases() { | |
1223 | + return __read_modules_desc_file(READ_MODULES_ALIAS); | |
1224 | +} | |
1225 | + | |
1226 | +static int read_modules_blacklist() { | |
1227 | + return __read_modules_desc_file(READ_MODULES_BLKLST); | |
897 | 1228 | } |
898 | 1229 | |
899 | 1230 | #define UEVENT_MSG_LEN 2048 |
900 | -void handle_device_fd() | |
1231 | +void handle_device_fd(bool child) | |
901 | 1232 | { |
902 | 1233 | char msg[UEVENT_MSG_LEN+2]; |
903 | 1234 | int n; |
@@ -920,8 +1251,11 @@ void handle_device_fd() | ||
920 | 1251 | } |
921 | 1252 | } |
922 | 1253 | |
923 | - handle_device_event(&uevent); | |
924 | - handle_firmware_event(&uevent); | |
1254 | + if (child) { | |
1255 | + handle_firmware_event(&uevent); | |
1256 | + } else { | |
1257 | + handle_device_event(&uevent); | |
1258 | + } | |
925 | 1259 | } |
926 | 1260 | } |
927 | 1261 |
@@ -977,7 +1311,8 @@ static void coldboot(const char *path) | ||
977 | 1311 | } |
978 | 1312 | } |
979 | 1313 | |
980 | -void device_init() { | |
1314 | +void device_init(bool child) | |
1315 | +{ | |
981 | 1316 | sehandle = selinux_android_file_context_handle(); |
982 | 1317 | selinux_status_open(true); |
983 | 1318 |
@@ -988,6 +1323,9 @@ void device_init() { | ||
988 | 1323 | } |
989 | 1324 | fcntl(device_fd, F_SETFL, O_NONBLOCK); |
990 | 1325 | |
1326 | + if (child) { | |
1327 | + return; // don't do coldboot in child | |
1328 | + } | |
991 | 1329 | if (access(COLDBOOT_DONE, F_OK) == 0) { |
992 | 1330 | NOTICE("Skipping coldboot, already done!\n"); |
993 | 1331 | return; |
@@ -19,8 +19,9 @@ | ||
19 | 19 | |
20 | 20 | #include <sys/stat.h> |
21 | 21 | |
22 | -extern void handle_device_fd(); | |
23 | -extern void device_init(void); | |
22 | +extern void handle_device_fd(bool = false); | |
23 | +extern void device_init(bool); | |
24 | +extern int modprobe_main(int argc, char **argv); | |
24 | 25 | extern int add_dev_perms(const char *name, const char *attr, |
25 | 26 | mode_t perm, unsigned int uid, |
26 | 27 | unsigned int gid, unsigned short prefix, |
@@ -585,6 +585,10 @@ static void selinux_initialize(bool in_kernel_domain) { | ||
585 | 585 | } |
586 | 586 | |
587 | 587 | int main(int argc, char** argv) { |
588 | + if (strstr(argv[0], "modprobe")) { | |
589 | + return modprobe_main(argc, argv); | |
590 | + } | |
591 | + | |
588 | 592 | if (!strcmp(basename(argv[0]), "ueventd")) { |
589 | 593 | return ueventd_main(argc, argv); |
590 | 594 | } |
@@ -15,12 +15,14 @@ | ||
15 | 15 | */ |
16 | 16 | |
17 | 17 | #include <ctype.h> |
18 | +#include <errno.h> | |
18 | 19 | #include <fcntl.h> |
19 | 20 | #include <poll.h> |
20 | 21 | #include <signal.h> |
21 | 22 | #include <stdio.h> |
22 | 23 | #include <stdlib.h> |
23 | 24 | #include <string.h> |
25 | +#include <unistd.h> | |
24 | 26 | |
25 | 27 | #include <android-base/stringprintf.h> |
26 | 28 | #include <private/android_filesystem_config.h> |
@@ -64,8 +66,12 @@ int ueventd_main(int argc, char **argv) | ||
64 | 66 | ueventd_parse_config_file("/ueventd.rc"); |
65 | 67 | ueventd_parse_config_file(android::base::StringPrintf("/ueventd.%s.rc", hardware.c_str()).c_str()); |
66 | 68 | |
67 | - device_init(); | |
69 | + pid_t pid = fork(); | |
70 | + if (pid < 0) { | |
71 | + ERROR("could not fork to process firmware event: %s\n", strerror(errno)); | |
72 | + } | |
68 | 73 | |
74 | + device_init(pid == 0); | |
69 | 75 | pollfd ufd; |
70 | 76 | ufd.events = POLLIN; |
71 | 77 | ufd.fd = get_device_fd(); |
@@ -77,7 +83,7 @@ int ueventd_main(int argc, char **argv) | ||
77 | 83 | continue; |
78 | 84 | } |
79 | 85 | if (ufd.revents & POLLIN) { |
80 | - handle_device_fd(); | |
86 | + handle_device_fd(pid == 0); | |
81 | 87 | } |
82 | 88 | } |
83 | 89 |
@@ -98,6 +98,7 @@ LOCAL_SRC_FILES := $(libcutils_common_sources) \ | ||
98 | 98 | debugger.c \ |
99 | 99 | klog.c \ |
100 | 100 | partition_utils.c \ |
101 | + probe_module.c \ | |
101 | 102 | properties.c \ |
102 | 103 | qtaguid.c \ |
103 | 104 | trace-dev.c \ |
@@ -0,0 +1,387 @@ | ||
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) | |
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, 0); | |
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); | |
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, | |
352 | + const char *dep_name) | |
353 | +{ | |
354 | + void *dep_file; | |
355 | + char **dep = NULL; | |
356 | + int ret = -1; | |
357 | + | |
358 | + if (!module_name || *module_name == '\0') { | |
359 | + ALOGE("need valid module name"); | |
360 | + return ret; | |
361 | + } | |
362 | + | |
363 | + dep_file = load_dep_file(dep_name); | |
364 | + | |
365 | + if (!dep_file) { | |
366 | + ALOGE("cannot load dep file : %s", dep_name); | |
367 | + return ret; | |
368 | + } | |
369 | + | |
370 | + dep = look_up_dep(module_name, dep_file); | |
371 | + | |
372 | + if (!dep) { | |
373 | + ALOGE("%s: cannot remove module: [%s]", __FUNCTION__, module_name); | |
374 | + goto free_file; | |
375 | + } | |
376 | + | |
377 | + ret = rmmod_s(dep, O_NONBLOCK); | |
378 | + | |
379 | + free(dep); | |
380 | + | |
381 | +free_file: | |
382 | + free(dep_file); | |
383 | + | |
384 | + return ret; | |
385 | +} | |
386 | + | |
387 | +/* end of file */ |