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(const char *pathname,
381 struct stat *sb UNUSED_PARAM,
382 void *modname_to_match,
383 int depth UNUSED_PARAM)
384{
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 0
756 );
757 dbg1_error_msg("dirscan complete");
758
759 if (module_found_idx >= 0) {
760 infovec = xzalloc(2 * sizeof(infovec[0]));
761 infovec[0] = &modinfo[module_found_idx];
762 } else {
763 infovec = find_alias(name);
764 }
765 } else {
766 infovec = find_alias(name);
767 }
768
769 if (!infovec) {
770
771 if (!is_remove && !is_depmod) {
772 bb_error_msg("module '%s' not found", name);
773
774
775 exitcode = EXIT_FAILURE;
776 }
777 goto ret;
778 }
779
780
781
782
783
784
785
786
787
788
789 if (is_remove) {
790 infoidx = 0;
791 while ((info = infovec[infoidx++]) != NULL) {
792 int r = rmmod(bb_get_last_path_component_nostrip(info->pathname));
793 if (r != 0) {
794 goto ret;
795 }
796 }
797
798
799
800
801
802
803 }
804
805 infoidx = 0;
806 while ((info = infovec[infoidx++]) != NULL) {
807
808 deps = str_2_list(info->deps);
809 for (s = deps; *s; s += strlen(s) + 1) {
810
811 dbg1_error_msg("recurse on dep '%s'", s);
812 process_module(s, NULL);
813 dbg1_error_msg("recurse on dep '%s' done", s);
814 }
815 free(deps);
816
817 if (is_remove)
818 continue;
819
820
821 if (options && strstr(options, "blacklist")) {
822 dbg1_error_msg("'%s': blacklisted", info->pathname);
823 continue;
824 }
825 if (info->open_read_failed) {
826
827 exitcode = EXIT_FAILURE;
828 continue;
829 }
830 errno = 0;
831 if (load_module(info->pathname, options) != 0) {
832 if (EEXIST != errno) {
833 bb_error_msg("'%s': %s",
834 info->pathname,
835 moderror(errno));
836 } else {
837 dbg1_error_msg("'%s': %s",
838 info->pathname,
839 moderror(errno));
840 }
841 exitcode = EXIT_FAILURE;
842 }
843 }
844 ret:
845 free(infovec);
846 free(options);
847
848 return exitcode;
849}
850#undef cmdline_options
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
932
933int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
934int modprobe_main(int argc UNUSED_PARAM, char **argv)
935{
936#if ENABLE_MODPROBE || ENABLE_INSMOD || ENABLE_RMMOD
937 int exitcode;
938#endif
939 struct utsname uts;
940 IF_FEATURE_CMDLINE_MODULE_OPTIONS(char *options = NULL;)
941
942 INIT_G();
943
944
945 modinfo = xzalloc(sizeof(modinfo[0]));
946
947 if ((MOD_APPLET_CNT == 2 && ENABLE_DEPMOD && ENABLE_MODPROBE)
948 || is_depmod || is_modprobe
949 ) {
950
951 xchdir(CONFIG_DEFAULT_MODULES_DIR);
952 uname(&uts);
953 }
954
955
956 if (is_depmod) {
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978 getopt32(argv, "na" "AeF:qru" , NULL);
979 argv += optind;
980
981
982 xchdir(argv[0] ? argv[0] : uts.release);
983
984
985 process_module((char*)"/", NULL);
986 return !wrote_dep_bb_ok;
987 }
988
989#if ENABLE_MODPROBE || ENABLE_INSMOD || ENABLE_RMMOD
990
991
992
993 getopt32(argv, "^" "qrfsvwb" "\0" "-1");
994 argv += optind;
995
996 if (is_modprobe) {
997
998 xchdir(uts.release);
999 }
1000
1001
1002
1003 if (is_rmmod) {
1004 if (!ONLY_APPLET)
1005 option_mask32 |= OPT_r;
1006 } else if (!ENABLE_MODPROBE || !(option_mask32 & OPT_r)) {
1007# if ENABLE_FEATURE_CMDLINE_MODULE_OPTIONS
1008
1009
1010 char **arg = argv;
1011 while (*++arg) {
1012
1013 char *s = options;
1014 options = xasprintf("%s \"%s\"", s ? s : "", *arg);
1015 free(s);
1016 *arg = NULL;
1017 }
1018# else
1019 argv[1] = NULL;
1020# endif
1021 }
1022
1023 if (is_insmod) {
1024 size_t len;
1025 void *map;
1026
1027 len = MAXINT(ssize_t);
1028 map = xmalloc_open_zipped_read_close(*argv, &len);
1029 if (!map)
1030 bb_perror_msg_and_die("can't read '%s'", *argv);
1031 if (init_module(map, len,
1032 (IF_FEATURE_CMDLINE_MODULE_OPTIONS(options ? options : ) "")
1033 ) != 0
1034 ) {
1035 bb_error_msg_and_die("can't insert '%s': %s",
1036 *argv, moderror(errno));
1037 }
1038 return EXIT_SUCCESS;
1039 }
1040
1041
1042 if (!is_rmmod) {
1043 load_dep_bb();
1044 }
1045
1046
1047
1048 exitcode = EXIT_SUCCESS;
1049 do {
1050 exitcode |= process_module(*argv, options);
1051 } while (*++argv);
1052
1053 if (ENABLE_FEATURE_CLEAN_UP) {
1054 IF_FEATURE_CMDLINE_MODULE_OPTIONS(free(options);)
1055 }
1056 return exitcode;
1057#endif
1058}
1059
1060#endif
1061