busybox: fix spurious rebuild issue
[openwrt.git] / package / busybox / patches / 470-insmod_search.patch
1 --- a/modutils/insmod.c
2 +++ b/modutils/insmod.c
3 @@ -61,21 +61,117 @@
4  #include "libbb.h"
5  #include <libgen.h>
6  #include <sys/utsname.h>
7 +#if ENABLE_FEATURE_2_6_MODULES
8 +#include <sys/mman.h>
9 +#include <asm/unistd.h>
10 +#include <sys/syscall.h>
11 +#endif
12  
13  #if !ENABLE_FEATURE_2_4_MODULES && !ENABLE_FEATURE_2_6_MODULES
14  #undef ENABLE_FEATURE_2_4_MODULES
15  #define ENABLE_FEATURE_2_4_MODULES 1
16  #endif
17  
18 -/*
19 - * Big piece of 2.4-specific code
20 - */
21  #if ENABLE_FEATURE_2_4_MODULES
22 -
23 +int insmod_main_24(int argc, char **argv);
24 +#endif
25  #if ENABLE_FEATURE_2_6_MODULES
26 -static int insmod_ng_main(int argc, char **argv);
27 +int insmod_main_26(int argc, char **argv);
28  #endif
29 +int insmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
30  
31 +static char *g_filename = NULL;
32 +#define _PATH_MODULES  "/lib/modules"
33 +
34 +static int check_module_name_match(const char *filename, struct stat *statbuf,
35 +                                  void *userdata, int depth)
36 +{
37 +       char *fullname = (char *) userdata;
38 +       char *tmp;
39 +
40 +       if (fullname[0] == '\0')
41 +               return FALSE;
42 +
43 +       tmp = bb_get_last_path_component_nostrip(filename);
44 +       if (strcmp(tmp, fullname) == 0) {
45 +               /* Stop searching if we find a match */
46 +               g_filename = xstrdup(filename);
47 +               return FALSE;
48 +       }
49 +
50 +       return TRUE;
51 +}
52 +
53 +static int find_module(char *filename)
54 +{
55 +       char *module_dir, real_module_dir[FILENAME_MAX];
56 +       int len, slen, ret = ENOENT, k_version;
57 +       struct utsname myuname;
58 +       const char *suffix;
59 +       struct stat st;
60 +
61 +       /* check the kernel version */
62 +       if ((uname(&myuname) != 0) || (myuname.release[0] != '2'))
63 +               return EINVAL;
64 +
65 +       k_version = myuname.release[2] - '0';
66 +#if ENABLE_FEATURE_2_4_MODULES
67 +       if (k_version <= 4)
68 +               suffix = ".o";
69 +       else
70 +#endif
71 +               suffix = ".ko";
72 +
73 +       len = strlen(filename);
74 +       slen = strlen(suffix);
75 +
76 +       /* check for suffix and absolute path first */
77 +       if ((len < slen + 2) || (strcmp(filename + len - slen, suffix) != 0)) {
78 +               filename = xasprintf("%s%s", filename, suffix);
79 +       } else {
80 +               filename = strdup(filename);
81 +               if ((stat(filename, &st) == 0) && S_ISREG(st.st_mode)) {
82 +                       g_filename = filename;
83 +                       return 0;
84 +               }
85 +               free(filename);
86 +               return ENOENT;
87 +       }
88 +
89 +       /* next: scan /lib/modules/<release> */
90 +       /* Jump through hoops in case /lib/modules/`uname -r`
91 +       * is a symlink.  We do not want recursive_action to
92 +       * follow symlinks, but we do want to follow the
93 +       * /lib/modules/`uname -r` dir, So resolve it ourselves
94 +       * if it is a link... */
95 +       module_dir = concat_path_file(_PATH_MODULES, myuname.release);
96 +       if (realpath(module_dir, real_module_dir) != NULL) {
97 +               free(module_dir);
98 +               module_dir = real_module_dir;
99 +       }
100 +
101 +       recursive_action(module_dir, ACTION_RECURSE,
102 +               check_module_name_match, 0, filename, 0);
103 +
104 +       /* Check if we have a complete path */
105 +       if (g_filename == NULL)
106 +               goto done;
107 +
108 +       if ((stat(g_filename, &st) == 0) && S_ISREG(st.st_mode))
109 +               ret = 0;
110 +       else
111 +               free(g_filename);
112 +
113 +done:
114 +       free(filename);
115 +
116 +       return ret;
117 +}
118 +
119 +/*
120 + * Big piece of 2.4-specific code
121 + */
122 +#if ENABLE_FEATURE_2_4_MODULES
123  #if ENABLE_FEATURE_INSMOD_LOADINKMEM
124  #define LOADBITS 0
125  #else
126 @@ -184,7 +280,6 @@ static int insmod_ng_main(int argc, char
127  /* Microblaze */
128  #if defined(__microblaze__)
129  #define USE_SINGLE
130 -#include <linux/elf-em.h>
131  #define MATCH_MACHINE(x) (x == EM_XILINX_MICROBLAZE)
132  #define SHT_RELM       SHT_RELA
133  #define Elf32_RelM     Elf32_Rela
134 @@ -452,7 +547,7 @@ enum {
135  /* The system calls unchanged between 2.0 and 2.1.  */
136  
137  unsigned long create_module(const char *, size_t);
138 -int delete_module(const char *module, unsigned int flags);
139 +int delete_module(const char *);
140  
141  
142  #endif /* module.h */
143 @@ -652,7 +747,7 @@ static struct obj_symbol *arch_new_symbo
144  
145  static enum obj_reloc arch_apply_relocation(struct obj_file *f,
146                                       struct obj_section *targsec,
147 -                                     /*struct obj_section *symsec,*/
148 +                                     struct obj_section *symsec,
149                                       struct obj_symbol *sym,
150                                       ElfW(RelM) *rel, ElfW(Addr) value);
151  
152 @@ -673,6 +768,7 @@ static int obj_gpl_license(struct obj_fi
153  #define SPFX   ""
154  #endif
155  
156 +
157  enum { STRVERSIONLEN = 64 };
158  
159  /*======================================================================*/
160 @@ -788,28 +884,6 @@ static char *m_filename;
161  static char *m_fullName;
162  
163  
164 -/*======================================================================*/
165 -
166 -
167 -static int check_module_name_match(const char *filename,
168 -               struct stat *statbuf ATTRIBUTE_UNUSED,
169 -               void *userdata, int depth ATTRIBUTE_UNUSED)
170 -{
171 -       char *fullname = (char *) userdata;
172 -       char *tmp;
173 -
174 -       if (fullname[0] == '\0')
175 -               return FALSE;
176 -
177 -       tmp = bb_get_last_path_component_nostrip(filename);
178 -       if (strcmp(tmp, fullname) == 0) {
179 -               /* Stop searching if we find a match */
180 -               m_filename = xstrdup(filename);
181 -               return FALSE;
182 -       }
183 -       return TRUE;
184 -}
185 -
186  
187  /*======================================================================*/
188  
189 @@ -835,32 +909,20 @@ static struct obj_symbol *arch_new_symbo
190  static enum obj_reloc
191  arch_apply_relocation(struct obj_file *f,
192                                 struct obj_section *targsec,
193 -                               /*struct obj_section *symsec,*/
194 +                               struct obj_section *symsec,
195                                 struct obj_symbol *sym,
196                                 ElfW(RelM) *rel, ElfW(Addr) v)
197  {
198 -#if defined(__arm__) || defined(__i386__) || defined(__mc68000__) \
199 - || defined(__sh__) || defined(__s390__) || defined(__x86_64__) \
200 - || defined(__powerpc__) || defined(__mips__)
201         struct arch_file *ifile = (struct arch_file *) f;
202 -#endif
203         enum obj_reloc ret = obj_reloc_ok;
204         ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + rel->r_offset);
205 -#if defined(__arm__) || defined(__H8300H__) || defined(__H8300S__) \
206 - || defined(__i386__) || defined(__mc68000__) || defined(__microblaze__) \
207 - || defined(__mips__) || defined(__nios2__) || defined(__powerpc__) \
208 - || defined(__s390__) || defined(__sh__) || defined(__x86_64__)
209         ElfW(Addr) dot = targsec->header.sh_addr + rel->r_offset;
210 -#endif
211  #if defined(USE_GOT_ENTRIES) || defined(USE_PLT_ENTRIES)
212         struct arch_symbol *isym = (struct arch_symbol *) sym;
213  #endif
214 -#if defined(__arm__) || defined(__i386__) || defined(__mc68000__) \
215 - || defined(__sh__) || defined(__s390__)
216  #if defined(USE_GOT_ENTRIES)
217         ElfW(Addr) got = ifile->got ? ifile->got->header.sh_addr : 0;
218  #endif
219 -#endif
220  #if defined(USE_PLT_ENTRIES)
221         ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0;
222         unsigned long *ip;
223 @@ -954,7 +1016,6 @@ arch_apply_relocation(struct obj_file *f
224  
225                 case R_386_PLT32:
226                 case R_386_PC32:
227 -               case R_386_GOTOFF:
228                         *loc += v - dot;
229                         break;
230  
231 @@ -973,6 +1034,9 @@ arch_apply_relocation(struct obj_file *f
232  
233                 case R_386_GOT32:
234                         goto bb_use_got;
235 +
236 +               case R_386_GOTOFF:
237 +                       *loc += v - got;
238                         break;
239  
240  #elif defined(__microblaze__)
241 @@ -1759,7 +1823,7 @@ static int arch_list_add(ElfW(RelM) *rel
242  
243  #if defined(USE_SINGLE)
244  
245 -static int arch_single_init(/*ElfW(RelM) *rel,*/ struct arch_single_entry *single,
246 +static int arch_single_init(ElfW(RelM) *rel, struct arch_single_entry *single,
247                              int offset, int size)
248  {
249         if (single->allocated == 0) {
250 @@ -1907,7 +1971,7 @@ static void arch_create_got(struct obj_f
251  #if defined(USE_GOT_ENTRIES)
252                         if (got_allocate) {
253                                 got_offset += arch_single_init(
254 -                                               /*rel,*/ &intsym->gotent,
255 +                                               rel, &intsym->gotent,
256                                                 got_offset, GOT_ENTRY_SIZE);
257  
258                                 got_needed = 1;
259 @@ -1921,7 +1985,7 @@ static void arch_create_got(struct obj_f
260                                                 plt_offset, PLT_ENTRY_SIZE);
261  #else
262                                 plt_offset += arch_single_init(
263 -                                               /*rel,*/ &intsym->pltent,
264 +                                               rel, &intsym->pltent,
265                                                 plt_offset, PLT_ENTRY_SIZE);
266  #endif
267                                 plt_needed = 1;
268 @@ -1959,8 +2023,7 @@ static unsigned long obj_elf_hash_n(cons
269         while (n > 0) {
270                 ch = *name++;
271                 h = (h << 4) + ch;
272 -               g = (h & 0xf0000000);
273 -               if (g != 0) {
274 +               if ((g = (h & 0xf0000000)) != 0) {
275                         h ^= g >> 24;
276                         h &= ~g;
277                 }
278 @@ -2039,7 +2102,7 @@ obj_add_symbol(struct obj_file *f, const
279         int n_type = ELF_ST_TYPE(info);
280         int n_binding = ELF_ST_BIND(info);
281  
282 -       for (sym = f->symtab[hash]; sym; sym = sym->next) {
283 +       for (sym = f->symtab[hash]; sym; sym = sym->next)
284                 if (f->symbol_cmp(sym->name, name) == 0) {
285                         int o_secidx = sym->secidx;
286                         int o_info = sym->info;
287 @@ -2098,14 +2161,14 @@ obj_add_symbol(struct obj_file *f, const
288                                 return sym;
289                         }
290                 }
291 -       }
292  
293         /* Completely new symbol.  */
294         sym = arch_new_symbol();
295         sym->next = f->symtab[hash];
296         f->symtab[hash] = sym;
297         sym->ksymidx = -1;
298 -       if (ELF_ST_BIND(info) == STB_LOCAL && symidx != (unsigned long)(-1)) {
299 +
300 +       if (ELF_ST_BIND(info) == STB_LOCAL && symidx != -1) {
301                 if (symidx >= f->local_symtab_size)
302                         bb_error_msg("local symbol %s with index %ld exceeds local_symtab_size %ld",
303                                         name, (long) symidx, (long) f->local_symtab_size);
304 @@ -3228,7 +3291,7 @@ static int obj_relocate(struct obj_file 
305  
306                         /* Do it! */
307                         switch (arch_apply_relocation
308 -                                       (f, targsec, /*symsec,*/ intsym, rel, value)
309 +                                       (f, targsec, symsec, intsym, rel, value)
310                         ) {
311                         case obj_reloc_ok:
312                                 break;
313 @@ -3307,11 +3370,11 @@ static int obj_create_image(struct obj_f
314  
315  /*======================================================================*/
316  
317 -static struct obj_file *obj_load(FILE * fp, int loadprogbits ATTRIBUTE_UNUSED)
318 +static struct obj_file *obj_load(FILE * fp, int loadprogbits)
319  {
320         struct obj_file *f;
321         ElfW(Shdr) * section_headers;
322 -       size_t shnum, i;
323 +       int shnum, i;
324         char *shstrtab;
325  
326         /* Read the file header.  */
327 @@ -3583,7 +3646,7 @@ static int obj_gpl_license(struct obj_fi
328                 while (ptr < endptr) {
329                         value = strchr(ptr, '=');
330                         if (value && strncmp(ptr, "license", value-ptr) == 0) {
331 -                               unsigned i;
332 +                               int i;
333                                 if (license)
334                                         *license = value+1;
335                                 for (i = 0; i < ARRAY_SIZE(gpl_licenses); ++i) {
336 @@ -3687,9 +3750,6 @@ static void check_tainted_module(struct 
337   * start of some sections.  this info is used by ksymoops to do better
338   * debugging.
339   */
340 -#if !ENABLE_FEATURE_INSMOD_VERSION_CHECKING
341 -#define get_module_version(f, str) get_module_version(str)
342 -#endif
343  static int
344  get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
345  {
346 @@ -3722,8 +3782,7 @@ add_ksymoops_symbols(struct obj_file *f,
347         struct obj_symbol *sym;
348         char *name, *absolute_filename;
349         char str[STRVERSIONLEN];
350 -       unsigned i;
351 -       int l, lm_name, lfilename, use_ksymtab, version;
352 +       int i, l, lm_name, lfilename, use_ksymtab, version;
353         struct stat statbuf;
354  
355         /* WARNING: was using realpath, but replaced by readlink to stop using
356 @@ -3910,145 +3969,57 @@ static void print_load_map(struct obj_fi
357  void print_load_map(struct obj_file *f);
358  #endif
359  
360 -int insmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
361 -int insmod_main(int argc, char **argv)
362 +int insmod_main_24( int argc, char **argv)
363  {
364         char *opt_o, *arg1;
365 -       int len;
366         int k_crcs;
367 -       char *tmp, *tmp1;
368         unsigned long m_size;
369         ElfW(Addr) m_addr;
370         struct obj_file *f;
371 -       struct stat st;
372 -       char *m_name = NULL;
373 -       int exit_status = EXIT_FAILURE;
374 +       char *tmp = NULL, *m_name = NULL;
375 +       int ret = EINVAL;
376         int m_has_modinfo;
377  #if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
378         struct utsname uts_info;
379         char m_strversion[STRVERSIONLEN];
380         int m_version, m_crcs;
381  #endif
382 -#if ENABLE_FEATURE_CLEAN_UP
383         FILE *fp = NULL;
384 -#else
385 -       FILE *fp;
386 -#endif
387 -       int k_version = 0;
388 +       int k_version;
389         struct utsname myuname;
390  
391 +       /* check the kernel version */
392 +       if ((uname(&myuname) != 0) || (myuname.release[0] != '2'))
393 +               return EINVAL;
394 +
395 +       k_version = myuname.release[2] - '0';
396 +       if (k_version > 4)
397 +               return ENOTSUP;
398 +
399         /* Parse any options */
400         getopt32(argv, OPTION_STR, &opt_o);
401         arg1 = argv[optind];
402         if (option_mask32 & OPT_o) { // -o /* name the output module */
403 -               free(m_name);
404                 m_name = xstrdup(opt_o);
405         }
406  
407 -       if (arg1 == NULL) {
408 +       if (arg1 == NULL)
409                 bb_show_usage();
410 -       }
411  
412 -       /* Grab the module name */
413 -       tmp1 = xstrdup(arg1);
414 -       tmp = basename(tmp1);
415 -       len = strlen(tmp);
416 -
417 -       if (uname(&myuname) == 0) {
418 -               if (myuname.release[0] == '2') {
419 -                       k_version = myuname.release[2] - '0';
420 -               }
421 -       }
422 -
423 -#if ENABLE_FEATURE_2_6_MODULES
424 -       if (k_version > 4 && len > 3 && tmp[len - 3] == '.'
425 -        && tmp[len - 2] == 'k' && tmp[len - 1] == 'o'
426 -       ) {
427 -               len -= 3;
428 -               tmp[len] = '\0';
429 -       } else
430 -#endif
431 -               if (len > 2 && tmp[len - 2] == '.' && tmp[len - 1] == 'o') {
432 -                       len -= 2;
433 -                       tmp[len] = '\0';
434 -               }
435 -
436 -
437 -#if ENABLE_FEATURE_2_6_MODULES
438 -       if (k_version > 4)
439 -               m_fullName = xasprintf("%s.ko", tmp);
440 -       else
441 -#endif
442 -               m_fullName = xasprintf("%s.o", tmp);
443 +       ret = find_module(arg1);
444 +       if (ret)
445 +               goto out;
446  
447         if (!m_name) {
448 -               m_name = tmp;
449 -       } else {
450 -               free(tmp1);
451 -               tmp1 = NULL;       /* flag for free(m_name) before exit() */
452 -       }
453 -
454 -       /* Get a filedesc for the module.  Check that we have a complete path */
455 -       if (stat(arg1, &st) < 0 || !S_ISREG(st.st_mode)
456 -        || (fp = fopen(arg1, "r")) == NULL
457 -       ) {
458 -               /* Hmm.  Could not open it.  First search under /lib/modules/`uname -r`,
459 -                * but do not error out yet if we fail to find it... */
460 -               if (k_version) {        /* uname succeedd */
461 -                       char *module_dir;
462 -                       char *tmdn;
463 -
464 -                       tmdn = concat_path_file(CONFIG_DEFAULT_MODULES_DIR, myuname.release);
465 -                       /* Jump through hoops in case /lib/modules/`uname -r`
466 -                        * is a symlink.  We do not want recursive_action to
467 -                        * follow symlinks, but we do want to follow the
468 -                        * /lib/modules/`uname -r` dir, So resolve it ourselves
469 -                        * if it is a link... */
470 -                       module_dir = xmalloc_readlink(tmdn);
471 -                       if (!module_dir)
472 -                               module_dir = xstrdup(tmdn);
473 -                       recursive_action(module_dir, ACTION_RECURSE,
474 -                                       check_module_name_match, NULL, m_fullName, 0);
475 -                       free(module_dir);
476 -                       free(tmdn);
477 -               }
478 -
479 -               /* Check if we have found anything yet */
480 -               if (!m_filename || ((fp = fopen(m_filename, "r")) == NULL)) {
481 -                       int r;
482 -                       char *module_dir;
483 -
484 -                       free(m_filename);
485 -                       m_filename = NULL;
486 -                       module_dir = xmalloc_readlink(CONFIG_DEFAULT_MODULES_DIR);
487 -                       if (!module_dir)
488 -                               module_dir = xstrdup(CONFIG_DEFAULT_MODULES_DIR);
489 -                       /* No module found under /lib/modules/`uname -r`, this
490 -                        * time cast the net a bit wider.  Search /lib/modules/ */
491 -                       r = recursive_action(module_dir, ACTION_RECURSE,
492 -                                       check_module_name_match, NULL, m_fullName, 0);
493 -                       if (r)
494 -                               bb_error_msg_and_die("%s: module not found", m_fullName);
495 -                       free(module_dir);
496 -                       if (m_filename == NULL
497 -                        || ((fp = fopen(m_filename, "r")) == NULL)
498 -                       ) {
499 -                               bb_error_msg_and_die("%s: module not found", m_fullName);
500 -                       }
501 +               tmp = xstrdup(arg1);
502 +               m_name = basename(tmp);
503                 }
504 -       } else
505 -               m_filename = xstrdup(arg1);
506  
507 -       if (flag_verbose)
508 -               printf("Using %s\n", m_filename);
509 -
510 -#if ENABLE_FEATURE_2_6_MODULES
511 -       if (k_version > 4) {
512 -               argv[optind] = m_filename;
513 -               optind--;
514 -               return insmod_ng_main(argc - optind, argv + optind);
515 +       fp = fopen(g_filename, "r");
516 +       if (!fp) {
517 +               ret = errno;
518 +               goto out;
519         }
520 -#endif
521  
522         f = obj_load(fp, LOADBITS);
523  
524 @@ -4075,7 +4046,7 @@ int insmod_main(int argc, char **argv)
525                                 "\t%s was compiled for kernel version %s\n"
526                                 "\twhile this kernel is version %s",
527                                 flag_force_load ? "warning: " : "",
528 -                               m_filename, m_strversion, uts_info.release);
529 +                               g_filename, m_strversion, uts_info.release);
530                         if (!flag_force_load)
531                                 goto out;
532                 }
533 @@ -4117,7 +4088,7 @@ int insmod_main(int argc, char **argv)
534         hide_special_symbols(f);
535  
536  #if ENABLE_FEATURE_INSMOD_KSYMOOPS_SYMBOLS
537 -       add_ksymoops_symbols(f, m_filename, m_name);
538 +       add_ksymoops_symbols(f, g_filename, m_name);
539  #endif /* FEATURE_INSMOD_KSYMOOPS_SYMBOLS */
540  
541         new_create_module_ksymtab(f);
542 @@ -4126,7 +4097,7 @@ int insmod_main(int argc, char **argv)
543         m_size = obj_load_size(f);
544  
545         m_addr = create_module(m_name, m_size);
546 -       if (m_addr == (ElfW(Addr))(-1)) switch (errno) {
547 +       if (m_addr == -1) switch (errno) {
548                 case EEXIST:
549                         bb_error_msg_and_die("a module named %s already exists", m_name);
550                 case ENOMEM:
551 @@ -4142,36 +4113,37 @@ int insmod_main(int argc, char **argv)
552          * now we can load them directly into the kernel memory
553          */
554         if (!obj_load_progbits(fp, f, (char*)m_addr)) {
555 -               delete_module(m_name, 0);
556 +               delete_module(m_name);
557                 goto out;
558         }
559  #endif
560  
561         if (!obj_relocate(f, m_addr)) {
562 -               delete_module(m_name, 0);
563 +               delete_module(m_name);
564                 goto out;
565         }
566  
567         if (!new_init_module(m_name, f, m_size)) {
568 -               delete_module(m_name, 0);
569 +               delete_module(m_name);
570                 goto out;
571         }
572  
573         if (flag_print_load_map)
574                 print_load_map(f);
575  
576 -       exit_status = EXIT_SUCCESS;
577 +       ret = EXIT_SUCCESS;
578  
579   out:
580  #if ENABLE_FEATURE_CLEAN_UP
581         if (fp)
582                 fclose(fp);
583 -       free(tmp1);
584 -       if (!tmp1)
585 +       if (tmp)
586 +               free(tmp);
587 +       else if (m_name)
588                 free(m_name);
589 -       free(m_filename);
590 +       free(g_filename);
591  #endif
592 -       return exit_status;
593 +       return ret;
594  }
595  
596  #endif /* ENABLE_FEATURE_2_4_MODULES */
597 @@ -4183,15 +4155,8 @@ int insmod_main(int argc, char **argv)
598  #if ENABLE_FEATURE_2_6_MODULES
599  
600  #include <sys/mman.h>
601 -
602 -#if defined __UCLIBC__ && !ENABLE_FEATURE_2_4_MODULES
603 -/* big time suckage. The old prototype above renders our nice fwd-decl wrong */
604 -extern int init_module(void *module, unsigned long len, const char *options);
605 -#else
606  #include <asm/unistd.h>
607  #include <sys/syscall.h>
608 -#define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)
609 -#endif
610  
611  /* We use error numbers in a loose translation... */
612  static const char *moderror(int err)
613 @@ -4210,22 +4175,32 @@ static const char *moderror(int err)
614         }
615  }
616  
617 -#if !ENABLE_FEATURE_2_4_MODULES
618 -int insmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
619 -int insmod_main(int argc ATTRIBUTE_UNUSED, char **argv)
620 -#else
621 -static int insmod_ng_main(int argc ATTRIBUTE_UNUSED, char **argv)
622 -#endif
623 +int insmod_main_26(int argc, char **argv)
624  {
625 -       size_t len;
626 +       char *filename, *options;
627 +       struct utsname myuname;
628 +       int k_version;
629         int optlen;
630 +       size_t len;
631         void *map;
632 -       char *filename, *options;
633 +       long ret = 0;
634 +
635 +       /* check the kernel version */
636 +       if ((uname(&myuname) != 0) || (myuname.release[0] != '2'))
637 +               return EINVAL;
638 +
639 +       k_version = myuname.release[2] - '0';
640 +       if (k_version <= 4)
641 +               return ENOTSUP;
642  
643         filename = *++argv;
644         if (!filename)
645                 bb_show_usage();
646  
647 +       ret = find_module(filename);
648 +       if (ret || (g_filename == NULL))
649 +               goto done;
650 +
651         /* Rest is options */
652         options = xzalloc(1);
653         optlen = 0;
654 @@ -4235,41 +4210,47 @@ static int insmod_ng_main(int argc ATTRI
655                 optlen += sprintf(options + optlen, (strchr(*argv,' ') ? "\"%s\" " : "%s "), *argv);
656         }
657  
658 -#if 0
659 -       /* Any special reason why mmap? It isn't performance critical. -vda */
660 -       /* Yes, xmalloc'ing can use *alot* of RAM. Don't forget that there are
661 -        * modules out there that are half a megabyte! mmap()ing is way nicer
662 -        * for small mem boxes, i guess. */
663 -       /* But after load, these modules will take up that 0.5mb in kernel
664 -        * anyway. Using malloc here causes only a transient spike to 1mb,
665 -        * after module is loaded, we go back to normal 0.5mb usage
666 -        * (in kernel). Also, mmap isn't magic - when we touch mapped data,
667 -        * we use memory. -vda */
668 -       int fd;
669 -       struct stat st;
670 -       unsigned long len;
671 -       fd = xopen(filename, O_RDONLY);
672 -       fstat(fd, &st);
673 -       len = st.st_size;
674 -       map = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
675 -       if (map == MAP_FAILED) {
676 -               bb_perror_msg_and_die("cannot mmap '%s'", filename);
677 -       }
678 -
679 -       /* map == NULL on Blackfin, probably on other MMU-less systems too. Workaround. */
680 -       if (map == NULL) {
681 -               map = xmalloc(len);
682 -               xread(fd, map, len);
683 -       }
684 -#else
685         len = MAXINT(ssize_t);
686 -       map = xmalloc_open_read_close(filename, &len);
687 -#endif
688 +       map = xmalloc_open_read_close(g_filename, &len);
689 +       ret = syscall(__NR_init_module, map, len, options);
690 +       if (ret != 0) {
691 +               bb_perror_msg_and_die("cannot insert '%s': %s (%li)",
692 +                               g_filename, moderror(errno), ret);
693 +       }
694 +done:
695 +       if (g_filename && (g_filename != filename))
696 +               free(g_filename);
697  
698 -       if (init_module(map, len, options) != 0)
699 -               bb_error_msg_and_die("cannot insert '%s': %s",
700 -                               filename, moderror(errno));
701 -       return 0;
702 +       return ret;
703  }
704  
705  #endif
706 +
707 +int insmod_main(int argc, char **argv)
708 +{
709 +       int ret;
710 +
711 +       g_filename = NULL;
712 +#if ENABLE_FEATURE_2_6_MODULES
713 +       ret = insmod_main_26(argc, argv);
714 +       if (ret != ENOTSUP)
715 +               goto done;
716 +#endif
717 +
718 +#if ENABLE_FEATURE_2_4_MODULES
719 +       ret = insmod_main_24(argc, argv);
720 +       if (ret != ENOTSUP)
721 +               goto done;
722 +#endif
723 +
724 +       fprintf(stderr, "Error: Kernel version not supported\n");
725 +       return 1;
726 +
727 +done:
728 +       if (ret) {
729 +               errno = ret;
730 +               bb_perror_msg("Loading module failed");
731 +               return ret;
732 +       } else
733 +               return 0;
734 +}