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