Contents of /tags/mkinitrd-6_1_11/busybox/modutils/modprobe-small.c
Parent Directory | Revision Log
Revision 928 -
(show annotations)
(download)
Wed Oct 28 13:31:19 2009 UTC (14 years, 11 months ago) by niro
File MIME type: text/plain
File size: 21651 byte(s)
Wed Oct 28 13:31:19 2009 UTC (14 years, 11 months ago) by niro
File MIME type: text/plain
File size: 21651 byte(s)
tagged 'mkinitrd-6_1_11'
1 | /* vi: set sw=4 ts=4: */ |
2 | /* |
3 | * simplified modprobe |
4 | * |
5 | * Copyright (c) 2008 Vladimir Dronnikov |
6 | * Copyright (c) 2008 Bernhard Reutner-Fischer (initial depmod code) |
7 | * |
8 | * Licensed under GPLv2, see file LICENSE in this tarball for details. |
9 | */ |
10 | |
11 | #include "libbb.h" |
12 | |
13 | #include <sys/utsname.h> /* uname() */ |
14 | #include <fnmatch.h> |
15 | |
16 | extern int init_module(void *module, unsigned long len, const char *options); |
17 | extern int delete_module(const char *module, unsigned flags); |
18 | extern int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret); |
19 | |
20 | |
21 | #define dbg1_error_msg(...) ((void)0) |
22 | #define dbg2_error_msg(...) ((void)0) |
23 | //#define dbg1_error_msg(...) bb_error_msg(__VA_ARGS__) |
24 | //#define dbg2_error_msg(...) bb_error_msg(__VA_ARGS__) |
25 | |
26 | #define DEPFILE_BB CONFIG_DEFAULT_DEPMOD_FILE".bb" |
27 | |
28 | enum { |
29 | OPT_q = (1 << 0), /* be quiet */ |
30 | OPT_r = (1 << 1), /* module removal instead of loading */ |
31 | }; |
32 | |
33 | typedef struct module_info { |
34 | char *pathname; |
35 | char *aliases; |
36 | char *deps; |
37 | } module_info; |
38 | |
39 | /* |
40 | * GLOBALS |
41 | */ |
42 | struct globals { |
43 | module_info *modinfo; |
44 | char *module_load_options; |
45 | smallint dep_bb_seen; |
46 | smallint wrote_dep_bb_ok; |
47 | int module_count; |
48 | int module_found_idx; |
49 | int stringbuf_idx; |
50 | char stringbuf[32 * 1024]; /* some modules have lots of stuff */ |
51 | /* for example, drivers/media/video/saa7134/saa7134.ko */ |
52 | }; |
53 | #define G (*ptr_to_globals) |
54 | #define modinfo (G.modinfo ) |
55 | #define dep_bb_seen (G.dep_bb_seen ) |
56 | #define wrote_dep_bb_ok (G.wrote_dep_bb_ok ) |
57 | #define module_count (G.module_count ) |
58 | #define module_found_idx (G.module_found_idx ) |
59 | #define module_load_options (G.module_load_options) |
60 | #define stringbuf_idx (G.stringbuf_idx ) |
61 | #define stringbuf (G.stringbuf ) |
62 | #define INIT_G() do { \ |
63 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ |
64 | } while (0) |
65 | |
66 | |
67 | static void appendc(char c) |
68 | { |
69 | if (stringbuf_idx < sizeof(stringbuf)) |
70 | stringbuf[stringbuf_idx++] = c; |
71 | } |
72 | |
73 | static void bksp(void) |
74 | { |
75 | if (stringbuf_idx) |
76 | stringbuf_idx--; |
77 | } |
78 | |
79 | static void append(const char *s) |
80 | { |
81 | size_t len = strlen(s); |
82 | if (stringbuf_idx + len < sizeof(stringbuf)) { |
83 | memcpy(stringbuf + stringbuf_idx, s, len); |
84 | stringbuf_idx += len; |
85 | } |
86 | } |
87 | |
88 | static void reset_stringbuf(void) |
89 | { |
90 | stringbuf_idx = 0; |
91 | } |
92 | |
93 | static char* copy_stringbuf(void) |
94 | { |
95 | char *copy = xmalloc(stringbuf_idx); |
96 | return memcpy(copy, stringbuf, stringbuf_idx); |
97 | } |
98 | |
99 | static char* find_keyword(char *ptr, size_t len, const char *word) |
100 | { |
101 | int wlen; |
102 | |
103 | if (!ptr) /* happens if xmalloc_open_zipped_read_close cannot read it */ |
104 | return NULL; |
105 | |
106 | wlen = strlen(word); |
107 | len -= wlen - 1; |
108 | while ((ssize_t)len > 0) { |
109 | char *old = ptr; |
110 | /* search for the first char in word */ |
111 | ptr = memchr(ptr, *word, len); |
112 | if (ptr == NULL) /* no occurance left, done */ |
113 | break; |
114 | if (strncmp(ptr, word, wlen) == 0) |
115 | return ptr + wlen; /* found, return ptr past it */ |
116 | ++ptr; |
117 | len -= (ptr - old); |
118 | } |
119 | return NULL; |
120 | } |
121 | |
122 | static void replace(char *s, char what, char with) |
123 | { |
124 | while (*s) { |
125 | if (what == *s) |
126 | *s = with; |
127 | ++s; |
128 | } |
129 | } |
130 | |
131 | /* Take "word word", return malloced "word",NUL,"word",NUL,NUL */ |
132 | static char* str_2_list(const char *str) |
133 | { |
134 | int len = strlen(str) + 1; |
135 | char *dst = xmalloc(len + 1); |
136 | |
137 | dst[len] = '\0'; |
138 | memcpy(dst, str, len); |
139 | //TODO: protect against 2+ spaces: "word word" |
140 | replace(dst, ' ', '\0'); |
141 | return dst; |
142 | } |
143 | |
144 | /* We use error numbers in a loose translation... */ |
145 | static const char *moderror(int err) |
146 | { |
147 | switch (err) { |
148 | case ENOEXEC: |
149 | return "invalid module format"; |
150 | case ENOENT: |
151 | return "unknown symbol in module or invalid parameter"; |
152 | case ESRCH: |
153 | return "module has wrong symbol version"; |
154 | case EINVAL: /* "invalid parameter" */ |
155 | return "unknown symbol in module or invalid parameter" |
156 | + sizeof("unknown symbol in module or"); |
157 | default: |
158 | return strerror(err); |
159 | } |
160 | } |
161 | |
162 | static int load_module(const char *fname, const char *options) |
163 | { |
164 | #if 1 |
165 | int r; |
166 | size_t len = MAXINT(ssize_t); |
167 | char *module_image; |
168 | dbg1_error_msg("load_module('%s','%s')", fname, options); |
169 | |
170 | module_image = xmalloc_open_zipped_read_close(fname, &len); |
171 | r = (!module_image || init_module(module_image, len, options ? options : "") != 0); |
172 | free(module_image); |
173 | dbg1_error_msg("load_module:%d", r); |
174 | return r; /* 0 = success */ |
175 | #else |
176 | /* For testing */ |
177 | dbg1_error_msg("load_module('%s','%s')", fname, options); |
178 | return 1; |
179 | #endif |
180 | } |
181 | |
182 | static void parse_module(module_info *info, const char *pathname) |
183 | { |
184 | char *module_image; |
185 | char *ptr; |
186 | size_t len; |
187 | size_t pos; |
188 | dbg1_error_msg("parse_module('%s')", pathname); |
189 | |
190 | /* Read (possibly compressed) module */ |
191 | len = 64 * 1024 * 1024; /* 64 Mb at most */ |
192 | module_image = xmalloc_open_zipped_read_close(pathname, &len); |
193 | //TODO: optimize redundant module body reads |
194 | |
195 | /* "alias1 symbol:sym1 alias2 symbol:sym2" */ |
196 | reset_stringbuf(); |
197 | pos = 0; |
198 | while (1) { |
199 | ptr = find_keyword(module_image + pos, len - pos, "alias="); |
200 | if (!ptr) { |
201 | ptr = find_keyword(module_image + pos, len - pos, "__ksymtab_"); |
202 | if (!ptr) |
203 | break; |
204 | /* DOCME: __ksymtab_gpl and __ksymtab_strings occur |
205 | * in many modules. What do they mean? */ |
206 | if (strcmp(ptr, "gpl") == 0 || strcmp(ptr, "strings") == 0) |
207 | goto skip; |
208 | dbg2_error_msg("alias:'symbol:%s'", ptr); |
209 | append("symbol:"); |
210 | } else { |
211 | dbg2_error_msg("alias:'%s'", ptr); |
212 | } |
213 | append(ptr); |
214 | appendc(' '); |
215 | skip: |
216 | pos = (ptr - module_image); |
217 | } |
218 | bksp(); /* remove last ' ' */ |
219 | appendc('\0'); |
220 | info->aliases = copy_stringbuf(); |
221 | |
222 | /* "dependency1 depandency2" */ |
223 | reset_stringbuf(); |
224 | ptr = find_keyword(module_image, len, "depends="); |
225 | if (ptr && *ptr) { |
226 | replace(ptr, ',', ' '); |
227 | replace(ptr, '-', '_'); |
228 | dbg2_error_msg("dep:'%s'", ptr); |
229 | append(ptr); |
230 | } |
231 | appendc('\0'); |
232 | info->deps = copy_stringbuf(); |
233 | |
234 | free(module_image); |
235 | } |
236 | |
237 | static int pathname_matches_modname(const char *pathname, const char *modname) |
238 | { |
239 | const char *fname = bb_get_last_path_component_nostrip(pathname); |
240 | const char *suffix = strrstr(fname, ".ko"); |
241 | //TODO: can do without malloc? |
242 | char *name = xstrndup(fname, suffix - fname); |
243 | int r; |
244 | replace(name, '-', '_'); |
245 | r = (strcmp(name, modname) == 0); |
246 | free(name); |
247 | return r; |
248 | } |
249 | |
250 | static FAST_FUNC int fileAction(const char *pathname, |
251 | struct stat *sb UNUSED_PARAM, |
252 | void *modname_to_match, |
253 | int depth UNUSED_PARAM) |
254 | { |
255 | int cur; |
256 | const char *fname; |
257 | |
258 | pathname += 2; /* skip "./" */ |
259 | fname = bb_get_last_path_component_nostrip(pathname); |
260 | if (!strrstr(fname, ".ko")) { |
261 | dbg1_error_msg("'%s' is not a module", pathname); |
262 | return TRUE; /* not a module, continue search */ |
263 | } |
264 | |
265 | cur = module_count++; |
266 | modinfo = xrealloc_vector(modinfo, 12, cur); |
267 | modinfo[cur].pathname = xstrdup(pathname); |
268 | /*modinfo[cur].aliases = NULL; - xrealloc_vector did it */ |
269 | /*modinfo[cur+1].pathname = NULL;*/ |
270 | |
271 | if (!pathname_matches_modname(fname, modname_to_match)) { |
272 | dbg1_error_msg("'%s' module name doesn't match", pathname); |
273 | return TRUE; /* module name doesn't match, continue search */ |
274 | } |
275 | |
276 | dbg1_error_msg("'%s' module name matches", pathname); |
277 | module_found_idx = cur; |
278 | parse_module(&modinfo[cur], pathname); |
279 | |
280 | if (!(option_mask32 & OPT_r)) { |
281 | if (load_module(pathname, module_load_options) == 0) { |
282 | /* Load was successful, there is nothing else to do. |
283 | * This can happen ONLY for "top-level" module load, |
284 | * not a dep, because deps dont do dirscan. */ |
285 | exit(EXIT_SUCCESS); |
286 | } |
287 | } |
288 | |
289 | return TRUE; |
290 | } |
291 | |
292 | static int load_dep_bb(void) |
293 | { |
294 | char *line; |
295 | FILE *fp = fopen_for_read(DEPFILE_BB); |
296 | |
297 | if (!fp) |
298 | return 0; |
299 | |
300 | dep_bb_seen = 1; |
301 | dbg1_error_msg("loading "DEPFILE_BB); |
302 | |
303 | /* Why? There is a rare scenario: we did not find modprobe.dep.bb, |
304 | * we scanned the dir and found no module by name, then we search |
305 | * for alias (full scan), and we decided to generate modprobe.dep.bb. |
306 | * But we see modprobe.dep.bb.new! Other modprobe is at work! |
307 | * We wait and other modprobe renames it to modprobe.dep.bb. |
308 | * Now we can use it. |
309 | * But we already have modinfo[] filled, and "module_count = 0" |
310 | * makes us start anew. Yes, we leak modinfo[].xxx pointers - |
311 | * there is not much of data there anyway. */ |
312 | module_count = 0; |
313 | memset(&modinfo[0], 0, sizeof(modinfo[0])); |
314 | |
315 | while ((line = xmalloc_fgetline(fp)) != NULL) { |
316 | char* space; |
317 | int cur; |
318 | |
319 | if (!line[0]) { |
320 | free(line); |
321 | continue; |
322 | } |
323 | space = strchrnul(line, ' '); |
324 | cur = module_count++; |
325 | modinfo = xrealloc_vector(modinfo, 12, cur); |
326 | /*modinfo[cur+1].pathname = NULL; - xrealloc_vector did it */ |
327 | modinfo[cur].pathname = line; /* we take ownership of malloced block here */ |
328 | if (*space) |
329 | *space++ = '\0'; |
330 | modinfo[cur].aliases = space; |
331 | modinfo[cur].deps = xmalloc_fgetline(fp) ? : xzalloc(1); |
332 | if (modinfo[cur].deps[0]) { |
333 | /* deps are not "", so next line must be empty */ |
334 | line = xmalloc_fgetline(fp); |
335 | /* Refuse to work with damaged config file */ |
336 | if (line && line[0]) |
337 | bb_error_msg_and_die("error in %s at '%s'", DEPFILE_BB, line); |
338 | free(line); |
339 | } |
340 | } |
341 | return 1; |
342 | } |
343 | |
344 | static int start_dep_bb_writeout(void) |
345 | { |
346 | int fd; |
347 | |
348 | /* depmod -n: write result to stdout */ |
349 | if (applet_name[0] == 'd' && (option_mask32 & 1)) |
350 | return STDOUT_FILENO; |
351 | |
352 | fd = open(DEPFILE_BB".new", O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0644); |
353 | if (fd < 0) { |
354 | if (errno == EEXIST) { |
355 | int count = 5 * 20; |
356 | dbg1_error_msg(DEPFILE_BB".new exists, waiting for "DEPFILE_BB); |
357 | while (1) { |
358 | usleep(1000*1000 / 20); |
359 | if (load_dep_bb()) { |
360 | dbg1_error_msg(DEPFILE_BB" appeared"); |
361 | return -2; /* magic number */ |
362 | } |
363 | if (!--count) |
364 | break; |
365 | } |
366 | bb_error_msg("deleting stale %s", DEPFILE_BB".new"); |
367 | fd = open_or_warn(DEPFILE_BB".new", O_WRONLY | O_CREAT | O_TRUNC); |
368 | } |
369 | } |
370 | dbg1_error_msg("opened "DEPFILE_BB".new:%d", fd); |
371 | return fd; |
372 | } |
373 | |
374 | static void write_out_dep_bb(int fd) |
375 | { |
376 | int i; |
377 | FILE *fp; |
378 | |
379 | /* We want good error reporting. fdprintf is not good enough. */ |
380 | fp = fdopen(fd, "w"); |
381 | if (!fp) { |
382 | close(fd); |
383 | goto err; |
384 | } |
385 | i = 0; |
386 | while (modinfo[i].pathname) { |
387 | fprintf(fp, "%s%s%s\n" "%s%s\n", |
388 | modinfo[i].pathname, modinfo[i].aliases[0] ? " " : "", modinfo[i].aliases, |
389 | modinfo[i].deps, modinfo[i].deps[0] ? "\n" : ""); |
390 | i++; |
391 | } |
392 | /* Badly formatted depfile is a no-no. Be paranoid. */ |
393 | errno = 0; |
394 | if (ferror(fp) | fclose(fp)) /* | instead of || is intended */ |
395 | goto err; |
396 | |
397 | if (fd == STDOUT_FILENO) /* it was depmod -n */ |
398 | goto ok; |
399 | |
400 | if (rename(DEPFILE_BB".new", DEPFILE_BB) != 0) { |
401 | err: |
402 | bb_perror_msg("can't create %s", DEPFILE_BB); |
403 | unlink(DEPFILE_BB".new"); |
404 | } else { |
405 | ok: |
406 | wrote_dep_bb_ok = 1; |
407 | dbg1_error_msg("created "DEPFILE_BB); |
408 | } |
409 | } |
410 | |
411 | static module_info* find_alias(const char *alias) |
412 | { |
413 | int i; |
414 | int dep_bb_fd; |
415 | module_info *result; |
416 | dbg1_error_msg("find_alias('%s')", alias); |
417 | |
418 | try_again: |
419 | /* First try to find by name (cheaper) */ |
420 | i = 0; |
421 | while (modinfo[i].pathname) { |
422 | if (pathname_matches_modname(modinfo[i].pathname, alias)) { |
423 | dbg1_error_msg("found '%s' in module '%s'", |
424 | alias, modinfo[i].pathname); |
425 | if (!modinfo[i].aliases) { |
426 | parse_module(&modinfo[i], modinfo[i].pathname); |
427 | } |
428 | return &modinfo[i]; |
429 | } |
430 | i++; |
431 | } |
432 | |
433 | /* Ok, we definitely have to scan module bodies. This is a good |
434 | * moment to generate modprobe.dep.bb, if it does not exist yet */ |
435 | dep_bb_fd = dep_bb_seen ? -1 : start_dep_bb_writeout(); |
436 | if (dep_bb_fd == -2) /* modprobe.dep.bb appeared? */ |
437 | goto try_again; |
438 | |
439 | /* Scan all module bodies, extract modinfo (it contains aliases) */ |
440 | i = 0; |
441 | result = NULL; |
442 | while (modinfo[i].pathname) { |
443 | char *desc, *s; |
444 | if (!modinfo[i].aliases) { |
445 | parse_module(&modinfo[i], modinfo[i].pathname); |
446 | } |
447 | if (result) { |
448 | i++; |
449 | continue; |
450 | } |
451 | /* "alias1 symbol:sym1 alias2 symbol:sym2" */ |
452 | desc = str_2_list(modinfo[i].aliases); |
453 | /* Does matching substring exist? */ |
454 | for (s = desc; *s; s += strlen(s) + 1) { |
455 | /* Aliases in module bodies can be defined with |
456 | * shell patterns. Example: |
457 | * "pci:v000010DEd000000D9sv*sd*bc*sc*i*". |
458 | * Plain strcmp() won't catch that */ |
459 | if (fnmatch(s, alias, 0) == 0) { |
460 | dbg1_error_msg("found alias '%s' in module '%s'", |
461 | alias, modinfo[i].pathname); |
462 | result = &modinfo[i]; |
463 | break; |
464 | } |
465 | } |
466 | free(desc); |
467 | if (result && dep_bb_fd < 0) |
468 | return result; |
469 | i++; |
470 | } |
471 | |
472 | /* Create module.dep.bb if needed */ |
473 | if (dep_bb_fd >= 0) { |
474 | write_out_dep_bb(dep_bb_fd); |
475 | } |
476 | |
477 | dbg1_error_msg("find_alias '%s' returns %p", alias, result); |
478 | return result; |
479 | } |
480 | |
481 | #if ENABLE_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED |
482 | // TODO: open only once, invent config_rewind() |
483 | static int already_loaded(const char *name) |
484 | { |
485 | int ret = 0; |
486 | char *s; |
487 | parser_t *parser = config_open2("/proc/modules", xfopen_for_read); |
488 | while (config_read(parser, &s, 1, 1, "# \t", PARSE_NORMAL & ~PARSE_GREEDY)) { |
489 | if (strcmp(s, name) == 0) { |
490 | ret = 1; |
491 | break; |
492 | } |
493 | } |
494 | config_close(parser); |
495 | return ret; |
496 | } |
497 | #else |
498 | #define already_loaded(name) is_rmmod |
499 | #endif |
500 | |
501 | /* |
502 | * Given modules definition and module name (or alias, or symbol) |
503 | * load/remove the module respecting dependencies. |
504 | * NB: also called by depmod with bogus name "/", |
505 | * just in order to force modprobe.dep.bb creation. |
506 | */ |
507 | #if !ENABLE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE |
508 | #define process_module(a,b) process_module(a) |
509 | #define cmdline_options "" |
510 | #endif |
511 | static void process_module(char *name, const char *cmdline_options) |
512 | { |
513 | char *s, *deps, *options; |
514 | module_info *info; |
515 | int is_rmmod = (option_mask32 & OPT_r) != 0; |
516 | dbg1_error_msg("process_module('%s','%s')", name, cmdline_options); |
517 | |
518 | replace(name, '-', '_'); |
519 | |
520 | dbg1_error_msg("already_loaded:%d is_rmmod:%d", already_loaded(name), is_rmmod); |
521 | if (already_loaded(name) != is_rmmod) { |
522 | dbg1_error_msg("nothing to do for '%s'", name); |
523 | return; |
524 | } |
525 | |
526 | options = NULL; |
527 | if (!is_rmmod) { |
528 | char *opt_filename = xasprintf("/etc/modules/%s", name); |
529 | options = xmalloc_open_read_close(opt_filename, NULL); |
530 | if (options) |
531 | replace(options, '\n', ' '); |
532 | #if ENABLE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE |
533 | if (cmdline_options) { |
534 | /* NB: cmdline_options always have one leading ' ' |
535 | * (see main()), we remove it here */ |
536 | char *op = xasprintf(options ? "%s %s" : "%s %s" + 3, |
537 | cmdline_options + 1, options); |
538 | free(options); |
539 | options = op; |
540 | } |
541 | #endif |
542 | free(opt_filename); |
543 | module_load_options = options; |
544 | dbg1_error_msg("process_module('%s'): options:'%s'", name, options); |
545 | } |
546 | |
547 | if (!module_count) { |
548 | /* Scan module directory. This is done only once. |
549 | * It will attempt module load, and will exit(EXIT_SUCCESS) |
550 | * on success. */ |
551 | module_found_idx = -1; |
552 | recursive_action(".", |
553 | ACTION_RECURSE, /* flags */ |
554 | fileAction, /* file action */ |
555 | NULL, /* dir action */ |
556 | name, /* user data */ |
557 | 0); /* depth */ |
558 | dbg1_error_msg("dirscan complete"); |
559 | /* Module was not found, or load failed, or is_rmmod */ |
560 | if (module_found_idx >= 0) { /* module was found */ |
561 | info = &modinfo[module_found_idx]; |
562 | } else { /* search for alias, not a plain module name */ |
563 | info = find_alias(name); |
564 | } |
565 | } else { |
566 | info = find_alias(name); |
567 | } |
568 | |
569 | /* rmmod? unload it by name */ |
570 | if (is_rmmod) { |
571 | if (delete_module(name, O_NONBLOCK | O_EXCL) != 0 |
572 | && !(option_mask32 & OPT_q) |
573 | ) { |
574 | bb_perror_msg("remove '%s'", name); |
575 | goto ret; |
576 | } |
577 | /* N.B. we do not stop here - |
578 | * continue to unload modules on which the module depends: |
579 | * "-r --remove: option causes modprobe to remove a module. |
580 | * If the modules it depends on are also unused, modprobe |
581 | * will try to remove them, too." */ |
582 | } |
583 | |
584 | if (!info) { |
585 | /* both dirscan and find_alias found nothing */ |
586 | if (applet_name[0] != 'd') /* it wasn't depmod */ |
587 | bb_error_msg("module '%s' not found", name); |
588 | //TODO: _and_die()? |
589 | goto ret; |
590 | } |
591 | |
592 | /* Iterate thru dependencies, trying to (un)load them */ |
593 | deps = str_2_list(info->deps); |
594 | for (s = deps; *s; s += strlen(s) + 1) { |
595 | //if (strcmp(name, s) != 0) // N.B. do loops exist? |
596 | dbg1_error_msg("recurse on dep '%s'", s); |
597 | process_module(s, NULL); |
598 | dbg1_error_msg("recurse on dep '%s' done", s); |
599 | } |
600 | free(deps); |
601 | |
602 | /* modprobe -> load it */ |
603 | if (!is_rmmod) { |
604 | if (!options || strstr(options, "blacklist") == NULL) { |
605 | errno = 0; |
606 | if (load_module(info->pathname, options) != 0) { |
607 | if (EEXIST != errno) { |
608 | bb_error_msg("'%s': %s", |
609 | info->pathname, |
610 | moderror(errno)); |
611 | } else { |
612 | dbg1_error_msg("'%s': %s", |
613 | info->pathname, |
614 | moderror(errno)); |
615 | } |
616 | } |
617 | } else { |
618 | dbg1_error_msg("'%s': blacklisted", info->pathname); |
619 | } |
620 | } |
621 | ret: |
622 | free(options); |
623 | //TODO: return load attempt result from process_module. |
624 | //If dep didn't load ok, continuing makes little sense. |
625 | } |
626 | #undef cmdline_options |
627 | |
628 | |
629 | /* For reference, module-init-tools v3.4 options: |
630 | |
631 | # insmod |
632 | Usage: insmod filename [args] |
633 | |
634 | # rmmod --help |
635 | Usage: rmmod [-fhswvV] modulename ... |
636 | -f (or --force) forces a module unload, and may crash your |
637 | machine. This requires the Forced Module Removal option |
638 | when the kernel was compiled. |
639 | -h (or --help) prints this help text |
640 | -s (or --syslog) says use syslog, not stderr |
641 | -v (or --verbose) enables more messages |
642 | -V (or --version) prints the version code |
643 | -w (or --wait) begins module removal even if it is used |
644 | and will stop new users from accessing the module (so it |
645 | should eventually fall to zero). |
646 | |
647 | # modprobe |
648 | Usage: modprobe [-v] [-V] [-C config-file] [-n] [-i] [-q] [-b] |
649 | [-o <modname>] [ --dump-modversions ] <modname> [parameters...] |
650 | modprobe -r [-n] [-i] [-v] <modulename> ... |
651 | modprobe -l -t <dirname> [ -a <modulename> ...] |
652 | |
653 | # depmod --help |
654 | depmod 3.4 -- part of module-init-tools |
655 | depmod -[aA] [-n -e -v -q -V -r -u] |
656 | [-b basedirectory] [forced_version] |
657 | depmod [-n -e -v -q -r -u] [-F kernelsyms] module1.ko module2.ko ... |
658 | If no arguments (except options) are given, "depmod -a" is assumed. |
659 | depmod will output a dependancy list suitable for the modprobe utility. |
660 | Options: |
661 | -a, --all Probe all modules |
662 | -A, --quick Only does the work if there's a new module |
663 | -n, --show Write the dependency file on stdout only |
664 | -e, --errsyms Report not supplied symbols |
665 | -V, --version Print the release version |
666 | -v, --verbose Enable verbose mode |
667 | -h, --help Print this usage message |
668 | The following options are useful for people managing distributions: |
669 | -b basedirectory |
670 | --basedir basedirectory |
671 | Use an image of a module tree |
672 | -F kernelsyms |
673 | --filesyms kernelsyms |
674 | Use the file instead of the current kernel symbols |
675 | */ |
676 | |
677 | int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
678 | int modprobe_main(int argc UNUSED_PARAM, char **argv) |
679 | { |
680 | struct utsname uts; |
681 | char applet0 = applet_name[0]; |
682 | USE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(char *options;) |
683 | |
684 | /* are we lsmod? -> just dump /proc/modules */ |
685 | if ('l' == applet0) { |
686 | xprint_and_close_file(xfopen_for_read("/proc/modules")); |
687 | return EXIT_SUCCESS; |
688 | } |
689 | |
690 | INIT_G(); |
691 | |
692 | /* Prevent ugly corner cases with no modules at all */ |
693 | modinfo = xzalloc(sizeof(modinfo[0])); |
694 | |
695 | if ('i' != applet0) { /* not insmod */ |
696 | /* Goto modules directory */ |
697 | xchdir(CONFIG_DEFAULT_MODULES_DIR); |
698 | } |
699 | uname(&uts); /* never fails */ |
700 | |
701 | /* depmod? */ |
702 | if ('d' == applet0) { |
703 | /* Supported: |
704 | * -n: print result to stdout |
705 | * -a: process all modules (default) |
706 | * optional VERSION parameter |
707 | * Ignored: |
708 | * -A: do work only if a module is newer than depfile |
709 | * -e: report any symbols which a module needs |
710 | * which are not supplied by other modules or the kernel |
711 | * -F FILE: System.map (symbols for -e) |
712 | * -q, -r, -u: noop? |
713 | * Not supported: |
714 | * -b BASEDIR: (TODO!) modules are in |
715 | * $BASEDIR/lib/modules/$VERSION |
716 | * -v: human readable deps to stdout |
717 | * -V: version (don't want to support it - people may depend |
718 | * on it as an indicator of "standard" depmod) |
719 | * -h: help (well duh) |
720 | * module1.o module2.o parameters (just ignored for now) |
721 | */ |
722 | getopt32(argv, "na" "AeF:qru" /* "b:vV", NULL */, NULL); |
723 | argv += optind; |
724 | /* if (argv[0] && argv[1]) bb_show_usage(); */ |
725 | /* Goto $VERSION directory */ |
726 | xchdir(argv[0] ? argv[0] : uts.release); |
727 | /* Force full module scan by asking to find a bogus module. |
728 | * This will generate modules.dep.bb as a side effect. */ |
729 | process_module((char*)"/", NULL); |
730 | return !wrote_dep_bb_ok; |
731 | } |
732 | |
733 | /* insmod, modprobe, rmmod require at least one argument */ |
734 | opt_complementary = "-1"; |
735 | /* only -q (quiet) and -r (rmmod), |
736 | * the rest are accepted and ignored (compat) */ |
737 | getopt32(argv, "qrfsvw"); |
738 | argv += optind; |
739 | |
740 | /* are we rmmod? -> simulate modprobe -r */ |
741 | if ('r' == applet0) { |
742 | option_mask32 |= OPT_r; |
743 | } |
744 | |
745 | if ('i' != applet0) { /* not insmod */ |
746 | /* Goto $VERSION directory */ |
747 | xchdir(uts.release); |
748 | } |
749 | |
750 | #if ENABLE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE |
751 | /* If not rmmod, parse possible module options given on command line. |
752 | * insmod/modprobe takes one module name, the rest are parameters. */ |
753 | options = NULL; |
754 | if ('r' != applet0) { |
755 | char **arg = argv; |
756 | while (*++arg) { |
757 | /* Enclose options in quotes */ |
758 | char *s = options; |
759 | options = xasprintf("%s \"%s\"", s ? s : "", *arg); |
760 | free(s); |
761 | *arg = NULL; |
762 | } |
763 | } |
764 | #else |
765 | if ('r' != applet0) |
766 | argv[1] = NULL; |
767 | #endif |
768 | |
769 | if ('i' == applet0) { /* insmod */ |
770 | size_t len; |
771 | void *map; |
772 | |
773 | len = MAXINT(ssize_t); |
774 | map = xmalloc_xopen_read_close(*argv, &len); |
775 | if (init_module(map, len, |
776 | USE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(options ? options : "") |
777 | SKIP_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE("") |
778 | ) != 0) |
779 | bb_error_msg_and_die("cannot insert '%s': %s", |
780 | *argv, moderror(errno)); |
781 | return 0; |
782 | } |
783 | |
784 | /* Try to load modprobe.dep.bb */ |
785 | load_dep_bb(); |
786 | |
787 | /* Load/remove modules. |
788 | * Only rmmod loops here, modprobe has only argv[0] */ |
789 | do { |
790 | process_module(*argv++, options); |
791 | } while (*argv); |
792 | |
793 | if (ENABLE_FEATURE_CLEAN_UP) { |
794 | USE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(free(options);) |
795 | } |
796 | return EXIT_SUCCESS; |
797 | } |