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#include "libbb.h"
27
28#include <sys/utsname.h>
29#include <fnmatch.h>
30#include <sys/syscall.h>
31
32#define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)
33#define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags)
34#ifdef __NR_finit_module
35# define finit_module(fd, uargs, flags) syscall(__NR_finit_module, fd, uargs, flags)
36#endif
37
38#undef MODULE_NAME_LEN
39#define MODULE_NAME_LEN 64
40
41
42#if 1
43# define dbg1_error_msg(...) ((void)0)
44# define dbg2_error_msg(...) ((void)0)
45#else
46# define dbg1_error_msg(...) bb_error_msg(__VA_ARGS__)
47# define dbg2_error_msg(...) bb_error_msg(__VA_ARGS__)
48#endif
49
50#define DEPFILE_BB CONFIG_DEFAULT_DEPMOD_FILE".bb"
51
52
53
54
55
56
57
58
59
60
61#if ENABLE_LSMOD
62int lsmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
63int lsmod_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
64{
65 xprint_and_close_file(xfopen_for_read("/proc/modules"));
66 return EXIT_SUCCESS;
67}
68#endif
69
70
71
72#define MOD_APPLET_CNT (ENABLE_MODPROBE + ENABLE_DEPMOD + ENABLE_INSMOD + ENABLE_RMMOD)
73
74
75
76#if MOD_APPLET_CNT > 0
77
78#define ONLY_APPLET (MOD_APPLET_CNT == 1)
79#define is_modprobe (ENABLE_MODPROBE && (ONLY_APPLET || applet_name[0] == 'm'))
80#define is_depmod (ENABLE_DEPMOD && (ONLY_APPLET || applet_name[0] == 'd'))
81#define is_insmod (ENABLE_INSMOD && (ONLY_APPLET || applet_name[0] == 'i'))
82#define is_rmmod (ENABLE_RMMOD && (ONLY_APPLET || applet_name[0] == 'r'))
83
84enum {
85 DEPMOD_OPT_n = (1 << 0),
86 OPT_q = (1 << 0),
87 OPT_r = (1 << 1),
88};
89
90typedef struct module_info {
91 char *pathname;
92 char *aliases;
93 char *deps;
94 smallint open_read_failed;
95} module_info;
96
97
98
99
100struct globals {
101 module_info *modinfo;
102 char *module_load_options;
103 smallint dep_bb_seen;
104 smallint wrote_dep_bb_ok;
105 unsigned module_count;
106 int module_found_idx;
107 unsigned stringbuf_idx;
108 unsigned stringbuf_size;
109 char *stringbuf;
110
111
112};
113#define G (*ptr_to_globals)
114#define modinfo (G.modinfo )
115#define dep_bb_seen (G.dep_bb_seen )
116#define wrote_dep_bb_ok (G.wrote_dep_bb_ok )
117#define module_count (G.module_count )
118#define module_found_idx (G.module_found_idx )
119#define module_load_options (G.module_load_options)
120#define stringbuf_idx (G.stringbuf_idx )
121#define stringbuf_size (G.stringbuf_size )
122#define stringbuf (G.stringbuf )
123#define INIT_G() do { \
124 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
125} while (0)
126
127static void append(const char *s)
128{
129 unsigned len = strlen(s);
130 if (stringbuf_idx + len + 15 > stringbuf_size) {
131 stringbuf_size = stringbuf_idx + len + 127;
132 dbg2_error_msg("grow stringbuf to %u", stringbuf_size);
133 stringbuf = xrealloc(stringbuf, stringbuf_size);
134 }
135 memcpy(stringbuf + stringbuf_idx, s, len);
136 stringbuf_idx += len;
137}
138
139static void appendc(char c)
140{
141
142
143 stringbuf[stringbuf_idx++] = c;
144}
145
146static void bksp(void)
147{
148 if (stringbuf_idx)
149 stringbuf_idx--;
150}
151
152static void reset_stringbuf(void)
153{
154 stringbuf_idx = 0;
155}
156
157static char* copy_stringbuf(void)
158{
159 char *copy = xzalloc(stringbuf_idx + 1);
160 return memcpy(copy, stringbuf, stringbuf_idx);
161}
162
163static char* find_keyword(char *ptr, size_t len, const char *word)
164{
165 if (!ptr)
166 return NULL;
167
168 len -= strlen(word) - 1;
169 while ((ssize_t)len > 0) {
170 char *old = ptr;
171 char *after_word;
172
173
174 ptr = memchr(ptr, word[0], len);
175 if (ptr == NULL)
176 break;
177 after_word = is_prefixed_with(ptr, word);
178 if (after_word)
179 return after_word;
180 ++ptr;
181 len -= (ptr - old);
182 }
183 return NULL;
184}
185
186static void replace(char *s, char what, char with)
187{
188 while (*s) {
189 if (what == *s)
190 *s = with;
191 ++s;
192 }
193}
194
195static char *filename2modname(const char *filename, char *modname)
196{
197 int i;
198 const char *from;
199
200
201
202
203
204 from = filename;
205 for (i = 0; i < (MODULE_NAME_LEN-1) && from[i] != '\0' && from[i] != '.'; i++)
206 modname[i] = (from[i] == '-') ? '_' : from[i];
207 modname[i] = '\0';
208
209 return modname;
210}
211
212static int pathname_matches_modname(const char *pathname, const char *modname)
213{
214 int r;
215 char name[MODULE_NAME_LEN];
216 filename2modname(bb_get_last_path_component_nostrip(pathname), name);
217 r = (strcmp(name, modname) == 0);
218 return r;
219}
220
221
222static char* str_2_list(const char *str)
223{
224 int len = strlen(str) + 1;
225 char *dst = xmalloc(len + 1);
226
227 dst[len] = '\0';
228 memcpy(dst, str, len);
229
230 replace(dst, ' ', '\0');
231 return dst;
232}
233
234
235static const char *moderror(int err)
236{
237 switch (err) {
238 case ENOEXEC:
239 return "invalid module format";
240 case ENOENT:
241 return "unknown symbol in module or invalid parameter";
242 case ESRCH:
243 return "module has wrong symbol version";
244 case EINVAL:
245 return "unknown symbol in module or invalid parameter"
246 + sizeof("unknown symbol in module or");
247 default:
248 return strerror(err);
249 }
250}
251
252static int load_module(const char *fname, const char *options)
253{
254#if 1
255 int r;
256 size_t len = MAXINT(ssize_t);
257 char *module_image;
258
259 if (!options)
260 options = "";
261
262 dbg1_error_msg("load_module('%s','%s')", fname, options);
263
264
265
266
267
268
269
270 r = 1;
271# ifdef __NR_finit_module
272 {
273 int fd = open(fname, O_RDONLY | O_CLOEXEC);
274 if (fd >= 0) {
275 r = finit_module(fd, options, 0) != 0;
276 close(fd);
277 }
278 }
279# endif
280 if (r != 0) {
281 module_image = xmalloc_open_zipped_read_close(fname, &len);
282 r = (!module_image || init_module(module_image, len, options) != 0);
283 free(module_image);
284 }
285
286 dbg1_error_msg("load_module:%d", r);
287 return r;
288#else
289
290 dbg1_error_msg("load_module('%s','%s')", fname, options);
291 return 1;
292#endif
293}
294
295
296static int parse_module(module_info *info, const char *pathname)
297{
298 char *module_image;
299 char *ptr;
300 size_t len;
301 size_t pos;
302 dbg1_error_msg("parse_module('%s')", pathname);
303
304
305 errno = 0;
306 len = 64 * 1024 * 1024;
307 module_image = xmalloc_open_zipped_read_close(pathname, &len);
308
309
310
311
312 reset_stringbuf();
313 pos = 0;
314 while (1) {
315 unsigned start = stringbuf_idx;
316 ptr = find_keyword(module_image + pos, len - pos, "alias=");
317 if (!ptr) {
318 ptr = find_keyword(module_image + pos, len - pos, "__ksymtab_");
319 if (!ptr)
320 break;
321
322
323 if (strcmp(ptr, "gpl") == 0 || strcmp(ptr, "strings") == 0)
324 goto skip;
325 dbg2_error_msg("alias:'symbol:%s'", ptr);
326 append("symbol:");
327 } else {
328 dbg2_error_msg("alias:'%s'", ptr);
329 }
330 append(ptr);
331 appendc(' ');
332
333
334
335
336 if (start) {
337 char *found, *last;
338 stringbuf[stringbuf_idx] = '\0';
339 last = stringbuf + start;
340
341
342
343
344 if (strncmp(stringbuf, last, stringbuf_idx - start) == 0)
345
346 found = stringbuf;
347 else
348
349 found = strstr(stringbuf, last-1);
350 if (found < last-1) {
351
352 dbg2_error_msg("redundant:'%s'", last);
353 stringbuf_idx = start;
354 goto skip;
355 }
356 }
357 skip:
358 pos = (ptr - module_image);
359 }
360 bksp();
361 info->aliases = copy_stringbuf();
362 replace(info->aliases, '-', '_');
363
364
365 reset_stringbuf();
366 ptr = find_keyword(module_image, len, "depends=");
367 if (ptr && *ptr) {
368 replace(ptr, ',', ' ');
369 replace(ptr, '-', '_');
370 dbg2_error_msg("dep:'%s'", ptr);
371 append(ptr);
372 }
373 free(module_image);
374 info->deps = copy_stringbuf();
375
376 info->open_read_failed = (module_image == NULL);
377 return info->open_read_failed;
378}
379
380static FAST_FUNC int fileAction(struct recursive_state *state,
381 const char *pathname,
382 struct stat *sb UNUSED_PARAM)
383{
384 const char *modname_to_match = state->userData;
385 int cur;
386 const char *fname;
387 bool is_remove = (ENABLE_RMMOD && ONLY_APPLET)
388 || ((ENABLE_RMMOD || ENABLE_MODPROBE) && (option_mask32 & OPT_r));
389
390 pathname += 2;
391 fname = bb_get_last_path_component_nostrip(pathname);
392 if (!strrstr(fname, ".ko")) {
393 dbg1_error_msg("'%s' is not a module", pathname);
394 return TRUE;
395 }
396
397 cur = module_count++;
398 modinfo = xrealloc_vector(modinfo, 12, cur);
399 modinfo[cur].pathname = xstrdup(pathname);
400
401
402
403 if (!pathname_matches_modname(fname, modname_to_match)) {
404 dbg1_error_msg("'%s' module name doesn't match", pathname);
405 return TRUE;
406 }
407
408 dbg1_error_msg("'%s' module name matches", pathname);
409 module_found_idx = cur;
410 if (parse_module(&modinfo[cur], pathname) != 0)
411 return TRUE;
412
413 if (!is_remove) {
414 if (load_module(pathname, module_load_options) == 0) {
415
416
417
418 exit(EXIT_SUCCESS);
419 }
420 }
421
422 return TRUE;
423}
424
425static int load_dep_bb(void)
426{
427 char *line;
428 FILE *fp = fopen_for_read(DEPFILE_BB);
429
430 if (!fp)
431 return 0;
432
433 dep_bb_seen = 1;
434 dbg1_error_msg("loading "DEPFILE_BB);
435
436
437
438
439
440
441
442
443
444
445 module_count = 0;
446 memset(&modinfo[0], 0, sizeof(modinfo[0]));
447
448 while ((line = xmalloc_fgetline(fp)) != NULL) {
449 char* space;
450 char* linebuf;
451 int cur;
452
453 if (!line[0]) {
454 free(line);
455 continue;
456 }
457 space = strchrnul(line, ' ');
458 cur = module_count++;
459 modinfo = xrealloc_vector(modinfo, 12, cur);
460
461 modinfo[cur].pathname = line;
462 if (*space)
463 *space++ = '\0';
464 modinfo[cur].aliases = space;
465 linebuf = xmalloc_fgetline(fp);
466 modinfo[cur].deps = linebuf ? linebuf : xzalloc(1);
467 if (modinfo[cur].deps[0]) {
468
469 line = xmalloc_fgetline(fp);
470
471 if (line && line[0])
472 bb_error_msg_and_die("error in %s at '%s'", DEPFILE_BB, line);
473 free(line);
474 }
475 }
476 return 1;
477}
478
479static int start_dep_bb_writeout(void)
480{
481 int fd;
482
483
484 if (is_depmod && (option_mask32 & DEPMOD_OPT_n))
485 return STDOUT_FILENO;
486
487 fd = open(DEPFILE_BB".new", O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0644);
488 if (fd < 0) {
489 if (errno == EEXIST) {
490 int count = 5 * 20;
491 dbg1_error_msg(DEPFILE_BB".new exists, waiting for "DEPFILE_BB);
492 while (1) {
493 usleep(1000*1000 / 20);
494 if (load_dep_bb()) {
495 dbg1_error_msg(DEPFILE_BB" appeared");
496 return -2;
497 }
498 if (!--count)
499 break;
500 }
501 bb_error_msg("deleting stale %s", DEPFILE_BB".new");
502 fd = open_or_warn(DEPFILE_BB".new", O_WRONLY | O_CREAT | O_TRUNC);
503 }
504 }
505 dbg1_error_msg("opened "DEPFILE_BB".new:%d", fd);
506 return fd;
507}
508
509static void write_out_dep_bb(int fd)
510{
511 int i;
512 FILE *fp;
513
514
515 fp = xfdopen_for_write(fd);
516 i = 0;
517 while (modinfo[i].pathname) {
518 fprintf(fp, "%s%s%s\n" "%s%s\n",
519 modinfo[i].pathname, modinfo[i].aliases[0] ? " " : "", modinfo[i].aliases,
520 modinfo[i].deps, modinfo[i].deps[0] ? "\n" : "");
521 i++;
522 }
523
524 errno = 0;
525 if (ferror(fp) | fclose(fp))
526 goto err;
527
528 if (fd == STDOUT_FILENO)
529 goto ok;
530
531 if (rename(DEPFILE_BB".new", DEPFILE_BB) != 0) {
532 err:
533 bb_perror_msg("can't create '%s'", DEPFILE_BB);
534 unlink(DEPFILE_BB".new");
535 } else {
536 ok:
537 wrote_dep_bb_ok = 1;
538 dbg1_error_msg("created "DEPFILE_BB);
539 }
540}
541
542static module_info** find_alias(const char *alias)
543{
544 int i;
545 int dep_bb_fd;
546 int infoidx;
547 module_info **infovec;
548 dbg1_error_msg("find_alias('%s')", alias);
549
550 try_again:
551
552 i = 0;
553 while (modinfo[i].pathname) {
554 if (pathname_matches_modname(modinfo[i].pathname, alias)) {
555 dbg1_error_msg("found '%s' in module '%s'",
556 alias, modinfo[i].pathname);
557 if (!modinfo[i].aliases) {
558 parse_module(&modinfo[i], modinfo[i].pathname);
559 }
560 infovec = xzalloc(2 * sizeof(infovec[0]));
561 infovec[0] = &modinfo[i];
562 return infovec;
563 }
564 i++;
565 }
566
567
568
569 dep_bb_fd = dep_bb_seen ? -1 : start_dep_bb_writeout();
570 if (dep_bb_fd == -2)
571 goto try_again;
572
573
574 i = 0;
575 infoidx = 0;
576 infovec = NULL;
577 while (modinfo[i].pathname) {
578 char *desc, *s;
579 if (!modinfo[i].aliases) {
580 parse_module(&modinfo[i], modinfo[i].pathname);
581 }
582
583 desc = str_2_list(modinfo[i].aliases);
584
585 for (s = desc; *s; s += strlen(s) + 1) {
586
587
588
589
590 if (fnmatch(s, alias, 0) == 0) {
591 dbg1_error_msg("found alias '%s' in module '%s'",
592 alias, modinfo[i].pathname);
593 infovec = xrealloc_vector(infovec, 1, infoidx);
594 infovec[infoidx++] = &modinfo[i];
595 break;
596 }
597 }
598 free(desc);
599 i++;
600 }
601
602
603 if (dep_bb_fd >= 0) {
604 write_out_dep_bb(dep_bb_fd);
605 }
606
607 dbg1_error_msg("find_alias '%s' returns %d results", alias, infoidx);
608 return infovec;
609}
610
611#if ENABLE_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED
612
613static int already_loaded(const char *name)
614{
615 int ret;
616 char *line;
617 FILE *fp;
618
619 ret = 5 * 2;
620 again:
621 fp = fopen_for_read("/proc/modules");
622 if (!fp)
623 return 0;
624 while ((line = xmalloc_fgetline(fp)) != NULL) {
625 char *live;
626 char *after_name;
627
628
629
630
631
632 after_name = is_prefixed_with(line, name);
633 if (!after_name || *after_name != ' ') {
634 free(line);
635 continue;
636 }
637 live = strstr(line, " Live");
638 free(line);
639 if (!live) {
640
641
642
643
644
645
646 ret -= 2;
647 if (ret == 0)
648 break;
649 fclose(fp);
650 usleep(20*1000);
651 goto again;
652 }
653 ret = 1;
654 break;
655 }
656 fclose(fp);
657
658 return ret & 1;
659}
660#else
661#define already_loaded(name) 0
662#endif
663
664static int rmmod(const char *filename)
665{
666 int r;
667 char modname[MODULE_NAME_LEN];
668
669 filename2modname(filename, modname);
670 r = delete_module(modname, O_NONBLOCK | O_EXCL);
671 dbg1_error_msg("delete_module('%s', O_NONBLOCK | O_EXCL):%d", modname, r);
672 if (r != 0 && !(option_mask32 & OPT_q)) {
673 bb_perror_msg("remove '%s'", modname);
674 }
675 return r;
676}
677
678
679
680
681
682
683
684#if !ENABLE_FEATURE_CMDLINE_MODULE_OPTIONS
685#define process_module(a,b) process_module(a)
686#define cmdline_options ""
687#endif
688static int process_module(char *name, const char *cmdline_options)
689{
690 char *s, *deps, *options;
691 module_info **infovec;
692 module_info *info;
693 int infoidx;
694 bool is_remove = (ENABLE_RMMOD && ONLY_APPLET)
695 || ((ENABLE_RMMOD || ENABLE_MODPROBE) && (option_mask32 & OPT_r));
696 int exitcode = EXIT_SUCCESS;
697
698 dbg1_error_msg("process_module('%s','%s')", name, cmdline_options);
699
700 replace(name, '-', '_');
701
702 dbg1_error_msg("already_loaded:%d is_remove:%d", already_loaded(name), is_remove);
703
704 if (is_rmmod) {
705
706
707
708 rmmod(name);
709 return EXIT_SUCCESS;
710 }
711
712
713
714
715
716
717
718 if (!is_remove && already_loaded(name)) {
719 dbg1_error_msg("nothing to do for '%s'", name);
720 return EXIT_SUCCESS;
721 }
722
723 options = NULL;
724 if (!is_remove) {
725 char *opt_filename = xasprintf("/etc/modules/%s", name);
726 options = xmalloc_open_read_close(opt_filename, NULL);
727 if (options)
728 replace(options, '\n', ' ');
729#if ENABLE_FEATURE_CMDLINE_MODULE_OPTIONS
730 if (cmdline_options) {
731
732
733 char *op = xasprintf(options ? "%s %s" : "%s %s" + 3,
734 cmdline_options + 1, options);
735 free(options);
736 options = op;
737 }
738#endif
739 free(opt_filename);
740 module_load_options = options;
741 dbg1_error_msg("process_module('%s'): options:'%s'", name, options);
742 }
743
744 if (!module_count) {
745
746
747
748
749 module_found_idx = -1;
750 recursive_action(".",
751 ACTION_RECURSE,
752 fileAction,
753 NULL,
754 name
755 );
756 dbg1_error_msg("dirscan complete");
757
758 if (module_found_idx >= 0) {
759 infovec = xzalloc(2 * sizeof(infovec[0]));
760 infovec[0] = &modinfo[module_found_idx];
761 } else {
762 infovec = find_alias(name);
763 }
764 } else {
765 infovec = find_alias(name);
766 }
767
768 if (!infovec) {
769
770 if (!is_remove && !is_depmod) {
771 bb_error_msg("module '%s' not found", name);
772
773
774 exitcode = EXIT_FAILURE;
775 }
776 goto ret;
777 }
778
779
780
781
782
783
784
785
786
787
788 if (is_remove) {
789 infoidx = 0;
790 while ((info = infovec[infoidx++]) != NULL) {
791 int r = rmmod(bb_get_last_path_component_nostrip(info->pathname));
792 if (r != 0) {
793 goto ret;
794 }
795 }
796
797
798
799
800
801
802 }
803
804 infoidx = 0;
805 while ((info = infovec[infoidx++]) != NULL) {
806
807 deps = str_2_list(info->deps);
808 for (s = deps; *s; s += strlen(s) + 1) {
809
810 dbg1_error_msg("recurse on dep '%s'", s);
811 process_module(s, NULL);
812 dbg1_error_msg("recurse on dep '%s' done", s);
813 }
814 free(deps);
815
816 if (is_remove)
817 continue;
818
819
820 if (options && strstr(options, "blacklist")) {
821 dbg1_error_msg("'%s': blacklisted", info->pathname);
822 continue;
823 }
824 if (info->open_read_failed) {
825
826 exitcode = EXIT_FAILURE;
827 continue;
828 }
829 errno = 0;
830 if (load_module(info->pathname, options) != 0) {
831 if (EEXIST != errno) {
832 bb_error_msg("'%s': %s",
833 info->pathname,
834 moderror(errno));
835 } else {
836 dbg1_error_msg("'%s': %s",
837 info->pathname,
838 moderror(errno));
839 }
840 exitcode = EXIT_FAILURE;
841 }
842 }
843 ret:
844 free(infovec);
845 free(options);
846
847 return exitcode;
848}
849#undef cmdline_options
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
933int modprobe_main(int argc UNUSED_PARAM, char **argv)
934{
935#if ENABLE_MODPROBE || ENABLE_INSMOD || ENABLE_RMMOD
936 int exitcode;
937#endif
938 struct utsname uts;
939 IF_FEATURE_CMDLINE_MODULE_OPTIONS(char *options = NULL;)
940
941 INIT_G();
942
943
944 modinfo = xzalloc(sizeof(modinfo[0]));
945
946 if ((MOD_APPLET_CNT == 2 && ENABLE_DEPMOD && ENABLE_MODPROBE)
947 || is_depmod || is_modprobe
948 ) {
949
950 xchdir(CONFIG_DEFAULT_MODULES_DIR);
951 uname(&uts);
952 }
953
954
955 if (is_depmod) {
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977 getopt32(argv, "na" "AeF:qru" , NULL);
978 argv += optind;
979
980
981 xchdir(argv[0] ? argv[0] : uts.release);
982
983
984 process_module((char*)"/", NULL);
985 return !wrote_dep_bb_ok;
986 }
987
988#if ENABLE_MODPROBE || ENABLE_INSMOD || ENABLE_RMMOD
989
990
991
992 getopt32(argv, "^" "qrfsvwb" "\0" "-1");
993 argv += optind;
994
995 if (is_modprobe) {
996
997 xchdir(uts.release);
998 }
999
1000
1001
1002 if (is_rmmod) {
1003 if (!ONLY_APPLET)
1004 option_mask32 |= OPT_r;
1005 } else if (!ENABLE_MODPROBE || !(option_mask32 & OPT_r)) {
1006# if ENABLE_FEATURE_CMDLINE_MODULE_OPTIONS
1007
1008
1009 char **arg = argv;
1010 while (*++arg) {
1011
1012 char *s = options;
1013 options = xasprintf("%s \"%s\"", s ? s : "", *arg);
1014 free(s);
1015 *arg = NULL;
1016 }
1017# else
1018 argv[1] = NULL;
1019# endif
1020 }
1021
1022 if (is_insmod) {
1023 size_t len;
1024 void *map;
1025
1026 len = MAXINT(ssize_t);
1027 map = xmalloc_open_zipped_read_close(*argv, &len);
1028 if (!map)
1029 bb_perror_msg_and_die("can't read '%s'", *argv);
1030 if (init_module(map, len,
1031 (IF_FEATURE_CMDLINE_MODULE_OPTIONS(options ? options : ) "")
1032 ) != 0
1033 ) {
1034 bb_error_msg_and_die("can't insert '%s': %s",
1035 *argv, moderror(errno));
1036 }
1037 return EXIT_SUCCESS;
1038 }
1039
1040
1041 if (!is_rmmod) {
1042 load_dep_bb();
1043 }
1044
1045
1046
1047 exitcode = EXIT_SUCCESS;
1048 do {
1049 exitcode |= process_module(*argv, options);
1050 } while (*++argv);
1051
1052 if (ENABLE_FEATURE_CLEAN_UP) {
1053 IF_FEATURE_CMDLINE_MODULE_OPTIONS(free(options);)
1054 }
1055 return exitcode;
1056#endif
1057}
1058
1059#endif
1060