Annotation of /tags/mkinitrd-6_1_11/busybox/modutils/modprobe.c
Parent Directory | Revision Log
Revision 928 -
(hide annotations)
(download)
Wed Oct 28 13:31:19 2009 UTC (14 years, 7 months ago) by niro
File MIME type: text/plain
File size: 7846 byte(s)
Wed Oct 28 13:31:19 2009 UTC (14 years, 7 months ago) by niro
File MIME type: text/plain
File size: 7846 byte(s)
tagged 'mkinitrd-6_1_11'
1 | niro | 532 | /* vi: set sw=4 ts=4: */ |
2 | /* | ||
3 | * Modprobe written from scratch for BusyBox | ||
4 | * | ||
5 | niro | 816 | * Copyright (c) 2008 Timo Teras <timo.teras@iki.fi> |
6 | * Copyright (c) 2008 Vladimir Dronnikov | ||
7 | niro | 532 | * |
8 | * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | ||
9 | niro | 816 | */ |
10 | niro | 532 | |
11 | niro | 816 | #include "libbb.h" |
12 | #include "modutils.h" | ||
13 | niro | 532 | #include <sys/utsname.h> |
14 | #include <fnmatch.h> | ||
15 | |||
16 | niro | 816 | struct modprobe_option { |
17 | char *module; | ||
18 | char *option; | ||
19 | niro | 532 | }; |
20 | |||
21 | niro | 816 | struct modprobe_conf { |
22 | char probename[MODULE_NAME_LEN]; | ||
23 | llist_t *options; | ||
24 | llist_t *aliases; | ||
25 | #if ENABLE_FEATURE_MODPROBE_BLACKLIST | ||
26 | #define add_to_blacklist(conf, name) llist_add_to(&conf->blacklist, name) | ||
27 | #define check_blacklist(conf, name) (llist_find(conf->blacklist, name) == NULL) | ||
28 | llist_t *blacklist; | ||
29 | #else | ||
30 | #define add_to_blacklist(conf, name) do {} while (0) | ||
31 | #define check_blacklist(conf, name) (1) | ||
32 | #endif | ||
33 | niro | 532 | }; |
34 | |||
35 | niro | 816 | #define MODPROBE_OPTS "acdlnrt:VC:" USE_FEATURE_MODPROBE_BLACKLIST("b") |
36 | enum { | ||
37 | MODPROBE_OPT_INSERT_ALL = (INSMOD_OPT_UNUSED << 0), /* a */ | ||
38 | MODPROBE_OPT_DUMP_ONLY = (INSMOD_OPT_UNUSED << 1), /* c */ | ||
39 | MODPROBE_OPT_D = (INSMOD_OPT_UNUSED << 2), /* d */ | ||
40 | MODPROBE_OPT_LIST_ONLY = (INSMOD_OPT_UNUSED << 3), /* l */ | ||
41 | MODPROBE_OPT_SHOW_ONLY = (INSMOD_OPT_UNUSED << 4), /* n */ | ||
42 | MODPROBE_OPT_REMOVE = (INSMOD_OPT_UNUSED << 5), /* r */ | ||
43 | MODPROBE_OPT_RESTRICT = (INSMOD_OPT_UNUSED << 6), /* t */ | ||
44 | MODPROBE_OPT_VERONLY = (INSMOD_OPT_UNUSED << 7), /* V */ | ||
45 | MODPROBE_OPT_CONFIGFILE = (INSMOD_OPT_UNUSED << 8), /* C */ | ||
46 | MODPROBE_OPT_BLACKLIST = (INSMOD_OPT_UNUSED << 9) * ENABLE_FEATURE_MODPROBE_BLACKLIST, | ||
47 | niro | 532 | }; |
48 | |||
49 | niro | 816 | static llist_t *loaded; |
50 | niro | 532 | |
51 | niro | 816 | static int read_config(struct modprobe_conf *conf, const char *path); |
52 | niro | 532 | |
53 | niro | 816 | static void add_option(llist_t **all_opts, const char *module, const char *opts) |
54 | { | ||
55 | struct modprobe_option *o; | ||
56 | niro | 532 | |
57 | niro | 816 | o = xzalloc(sizeof(struct modprobe_option)); |
58 | if (module) | ||
59 | o->module = filename2modname(module, NULL); | ||
60 | o->option = xstrdup(opts); | ||
61 | llist_add_to(all_opts, o); | ||
62 | } | ||
63 | niro | 532 | |
64 | niro | 816 | static int FAST_FUNC config_file_action(const char *filename, |
65 | struct stat *statbuf UNUSED_PARAM, | ||
66 | void *userdata, | ||
67 | int depth UNUSED_PARAM) | ||
68 | niro | 532 | { |
69 | niro | 816 | struct modprobe_conf *conf = (struct modprobe_conf *) userdata; |
70 | RESERVE_CONFIG_BUFFER(modname, MODULE_NAME_LEN); | ||
71 | char *tokens[3]; | ||
72 | parser_t *p; | ||
73 | int rc = TRUE; | ||
74 | niro | 532 | |
75 | niro | 816 | if (bb_basename(filename)[0] == '.') |
76 | goto error; | ||
77 | niro | 532 | |
78 | niro | 816 | p = config_open2(filename, fopen_for_read); |
79 | if (p == NULL) { | ||
80 | rc = FALSE; | ||
81 | goto error; | ||
82 | } | ||
83 | niro | 532 | |
84 | niro | 816 | while (config_read(p, tokens, 3, 2, "# \t", PARSE_NORMAL)) { |
85 | if (strcmp(tokens[0], "alias") == 0) { | ||
86 | filename2modname(tokens[1], modname); | ||
87 | if (tokens[2] && | ||
88 | fnmatch(modname, conf->probename, 0) == 0) | ||
89 | llist_add_to(&conf->aliases, | ||
90 | filename2modname(tokens[2], NULL)); | ||
91 | } else if (strcmp(tokens[0], "options") == 0) { | ||
92 | if (tokens[2]) | ||
93 | add_option(&conf->options, tokens[1], tokens[2]); | ||
94 | } else if (strcmp(tokens[0], "include") == 0) { | ||
95 | read_config(conf, tokens[1]); | ||
96 | } else if (ENABLE_FEATURE_MODPROBE_BLACKLIST && | ||
97 | strcmp(tokens[0], "blacklist") == 0) { | ||
98 | add_to_blacklist(conf, xstrdup(tokens[1])); | ||
99 | niro | 532 | } |
100 | } | ||
101 | niro | 816 | config_close(p); |
102 | error: | ||
103 | if (ENABLE_FEATURE_CLEAN_UP) | ||
104 | RELEASE_CONFIG_BUFFER(modname); | ||
105 | return rc; | ||
106 | niro | 532 | } |
107 | |||
108 | niro | 816 | static int read_config(struct modprobe_conf *conf, const char *path) |
109 | niro | 532 | { |
110 | niro | 816 | return recursive_action(path, ACTION_RECURSE | ACTION_QUIET, |
111 | config_file_action, NULL, conf, 1); | ||
112 | niro | 532 | } |
113 | |||
114 | niro | 816 | static char *gather_options(llist_t *first, const char *module, int usecmdline) |
115 | niro | 532 | { |
116 | niro | 816 | struct modprobe_option *opt; |
117 | llist_t *n; | ||
118 | char *opts = xstrdup(""); | ||
119 | int optlen = 0; | ||
120 | niro | 532 | |
121 | niro | 816 | for (n = first; n != NULL; n = n->link) { |
122 | opt = (struct modprobe_option *) n->data; | ||
123 | niro | 532 | |
124 | niro | 816 | if (opt->module == NULL && !usecmdline) |
125 | niro | 532 | continue; |
126 | niro | 816 | if (opt->module != NULL && strcmp(opt->module, module) != 0) |
127 | continue; | ||
128 | niro | 532 | |
129 | niro | 816 | opts = xrealloc(opts, optlen + strlen(opt->option) + 2); |
130 | optlen += sprintf(opts + optlen, "%s ", opt->option); | ||
131 | niro | 532 | } |
132 | niro | 816 | return opts; |
133 | niro | 532 | } |
134 | |||
135 | niro | 816 | static int do_modprobe(struct modprobe_conf *conf, const char *module) |
136 | niro | 532 | { |
137 | niro | 816 | RESERVE_CONFIG_BUFFER(modname, MODULE_NAME_LEN); |
138 | llist_t *deps = NULL; | ||
139 | char *fn, *options, *colon = NULL, *tokens[2]; | ||
140 | parser_t *p; | ||
141 | int rc = -1; | ||
142 | niro | 532 | |
143 | niro | 816 | p = config_open2(CONFIG_DEFAULT_DEPMOD_FILE, fopen_for_read); |
144 | if (p == NULL) | ||
145 | goto error; | ||
146 | niro | 532 | |
147 | niro | 816 | while (config_read(p, tokens, 2, 1, "# \t", PARSE_NORMAL)) { |
148 | colon = last_char_is(tokens[0], ':'); | ||
149 | if (colon == NULL) | ||
150 | niro | 532 | continue; |
151 | |||
152 | niro | 816 | filename2modname(tokens[0], modname); |
153 | if (strcmp(modname, module) == 0) | ||
154 | break; | ||
155 | niro | 532 | |
156 | niro | 816 | colon = NULL; |
157 | } | ||
158 | if (colon == NULL) | ||
159 | goto error_not_found; | ||
160 | niro | 532 | |
161 | niro | 816 | colon[0] = '\0'; |
162 | llist_add_to(&deps, xstrdup(tokens[0])); | ||
163 | if (tokens[1]) | ||
164 | string_to_llist(tokens[1], &deps, " "); | ||
165 | niro | 532 | |
166 | niro | 816 | if (!(option_mask32 & MODPROBE_OPT_REMOVE)) |
167 | deps = llist_rev(deps); | ||
168 | niro | 532 | |
169 | niro | 816 | rc = 0; |
170 | while (deps && rc == 0) { | ||
171 | fn = llist_pop(&deps); | ||
172 | filename2modname(fn, modname); | ||
173 | if (option_mask32 & MODPROBE_OPT_REMOVE) { | ||
174 | if (bb_delete_module(modname, O_EXCL) != 0) | ||
175 | rc = errno; | ||
176 | } else if (llist_find(loaded, modname) == NULL) { | ||
177 | options = gather_options(conf->options, modname, | ||
178 | strcmp(modname, module) == 0); | ||
179 | rc = bb_init_module(fn, options); | ||
180 | if (rc == 0) | ||
181 | llist_add_to(&loaded, xstrdup(modname)); | ||
182 | if (ENABLE_FEATURE_CLEAN_UP) | ||
183 | free(options); | ||
184 | niro | 532 | } |
185 | |||
186 | if (ENABLE_FEATURE_CLEAN_UP) | ||
187 | niro | 816 | free(fn); |
188 | niro | 532 | } |
189 | |||
190 | niro | 816 | error_not_found: |
191 | config_close(p); | ||
192 | error: | ||
193 | if (ENABLE_FEATURE_CLEAN_UP) | ||
194 | RELEASE_CONFIG_BUFFER(modname); | ||
195 | if (rc > 0 && !(option_mask32 & INSMOD_OPT_SILENT)) | ||
196 | bb_error_msg("Failed to %sload module %s: %s.", | ||
197 | (option_mask32 & MODPROBE_OPT_REMOVE) ? "un" : "", | ||
198 | module, moderror(rc)); | ||
199 | return rc; | ||
200 | niro | 532 | } |
201 | |||
202 | niro | 816 | int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
203 | int modprobe_main(int argc UNUSED_PARAM, char **argv) | ||
204 | niro | 532 | { |
205 | niro | 816 | struct utsname uts; |
206 | int rc; | ||
207 | unsigned opt; | ||
208 | llist_t *options = NULL; | ||
209 | niro | 532 | |
210 | niro | 816 | opt_complementary = "q-v:v-q"; |
211 | opt = getopt32(argv, INSMOD_OPTS MODPROBE_OPTS INSMOD_ARGS, | ||
212 | NULL, NULL); | ||
213 | argv += optind; | ||
214 | niro | 532 | |
215 | niro | 816 | if (opt & (MODPROBE_OPT_DUMP_ONLY | MODPROBE_OPT_LIST_ONLY | |
216 | MODPROBE_OPT_SHOW_ONLY)) | ||
217 | bb_error_msg_and_die("not supported"); | ||
218 | niro | 532 | |
219 | niro | 816 | /* goto modules location */ |
220 | xchdir(CONFIG_DEFAULT_MODULES_DIR); | ||
221 | uname(&uts); | ||
222 | xchdir(uts.release); | ||
223 | niro | 532 | |
224 | niro | 816 | if (!argv[0]) { |
225 | if (opt & MODPROBE_OPT_REMOVE) { | ||
226 | if (bb_delete_module(NULL, O_NONBLOCK|O_EXCL) != 0) | ||
227 | bb_perror_msg_and_die("rmmod"); | ||
228 | niro | 532 | } |
229 | niro | 816 | return EXIT_SUCCESS; |
230 | niro | 532 | } |
231 | niro | 816 | if (!(opt & MODPROBE_OPT_INSERT_ALL)) { |
232 | /* If not -a, we have only one module name, | ||
233 | * the rest of parameters are options */ | ||
234 | add_option(&options, NULL, parse_cmdline_module_options(argv)); | ||
235 | argv[1] = NULL; | ||
236 | niro | 532 | } |
237 | |||
238 | niro | 816 | /* cache modules */ |
239 | { | ||
240 | char *s; | ||
241 | parser_t *parser = config_open2("/proc/modules", fopen_for_read); | ||
242 | while (config_read(parser, &s, 1, 1, "# \t", PARSE_NORMAL & ~PARSE_GREEDY)) | ||
243 | llist_add_to(&loaded, xstrdup(s)); | ||
244 | config_close(parser); | ||
245 | niro | 532 | } |
246 | |||
247 | niro | 816 | while (*argv) { |
248 | const char *arg = *argv; | ||
249 | struct modprobe_conf *conf; | ||
250 | niro | 532 | |
251 | niro | 816 | conf = xzalloc(sizeof(*conf)); |
252 | conf->options = options; | ||
253 | filename2modname(arg, conf->probename); | ||
254 | read_config(conf, "/etc/modprobe.conf"); | ||
255 | read_config(conf, "/etc/modprobe.d"); | ||
256 | if (ENABLE_FEATURE_MODUTILS_SYMBOLS | ||
257 | && conf->aliases == NULL | ||
258 | && strncmp(arg, "symbol:", 7) == 0 | ||
259 | ) { | ||
260 | read_config(conf, "modules.symbols"); | ||
261 | niro | 532 | } |
262 | |||
263 | niro | 816 | if (ENABLE_FEATURE_MODUTILS_ALIAS && conf->aliases == NULL) |
264 | read_config(conf, "modules.alias"); | ||
265 | niro | 532 | |
266 | niro | 816 | if (conf->aliases == NULL) { |
267 | /* Try if module by literal name is found; literal | ||
268 | * names are blacklist only if '-b' is given. */ | ||
269 | if (!(opt & MODPROBE_OPT_BLACKLIST) || | ||
270 | check_blacklist(conf, conf->probename)) { | ||
271 | rc = do_modprobe(conf, conf->probename); | ||
272 | if (rc < 0 && !(opt & INSMOD_OPT_SILENT)) | ||
273 | bb_error_msg("Module %s not found.", arg); | ||
274 | niro | 532 | } |
275 | niro | 816 | } else { |
276 | /* Probe all aliases */ | ||
277 | while (conf->aliases != NULL) { | ||
278 | char *realname = llist_pop(&conf->aliases); | ||
279 | if (check_blacklist(conf, realname)) | ||
280 | do_modprobe(conf, realname); | ||
281 | if (ENABLE_FEATURE_CLEAN_UP) | ||
282 | free(realname); | ||
283 | niro | 532 | } |
284 | } | ||
285 | niro | 816 | argv++; |
286 | niro | 532 | } |
287 | |||
288 | niro | 816 | return EXIT_SUCCESS; |
289 | niro | 532 | } |