source: MondoRescue/branches/3.3/mindi-busybox/modutils/modprobe-small.c@ 3909

Last change on this file since 3909 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 27.8 KB
Line 
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 source tree.
9 */
10
11//applet:IF_MODPROBE_SMALL(APPLET(modprobe, BB_DIR_SBIN, BB_SUID_DROP))
12//applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(depmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, depmod))
13//applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(insmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, insmod))
14//applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, lsmod))
15//applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(rmmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, rmmod))
16
17#include "libbb.h"
18/* After libbb.h, since it needs sys/types.h on some systems */
19#include <sys/utsname.h> /* uname() */
20#include <fnmatch.h>
21
22extern int init_module(void *module, unsigned long len, const char *options);
23extern int delete_module(const char *module, unsigned flags);
24/* linux/include/linux/module.h has limit of 64 chars on module names */
25#undef MODULE_NAME_LEN
26#define MODULE_NAME_LEN 64
27
28
29#if 1
30# define dbg1_error_msg(...) ((void)0)
31# define dbg2_error_msg(...) ((void)0)
32#else
33# define dbg1_error_msg(...) bb_error_msg(__VA_ARGS__)
34# define dbg2_error_msg(...) bb_error_msg(__VA_ARGS__)
35#endif
36
37#define DEPFILE_BB CONFIG_DEFAULT_DEPMOD_FILE".bb"
38
39enum {
40 OPT_q = (1 << 0), /* be quiet */
41 OPT_r = (1 << 1), /* module removal instead of loading */
42};
43
44typedef struct module_info {
45 char *pathname;
46 char *aliases;
47 char *deps;
48 smallint open_read_failed;
49} module_info;
50
51/*
52 * GLOBALS
53 */
54struct globals {
55 module_info *modinfo;
56 char *module_load_options;
57 smallint dep_bb_seen;
58 smallint wrote_dep_bb_ok;
59 unsigned module_count;
60 int module_found_idx;
61 unsigned stringbuf_idx;
62 unsigned stringbuf_size;
63 char *stringbuf; /* some modules have lots of stuff */
64 /* for example, drivers/media/video/saa7134/saa7134.ko */
65 /* therefore having a fixed biggish buffer is not wise */
66};
67#define G (*ptr_to_globals)
68#define modinfo (G.modinfo )
69#define dep_bb_seen (G.dep_bb_seen )
70#define wrote_dep_bb_ok (G.wrote_dep_bb_ok )
71#define module_count (G.module_count )
72#define module_found_idx (G.module_found_idx )
73#define module_load_options (G.module_load_options)
74#define stringbuf_idx (G.stringbuf_idx )
75#define stringbuf_size (G.stringbuf_size )
76#define stringbuf (G.stringbuf )
77#define INIT_G() do { \
78 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
79} while (0)
80
81static void append(const char *s)
82{
83 unsigned len = strlen(s);
84 if (stringbuf_idx + len + 15 > stringbuf_size) {
85 stringbuf_size = stringbuf_idx + len + 127;
86 dbg2_error_msg("grow stringbuf to %u", stringbuf_size);
87 stringbuf = xrealloc(stringbuf, stringbuf_size);
88 }
89 memcpy(stringbuf + stringbuf_idx, s, len);
90 stringbuf_idx += len;
91}
92
93static void appendc(char c)
94{
95 /* We appendc() only after append(), + 15 trick in append()
96 * makes it unnecessary to check for overflow here */
97 stringbuf[stringbuf_idx++] = c;
98}
99
100static void bksp(void)
101{
102 if (stringbuf_idx)
103 stringbuf_idx--;
104}
105
106static void reset_stringbuf(void)
107{
108 stringbuf_idx = 0;
109}
110
111static char* copy_stringbuf(void)
112{
113 char *copy = xzalloc(stringbuf_idx + 1); /* terminating NUL */
114 return memcpy(copy, stringbuf, stringbuf_idx);
115}
116
117static char* find_keyword(char *ptr, size_t len, const char *word)
118{
119 if (!ptr) /* happens if xmalloc_open_zipped_read_close cannot read it */
120 return NULL;
121
122 len -= strlen(word) - 1;
123 while ((ssize_t)len > 0) {
124 char *old = ptr;
125 char *after_word;
126
127 /* search for the first char in word */
128 ptr = memchr(ptr, word[0], len);
129 if (ptr == NULL) /* no occurance left, done */
130 break;
131 after_word = is_prefixed_with(ptr, word);
132 if (after_word)
133 return after_word; /* found, return ptr past it */
134 ++ptr;
135 len -= (ptr - old);
136 }
137 return NULL;
138}
139
140static void replace(char *s, char what, char with)
141{
142 while (*s) {
143 if (what == *s)
144 *s = with;
145 ++s;
146 }
147}
148
149static char *filename2modname(const char *filename, char *modname)
150{
151 int i;
152 const char *from;
153
154 // Disabled since otherwise "modprobe dir/name" would work
155 // as if it is "modprobe name". It is unclear why
156 // 'basenamization' was here in the first place.
157 //from = bb_get_last_path_component_nostrip(filename);
158 from = filename;
159 for (i = 0; i < (MODULE_NAME_LEN-1) && from[i] != '\0' && from[i] != '.'; i++)
160 modname[i] = (from[i] == '-') ? '_' : from[i];
161 modname[i] = '\0';
162
163 return modname;
164}
165
166static int pathname_matches_modname(const char *pathname, const char *modname)
167{
168 int r;
169 char name[MODULE_NAME_LEN];
170 filename2modname(bb_get_last_path_component_nostrip(pathname), name);
171 r = (strcmp(name, modname) == 0);
172 return r;
173}
174
175/* Take "word word", return malloced "word",NUL,"word",NUL,NUL */
176static char* str_2_list(const char *str)
177{
178 int len = strlen(str) + 1;
179 char *dst = xmalloc(len + 1);
180
181 dst[len] = '\0';
182 memcpy(dst, str, len);
183//TODO: protect against 2+ spaces: "word word"
184 replace(dst, ' ', '\0');
185 return dst;
186}
187
188/* We use error numbers in a loose translation... */
189static const char *moderror(int err)
190{
191 switch (err) {
192 case ENOEXEC:
193 return "invalid module format";
194 case ENOENT:
195 return "unknown symbol in module or invalid parameter";
196 case ESRCH:
197 return "module has wrong symbol version";
198 case EINVAL: /* "invalid parameter" */
199 return "unknown symbol in module or invalid parameter"
200 + sizeof("unknown symbol in module or");
201 default:
202 return strerror(err);
203 }
204}
205
206static int load_module(const char *fname, const char *options)
207{
208#if 1
209 int r;
210 size_t len = MAXINT(ssize_t);
211 char *module_image;
212 dbg1_error_msg("load_module('%s','%s')", fname, options);
213
214 module_image = xmalloc_open_zipped_read_close(fname, &len);
215 r = (!module_image || init_module(module_image, len, options ? options : "") != 0);
216 free(module_image);
217 dbg1_error_msg("load_module:%d", r);
218 return r; /* 0 = success */
219#else
220 /* For testing */
221 dbg1_error_msg("load_module('%s','%s')", fname, options);
222 return 1;
223#endif
224}
225
226/* Returns !0 if open/read was unsuccessful */
227static int parse_module(module_info *info, const char *pathname)
228{
229 char *module_image;
230 char *ptr;
231 size_t len;
232 size_t pos;
233 dbg1_error_msg("parse_module('%s')", pathname);
234
235 /* Read (possibly compressed) module */
236 errno = 0;
237 len = 64 * 1024 * 1024; /* 64 Mb at most */
238 module_image = xmalloc_open_zipped_read_close(pathname, &len);
239 /* module_image == NULL is ok here, find_keyword handles it */
240//TODO: optimize redundant module body reads
241
242 /* "alias1 symbol:sym1 alias2 symbol:sym2" */
243 reset_stringbuf();
244 pos = 0;
245 while (1) {
246 unsigned start = stringbuf_idx;
247 ptr = find_keyword(module_image + pos, len - pos, "alias=");
248 if (!ptr) {
249 ptr = find_keyword(module_image + pos, len - pos, "__ksymtab_");
250 if (!ptr)
251 break;
252 /* DOCME: __ksymtab_gpl and __ksymtab_strings occur
253 * in many modules. What do they mean? */
254 if (strcmp(ptr, "gpl") == 0 || strcmp(ptr, "strings") == 0)
255 goto skip;
256 dbg2_error_msg("alias:'symbol:%s'", ptr);
257 append("symbol:");
258 } else {
259 dbg2_error_msg("alias:'%s'", ptr);
260 }
261 append(ptr);
262 appendc(' ');
263 /*
264 * Don't add redundant aliases, such as:
265 * libcrc32c.ko symbol:crc32c symbol:crc32c
266 */
267 if (start) { /* "if we aren't the first alias" */
268 char *found, *last;
269 stringbuf[stringbuf_idx] = '\0';
270 last = stringbuf + start;
271 /*
272 * String at last-1 is " symbol:crc32c "
273 * (with both leading and trailing spaces).
274 */
275 if (strncmp(stringbuf, last, stringbuf_idx - start) == 0)
276 /* First alias matches us */
277 found = stringbuf;
278 else
279 /* Does any other alias match? */
280 found = strstr(stringbuf, last-1);
281 if (found < last-1) {
282 /* There is absolutely the same string before us */
283 dbg2_error_msg("redundant:'%s'", last);
284 stringbuf_idx = start;
285 goto skip;
286 }
287 }
288 skip:
289 pos = (ptr - module_image);
290 }
291 bksp(); /* remove last ' ' */
292 info->aliases = copy_stringbuf();
293 replace(info->aliases, '-', '_');
294
295 /* "dependency1 depandency2" */
296 reset_stringbuf();
297 ptr = find_keyword(module_image, len, "depends=");
298 if (ptr && *ptr) {
299 replace(ptr, ',', ' ');
300 replace(ptr, '-', '_');
301 dbg2_error_msg("dep:'%s'", ptr);
302 append(ptr);
303 }
304 free(module_image);
305 info->deps = copy_stringbuf();
306
307 info->open_read_failed = (module_image == NULL);
308 return info->open_read_failed;
309}
310
311static FAST_FUNC int fileAction(const char *pathname,
312 struct stat *sb UNUSED_PARAM,
313 void *modname_to_match,
314 int depth UNUSED_PARAM)
315{
316 int cur;
317 const char *fname;
318
319 pathname += 2; /* skip "./" */
320 fname = bb_get_last_path_component_nostrip(pathname);
321 if (!strrstr(fname, ".ko")) {
322 dbg1_error_msg("'%s' is not a module", pathname);
323 return TRUE; /* not a module, continue search */
324 }
325
326 cur = module_count++;
327 modinfo = xrealloc_vector(modinfo, 12, cur);
328 modinfo[cur].pathname = xstrdup(pathname);
329 /*modinfo[cur].aliases = NULL; - xrealloc_vector did it */
330 /*modinfo[cur+1].pathname = NULL;*/
331
332 if (!pathname_matches_modname(fname, modname_to_match)) {
333 dbg1_error_msg("'%s' module name doesn't match", pathname);
334 return TRUE; /* module name doesn't match, continue search */
335 }
336
337 dbg1_error_msg("'%s' module name matches", pathname);
338 module_found_idx = cur;
339 if (parse_module(&modinfo[cur], pathname) != 0)
340 return TRUE; /* failed to open/read it, no point in trying loading */
341
342 if (!(option_mask32 & OPT_r)) {
343 if (load_module(pathname, module_load_options) == 0) {
344 /* Load was successful, there is nothing else to do.
345 * This can happen ONLY for "top-level" module load,
346 * not a dep, because deps dont do dirscan. */
347 exit(EXIT_SUCCESS);
348 }
349 }
350
351 return TRUE;
352}
353
354static int load_dep_bb(void)
355{
356 char *line;
357 FILE *fp = fopen_for_read(DEPFILE_BB);
358
359 if (!fp)
360 return 0;
361
362 dep_bb_seen = 1;
363 dbg1_error_msg("loading "DEPFILE_BB);
364
365 /* Why? There is a rare scenario: we did not find modprobe.dep.bb,
366 * we scanned the dir and found no module by name, then we search
367 * for alias (full scan), and we decided to generate modprobe.dep.bb.
368 * But we see modprobe.dep.bb.new! Other modprobe is at work!
369 * We wait and other modprobe renames it to modprobe.dep.bb.
370 * Now we can use it.
371 * But we already have modinfo[] filled, and "module_count = 0"
372 * makes us start anew. Yes, we leak modinfo[].xxx pointers -
373 * there is not much of data there anyway. */
374 module_count = 0;
375 memset(&modinfo[0], 0, sizeof(modinfo[0]));
376
377 while ((line = xmalloc_fgetline(fp)) != NULL) {
378 char* space;
379 char* linebuf;
380 int cur;
381
382 if (!line[0]) {
383 free(line);
384 continue;
385 }
386 space = strchrnul(line, ' ');
387 cur = module_count++;
388 modinfo = xrealloc_vector(modinfo, 12, cur);
389 /*modinfo[cur+1].pathname = NULL; - xrealloc_vector did it */
390 modinfo[cur].pathname = line; /* we take ownership of malloced block here */
391 if (*space)
392 *space++ = '\0';
393 modinfo[cur].aliases = space;
394 linebuf = xmalloc_fgetline(fp);
395 modinfo[cur].deps = linebuf ? linebuf : xzalloc(1);
396 if (modinfo[cur].deps[0]) {
397 /* deps are not "", so next line must be empty */
398 line = xmalloc_fgetline(fp);
399 /* Refuse to work with damaged config file */
400 if (line && line[0])
401 bb_error_msg_and_die("error in %s at '%s'", DEPFILE_BB, line);
402 free(line);
403 }
404 }
405 return 1;
406}
407
408static int start_dep_bb_writeout(void)
409{
410 int fd;
411
412 /* depmod -n: write result to stdout */
413 if (applet_name[0] == 'd' && (option_mask32 & 1))
414 return STDOUT_FILENO;
415
416 fd = open(DEPFILE_BB".new", O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0644);
417 if (fd < 0) {
418 if (errno == EEXIST) {
419 int count = 5 * 20;
420 dbg1_error_msg(DEPFILE_BB".new exists, waiting for "DEPFILE_BB);
421 while (1) {
422 usleep(1000*1000 / 20);
423 if (load_dep_bb()) {
424 dbg1_error_msg(DEPFILE_BB" appeared");
425 return -2; /* magic number */
426 }
427 if (!--count)
428 break;
429 }
430 bb_error_msg("deleting stale %s", DEPFILE_BB".new");
431 fd = open_or_warn(DEPFILE_BB".new", O_WRONLY | O_CREAT | O_TRUNC);
432 }
433 }
434 dbg1_error_msg("opened "DEPFILE_BB".new:%d", fd);
435 return fd;
436}
437
438static void write_out_dep_bb(int fd)
439{
440 int i;
441 FILE *fp;
442
443 /* We want good error reporting. fdprintf is not good enough. */
444 fp = xfdopen_for_write(fd);
445 i = 0;
446 while (modinfo[i].pathname) {
447 fprintf(fp, "%s%s%s\n" "%s%s\n",
448 modinfo[i].pathname, modinfo[i].aliases[0] ? " " : "", modinfo[i].aliases,
449 modinfo[i].deps, modinfo[i].deps[0] ? "\n" : "");
450 i++;
451 }
452 /* Badly formatted depfile is a no-no. Be paranoid. */
453 errno = 0;
454 if (ferror(fp) | fclose(fp)) /* | instead of || is intended */
455 goto err;
456
457 if (fd == STDOUT_FILENO) /* it was depmod -n */
458 goto ok;
459
460 if (rename(DEPFILE_BB".new", DEPFILE_BB) != 0) {
461 err:
462 bb_perror_msg("can't create '%s'", DEPFILE_BB);
463 unlink(DEPFILE_BB".new");
464 } else {
465 ok:
466 wrote_dep_bb_ok = 1;
467 dbg1_error_msg("created "DEPFILE_BB);
468 }
469}
470
471static module_info** find_alias(const char *alias)
472{
473 int i;
474 int dep_bb_fd;
475 int infoidx;
476 module_info **infovec;
477 dbg1_error_msg("find_alias('%s')", alias);
478
479 try_again:
480 /* First try to find by name (cheaper) */
481 i = 0;
482 while (modinfo[i].pathname) {
483 if (pathname_matches_modname(modinfo[i].pathname, alias)) {
484 dbg1_error_msg("found '%s' in module '%s'",
485 alias, modinfo[i].pathname);
486 if (!modinfo[i].aliases) {
487 parse_module(&modinfo[i], modinfo[i].pathname);
488 }
489 infovec = xzalloc(2 * sizeof(infovec[0]));
490 infovec[0] = &modinfo[i];
491 return infovec;
492 }
493 i++;
494 }
495
496 /* Ok, we definitely have to scan module bodies. This is a good
497 * moment to generate modprobe.dep.bb, if it does not exist yet */
498 dep_bb_fd = dep_bb_seen ? -1 : start_dep_bb_writeout();
499 if (dep_bb_fd == -2) /* modprobe.dep.bb appeared? */
500 goto try_again;
501
502 /* Scan all module bodies, extract modinfo (it contains aliases) */
503 i = 0;
504 infoidx = 0;
505 infovec = NULL;
506 while (modinfo[i].pathname) {
507 char *desc, *s;
508 if (!modinfo[i].aliases) {
509 parse_module(&modinfo[i], modinfo[i].pathname);
510 }
511 /* "alias1 symbol:sym1 alias2 symbol:sym2" */
512 desc = str_2_list(modinfo[i].aliases);
513 /* Does matching substring exist? */
514 for (s = desc; *s; s += strlen(s) + 1) {
515 /* Aliases in module bodies can be defined with
516 * shell patterns. Example:
517 * "pci:v000010DEd000000D9sv*sd*bc*sc*i*".
518 * Plain strcmp() won't catch that */
519 if (fnmatch(s, alias, 0) == 0) {
520 dbg1_error_msg("found alias '%s' in module '%s'",
521 alias, modinfo[i].pathname);
522 infovec = xrealloc_vector(infovec, 1, infoidx);
523 infovec[infoidx++] = &modinfo[i];
524 break;
525 }
526 }
527 free(desc);
528 i++;
529 }
530
531 /* Create module.dep.bb if needed */
532 if (dep_bb_fd >= 0) {
533 write_out_dep_bb(dep_bb_fd);
534 }
535
536 dbg1_error_msg("find_alias '%s' returns %d results", alias, infoidx);
537 return infovec;
538}
539
540#if ENABLE_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED
541// TODO: open only once, invent config_rewind()
542static int already_loaded(const char *name)
543{
544 int ret;
545 char *line;
546 FILE *fp;
547
548 ret = 5 * 2;
549 again:
550 fp = fopen_for_read("/proc/modules");
551 if (!fp)
552 return 0;
553 while ((line = xmalloc_fgetline(fp)) != NULL) {
554 char *live;
555 char *after_name;
556
557 // Examples from kernel 3.14.6:
558 //pcspkr 12718 0 - Live 0xffffffffa017e000
559 //snd_timer 28690 2 snd_seq,snd_pcm, Live 0xffffffffa025e000
560 //i915 801405 2 - Live 0xffffffffa0096000
561 after_name = is_prefixed_with(line, name);
562 if (!after_name || *after_name != ' ') {
563 free(line);
564 continue;
565 }
566 live = strstr(line, " Live");
567 free(line);
568 if (!live) {
569 /* State can be Unloading, Loading, or Live.
570 * modprobe must not return prematurely if we see "Loading":
571 * it can cause further programs to assume load completed,
572 * but it did not (yet)!
573 * Wait up to 5*20 ms for it to resolve.
574 */
575 ret -= 2;
576 if (ret == 0)
577 break; /* huh? report as "not loaded" */
578 fclose(fp);
579 usleep(20*1000);
580 goto again;
581 }
582 ret = 1;
583 break;
584 }
585 fclose(fp);
586
587 return ret & 1;
588}
589#else
590#define already_loaded(name) 0
591#endif
592
593static int rmmod(const char *filename)
594{
595 int r;
596 char modname[MODULE_NAME_LEN];
597
598 filename2modname(filename, modname);
599 r = delete_module(modname, O_NONBLOCK | O_EXCL);
600 dbg1_error_msg("delete_module('%s', O_NONBLOCK | O_EXCL):%d", modname, r);
601 if (r != 0 && !(option_mask32 & OPT_q)) {
602 bb_perror_msg("remove '%s'", modname);
603 }
604 return r;
605}
606
607/*
608 * Given modules definition and module name (or alias, or symbol)
609 * load/remove the module respecting dependencies.
610 * NB: also called by depmod with bogus name "/",
611 * just in order to force modprobe.dep.bb creation.
612*/
613#if !ENABLE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE
614#define process_module(a,b) process_module(a)
615#define cmdline_options ""
616#endif
617static int process_module(char *name, const char *cmdline_options)
618{
619 char *s, *deps, *options;
620 module_info **infovec;
621 module_info *info;
622 int infoidx;
623 int is_remove = (option_mask32 & OPT_r) != 0;
624 int exitcode = EXIT_SUCCESS;
625
626 dbg1_error_msg("process_module('%s','%s')", name, cmdline_options);
627
628 replace(name, '-', '_');
629
630 dbg1_error_msg("already_loaded:%d is_remove:%d", already_loaded(name), is_remove);
631
632 if (applet_name[0] == 'r') {
633 /* rmmod.
634 * Does not remove dependencies, no need to scan, just remove.
635 * (compat note: this allows and strips .ko suffix)
636 */
637 rmmod(name);
638 return EXIT_SUCCESS;
639 }
640
641 /*
642 * We used to have "is_remove != already_loaded(name)" check here, but
643 * modprobe -r pci:v00008086d00007010sv00000000sd00000000bc01sc01i80
644 * won't unload modules (there are more than one)
645 * which have this alias.
646 */
647 if (!is_remove && already_loaded(name)) {
648 dbg1_error_msg("nothing to do for '%s'", name);
649 return EXIT_SUCCESS;
650 }
651
652 options = NULL;
653 if (!is_remove) {
654 char *opt_filename = xasprintf("/etc/modules/%s", name);
655 options = xmalloc_open_read_close(opt_filename, NULL);
656 if (options)
657 replace(options, '\n', ' ');
658#if ENABLE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE
659 if (cmdline_options) {
660 /* NB: cmdline_options always have one leading ' '
661 * (see main()), we remove it here */
662 char *op = xasprintf(options ? "%s %s" : "%s %s" + 3,
663 cmdline_options + 1, options);
664 free(options);
665 options = op;
666 }
667#endif
668 free(opt_filename);
669 module_load_options = options;
670 dbg1_error_msg("process_module('%s'): options:'%s'", name, options);
671 }
672
673 if (!module_count) {
674 /* Scan module directory. This is done only once.
675 * It will attempt module load, and will exit(EXIT_SUCCESS)
676 * on success.
677 */
678 module_found_idx = -1;
679 recursive_action(".",
680 ACTION_RECURSE, /* flags */
681 fileAction, /* file action */
682 NULL, /* dir action */
683 name, /* user data */
684 0 /* depth */
685 );
686 dbg1_error_msg("dirscan complete");
687 /* Module was not found, or load failed, or is_remove */
688 if (module_found_idx >= 0) { /* module was found */
689 infovec = xzalloc(2 * sizeof(infovec[0]));
690 infovec[0] = &modinfo[module_found_idx];
691 } else { /* search for alias, not a plain module name */
692 infovec = find_alias(name);
693 }
694 } else {
695 infovec = find_alias(name);
696 }
697
698 if (!infovec) {
699 /* both dirscan and find_alias found nothing */
700 if (!is_remove && applet_name[0] != 'd') /* it wasn't rmmod or depmod */
701 bb_error_msg("module '%s' not found", name);
702//TODO: _and_die()? or should we continue (un)loading modules listed on cmdline?
703 goto ret;
704 }
705
706 /* There can be more than one module for the given alias. For example,
707 * "pci:v00008086d00007010sv00000000sd00000000bc01sc01i80" matches
708 * ata_piix because it has alias "pci:v00008086d00007010sv*sd*bc*sc*i*"
709 * and ata_generic, it has alias "pci:v*d*sv*sd*bc01sc01i*"
710 * Standard modprobe loads them both. We achieve it by returning
711 * a *list* of modinfo pointers from find_alias().
712 */
713
714 /* modprobe -r? unload module(s) */
715 if (is_remove) {
716 infoidx = 0;
717 while ((info = infovec[infoidx++]) != NULL) {
718 int r = rmmod(bb_get_last_path_component_nostrip(info->pathname));
719 if (r != 0) {
720 goto ret; /* error */
721 }
722 }
723 /* modprobe -r: we do not stop here -
724 * continue to unload modules on which the module depends:
725 * "-r --remove: option causes modprobe to remove a module.
726 * If the modules it depends on are also unused, modprobe
727 * will try to remove them, too."
728 */
729 }
730
731 infoidx = 0;
732 while ((info = infovec[infoidx++]) != NULL) {
733 /* Iterate thru dependencies, trying to (un)load them */
734 deps = str_2_list(info->deps);
735 for (s = deps; *s; s += strlen(s) + 1) {
736 //if (strcmp(name, s) != 0) // N.B. do loops exist?
737 dbg1_error_msg("recurse on dep '%s'", s);
738 process_module(s, NULL);
739 dbg1_error_msg("recurse on dep '%s' done", s);
740 }
741 free(deps);
742
743 if (is_remove)
744 continue;
745
746 /* We are modprobe: load it */
747 if (options && strstr(options, "blacklist")) {
748 dbg1_error_msg("'%s': blacklisted", info->pathname);
749 continue;
750 }
751 if (info->open_read_failed) {
752 /* We already tried it, didn't work. Don't try load again */
753 exitcode = EXIT_FAILURE;
754 continue;
755 }
756 errno = 0;
757 if (load_module(info->pathname, options) != 0) {
758 if (EEXIST != errno) {
759 bb_error_msg("'%s': %s",
760 info->pathname,
761 moderror(errno));
762 } else {
763 dbg1_error_msg("'%s': %s",
764 info->pathname,
765 moderror(errno));
766 }
767 exitcode = EXIT_FAILURE;
768 }
769 }
770 ret:
771 free(infovec);
772 free(options);
773
774 return exitcode;
775}
776#undef cmdline_options
777
778
779/* For reference, module-init-tools v3.4 options:
780
781# insmod
782Usage: insmod filename [args]
783
784# rmmod --help
785Usage: rmmod [-fhswvV] modulename ...
786 -f (or --force) forces a module unload, and may crash your
787 machine. This requires the Forced Module Removal option
788 when the kernel was compiled.
789 -h (or --help) prints this help text
790 -s (or --syslog) says use syslog, not stderr
791 -v (or --verbose) enables more messages
792 -V (or --version) prints the version code
793 -w (or --wait) begins module removal even if it is used
794 and will stop new users from accessing the module (so it
795 should eventually fall to zero).
796
797# modprobe
798Usage: modprobe [-v] [-V] [-C config-file] [-n] [-i] [-q] [-b]
799 [-o <modname>] [ --dump-modversions ] <modname> [parameters...]
800modprobe -r [-n] [-i] [-v] <modulename> ...
801modprobe -l -t <dirname> [ -a <modulename> ...]
802
803# depmod --help
804depmod 3.4 -- part of module-init-tools
805depmod -[aA] [-n -e -v -q -V -r -u]
806 [-b basedirectory] [forced_version]
807depmod [-n -e -v -q -r -u] [-F kernelsyms] module1.ko module2.ko ...
808If no arguments (except options) are given, "depmod -a" is assumed.
809depmod will output a dependency list suitable for the modprobe utility.
810Options:
811 -a, --all Probe all modules
812 -A, --quick Only does the work if there's a new module
813 -n, --show Write the dependency file on stdout only
814 -e, --errsyms Report not supplied symbols
815 -V, --version Print the release version
816 -v, --verbose Enable verbose mode
817 -h, --help Print this usage message
818The following options are useful for people managing distributions:
819 -b basedirectory
820 --basedir basedirectory
821 Use an image of a module tree
822 -F kernelsyms
823 --filesyms kernelsyms
824 Use the file instead of the current kernel symbols
825*/
826
827//usage:#if ENABLE_MODPROBE_SMALL
828
829//usage:#define depmod_trivial_usage NOUSAGE_STR
830//usage:#define depmod_full_usage ""
831
832//usage:#define lsmod_trivial_usage
833//usage: ""
834//usage:#define lsmod_full_usage "\n\n"
835//usage: "List the currently loaded kernel modules"
836
837//usage:#define insmod_trivial_usage
838//usage: IF_FEATURE_2_4_MODULES("[OPTIONS] MODULE ")
839//usage: IF_NOT_FEATURE_2_4_MODULES("FILE ")
840//usage: "[SYMBOL=VALUE]..."
841//usage:#define insmod_full_usage "\n\n"
842//usage: "Load kernel module"
843//usage: IF_FEATURE_2_4_MODULES( "\n"
844//usage: "\n -f Force module to load into the wrong kernel version"
845//usage: "\n -k Make module autoclean-able"
846//usage: "\n -v Verbose"
847//usage: "\n -q Quiet"
848//usage: "\n -L Lock: prevent simultaneous loads"
849//usage: IF_FEATURE_INSMOD_LOAD_MAP(
850//usage: "\n -m Output load map to stdout"
851//usage: )
852//usage: "\n -x Don't export externs"
853//usage: )
854
855//usage:#define rmmod_trivial_usage
856//usage: "[-wfa] [MODULE]..."
857//usage:#define rmmod_full_usage "\n\n"
858//usage: "Unload kernel modules\n"
859//usage: "\n -w Wait until the module is no longer used"
860//usage: "\n -f Force unload"
861//usage: "\n -a Remove all unused modules (recursively)"
862//usage:
863//usage:#define rmmod_example_usage
864//usage: "$ rmmod tulip\n"
865
866//usage:#define modprobe_trivial_usage
867//usage: "[-qfwrsv] MODULE [SYMBOL=VALUE]..."
868//usage:#define modprobe_full_usage "\n\n"
869//usage: " -r Remove MODULE (stacks) or do autoclean"
870//usage: "\n -q Quiet"
871//usage: "\n -v Verbose"
872//usage: "\n -f Force"
873//usage: "\n -w Wait for unload"
874//usage: "\n -s Report via syslog instead of stderr"
875
876//usage:#endif
877
878int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
879int modprobe_main(int argc UNUSED_PARAM, char **argv)
880{
881 int exitcode;
882 struct utsname uts;
883 char applet0 = applet_name[0];
884 IF_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(char *options;)
885
886 /* are we lsmod? -> just dump /proc/modules */
887 if ('l' == applet0) {
888 xprint_and_close_file(xfopen_for_read("/proc/modules"));
889 return EXIT_SUCCESS;
890 }
891
892 INIT_G();
893
894 /* Prevent ugly corner cases with no modules at all */
895 modinfo = xzalloc(sizeof(modinfo[0]));
896
897 if ('i' != applet0) { /* not insmod */
898 /* Goto modules directory */
899 xchdir(CONFIG_DEFAULT_MODULES_DIR);
900 }
901 uname(&uts); /* never fails */
902
903 /* depmod? */
904 if ('d' == applet0) {
905 /* Supported:
906 * -n: print result to stdout
907 * -a: process all modules (default)
908 * optional VERSION parameter
909 * Ignored:
910 * -A: do work only if a module is newer than depfile
911 * -e: report any symbols which a module needs
912 * which are not supplied by other modules or the kernel
913 * -F FILE: System.map (symbols for -e)
914 * -q, -r, -u: noop?
915 * Not supported:
916 * -b BASEDIR: (TODO!) modules are in
917 * $BASEDIR/lib/modules/$VERSION
918 * -v: human readable deps to stdout
919 * -V: version (don't want to support it - people may depend
920 * on it as an indicator of "standard" depmod)
921 * -h: help (well duh)
922 * module1.o module2.o parameters (just ignored for now)
923 */
924 getopt32(argv, "na" "AeF:qru" /* "b:vV", NULL */, NULL);
925 argv += optind;
926 /* if (argv[0] && argv[1]) bb_show_usage(); */
927 /* Goto $VERSION directory */
928 xchdir(argv[0] ? argv[0] : uts.release);
929 /* Force full module scan by asking to find a bogus module.
930 * This will generate modules.dep.bb as a side effect. */
931 process_module((char*)"/", NULL);
932 return !wrote_dep_bb_ok;
933 }
934
935 /* insmod, modprobe, rmmod require at least one argument */
936 opt_complementary = "-1";
937 /* only -q (quiet) and -r (rmmod),
938 * the rest are accepted and ignored (compat) */
939 getopt32(argv, "qrfsvwb");
940 argv += optind;
941
942 /* are we rmmod? -> simulate modprobe -r */
943 if ('r' == applet0) {
944 option_mask32 |= OPT_r;
945 }
946
947 if ('i' != applet0) { /* not insmod */
948 /* Goto $VERSION directory */
949 xchdir(uts.release);
950 }
951
952#if ENABLE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE
953 /* If not rmmod/-r, parse possible module options given on command line.
954 * insmod/modprobe takes one module name, the rest are parameters. */
955 options = NULL;
956 if (!(option_mask32 & OPT_r)) {
957 char **arg = argv;
958 while (*++arg) {
959 /* Enclose options in quotes */
960 char *s = options;
961 options = xasprintf("%s \"%s\"", s ? s : "", *arg);
962 free(s);
963 *arg = NULL;
964 }
965 }
966#else
967 if (!(option_mask32 & OPT_r))
968 argv[1] = NULL;
969#endif
970
971 if ('i' == applet0) { /* insmod */
972 size_t len;
973 void *map;
974
975 len = MAXINT(ssize_t);
976 map = xmalloc_open_zipped_read_close(*argv, &len);
977 if (!map)
978 bb_perror_msg_and_die("can't read '%s'", *argv);
979 if (init_module(map, len,
980 IF_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(options ? options : "")
981 IF_NOT_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE("")
982 ) != 0
983 ) {
984 bb_error_msg_and_die("can't insert '%s': %s",
985 *argv, moderror(errno));
986 }
987 return EXIT_SUCCESS;
988 }
989
990 /* Try to load modprobe.dep.bb */
991 if ('r' != applet0) { /* not rmmod */
992 load_dep_bb();
993 }
994
995 /* Load/remove modules.
996 * Only rmmod/modprobe -r loops here, insmod/modprobe has only argv[0] */
997 exitcode = EXIT_SUCCESS;
998 do {
999 exitcode |= process_module(*argv, options);
1000 } while (*++argv);
1001
1002 if (ENABLE_FEATURE_CLEAN_UP) {
1003 IF_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(free(options);)
1004 }
1005 return exitcode;
1006}
Note: See TracBrowser for help on using the repository browser.