aboutsummaryrefslogtreecommitdiff
path: root/modutils/modprobe.c
diff options
context:
space:
mode:
Diffstat (limited to 'modutils/modprobe.c')
-rw-r--r--modutils/modprobe.c159
1 files changed, 95 insertions, 64 deletions
diff --git a/modutils/modprobe.c b/modutils/modprobe.c
index d000c9123..cfc16cb34 100644
--- a/modutils/modprobe.c
+++ b/modutils/modprobe.c
@@ -9,10 +9,9 @@
9 */ 9 */
10 10
11/* Note that unlike older versions of modules.dep/depmod (busybox and m-i-t), 11/* Note that unlike older versions of modules.dep/depmod (busybox and m-i-t),
12 * we expect the full dependency list to be specified in modules.dep. Older 12 * we expect the full dependency list to be specified in modules.dep.
13 * versions would only export the direct dependency list. 13 * Older versions would only export the direct dependency list.
14 */ 14 */
15
16#include "libbb.h" 15#include "libbb.h"
17#include "modutils.h" 16#include "modutils.h"
18#include <sys/utsname.h> 17#include <sys/utsname.h>
@@ -21,11 +20,11 @@
21//#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__) 20//#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__)
22#define DBG(...) ((void)0) 21#define DBG(...) ((void)0)
23 22
24#define MODULE_FLAG_LOADED 0x0001 23#define MODULE_FLAG_LOADED 0x0001
25#define MODULE_FLAG_NEED_DEPS 0x0002 24#define MODULE_FLAG_NEED_DEPS 0x0002
26/* "was seen in modules.dep": */ 25/* "was seen in modules.dep": */
27#define MODULE_FLAG_FOUND_IN_MODDEP 0x0004 26#define MODULE_FLAG_FOUND_IN_MODDEP 0x0004
28#define MODULE_FLAG_BLACKLISTED 0x0008 27#define MODULE_FLAG_BLACKLISTED 0x0008
29 28
30struct module_entry { /* I'll call it ME. */ 29struct module_entry { /* I'll call it ME. */
31 unsigned flags; 30 unsigned flags;
@@ -38,18 +37,30 @@ struct module_entry { /* I'll call it ME. */
38 llist_t *deps; /* strings. modules we depend on */ 37 llist_t *deps; /* strings. modules we depend on */
39}; 38};
40 39
40/* NB: INSMOD_OPT_SILENT bit suppresses ONLY non-existent modules,
41 * not deleted ones (those are still listed in modules.dep).
42 * module-init-tools version 3.4:
43 * # modprobe bogus
44 * FATAL: Module bogus not found. [exitcode 1]
45 * # modprobe -q bogus [silent, exitcode still 1]
46 * but:
47 * # rm kernel/drivers/net/dummy.ko
48 * # modprobe -q dummy
49 * FATAL: Could not open '/lib/modules/xxx/kernel/drivers/net/dummy.ko': No such file or directory
50 * [exitcode 1]
51 */
41#define MODPROBE_OPTS "acdlnrt:VC:" IF_FEATURE_MODPROBE_BLACKLIST("b") 52#define MODPROBE_OPTS "acdlnrt:VC:" IF_FEATURE_MODPROBE_BLACKLIST("b")
42enum { 53enum {
43 MODPROBE_OPT_INSERT_ALL = (INSMOD_OPT_UNUSED << 0), /* a */ 54 MODPROBE_OPT_INSERT_ALL = (INSMOD_OPT_UNUSED << 0), /* a */
44 MODPROBE_OPT_DUMP_ONLY = (INSMOD_OPT_UNUSED << 1), /* c */ 55 MODPROBE_OPT_DUMP_ONLY = (INSMOD_OPT_UNUSED << 1), /* c */
45 MODPROBE_OPT_D = (INSMOD_OPT_UNUSED << 2), /* d */ 56 MODPROBE_OPT_D = (INSMOD_OPT_UNUSED << 2), /* d */
46 MODPROBE_OPT_LIST_ONLY = (INSMOD_OPT_UNUSED << 3), /* l */ 57 MODPROBE_OPT_LIST_ONLY = (INSMOD_OPT_UNUSED << 3), /* l */
47 MODPROBE_OPT_SHOW_ONLY = (INSMOD_OPT_UNUSED << 4), /* n */ 58 MODPROBE_OPT_SHOW_ONLY = (INSMOD_OPT_UNUSED << 4), /* n */
48 MODPROBE_OPT_REMOVE = (INSMOD_OPT_UNUSED << 5), /* r */ 59 MODPROBE_OPT_REMOVE = (INSMOD_OPT_UNUSED << 5), /* r */
49 MODPROBE_OPT_RESTRICT = (INSMOD_OPT_UNUSED << 6), /* t */ 60 MODPROBE_OPT_RESTRICT = (INSMOD_OPT_UNUSED << 6), /* t */
50 MODPROBE_OPT_VERONLY = (INSMOD_OPT_UNUSED << 7), /* V */ 61 MODPROBE_OPT_VERONLY = (INSMOD_OPT_UNUSED << 7), /* V */
51 MODPROBE_OPT_CONFIGFILE = (INSMOD_OPT_UNUSED << 8), /* C */ 62 MODPROBE_OPT_CONFIGFILE = (INSMOD_OPT_UNUSED << 8), /* C */
52 MODPROBE_OPT_BLACKLIST = (INSMOD_OPT_UNUSED << 9) * ENABLE_FEATURE_MODPROBE_BLACKLIST, 63 MODPROBE_OPT_BLACKLIST = (INSMOD_OPT_UNUSED << 9) * ENABLE_FEATURE_MODPROBE_BLACKLIST,
53}; 64};
54 65
55struct globals { 66struct globals {
@@ -140,7 +151,7 @@ static int FAST_FUNC config_file_action(const char *filename,
140{ 151{
141 char *tokens[3]; 152 char *tokens[3];
142 parser_t *p; 153 parser_t *p;
143 struct module_entry *m; 154 struct module_entry *m;
144 int rc = TRUE; 155 int rc = TRUE;
145 156
146 if (bb_basename(filename)[0] == '.') 157 if (bb_basename(filename)[0] == '.')
@@ -199,7 +210,7 @@ static int FAST_FUNC config_file_action(const char *filename,
199 } 210 }
200 } 211 }
201 config_close(p); 212 config_close(p);
202error: 213 error:
203 return rc; 214 return rc;
204} 215}
205 216
@@ -209,6 +220,11 @@ static int read_config(const char *path)
209 config_file_action, NULL, NULL, 1); 220 config_file_action, NULL, NULL, 1);
210} 221}
211 222
223/* Return: similar to bb_init_module:
224 * 0 on success,
225 * -errno on open/read error,
226 * errno on init_module() error
227 */
212static int do_modprobe(struct module_entry *m) 228static int do_modprobe(struct module_entry *m)
213{ 229{
214 struct module_entry *m2 = m2; /* for compiler */ 230 struct module_entry *m2 = m2; /* for compiler */
@@ -217,7 +233,8 @@ static int do_modprobe(struct module_entry *m)
217 llist_t *l; 233 llist_t *l;
218 234
219 if (!(m->flags & MODULE_FLAG_FOUND_IN_MODDEP)) { 235 if (!(m->flags & MODULE_FLAG_FOUND_IN_MODDEP)) {
220 DBG("skipping %s, not found in modules.dep", m->modname); 236 if (!(option_mask32 & INSMOD_OPT_SILENT))
237 bb_error_msg("module %s not found in modules.dep", m->probed_name);
221 return -ENOENT; 238 return -ENOENT;
222 } 239 }
223 DBG("do_modprob'ing %s", m->modname); 240 DBG("do_modprob'ing %s", m->modname);
@@ -230,43 +247,52 @@ static int do_modprobe(struct module_entry *m)
230 247
231 first = 1; 248 first = 1;
232 rc = 0; 249 rc = 0;
233 while (m->deps && rc == 0) { 250 while (m->deps) {
234 fn = llist_pop(&m->deps); 251 rc = 0;
252 fn = llist_pop(&m->deps); /* we leak it */
235 m2 = get_or_add_modentry(fn); 253 m2 = get_or_add_modentry(fn);
254
236 if (option_mask32 & MODPROBE_OPT_REMOVE) { 255 if (option_mask32 & MODPROBE_OPT_REMOVE) {
256 /* modprobe -r */
237 if (m2->flags & MODULE_FLAG_LOADED) { 257 if (m2->flags & MODULE_FLAG_LOADED) {
238 if (bb_delete_module(m2->modname, O_EXCL) != 0) { 258 rc = bb_delete_module(m2->modname, O_EXCL);
239 if (first) 259 if (rc) {
240 rc = errno; 260 if (first) {
261 bb_error_msg("failed to unload module %s: %s",
262 m2->probed_name ? m2->probed_name : m2->modname,
263 moderror(rc));
264 break;
265 }
241 } else { 266 } else {
242 m2->flags &= ~MODULE_FLAG_LOADED; 267 m2->flags &= ~MODULE_FLAG_LOADED;
243 } 268 }
244 } 269 }
245 /* do not error out if *deps* fail to unload */ 270 /* do not error out if *deps* fail to unload */
246 first = 0; 271 first = 0;
247 } else if (!(m2->flags & MODULE_FLAG_LOADED)) { 272 continue;
248 options = m2->options;
249 m2->options = NULL;
250 if (m == m2)
251 options = gather_options_str(options, G.cmdline_mopts);
252 rc = bb_init_module(fn, options);
253 DBG("loaded %s '%s', rc:%d", fn, options, rc);
254 if (rc == 0)
255 m2->flags |= MODULE_FLAG_LOADED;
256 free(options);
257 } else {
258 DBG("%s is already loaded, skipping", fn);
259 } 273 }
260 274
261 free(fn); 275 if (m2->flags & MODULE_FLAG_LOADED) {
262 } 276 DBG("%s is already loaded, skipping", fn);
277 continue;
278 }
263 279
264 if (rc && !(option_mask32 & INSMOD_OPT_SILENT)) { 280 options = m2->options;
265 bb_error_msg("failed to %sload module %s: %s", 281 m2->options = NULL;
266 (option_mask32 & MODPROBE_OPT_REMOVE) ? "un" : "", 282 if (m == m2)
283 options = gather_options_str(options, G.cmdline_mopts);
284 rc = bb_init_module(fn, options);
285 DBG("loaded %s '%s', rc:%d", fn, options, rc);
286 free(options);
287 if (rc) {
288 bb_error_msg("failed to load module %s (%s): %s",
267 m2->probed_name ? m2->probed_name : m2->modname, 289 m2->probed_name ? m2->probed_name : m2->modname,
268 moderror(rc) 290 fn,
269 ); 291 moderror(rc)
292 );
293 break;
294 }
295 m2->flags |= MODULE_FLAG_LOADED;
270 } 296 }
271 297
272 return rc; 298 return rc;
@@ -278,7 +304,7 @@ static void load_modules_dep(void)
278 char *colon, *tokens[2]; 304 char *colon, *tokens[2];
279 parser_t *p; 305 parser_t *p;
280 306
281 /* Modprobe does not work at all without modprobe.dep, 307 /* Modprobe does not work at all without modules.dep,
282 * even if the full module name is given. Returning error here 308 * even if the full module name is given. Returning error here
283 * was making us later confuse user with this message: 309 * was making us later confuse user with this message:
284 * "module /full/path/to/existing/file/module.ko not found". 310 * "module /full/path/to/existing/file/module.ko not found".
@@ -387,35 +413,40 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
387 load_modules_dep(); 413 load_modules_dep();
388 } 414 }
389 415
416 rc = 0;
390 while ((me = llist_pop(&G.probes)) != NULL) { 417 while ((me = llist_pop(&G.probes)) != NULL) {
391 if (me->realnames == NULL) { 418 if (me->realnames == NULL) {
419 DBG("probing by module name");
392 /* This is not an alias. Literal names are blacklisted 420 /* This is not an alias. Literal names are blacklisted
393 * only if '-b' is given. 421 * only if '-b' is given.
394 */ 422 */
395 if (!(opt & MODPROBE_OPT_BLACKLIST) 423 if (!(opt & MODPROBE_OPT_BLACKLIST)
396 || !(me->flags & MODULE_FLAG_BLACKLISTED) 424 || !(me->flags & MODULE_FLAG_BLACKLISTED)
397 ) { 425 ) {
398 rc = do_modprobe(me); 426 rc |= do_modprobe(me);
399//FIXME: what if rc > 0?
400 if (rc < 0 && !(opt & INSMOD_OPT_SILENT))
401 bb_error_msg("module %s not found",
402 me->probed_name);
403 } 427 }
404 } else { 428 continue;
405 /* Probe all realnames */
406 do {
407 char *realname = llist_pop(&me->realnames);
408 struct module_entry *m2;
409
410 DBG("probing %s by realname %s", me->modname, realname);
411 m2 = get_or_add_modentry(realname);
412 if (!(m2->flags & MODULE_FLAG_BLACKLISTED))
413 do_modprobe(m2);
414//FIXME: error check?
415 free(realname);
416 } while (me->realnames != NULL);
417 } 429 }
430
431 /* Probe all real names for the alias */
432 do {
433 char *realname = llist_pop(&me->realnames);
434 struct module_entry *m2;
435
436 DBG("probing alias %s by realname %s", me->modname, realname);
437 m2 = get_or_add_modentry(realname);
438 if (!(m2->flags & MODULE_FLAG_BLACKLISTED)
439 && (!(m2->flags & MODULE_FLAG_LOADED)
440 || (opt & MODPROBE_OPT_REMOVE))
441 ) {
442//TODO: we can pass "me" as 2nd param to do_modprobe,
443//and make do_modprobe emit more meaningful error messages
444//with alias name included, not just module name alias resolves to.
445 rc |= do_modprobe(m2);
446 }
447 free(realname);
448 } while (me->realnames != NULL);
418 } 449 }
419 450
420 return EXIT_SUCCESS; 451 return (rc != 0);
421} 452}