1 /* vi: set sw=4 ts=4: */
3 * Modprobe written from scratch for BusyBox
5 * Copyright (c) 2008 Timo Teras <timo.teras@iki.fi>
6 * Copyright (c) 2008 Vladimir Dronnikov
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
13 #include <sys/utsname.h>
16 //#define DBG(...) bb_error_msg(__VA_ARGS__)
17 #define DBG(...) ((void)0)
19 #define MODULE_FLAG_LOADED 0x0001
20 #define MODULE_FLAG_NEED_DEPS 0x0002
21 /* "was seen in modules.dep": */
22 #define MODULE_FLAG_FOUND_IN_MODDEP 0x0004
23 #define MODULE_FLAG_BLACKLISTED 0x0008
25 struct module_entry
{ /* I'll call it ME. */
27 char *modname
; /* stripped of /path/, .ext and s/-/_/g */
28 const char *probed_name
; /* verbatim as seen on cmdline */
29 char *options
; /* options from config files */
30 llist_t
*realnames
; /* strings. if this module is an alias, */
31 /* real module name is one of these. */
32 //Can there really be more than one? Example from real kernel?
33 llist_t
*deps
; /* strings. modules we depend on */
36 #define MODPROBE_OPTS "acdlnrt:VC:" USE_FEATURE_MODPROBE_BLACKLIST("b")
38 MODPROBE_OPT_INSERT_ALL
= (INSMOD_OPT_UNUSED
<< 0), /* a */
39 MODPROBE_OPT_DUMP_ONLY
= (INSMOD_OPT_UNUSED
<< 1), /* c */
40 MODPROBE_OPT_D
= (INSMOD_OPT_UNUSED
<< 2), /* d */
41 MODPROBE_OPT_LIST_ONLY
= (INSMOD_OPT_UNUSED
<< 3), /* l */
42 MODPROBE_OPT_SHOW_ONLY
= (INSMOD_OPT_UNUSED
<< 4), /* n */
43 MODPROBE_OPT_REMOVE
= (INSMOD_OPT_UNUSED
<< 5), /* r */
44 MODPROBE_OPT_RESTRICT
= (INSMOD_OPT_UNUSED
<< 6), /* t */
45 MODPROBE_OPT_VERONLY
= (INSMOD_OPT_UNUSED
<< 7), /* V */
46 MODPROBE_OPT_CONFIGFILE
= (INSMOD_OPT_UNUSED
<< 8), /* C */
47 MODPROBE_OPT_BLACKLIST
= (INSMOD_OPT_UNUSED
<< 9) * ENABLE_FEATURE_MODPROBE_BLACKLIST
,
51 llist_t
*db
; /* MEs of all modules ever seen (caching for speed) */
52 llist_t
*probes
; /* MEs of module(s) requested on cmdline */
53 char *cmdline_mopts
; /* module options from cmdline */
54 int num_unresolved_deps
;
55 /* bool. "Did we have 'symbol:FOO' requested on cmdline?" */
56 smallint need_symbols
;
58 #define G (*(struct globals*)&bb_common_bufsiz1)
59 #define INIT_G() do { } while (0)
62 static int read_config(const char *path
);
64 static char *gather_options_str(char *opts
, const char *append
)
66 /* Speed-optimized. We call gather_options_str many times. */
68 opts
= xstrdup(append
);
70 int optlen
= strlen(opts
);
71 opts
= xrealloc(opts
, optlen
+ strlen(append
) + 2);
72 sprintf(opts
+ optlen
, " %s", append
);
77 static struct module_entry
*helper_get_module(const char *module
, int create
)
79 char modname
[MODULE_NAME_LEN
];
80 struct module_entry
*e
;
83 filename2modname(module
, modname
);
84 for (l
= G
.db
; l
!= NULL
; l
= l
->link
) {
85 e
= (struct module_entry
*) l
->data
;
86 if (strcmp(e
->modname
, modname
) == 0)
92 e
= xzalloc(sizeof(*e
));
93 e
->modname
= xstrdup(modname
);
94 llist_add_to(&G
.db
, e
);
98 static struct module_entry
*get_or_add_modentry(const char *module
)
100 return helper_get_module(module
, 1);
102 static struct module_entry
*get_modentry(const char *module
)
104 return helper_get_module(module
, 0);
107 static void add_probe(const char *name
)
109 struct module_entry
*m
;
111 m
= get_or_add_modentry(name
);
112 if (m
->flags
& MODULE_FLAG_LOADED
) {
113 DBG("skipping %s, it is already loaded", name
);
117 m
->probed_name
= name
;
118 m
->flags
|= MODULE_FLAG_NEED_DEPS
;
119 llist_add_to_end(&G
.probes
, m
);
120 G
.num_unresolved_deps
++;
121 if (ENABLE_FEATURE_MODUTILS_SYMBOLS
122 && strncmp(m
->modname
, "symbol:", 7) == 0
128 static int FAST_FUNC
config_file_action(const char *filename
,
129 struct stat
*statbuf UNUSED_PARAM
,
130 void *userdata UNUSED_PARAM
,
131 int depth UNUSED_PARAM
)
135 struct module_entry
*m
;
138 if (bb_basename(filename
)[0] == '.')
141 p
= config_open2(filename
, fopen_for_read
);
147 while (config_read(p
, tokens
, 3, 2, "# \t", PARSE_NORMAL
)) {
148 //Use index_in_strings?
149 if (strcmp(tokens
[0], "alias") == 0) {
150 /* alias <wildcard> <modulename> */
152 char wildcard
[MODULE_NAME_LEN
];
155 if (tokens
[2] == NULL
)
157 filename2modname(tokens
[1], wildcard
);
159 for (l
= G
.probes
; l
!= NULL
; l
= l
->link
) {
160 m
= (struct module_entry
*) l
->data
;
161 if (fnmatch(wildcard
, m
->modname
, 0) != 0)
163 rmod
= filename2modname(tokens
[2], NULL
);
164 llist_add_to(&m
->realnames
, rmod
);
166 if (m
->flags
& MODULE_FLAG_NEED_DEPS
) {
167 m
->flags
&= ~MODULE_FLAG_NEED_DEPS
;
168 G
.num_unresolved_deps
--;
171 m
= get_or_add_modentry(rmod
);
172 if (!(m
->flags
& MODULE_FLAG_NEED_DEPS
)) {
173 m
->flags
|= MODULE_FLAG_NEED_DEPS
;
174 G
.num_unresolved_deps
++;
177 } else if (strcmp(tokens
[0], "options") == 0) {
178 /* options <modulename> <option...> */
179 if (tokens
[2] == NULL
)
181 m
= get_or_add_modentry(tokens
[1]);
182 m
->options
= gather_options_str(m
->options
, tokens
[2]);
183 } else if (strcmp(tokens
[0], "include") == 0) {
184 /* include <filename> */
185 read_config(tokens
[1]);
186 } else if (ENABLE_FEATURE_MODPROBE_BLACKLIST
187 && strcmp(tokens
[0], "blacklist") == 0
189 /* blacklist <modulename> */
190 get_or_add_modentry(tokens
[1])->flags
|= MODULE_FLAG_BLACKLISTED
;
198 static int read_config(const char *path
)
200 return recursive_action(path
, ACTION_RECURSE
| ACTION_QUIET
,
201 config_file_action
, NULL
, NULL
, 1);
204 static int do_modprobe(struct module_entry
*m
)
206 struct module_entry
*m2
;
210 if (!(m
->flags
& MODULE_FLAG_FOUND_IN_MODDEP
)) {
211 DBG("skipping %s, not found in modules.dep", m
->modname
);
214 DBG("do_modprob'ing %s", m
->modname
);
216 if (!(option_mask32
& MODPROBE_OPT_REMOVE
))
217 m
->deps
= llist_rev(m
->deps
);
220 while (m
->deps
&& rc
== 0) {
221 fn
= llist_pop(&m
->deps
);
222 m2
= get_or_add_modentry(fn
);
223 if (option_mask32
& MODPROBE_OPT_REMOVE
) {
224 if (bb_delete_module(m
->modname
, O_EXCL
) != 0)
226 } else if (!(m2
->flags
& MODULE_FLAG_LOADED
)) {
227 options
= m2
->options
;
230 options
= gather_options_str(options
, G
.cmdline_mopts
);
231 rc
= bb_init_module(fn
, options
);
232 DBG("loaded %s '%s', rc:%d", fn
, options
, rc
);
234 m2
->flags
|= MODULE_FLAG_LOADED
;
237 DBG("%s is already loaded, skipping", fn
);
243 //FIXME: what if rc < 0?
244 if (rc
> 0 && !(option_mask32
& INSMOD_OPT_SILENT
)) {
245 bb_error_msg("failed to %sload module %s: %s",
246 (option_mask32
& MODPROBE_OPT_REMOVE
) ? "un" : "",
247 m
->probed_name
? m
->probed_name
: m
->modname
,
255 static void load_modules_dep(void)
257 struct module_entry
*m
;
258 char *colon
, *tokens
[2];
261 /* Modprobe does not work at all without modprobe.dep,
262 * even if the full module name is given. Returning error here
263 * was making us later confuse user with this message:
264 * "module /full/path/to/existing/file/module.ko not found".
265 * It's better to die immediately, with good message.
266 * xfopen_for_read provides that. */
267 p
= config_open2(CONFIG_DEFAULT_DEPMOD_FILE
, xfopen_for_read
);
269 while (G
.num_unresolved_deps
270 && config_read(p
, tokens
, 2, 1, "# \t", PARSE_NORMAL
)
272 colon
= last_char_is(tokens
[0], ':');
277 m
= get_modentry(tokens
[0]);
281 /* Optimization... */
282 if ((m
->flags
& MODULE_FLAG_LOADED
)
283 && !(option_mask32
& MODPROBE_OPT_REMOVE
)
285 DBG("skip deps of %s, it's already loaded", tokens
[0]);
289 m
->flags
|= MODULE_FLAG_FOUND_IN_MODDEP
;
290 if ((m
->flags
& MODULE_FLAG_NEED_DEPS
) && (m
->deps
== NULL
)) {
291 G
.num_unresolved_deps
--;
292 llist_add_to(&m
->deps
, xstrdup(tokens
[0]));
294 string_to_llist(tokens
[1], &m
->deps
, " ");
300 int modprobe_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
301 int modprobe_main(int argc UNUSED_PARAM
, char **argv
)
306 struct module_entry
*me
;
308 opt_complementary
= "q-v:v-q";
309 opt
= getopt32(argv
, INSMOD_OPTS MODPROBE_OPTS INSMOD_ARGS
, NULL
, NULL
);
312 if (opt
& (MODPROBE_OPT_DUMP_ONLY
| MODPROBE_OPT_LIST_ONLY
|
313 MODPROBE_OPT_SHOW_ONLY
))
314 bb_error_msg_and_die("not supported");
317 if (opt
& MODPROBE_OPT_REMOVE
) {
318 /* "modprobe -r" (w/o params).
319 * "If name is NULL, all unused modules marked
320 * autoclean will be removed".
322 if (bb_delete_module(NULL
, O_NONBLOCK
|O_EXCL
) != 0)
323 bb_perror_msg_and_die("rmmod");
328 /* Goto modules location */
329 xchdir(CONFIG_DEFAULT_MODULES_DIR
);
333 /* Retrieve module names of already loaded modules */
336 parser_t
*parser
= config_open2("/proc/modules", fopen_for_read
);
337 while (config_read(parser
, &s
, 1, 1, "# \t", PARSE_NORMAL
& ~PARSE_GREEDY
))
338 get_or_add_modentry(s
)->flags
|= MODULE_FLAG_LOADED
;
339 config_close(parser
);
342 if (opt
& MODPROBE_OPT_INSERT_ALL
) {
343 /* Each argument is a module name */
348 /* First argument is module name, rest are parameters */
350 G
.cmdline_mopts
= parse_cmdline_module_options(argv
);
353 /* Happens if all requested modules are already loaded */
354 if (G
.probes
== NULL
)
357 read_config("/etc/modprobe.conf");
358 read_config("/etc/modprobe.d");
359 if (ENABLE_FEATURE_MODUTILS_SYMBOLS
&& G
.need_symbols
)
360 read_config("modules.symbols");
362 if (ENABLE_FEATURE_MODUTILS_ALIAS
&& G
.num_unresolved_deps
) {
363 read_config("modules.alias");
367 while ((me
= llist_pop(&G
.probes
)) != NULL
) {
368 if (me
->realnames
== NULL
) {
369 /* This is not an alias. Literal names are blacklisted
370 * only if '-b' is given.
372 if (!(opt
& MODPROBE_OPT_BLACKLIST
)
373 || !(me
->flags
& MODULE_FLAG_BLACKLISTED
)
375 rc
= do_modprobe(me
);
376 //FIXME: what if rc > 0?
377 if (rc
< 0 && !(opt
& INSMOD_OPT_SILENT
))
378 bb_error_msg("module %s not found",
382 /* Probe all realnames */
384 char *realname
= llist_pop(&me
->realnames
);
385 struct module_entry
*m2
;
387 DBG("probing %s by realname %s", me
->modname
, realname
);
388 m2
= get_or_add_modentry(realname
);
389 if (!(m2
->flags
& MODULE_FLAG_BLACKLISTED
))
391 //FIXME: error check?
393 } while (me
->realnames
!= NULL
);