aboutsummaryrefslogtreecommitdiff
path: root/modutils/modprobe-small.c
diff options
context:
space:
mode:
Diffstat (limited to 'modutils/modprobe-small.c')
-rw-r--r--modutils/modprobe-small.c182
1 files changed, 114 insertions, 68 deletions
diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c
index b7990bff1..9c941064b 100644
--- a/modutils/modprobe-small.c
+++ b/modutils/modprobe-small.c
@@ -116,21 +116,21 @@ static char* copy_stringbuf(void)
116 116
117static char* find_keyword(char *ptr, size_t len, const char *word) 117static char* find_keyword(char *ptr, size_t len, const char *word)
118{ 118{
119 int wlen;
120
121 if (!ptr) /* happens if xmalloc_open_zipped_read_close cannot read it */ 119 if (!ptr) /* happens if xmalloc_open_zipped_read_close cannot read it */
122 return NULL; 120 return NULL;
123 121
124 wlen = strlen(word); 122 len -= strlen(word) - 1;
125 len -= wlen - 1;
126 while ((ssize_t)len > 0) { 123 while ((ssize_t)len > 0) {
127 char *old = ptr; 124 char *old = ptr;
125 char *after_word;
126
128 /* search for the first char in word */ 127 /* search for the first char in word */
129 ptr = memchr(ptr, *word, len); 128 ptr = memchr(ptr, word[0], len);
130 if (ptr == NULL) /* no occurance left, done */ 129 if (ptr == NULL) /* no occurance left, done */
131 break; 130 break;
132 if (strncmp(ptr, word, wlen) == 0) 131 after_word = is_prefixed_with(ptr, word);
133 return ptr + wlen; /* found, return ptr past it */ 132 if (after_word)
133 return after_word; /* found, return ptr past it */
134 ++ptr; 134 ++ptr;
135 len -= (ptr - old); 135 len -= (ptr - old);
136 } 136 }
@@ -149,9 +149,13 @@ static void replace(char *s, char what, char with)
149static char *filename2modname(const char *filename, char *modname) 149static char *filename2modname(const char *filename, char *modname)
150{ 150{
151 int i; 151 int i;
152 char *from; 152 const char *from;
153 153
154 from = bb_get_last_path_component_nostrip(filename); 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;
155 for (i = 0; i < (MODULE_NAME_LEN-1) && from[i] != '\0' && from[i] != '.'; i++) 159 for (i = 0; i < (MODULE_NAME_LEN-1) && from[i] != '\0' && from[i] != '.'; i++)
156 modname[i] = (from[i] == '-') ? '_' : from[i]; 160 modname[i] = (from[i] == '-') ? '_' : from[i];
157 modname[i] = '\0'; 161 modname[i] = '\0';
@@ -159,6 +163,15 @@ static char *filename2modname(const char *filename, char *modname)
159 return modname; 163 return modname;
160} 164}
161 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
162/* Take "word word", return malloced "word",NUL,"word",NUL,NUL */ 175/* Take "word word", return malloced "word",NUL,"word",NUL,NUL */
163static char* str_2_list(const char *str) 176static char* str_2_list(const char *str)
164{ 177{
@@ -291,18 +304,6 @@ static void parse_module(module_info *info, const char *pathname)
291 free(module_image); 304 free(module_image);
292} 305}
293 306
294static int pathname_matches_modname(const char *pathname, const char *modname)
295{
296 int r;
297 char name[MODULE_NAME_LEN];
298 const char *fname = bb_get_last_path_component_nostrip(pathname);
299 const char *suffix = strrstr(fname, ".ko");
300 safe_strncpy(name, fname, suffix - fname + 1);
301 replace(name, '-', '_');
302 r = (strcmp(name, modname) == 0);
303 return r;
304}
305
306static FAST_FUNC int fileAction(const char *pathname, 307static FAST_FUNC int fileAction(const char *pathname,
307 struct stat *sb UNUSED_PARAM, 308 struct stat *sb UNUSED_PARAM,
308 void *modname_to_match, 309 void *modname_to_match,
@@ -535,22 +536,69 @@ static module_info** find_alias(const char *alias)
535// TODO: open only once, invent config_rewind() 536// TODO: open only once, invent config_rewind()
536static int already_loaded(const char *name) 537static int already_loaded(const char *name)
537{ 538{
538 int ret = 0; 539 int ret;
539 char *s; 540 char *line;
540 parser_t *parser = config_open2("/proc/modules", xfopen_for_read); 541 FILE *fp;
541 while (config_read(parser, &s, 1, 1, "# \t", PARSE_NORMAL & ~PARSE_GREEDY)) { 542
542 if (strcmp(s, name) == 0) { 543 ret = 5 * 2;
543 ret = 1; 544 again:
544 break; 545 fp = fopen_for_read("/proc/modules");
546 if (!fp)
547 return 0;
548 while ((line = xmalloc_fgetline(fp)) != NULL) {
549 char *live;
550 char *after_name;
551
552 // Examples from kernel 3.14.6:
553 //pcspkr 12718 0 - Live 0xffffffffa017e000
554 //snd_timer 28690 2 snd_seq,snd_pcm, Live 0xffffffffa025e000
555 //i915 801405 2 - Live 0xffffffffa0096000
556 after_name = is_prefixed_with(line, name);
557 if (!after_name || *after_name != ' ') {
558 free(line);
559 continue;
545 } 560 }
561 live = strstr(line, " Live");
562 free(line);
563 if (!live) {
564 /* State can be Unloading, Loading, or Live.
565 * modprobe must not return prematurely if we see "Loading":
566 * it can cause further programs to assume load completed,
567 * but it did not (yet)!
568 * Wait up to 5*20 ms for it to resolve.
569 */
570 ret -= 2;
571 if (ret == 0)
572 break; /* huh? report as "not loaded" */
573 fclose(fp);
574 usleep(20*1000);
575 goto again;
576 }
577 ret = 1;
578 break;
546 } 579 }
547 config_close(parser); 580 fclose(fp);
548 return ret; 581
582 return ret & 1;
549} 583}
550#else 584#else
551#define already_loaded(name) is_rmmod 585#define already_loaded(name) 0
552#endif 586#endif
553 587
588static int rmmod(const char *filename)
589{
590 int r;
591 char modname[MODULE_NAME_LEN];
592
593 filename2modname(filename, modname);
594 r = delete_module(modname, O_NONBLOCK | O_EXCL);
595 dbg1_error_msg("delete_module('%s', O_NONBLOCK | O_EXCL):%d", modname, r);
596 if (r != 0 && !(option_mask32 & OPT_q)) {
597 bb_perror_msg("remove '%s'", modname);
598 }
599 return r;
600}
601
554/* 602/*
555 * Given modules definition and module name (or alias, or symbol) 603 * Given modules definition and module name (or alias, or symbol)
556 * load/remove the module respecting dependencies. 604 * load/remove the module respecting dependencies.
@@ -567,26 +615,36 @@ static void process_module(char *name, const char *cmdline_options)
567 module_info **infovec; 615 module_info **infovec;
568 module_info *info; 616 module_info *info;
569 int infoidx; 617 int infoidx;
570 int is_rmmod = (option_mask32 & OPT_r) != 0; 618 int is_remove = (option_mask32 & OPT_r) != 0;
571 619
572 dbg1_error_msg("process_module('%s','%s')", name, cmdline_options); 620 dbg1_error_msg("process_module('%s','%s')", name, cmdline_options);
573 621
574 replace(name, '-', '_'); 622 replace(name, '-', '_');
575 623
576 dbg1_error_msg("already_loaded:%d is_rmmod:%d", already_loaded(name), is_rmmod); 624 dbg1_error_msg("already_loaded:%d is_remove:%d", already_loaded(name), is_remove);
625
626 if (applet_name[0] == 'r') {
627 /* rmmod.
628 * Does not remove dependencies, no need to scan, just remove.
629 * (compat note: this allows and strips .ko suffix)
630 */
631 rmmod(name);
632 return;
633 }
634
577 /* 635 /*
578 * We used to have "is_rmmod != already_loaded(name)" check here, but 636 * We used to have "is_remove != already_loaded(name)" check here, but
579 * modprobe -r pci:v00008086d00007010sv00000000sd00000000bc01sc01i80 637 * modprobe -r pci:v00008086d00007010sv00000000sd00000000bc01sc01i80
580 * won't unload modules (there are more than one) 638 * won't unload modules (there are more than one)
581 * which have this alias. 639 * which have this alias.
582 */ 640 */
583 if (!is_rmmod && already_loaded(name)) { 641 if (!is_remove && already_loaded(name)) {
584 dbg1_error_msg("nothing to do for '%s'", name); 642 dbg1_error_msg("nothing to do for '%s'", name);
585 return; 643 return;
586 } 644 }
587 645
588 options = NULL; 646 options = NULL;
589 if (!is_rmmod) { 647 if (!is_remove) {
590 char *opt_filename = xasprintf("/etc/modules/%s", name); 648 char *opt_filename = xasprintf("/etc/modules/%s", name);
591 options = xmalloc_open_read_close(opt_filename, NULL); 649 options = xmalloc_open_read_close(opt_filename, NULL);
592 if (options) 650 if (options)
@@ -620,7 +678,7 @@ static void process_module(char *name, const char *cmdline_options)
620 0 /* depth */ 678 0 /* depth */
621 ); 679 );
622 dbg1_error_msg("dirscan complete"); 680 dbg1_error_msg("dirscan complete");
623 /* Module was not found, or load failed, or is_rmmod */ 681 /* Module was not found, or load failed, or is_remove */
624 if (module_found_idx >= 0) { /* module was found */ 682 if (module_found_idx >= 0) { /* module was found */
625 infovec = xzalloc(2 * sizeof(infovec[0])); 683 infovec = xzalloc(2 * sizeof(infovec[0]));
626 infovec[0] = &modinfo[module_found_idx]; 684 infovec[0] = &modinfo[module_found_idx];
@@ -631,6 +689,14 @@ static void process_module(char *name, const char *cmdline_options)
631 infovec = find_alias(name); 689 infovec = find_alias(name);
632 } 690 }
633 691
692 if (!infovec) {
693 /* both dirscan and find_alias found nothing */
694 if (!is_remove && applet_name[0] != 'd') /* it wasn't rmmod or depmod */
695 bb_error_msg("module '%s' not found", name);
696//TODO: _and_die()? or should we continue (un)loading modules listed on cmdline?
697 goto ret;
698 }
699
634 /* There can be more than one module for the given alias. For example, 700 /* There can be more than one module for the given alias. For example,
635 * "pci:v00008086d00007010sv00000000sd00000000bc01sc01i80" matches 701 * "pci:v00008086d00007010sv00000000sd00000000bc01sc01i80" matches
636 * ata_piix because it has alias "pci:v00008086d00007010sv*sd*bc*sc*i*" 702 * ata_piix because it has alias "pci:v00008086d00007010sv*sd*bc*sc*i*"
@@ -639,28 +705,15 @@ static void process_module(char *name, const char *cmdline_options)
639 * a *list* of modinfo pointers from find_alias(). 705 * a *list* of modinfo pointers from find_alias().
640 */ 706 */
641 707
642 /* rmmod or modprobe -r? unload module(s) */ 708 /* modprobe -r? unload module(s) */
643 if (is_rmmod) { 709 if (is_remove) {
644 infoidx = 0; 710 infoidx = 0;
645 while ((info = infovec[infoidx++]) != NULL) { 711 while ((info = infovec[infoidx++]) != NULL) {
646 int r; 712 int r = rmmod(bb_get_last_path_component_nostrip(info->pathname));
647 char modname[MODULE_NAME_LEN];
648
649 filename2modname(info->pathname, modname);
650 r = delete_module(modname, O_NONBLOCK | O_EXCL);
651 dbg1_error_msg("delete_module('%s', O_NONBLOCK | O_EXCL):%d", modname, r);
652 if (r != 0) { 713 if (r != 0) {
653 if (!(option_mask32 & OPT_q)) 714 goto ret; /* error */
654 bb_perror_msg("remove '%s'", modname);
655 goto ret;
656 } 715 }
657 } 716 }
658
659 if (applet_name[0] == 'r') {
660 /* rmmod: do not remove dependencies, exit */
661 goto ret;
662 }
663
664 /* modprobe -r: we do not stop here - 717 /* modprobe -r: we do not stop here -
665 * continue to unload modules on which the module depends: 718 * continue to unload modules on which the module depends:
666 * "-r --remove: option causes modprobe to remove a module. 719 * "-r --remove: option causes modprobe to remove a module.
@@ -669,14 +722,6 @@ static void process_module(char *name, const char *cmdline_options)
669 */ 722 */
670 } 723 }
671 724
672 if (!infovec) {
673 /* both dirscan and find_alias found nothing */
674 if (!is_rmmod && applet_name[0] != 'd') /* it wasn't rmmod or depmod */
675 bb_error_msg("module '%s' not found", name);
676//TODO: _and_die()? or should we continue (un)loading modules listed on cmdline?
677 goto ret;
678 }
679
680 infoidx = 0; 725 infoidx = 0;
681 while ((info = infovec[infoidx++]) != NULL) { 726 while ((info = infovec[infoidx++]) != NULL) {
682 /* Iterate thru dependencies, trying to (un)load them */ 727 /* Iterate thru dependencies, trying to (un)load them */
@@ -689,7 +734,7 @@ static void process_module(char *name, const char *cmdline_options)
689 } 734 }
690 free(deps); 735 free(deps);
691 736
692 if (is_rmmod) 737 if (is_remove)
693 continue; 738 continue;
694 739
695 /* We are modprobe: load it */ 740 /* We are modprobe: load it */
@@ -892,10 +937,10 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
892 } 937 }
893 938
894#if ENABLE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE 939#if ENABLE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE
895 /* If not rmmod, parse possible module options given on command line. 940 /* If not rmmod/-r, parse possible module options given on command line.
896 * insmod/modprobe takes one module name, the rest are parameters. */ 941 * insmod/modprobe takes one module name, the rest are parameters. */
897 options = NULL; 942 options = NULL;
898 if ('r' != applet0) { 943 if (!(option_mask32 & OPT_r)) {
899 char **arg = argv; 944 char **arg = argv;
900 while (*++arg) { 945 while (*++arg) {
901 /* Enclose options in quotes */ 946 /* Enclose options in quotes */
@@ -906,7 +951,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
906 } 951 }
907 } 952 }
908#else 953#else
909 if ('r' != applet0) 954 if (!(option_mask32 & OPT_r))
910 argv[1] = NULL; 955 argv[1] = NULL;
911#endif 956#endif
912 957
@@ -930,10 +975,11 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
930 } 975 }
931 976
932 /* Try to load modprobe.dep.bb */ 977 /* Try to load modprobe.dep.bb */
933 load_dep_bb(); 978 if ('r' != applet0) /* not rmmod */
979 load_dep_bb();
934 980
935 /* Load/remove modules. 981 /* Load/remove modules.
936 * Only rmmod loops here, modprobe has only argv[0] */ 982 * Only rmmod/modprobe -r loops here, insmod/modprobe has only argv[0] */
937 do { 983 do {
938 process_module(*argv, options); 984 process_module(*argv, options);
939 } while (*++argv); 985 } while (*++argv);