1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include "libbb.h"
16#include "modutils.h"
17#include <sys/utsname.h>
18#include <fnmatch.h>
19
20
21#define DBG(...) ((void)0)
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104#define MODPROBE_COMPLEMENTARY "q-v:v-q:l--ar:a--lr:r--al"
105#define MODPROBE_OPTS "alr" IF_FEATURE_MODPROBE_BLACKLIST("b")
106
107
108enum {
109 MODPROBE_OPT_INSERT_ALL = (INSMOD_OPT_UNUSED << 0),
110
111
112 MODPROBE_OPT_LIST_ONLY = (INSMOD_OPT_UNUSED << 1),
113
114 MODPROBE_OPT_REMOVE = (INSMOD_OPT_UNUSED << 2),
115
116
117
118 MODPROBE_OPT_BLACKLIST = (INSMOD_OPT_UNUSED << 3) * ENABLE_FEATURE_MODPROBE_BLACKLIST,
119};
120
121#define MODULE_FLAG_LOADED 0x0001
122#define MODULE_FLAG_NEED_DEPS 0x0002
123
124#define MODULE_FLAG_FOUND_IN_MODDEP 0x0004
125#define MODULE_FLAG_BLACKLISTED 0x0008
126
127struct module_entry {
128 unsigned flags;
129 char *modname;
130 const char *probed_name;
131 char *options;
132 llist_t *realnames;
133
134
135 llist_t *deps;
136};
137
138struct globals {
139 llist_t *db;
140 llist_t *probes;
141 char *cmdline_mopts;
142 int num_unresolved_deps;
143
144 smallint need_symbols;
145} FIX_ALIASING;
146#define G (*(struct globals*)&bb_common_bufsiz1)
147#define INIT_G() do { } while (0)
148
149
150static int read_config(const char *path);
151
152static char *gather_options_str(char *opts, const char *append)
153{
154
155 if (append) {
156 if (opts == NULL) {
157 opts = xstrdup(append);
158 } else {
159 int optlen = strlen(opts);
160 opts = xrealloc(opts, optlen + strlen(append) + 2);
161 sprintf(opts + optlen, " %s", append);
162 }
163 }
164 return opts;
165}
166
167static struct module_entry *helper_get_module(const char *module, int create)
168{
169 char modname[MODULE_NAME_LEN];
170 struct module_entry *e;
171 llist_t *l;
172
173 filename2modname(module, modname);
174 for (l = G.db; l != NULL; l = l->link) {
175 e = (struct module_entry *) l->data;
176 if (strcmp(e->modname, modname) == 0)
177 return e;
178 }
179 if (!create)
180 return NULL;
181
182 e = xzalloc(sizeof(*e));
183 e->modname = xstrdup(modname);
184 llist_add_to(&G.db, e);
185
186 return e;
187}
188static struct module_entry *get_or_add_modentry(const char *module)
189{
190 return helper_get_module(module, 1);
191}
192static struct module_entry *get_modentry(const char *module)
193{
194 return helper_get_module(module, 0);
195}
196
197static void add_probe(const char *name)
198{
199 struct module_entry *m;
200
201 m = get_or_add_modentry(name);
202 if (!(option_mask32 & MODPROBE_OPT_REMOVE)
203 && (m->flags & MODULE_FLAG_LOADED)
204 ) {
205 DBG("skipping %s, it is already loaded", name);
206 return;
207 }
208
209 DBG("queuing %s", name);
210 m->probed_name = name;
211 m->flags |= MODULE_FLAG_NEED_DEPS;
212 llist_add_to_end(&G.probes, m);
213 G.num_unresolved_deps++;
214 if (ENABLE_FEATURE_MODUTILS_SYMBOLS
215 && strncmp(m->modname, "symbol:", 7) == 0
216 ) {
217 G.need_symbols = 1;
218 }
219}
220
221static int FAST_FUNC config_file_action(const char *filename,
222 struct stat *statbuf UNUSED_PARAM,
223 void *userdata UNUSED_PARAM,
224 int depth UNUSED_PARAM)
225{
226 char *tokens[3];
227 parser_t *p;
228 struct module_entry *m;
229 int rc = TRUE;
230
231 if (bb_basename(filename)[0] == '.')
232 goto error;
233
234 p = config_open2(filename, fopen_for_read);
235 if (p == NULL) {
236 rc = FALSE;
237 goto error;
238 }
239
240 while (config_read(p, tokens, 3, 2, "# \t", PARSE_NORMAL)) {
241
242 if (strcmp(tokens[0], "alias") == 0) {
243
244 llist_t *l;
245 char wildcard[MODULE_NAME_LEN];
246 char *rmod;
247
248 if (tokens[2] == NULL)
249 continue;
250 filename2modname(tokens[1], wildcard);
251
252 for (l = G.probes; l != NULL; l = l->link) {
253 m = (struct module_entry *) l->data;
254 if (fnmatch(wildcard, m->modname, 0) != 0)
255 continue;
256 rmod = filename2modname(tokens[2], NULL);
257 llist_add_to(&m->realnames, rmod);
258
259 if (m->flags & MODULE_FLAG_NEED_DEPS) {
260 m->flags &= ~MODULE_FLAG_NEED_DEPS;
261 G.num_unresolved_deps--;
262 }
263
264 m = get_or_add_modentry(rmod);
265 if (!(m->flags & MODULE_FLAG_NEED_DEPS)) {
266 m->flags |= MODULE_FLAG_NEED_DEPS;
267 G.num_unresolved_deps++;
268 }
269 }
270 } else if (strcmp(tokens[0], "options") == 0) {
271
272 if (tokens[2] == NULL)
273 continue;
274 m = get_or_add_modentry(tokens[1]);
275 m->options = gather_options_str(m->options, tokens[2]);
276 } else if (strcmp(tokens[0], "include") == 0) {
277
278 read_config(tokens[1]);
279 } else if (ENABLE_FEATURE_MODPROBE_BLACKLIST
280 && strcmp(tokens[0], "blacklist") == 0
281 ) {
282
283 get_or_add_modentry(tokens[1])->flags |= MODULE_FLAG_BLACKLISTED;
284 }
285 }
286 config_close(p);
287 error:
288 return rc;
289}
290
291static int read_config(const char *path)
292{
293 return recursive_action(path, ACTION_RECURSE | ACTION_QUIET,
294 config_file_action, NULL, NULL, 1);
295}
296
297static const char *humanly_readable_name(struct module_entry *m)
298{
299
300 return m->probed_name ? m->probed_name : m->modname;
301}
302
303static char *parse_and_add_kcmdline_module_options(char *options, const char *modulename)
304{
305 char *kcmdline_buf;
306 char *kcmdline;
307 char *kptr;
308 int len;
309
310 kcmdline_buf = xmalloc_open_read_close("/proc/cmdline", NULL);
311 if (!kcmdline_buf)
312 return options;
313
314 kcmdline = kcmdline_buf;
315 len = strlen(modulename);
316 while ((kptr = strsep(&kcmdline, "\n\t ")) != NULL) {
317 if (strncmp(modulename, kptr, len) != 0)
318 continue;
319 kptr += len;
320 if (*kptr != '.')
321 continue;
322
323 kptr++;
324 if (strchr(kptr, '=') != NULL) {
325
326 options = gather_options_str(options, kptr);
327 }
328 }
329 free(kcmdline_buf);
330
331 return options;
332}
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351static int do_modprobe(struct module_entry *m)
352{
353 struct module_entry *m2 = m2;
354 char *fn, *options;
355 int rc, first;
356 llist_t *l;
357
358 if (!(m->flags & MODULE_FLAG_FOUND_IN_MODDEP)) {
359 if (!(option_mask32 & INSMOD_OPT_SILENT))
360 bb_error_msg("module %s not found in modules.dep",
361 humanly_readable_name(m));
362 return -ENOENT;
363 }
364 DBG("do_modprob'ing %s", m->modname);
365
366 if (!(option_mask32 & MODPROBE_OPT_REMOVE))
367 m->deps = llist_rev(m->deps);
368
369 for (l = m->deps; l != NULL; l = l->link)
370 DBG("dep: %s", l->data);
371
372 first = 1;
373 rc = 0;
374 while (m->deps) {
375 rc = 0;
376 fn = llist_pop(&m->deps);
377 m2 = get_or_add_modentry(fn);
378
379 if (option_mask32 & MODPROBE_OPT_REMOVE) {
380
381 if (m2->flags & MODULE_FLAG_LOADED) {
382 rc = bb_delete_module(m2->modname, O_EXCL);
383 if (rc) {
384 if (first) {
385 bb_error_msg("can't unload module %s: %s",
386 humanly_readable_name(m2),
387 moderror(rc));
388 break;
389 }
390 } else {
391 m2->flags &= ~MODULE_FLAG_LOADED;
392 }
393 }
394
395 first = 0;
396 continue;
397 }
398
399 if (m2->flags & MODULE_FLAG_LOADED) {
400 DBG("%s is already loaded, skipping", fn);
401 continue;
402 }
403
404 options = m2->options;
405 m2->options = NULL;
406 options = parse_and_add_kcmdline_module_options(options, m2->modname);
407 if (m == m2)
408 options = gather_options_str(options, G.cmdline_mopts);
409 rc = bb_init_module(fn, options);
410 DBG("loaded %s '%s', rc:%d", fn, options, rc);
411 if (rc == EEXIST)
412 rc = 0;
413 free(options);
414 if (rc) {
415 bb_error_msg("can't load module %s (%s): %s",
416 humanly_readable_name(m2),
417 fn,
418 moderror(rc)
419 );
420 break;
421 }
422 m2->flags |= MODULE_FLAG_LOADED;
423 }
424
425 return rc;
426}
427
428static void load_modules_dep(void)
429{
430 struct module_entry *m;
431 char *colon, *tokens[2];
432 parser_t *p;
433
434
435
436
437
438
439
440 p = config_open2(CONFIG_DEFAULT_DEPMOD_FILE, xfopen_for_read);
441
442 while (G.num_unresolved_deps
443 && config_read(p, tokens, 2, 1, "# \t", PARSE_NORMAL)
444 ) {
445 colon = last_char_is(tokens[0], ':');
446 if (colon == NULL)
447 continue;
448 *colon = 0;
449
450 m = get_modentry(tokens[0]);
451 if (m == NULL)
452 continue;
453
454
455 if ((m->flags & MODULE_FLAG_LOADED)
456 && !(option_mask32 & MODPROBE_OPT_REMOVE)
457 ) {
458 DBG("skip deps of %s, it's already loaded", tokens[0]);
459 continue;
460 }
461
462 m->flags |= MODULE_FLAG_FOUND_IN_MODDEP;
463 if ((m->flags & MODULE_FLAG_NEED_DEPS) && (m->deps == NULL)) {
464 G.num_unresolved_deps--;
465 llist_add_to(&m->deps, xstrdup(tokens[0]));
466 if (tokens[1])
467 string_to_llist(tokens[1], &m->deps, " \t");
468 } else
469 DBG("skipping dep line");
470 }
471 config_close(p);
472}
473
474int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
475int modprobe_main(int argc UNUSED_PARAM, char **argv)
476{
477 struct utsname uts;
478 int rc;
479 unsigned opt;
480 struct module_entry *me;
481
482 opt_complementary = MODPROBE_COMPLEMENTARY;
483 opt = getopt32(argv, INSMOD_OPTS MODPROBE_OPTS INSMOD_ARGS);
484 argv += optind;
485
486
487 xchdir(CONFIG_DEFAULT_MODULES_DIR);
488 uname(&uts);
489 xchdir(uts.release);
490
491 if (opt & MODPROBE_OPT_LIST_ONLY) {
492 char name[MODULE_NAME_LEN];
493 char *colon, *tokens[2];
494 parser_t *p = config_open2(CONFIG_DEFAULT_DEPMOD_FILE, xfopen_for_read);
495
496 while (config_read(p, tokens, 2, 1, "# \t", PARSE_NORMAL)) {
497 colon = last_char_is(tokens[0], ':');
498 if (!colon)
499 continue;
500 *colon = '\0';
501 filename2modname(tokens[0], name);
502 if (!argv[0])
503 puts(tokens[0]);
504 else {
505 int i;
506 for (i = 0; argv[i]; i++) {
507 if (fnmatch(argv[i], name, 0) == 0) {
508 puts(tokens[0]);
509 }
510 }
511 }
512 }
513 return EXIT_SUCCESS;
514 }
515
516
517 if (opt & INSMOD_OPT_SYSLOG)
518 logmode = LOGMODE_SYSLOG;
519
520 if (!argv[0]) {
521 if (opt & MODPROBE_OPT_REMOVE) {
522
523
524
525
526 if (bb_delete_module(NULL, O_NONBLOCK | O_EXCL) != 0)
527 bb_perror_msg_and_die("rmmod");
528 }
529 return EXIT_SUCCESS;
530 }
531
532
533 {
534 char *s;
535 parser_t *parser = config_open2("/proc/modules", fopen_for_read);
536 while (config_read(parser, &s, 1, 1, "# \t", PARSE_NORMAL & ~PARSE_GREEDY))
537 get_or_add_modentry(s)->flags |= MODULE_FLAG_LOADED;
538 config_close(parser);
539 }
540
541 if (opt & (MODPROBE_OPT_INSERT_ALL | MODPROBE_OPT_REMOVE)) {
542
543 do {
544 DBG("adding module %s", *argv);
545 add_probe(*argv++);
546 } while (*argv);
547 } else {
548
549 DBG("probing just module %s", *argv);
550 add_probe(argv[0]);
551 G.cmdline_mopts = parse_cmdline_module_options(argv);
552 }
553
554
555 if (G.probes == NULL)
556 return EXIT_SUCCESS;
557
558 read_config("/etc/modprobe.conf");
559 read_config("/etc/modprobe.d");
560 if (ENABLE_FEATURE_MODUTILS_SYMBOLS && G.need_symbols)
561 read_config("modules.symbols");
562 load_modules_dep();
563 if (ENABLE_FEATURE_MODUTILS_ALIAS && G.num_unresolved_deps) {
564 read_config("modules.alias");
565 load_modules_dep();
566 }
567
568 rc = 0;
569 while ((me = llist_pop(&G.probes)) != NULL) {
570 if (me->realnames == NULL) {
571 DBG("probing by module name");
572
573
574
575 if (!(opt & MODPROBE_OPT_BLACKLIST)
576 || !(me->flags & MODULE_FLAG_BLACKLISTED)
577 ) {
578 rc |= do_modprobe(me);
579 }
580 continue;
581 }
582
583
584 do {
585 char *realname = llist_pop(&me->realnames);
586 struct module_entry *m2;
587
588 DBG("probing alias %s by realname %s", me->modname, realname);
589 m2 = get_or_add_modentry(realname);
590 if (!(m2->flags & MODULE_FLAG_BLACKLISTED)
591 && (!(m2->flags & MODULE_FLAG_LOADED)
592 || (opt & MODPROBE_OPT_REMOVE))
593 ) {
594
595
596
597 rc |= do_modprobe(m2);
598 }
599 free(realname);
600 } while (me->realnames != NULL);
601 }
602
603 return (rc != 0);
604}
605