1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35#include "libbb.h"
36#include "modutils.h"
37#include <sys/utsname.h>
38#include <fnmatch.h>
39
40#if 1
41#define DBG(...) ((void)0)
42#else
43#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__)
44#endif
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134#define MODPROBE_OPTS "alrDb"
135
136#define MODPROBE_COMPLEMENTARY "q-v:v-q:l--arD:r--alD:a--lr:D--rl"
137
138
139enum {
140 OPT_INSERT_ALL = (INSMOD_OPT_UNUSED << 0),
141
142
143 OPT_LIST_ONLY = (INSMOD_OPT_UNUSED << 1),
144
145 OPT_REMOVE = (INSMOD_OPT_UNUSED << 2),
146
147
148
149 OPT_SHOW_DEPS = (INSMOD_OPT_UNUSED << 3),
150 OPT_BLACKLIST = (INSMOD_OPT_UNUSED << 4) * ENABLE_FEATURE_MODPROBE_BLACKLIST,
151};
152#if ENABLE_LONG_OPTS
153static const char modprobe_longopts[] ALIGN1 =
154
155
156
157
158
159
160
161
162
163
164 "show-depends\0" No_argument "D"
165
166 ;
167#endif
168
169#define MODULE_FLAG_LOADED 0x0001
170#define MODULE_FLAG_NEED_DEPS 0x0002
171
172#define MODULE_FLAG_FOUND_IN_MODDEP 0x0004
173#define MODULE_FLAG_BLACKLISTED 0x0008
174#define MODULE_FLAG_BUILTIN 0x0010
175
176struct globals {
177 llist_t *probes;
178#if ENABLE_FEATURE_CMDLINE_MODULE_OPTIONS
179 char *cmdline_mopts;
180#endif
181 int num_unresolved_deps;
182
183 smallint need_symbols;
184 struct utsname uts;
185 module_db db;
186} FIX_ALIASING;
187#define G (*ptr_to_globals)
188#define INIT_G() do { \
189 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
190} while (0)
191
192
193static int read_config(const char *path);
194
195static char *gather_options_str(char *opts, const char *append)
196{
197
198 if (append) {
199 if (opts == NULL) {
200 opts = xstrdup(append);
201 } else {
202 int optlen = strlen(opts);
203 opts = xrealloc(opts, optlen + strlen(append) + 2);
204 sprintf(opts + optlen, " %s", append);
205 }
206 }
207 return opts;
208}
209
210static struct module_entry *get_or_add_modentry(const char *module)
211{
212 return moddb_get_or_create(&G.db, module);
213}
214
215static void add_probe(const char *name)
216{
217 struct module_entry *m;
218
219 m = get_or_add_modentry(name);
220 if (!(option_mask32 & (OPT_REMOVE | OPT_SHOW_DEPS))
221 && (m->flags & (MODULE_FLAG_LOADED | MODULE_FLAG_BUILTIN))
222 ) {
223 DBG("skipping %s, it is already loaded", name);
224 return;
225 }
226
227 DBG("queuing %s", name);
228 m->probed_name = name;
229 m->flags |= MODULE_FLAG_NEED_DEPS;
230 llist_add_to_end(&G.probes, m);
231 G.num_unresolved_deps++;
232 if (ENABLE_FEATURE_MODUTILS_SYMBOLS
233 && is_prefixed_with(m->modname, "symbol:")
234 ) {
235 G.need_symbols = 1;
236 }
237}
238
239static int FAST_FUNC config_file_action(const char *filename,
240 struct stat *statbuf UNUSED_PARAM,
241 void *userdata UNUSED_PARAM,
242 int depth)
243{
244 char *tokens[3];
245 parser_t *p;
246 struct module_entry *m;
247 int rc = TRUE;
248 const char *base;
249
250
251 base = bb_basename(filename);
252 if (base[0] == '.')
253 goto error;
254
255
256
257
258
259 if (depth > 1)
260 return SKIP;
261
262
263
264
265
266
267
268 if (depth != 0) {
269 if (!is_suffixed_with(base, ".conf"))
270 goto error;
271 }
272
273 p = config_open2(filename, fopen_for_read);
274 if (p == NULL) {
275 rc = FALSE;
276 goto error;
277 }
278
279 while (config_read(p, tokens, 3, 2, "# \t", PARSE_NORMAL)) {
280
281 if (strcmp(tokens[0], "alias") == 0) {
282
283 llist_t *l;
284 char wildcard[MODULE_NAME_LEN];
285 char *rmod;
286
287 if (tokens[2] == NULL)
288 continue;
289 filename2modname(tokens[1], wildcard);
290
291 for (l = G.probes; l; l = l->link) {
292 m = (struct module_entry *) l->data;
293 if (fnmatch(wildcard, m->modname, 0) != 0)
294 continue;
295 rmod = filename2modname(tokens[2], NULL);
296 llist_add_to(&m->realnames, rmod);
297
298 if (m->flags & MODULE_FLAG_NEED_DEPS) {
299 m->flags &= ~MODULE_FLAG_NEED_DEPS;
300 G.num_unresolved_deps--;
301 }
302
303 m = get_or_add_modentry(rmod);
304 if (!(m->flags & MODULE_FLAG_NEED_DEPS)) {
305 m->flags |= MODULE_FLAG_NEED_DEPS;
306 G.num_unresolved_deps++;
307 }
308 }
309 } else if (strcmp(tokens[0], "options") == 0) {
310
311 if (tokens[2] == NULL)
312 continue;
313 m = get_or_add_modentry(tokens[1]);
314 m->options = gather_options_str(m->options, tokens[2]);
315 } else if (strcmp(tokens[0], "include") == 0) {
316
317 read_config(tokens[1]);
318 } else if (ENABLE_FEATURE_MODPROBE_BLACKLIST
319 && strcmp(tokens[0], "blacklist") == 0
320 ) {
321
322 get_or_add_modentry(tokens[1])->flags |= MODULE_FLAG_BLACKLISTED;
323 }
324 }
325 config_close(p);
326 error:
327 return rc;
328}
329
330static int read_config(const char *path)
331{
332 return recursive_action(path, ACTION_RECURSE | ACTION_QUIET,
333 config_file_action, NULL, NULL,
334 0);
335}
336
337static const char *humanly_readable_name(struct module_entry *m)
338{
339
340 return m->probed_name ? m->probed_name : m->modname;
341}
342
343
344
345
346static char *strsep_quotes(char **stringp)
347{
348 char *s, *start = *stringp;
349
350 if (!start)
351 return NULL;
352
353 for (s = start; ; s++) {
354 switch (*s) {
355 case '"':
356 s = strchrnul(s + 1, '"');
357 if (*s != '\0')
358 s++;
359
360 case '\0':
361 case '\n':
362 case '\t':
363 case ' ':
364 if (*s != '\0') {
365 *s = '\0';
366 *stringp = s + 1;
367 } else {
368 *stringp = NULL;
369 }
370 return start;
371 }
372 }
373}
374
375static char *parse_and_add_kcmdline_module_options(char *options, const char *modulename)
376{
377 char *kcmdline_buf;
378 char *kcmdline;
379 char *kptr;
380
381 kcmdline_buf = xmalloc_open_read_close("/proc/cmdline", NULL);
382 if (!kcmdline_buf)
383 return options;
384
385 kcmdline = kcmdline_buf;
386 while ((kptr = strsep_quotes(&kcmdline)) != NULL) {
387 char *after_modulename = is_prefixed_with(kptr, modulename);
388 if (!after_modulename || *after_modulename != '.')
389 continue;
390
391 kptr = after_modulename + 1;
392 if (strchr(kptr, '=') != NULL) {
393
394 options = gather_options_str(options, kptr);
395 }
396 }
397 free(kcmdline_buf);
398
399 return options;
400}
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419static int do_modprobe(struct module_entry *m)
420{
421 int rc, first;
422
423 if (!(m->flags & MODULE_FLAG_FOUND_IN_MODDEP)) {
424 if (!(option_mask32 & INSMOD_OPT_SILENT))
425 bb_error_msg((m->flags & MODULE_FLAG_BUILTIN) ?
426 "module %s is builtin" :
427 "module %s not found in modules.dep",
428 humanly_readable_name(m));
429 return -ENOENT;
430 }
431 DBG("do_modprob'ing %s", m->modname);
432
433 if (!(option_mask32 & OPT_REMOVE))
434 m->deps = llist_rev(m->deps);
435
436 if (0) {
437 llist_t *l;
438 for (l = m->deps; l; l = l->link)
439 DBG("dep: %s", l->data);
440 }
441
442 first = 1;
443 rc = 0;
444 while (m->deps) {
445 struct module_entry *m2;
446 char *fn, *options;
447
448 rc = 0;
449 fn = llist_pop(&m->deps);
450 m2 = get_or_add_modentry(bb_get_last_path_component_nostrip(fn));
451
452 if (option_mask32 & OPT_REMOVE) {
453
454 if (m2->flags & MODULE_FLAG_LOADED) {
455 rc = bb_delete_module(m2->modname, O_EXCL);
456 if (rc) {
457 if (first) {
458 bb_perror_msg("can't unload module '%s'",
459 humanly_readable_name(m2));
460 break;
461 }
462 } else {
463 m2->flags &= ~MODULE_FLAG_LOADED;
464 }
465 }
466
467 first = 0;
468 continue;
469 }
470
471 options = m2->options;
472 m2->options = NULL;
473 options = parse_and_add_kcmdline_module_options(options, m2->modname);
474#if ENABLE_FEATURE_CMDLINE_MODULE_OPTIONS
475 if (m == m2)
476 options = gather_options_str(options, G.cmdline_mopts);
477#endif
478
479 if (option_mask32 & OPT_SHOW_DEPS) {
480 printf(options ? "insmod %s/%s/%s %s\n"
481 : "insmod %s/%s/%s\n",
482 CONFIG_DEFAULT_MODULES_DIR, G.uts.release, fn,
483 options);
484 free(options);
485 continue;
486 }
487
488 if (m2->flags & MODULE_FLAG_LOADED) {
489 DBG("%s is already loaded, skipping", fn);
490 free(options);
491 continue;
492 }
493
494 rc = bb_init_module(fn, options);
495 DBG("loaded %s '%s', rc:%d", fn, options, rc);
496 if (rc == EEXIST)
497 rc = 0;
498 free(options);
499 if (rc) {
500 bb_error_msg("can't load module %s (%s): %s",
501 humanly_readable_name(m2),
502 fn,
503 moderror(rc)
504 );
505 break;
506 }
507 m2->flags |= MODULE_FLAG_LOADED;
508 }
509
510 return rc;
511}
512
513static void load_modules_dep(void)
514{
515 struct module_entry *m;
516 char *colon, *tokens[2];
517 parser_t *p;
518
519
520
521
522
523
524
525 p = config_open2(CONFIG_DEFAULT_DEPMOD_FILE, xfopen_for_read);
526
527 while (G.num_unresolved_deps
528 && config_read(p, tokens, 2, 1, "# \t", PARSE_NORMAL)
529 ) {
530 colon = last_char_is(tokens[0], ':');
531 if (colon == NULL)
532 continue;
533 *colon = '\0';
534
535 m = moddb_get(&G.db, bb_get_last_path_component_nostrip(tokens[0]));
536 if (m == NULL)
537 continue;
538
539
540 if ((m->flags & MODULE_FLAG_LOADED)
541 && !(option_mask32 & (OPT_REMOVE | OPT_SHOW_DEPS))
542 ) {
543 DBG("skip deps of %s, it's already loaded", tokens[0]);
544 continue;
545 }
546
547 m->flags |= MODULE_FLAG_FOUND_IN_MODDEP;
548 if ((m->flags & MODULE_FLAG_NEED_DEPS) && (m->deps == NULL)) {
549 G.num_unresolved_deps--;
550 llist_add_to(&m->deps, xstrdup(tokens[0]));
551 if (tokens[1])
552 string_to_llist(tokens[1], &m->deps, " \t");
553 } else
554 DBG("skipping dep line");
555 }
556 config_close(p);
557}
558
559int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
560int modprobe_main(int argc UNUSED_PARAM, char **argv)
561{
562 int rc;
563 unsigned opt;
564 struct module_entry *me;
565
566 INIT_G();
567
568 opt = getopt32long(argv, "^" INSMOD_OPTS MODPROBE_OPTS "\0" MODPROBE_COMPLEMENTARY,
569 modprobe_longopts
570 INSMOD_ARGS
571 );
572 argv += optind;
573
574
575 xchdir(CONFIG_DEFAULT_MODULES_DIR);
576 uname(&G.uts);
577 xchdir(G.uts.release);
578
579 if (opt & OPT_LIST_ONLY) {
580 int i;
581 char *colon, *tokens[2];
582 parser_t *p = config_open2(CONFIG_DEFAULT_DEPMOD_FILE, xfopen_for_read);
583
584 for (i = 0; argv[i]; i++)
585 replace(argv[i], '-', '_');
586
587 while (config_read(p, tokens, 2, 1, "# \t", PARSE_NORMAL)) {
588 colon = last_char_is(tokens[0], ':');
589 if (!colon)
590 continue;
591 *colon = '\0';
592 if (!argv[0])
593 puts(tokens[0]);
594 else {
595 char name[MODULE_NAME_LEN];
596 filename2modname(
597 bb_get_last_path_component_nostrip(tokens[0]),
598 name
599 );
600 for (i = 0; argv[i]; i++) {
601 if (fnmatch(argv[i], name, 0) == 0) {
602 puts(tokens[0]);
603 }
604 }
605 }
606 }
607 return EXIT_SUCCESS;
608 }
609
610
611 if (opt & INSMOD_OPT_SYSLOG)
612 logmode = LOGMODE_SYSLOG;
613
614 if (!argv[0]) {
615 if (opt & OPT_REMOVE) {
616
617
618
619
620 if (bb_delete_module(NULL, O_NONBLOCK | O_EXCL) != 0)
621 bb_perror_nomsg_and_die();
622 }
623 return EXIT_SUCCESS;
624 }
625
626
627 {
628 char *s;
629 parser_t *parser = config_open2("/proc/modules", fopen_for_read);
630 while (config_read(parser, &s, 1, 1, "# \t", PARSE_NORMAL & ~PARSE_GREEDY))
631 get_or_add_modentry(s)->flags |= MODULE_FLAG_LOADED;
632 config_close(parser);
633
634 parser = config_open2("modules.builtin", fopen_for_read);
635 while (config_read(parser, &s, 1, 1, "# \t", PARSE_NORMAL))
636 get_or_add_modentry(s)->flags |= MODULE_FLAG_BUILTIN;
637 config_close(parser);
638 }
639
640 if (opt & (OPT_INSERT_ALL | OPT_REMOVE)) {
641
642 do {
643 DBG("adding module %s", *argv);
644 add_probe(*argv++);
645 } while (*argv);
646 } else {
647
648 DBG("probing just module %s", *argv);
649 add_probe(argv[0]);
650#if ENABLE_FEATURE_CMDLINE_MODULE_OPTIONS
651 G.cmdline_mopts = parse_cmdline_module_options(argv, 1);
652#endif
653 }
654
655
656 if (G.probes == NULL)
657 return EXIT_SUCCESS;
658
659 read_config("/etc/modprobe.conf");
660 read_config("/etc/modprobe.d");
661 if (ENABLE_FEATURE_MODUTILS_SYMBOLS && G.need_symbols)
662 read_config("modules.symbols");
663 load_modules_dep();
664 if (ENABLE_FEATURE_MODUTILS_ALIAS && G.num_unresolved_deps) {
665 read_config("modules.alias");
666 load_modules_dep();
667 }
668
669 rc = 0;
670 while ((me = llist_pop(&G.probes)) != NULL) {
671 if (me->realnames == NULL) {
672 DBG("probing by module name");
673
674
675
676 if (!(opt & OPT_BLACKLIST)
677 || !(me->flags & MODULE_FLAG_BLACKLISTED)
678 ) {
679 rc |= do_modprobe(me);
680 }
681 continue;
682 }
683
684
685 do {
686 char *realname = llist_pop(&me->realnames);
687 struct module_entry *m2;
688
689 DBG("probing alias %s by realname %s", me->modname, realname);
690 m2 = get_or_add_modentry(realname);
691 if (!(m2->flags & MODULE_FLAG_BLACKLISTED)
692 && (!(m2->flags & MODULE_FLAG_LOADED)
693 || (opt & (OPT_REMOVE | OPT_SHOW_DEPS)))
694 ) {
695
696
697
698 rc |= do_modprobe(m2);
699 }
700 free(realname);
701 } while (me->realnames != NULL);
702 }
703
704 if (ENABLE_FEATURE_CLEAN_UP)
705 moddb_free(&G.db);
706
707 return (rc != 0);
708}
709