aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2008-10-18 09:16:29 +0000
committerNatanael Copa <ncopa@alpinelinux.org>2008-10-18 09:16:29 +0000
commit645531103b2ee8ef54d53a58eca3b52f7d3fb9ac (patch)
tree216abaf5725ec2ec8fd85ee16bb116ff8ecaf672 /core
added busybox
Diffstat (limited to 'core')
-rw-r--r--core/busybox/APKBUILD43
-rw-r--r--core/busybox/bb-modprobe-v9.diff10876
-rw-r--r--core/busybox/busybox-1.11.1-bb.patch12
-rw-r--r--core/busybox/busybox-1.12.0-mdev-exec.patch11
-rw-r--r--core/busybox/busybox-1.12.1-grep.patch27
-rw-r--r--core/busybox/busybox-1.12.1-iproute-metric.patch36
-rw-r--r--core/busybox/busybox-1.12.1-r1851
-rw-r--r--core/busybox/busybox-1.12.1-vi.patch11
-rw-r--r--core/busybox/busybox-1.7.0-vi-path.patch13
-rw-r--r--core/busybox/busybox-devmem.patch128
-rw-r--r--core/busybox/busyboxconfig851
11 files changed, 12859 insertions, 0 deletions
diff --git a/core/busybox/APKBUILD b/core/busybox/APKBUILD
new file mode 100644
index 00000000000..b1d017e7dcf
--- /dev/null
+++ b/core/busybox/APKBUILD
@@ -0,0 +1,43 @@
+pkgname=busybox
+pkgver=1.12.1
+pkgrel=1
+pkgdesc="Size optimized toolbox of many common UNIX utilities"
+url=http://busybox.net
+license=GPL-2
+arch=i486
+makedepends="binutils gcc linux-headers make patch uclibc-dev"
+
+source="http://busybox.net/downloads/busybox-1.12.1.tar.bz2
+ http://busybox.net/downloads/fixes-1.12.1/busybox-1.12.1-grep.patch
+ bb-modprobe-v9.diff
+ $pkgname-1.12.1-vi.patch
+ $pkgname-1.11.1-bb.patch
+ $pkgname-1.12.0-mdev-exec.patch
+ $pkgname-1.12.1-iproute-metric.patch
+ busyboxconfig"
+
+build() {
+ cd $srcdir/$pkgname-$pkgver
+
+ #patches
+ patch -p1 -i ../$pkgname-1.12.1-vi.patch || return 1
+ patch -p1 -i ../$pkgname-1.11.1-bb.patch || return 1
+ patch -p0 -i ../$pkgname-1.12.0-mdev-exec.patch || return 1
+ patch -p1 -i ../$pkgname-1.12.1-grep.patch || return 1
+ patch -p0 -i ../$pkgname-1.12.1-iproute-metric.patch || return 1
+ patch -p0 -i ../bb-modprobe-v9.diff || return 1
+
+ cp ../busyboxconfig .config
+ make silentoldconfig || return 1
+ make || return 1
+ make install DESTDIR=$pkgdir
+}
+
+md5sums="dc2e5e00d6fee8229ae92884c68733a7 busybox-1.12.1.tar.bz2
+76273f1580295a12270dcca0cdeb9a27 busybox-1.12.1-grep.patch
+a8aff3962d4481e8b402e739703fbe38 bb-modprobe-v9.diff
+a427a73c3d53d3c5bb05fba0fd34e397 busybox-1.12.1-vi-path.patch
+4c0f3b486eaa0674961b7ddcd0c60a9b busybox-1.11.1-bb.patch
+b4ce6235028c2c20fa367375534c3a18 busybox-1.12.0-mdev-exec.patch
+54de0abe27e0ad362973be7fa81c487e busybox-1.12.1-iproute-metric.patch
+997d1759dec4cbbf90594824a2ac34b5 busyboxconfig"
diff --git a/core/busybox/bb-modprobe-v9.diff b/core/busybox/bb-modprobe-v9.diff
new file mode 100644
index 00000000000..b3885988c2a
--- /dev/null
+++ b/core/busybox/bb-modprobe-v9.diff
@@ -0,0 +1,10876 @@
+Index: modutils/lsmod.c
+===================================================================
+--- modutils/lsmod.c (revision 23360)
++++ modutils/lsmod.c (working copy)
+@@ -3,192 +3,77 @@
+ * Mini lsmod implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
++ * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
+ *
+- * Modified by Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and
+- * Nicolas Ferre <nicolas.ferre@alcove.fr> to support pre 2.1 kernels
+- * (which lack the query_module() interface).
+- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+ #include "libbb.h"
++#include "modutils.h"
+
++#if ENABLE_FEATURE_CHECK_TAINTED_MODULE
++enum {
++ TAINT_PROPRIETORY_MODULE = (1<<0),
++ TAINT_FORCED_MODULE = (1<<1),
++ TAINT_UNSAFE_SMP = (1<<2),
++};
+
+-#if !ENABLE_FEATURE_CHECK_TAINTED_MODULE
+-static void check_tainted(void) { bb_putchar('\n'); }
+-#else
+-#define TAINT_FILENAME "/proc/sys/kernel/tainted"
+-#define TAINT_PROPRIETORY_MODULE (1<<0)
+-#define TAINT_FORCED_MODULE (1<<1)
+-#define TAINT_UNSAFE_SMP (1<<2)
+-
+ static void check_tainted(void)
+ {
+- int tainted;
+- FILE *f;
+-
+- tainted = 0;
+- f = fopen_for_read(TAINT_FILENAME);
+- if (f) {
+- fscanf(f, "%d", &tainted);
+- fclose(f);
++ int tainted = 0;
++ char *buf = xmalloc_open_read_close("/proc/sys/kernel/tainted", NULL);
++ if (buf) {
++ tainted = atoi(buf);
++ if (ENABLE_FEATURE_CLEAN_UP)
++ free(buf);
+ }
++
+ if (tainted) {
+ printf(" Tainted: %c%c%c\n",
+ tainted & TAINT_PROPRIETORY_MODULE ? 'P' : 'G',
+ tainted & TAINT_FORCED_MODULE ? 'F' : ' ',
+ tainted & TAINT_UNSAFE_SMP ? 'S' : ' ');
+ } else {
+- printf(" Not tainted\n");
++ puts(" Not tainted");
+ }
+ }
++#else
++static void check_tainted(void) { putchar('\n'); }
+ #endif
+
+-#if ENABLE_FEATURE_QUERY_MODULE_INTERFACE
+-
+-struct module_info
+-{
+- unsigned long addr;
+- unsigned long size;
+- unsigned long flags;
+- long usecount;
+-};
+-
+-
+-int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret);
+-
+-enum {
+-/* Values for query_module's which. */
+- QM_MODULES = 1,
+- QM_DEPS = 2,
+- QM_REFS = 3,
+- QM_SYMBOLS = 4,
+- QM_INFO = 5,
+-
+-/* Bits of module.flags. */
+- NEW_MOD_RUNNING = 1,
+- NEW_MOD_DELETED = 2,
+- NEW_MOD_AUTOCLEAN = 4,
+- NEW_MOD_VISITED = 8,
+- NEW_MOD_USED_ONCE = 16,
+- NEW_MOD_INITIALIZING = 64
+-};
+-
+ int lsmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+ int lsmod_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
+ {
+- struct module_info info;
+- char *module_names, *mn, *deps, *dn;
+- size_t bufsize, depsize, nmod, count, i, j;
+-
+- module_names = deps = NULL;
+- bufsize = depsize = 0;
+- while (query_module(NULL, QM_MODULES, module_names, bufsize, &nmod)) {
+- if (errno != ENOSPC) bb_perror_msg_and_die("QM_MODULES");
+- module_names = xmalloc(bufsize = nmod);
+- }
+-
+- deps = xmalloc(depsize = 256);
+- printf("Module\t\t\tSize Used by");
++#if ENABLE_FEATURE_LSMOD_PRETTY_2_6_OUTPUT
++ char *token[4];
++ parser_t *parser = config_open("/proc/modules");
++ printf("Module Size Used by");
+ check_tainted();
+
+- for (i = 0, mn = module_names; i < nmod; mn += strlen(mn) + 1, i++) {
+- if (query_module(mn, QM_INFO, &info, sizeof(info), &count)) {
+- if (errno == ENOENT) {
+- /* The module was removed out from underneath us. */
+- continue;
+- }
+- /* else choke */
+- bb_perror_msg_and_die("module %s: QM_INFO", mn);
++ if (ENABLE_FEATURE_2_4_MODULES &&
++ get_linux_version_code() < KERNEL_VERSION(2,6,0)) {
++ while (config_read(parser, token, 4, 3, "# \t", PARSE_NORMAL)) {
++ if (token[3] != NULL && token[3][0] == '[') {
++ token[3]++;
++ token[3][strlen(token[3])-1] = '\0';
++ } else
++ token[3] = (char *) "";
++ printf("%-19s %8s %2s %s\n", token[0], token[1], token[2], token[3]);
+ }
+- while (query_module(mn, QM_REFS, deps, depsize, &count)) {
+- if (errno == ENOENT) {
+- /* The module was removed out from underneath us. */
+- continue;
+- } else if (errno != ENOSPC)
+- bb_perror_msg_and_die("module %s: QM_REFS", mn);
+- deps = xrealloc(deps, count);
++ } else {
++ while (config_read(parser, token, 4, 4, "# \t", PARSE_NORMAL & ~PARSE_GREEDY)) {
++ // N.B. token[3] is either '-' (module is not used by others)
++ // or comma-separated list ended by comma
++ // so trimming the trailing char is just what we need!
++ token[3][strlen(token[3])-1] = '\0';
++ printf("%-19s %8s %2s %s\n", token[0], token[1], token[2], token[3]);
+ }
+- printf("%-20s%8lu%4ld", mn, info.size, info.usecount);
+- if (info.flags & NEW_MOD_DELETED)
+- printf(" (deleted)");
+- else if (info.flags & NEW_MOD_INITIALIZING)
+- printf(" (initializing)");
+- else if (!(info.flags & NEW_MOD_RUNNING))
+- printf(" (uninitialized)");
+- else {
+- if (info.flags & NEW_MOD_AUTOCLEAN)
+- printf(" (autoclean) ");
+- if (!(info.flags & NEW_MOD_USED_ONCE))
+- printf(" (unused)");
+- }
+- if (count)
+- printf(" [");
+- for (j = 0, dn = deps; j < count; dn += strlen(dn) + 1, j++) {
+- printf("%s%s", dn, (j==count-1)? "":" ");
+- }
+- if (count)
+- bb_putchar(']');
+-
+- bb_putchar('\n');
+ }
+-
+-#if ENABLE_FEATURE_CLEAN_UP
+- free(module_names);
+-#endif
+-
+- return 0;
+-}
+-
+-#else /* CONFIG_FEATURE_QUERY_MODULE_INTERFACE */
+-
+-int lsmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+-int lsmod_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
+-{
+- FILE *file = xfopen_for_read("/proc/modules");
+-
+- printf("Module Size Used by");
+- check_tainted();
+-#if ENABLE_FEATURE_LSMOD_PRETTY_2_6_OUTPUT
+- {
+- char *line;
+- while ((line = xmalloc_fgets(file)) != NULL) {
+- char *tok;
+-
+- tok = strtok(line, " \t");
+- printf("%-19s", tok);
+- tok = strtok(NULL, " \t\n");
+- printf(" %8s", tok);
+- tok = strtok(NULL, " \t\n");
+- /* Null if no module unloading support. */
+- if (tok) {
+- printf(" %s", tok);
+- tok = strtok(NULL, "\n");
+- if (!tok)
+- tok = (char*)"";
+- /* New-style has commas, or -. If so,
+- truncate (other fields might follow). */
+- else if (strchr(tok, ',')) {
+- tok = strtok(tok, "\t ");
+- /* Strip trailing comma. */
+- if (tok[strlen(tok)-1] == ',')
+- tok[strlen(tok)-1] = '\0';
+- } else if (tok[0] == '-'
+- && (tok[1] == '\0' || isspace(tok[1]))
+- ) {
+- tok = (char*)"";
+- }
+- printf(" %s", tok);
+- }
+- bb_putchar('\n');
+- free(line);
+- }
+- fclose(file);
+- }
++ if (ENABLE_FEATURE_CLEAN_UP)
++ config_close(parser);
+ #else
+- xprint_and_close_file(file);
+-#endif /* CONFIG_FEATURE_2_6_MODULES */
++ check_tainted();
++ xprint_and_close_file(xfopen_for_read("/proc/modules"));
++#endif
+ return EXIT_SUCCESS;
+ }
+-
+-#endif /* CONFIG_FEATURE_QUERY_MODULE_INTERFACE */
+Index: modutils/rmmod.c
+===================================================================
+--- modutils/rmmod.c (revision 23360)
++++ modutils/rmmod.c (working copy)
+@@ -3,98 +3,46 @@
+ * Mini rmmod implementation for busybox
+ *
+ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
++ * Copyright (C) 2008 Timo Teras <timo.teras@iki.fi>
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+ #include "libbb.h"
++#include "modutils.h"
+
+-#ifdef __UCLIBC__
+-extern int delete_module(const char *module, unsigned int flags);
+-#else
+-# include <sys/syscall.h>
+-# define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags)
+-#endif
+-
+-#if ENABLE_FEATURE_2_6_MODULES
+-static void filename2modname(char *modname, const char *afterslash)
+-{
+- unsigned int i;
+- int kr_chk = 1;
+-
+- if (ENABLE_FEATURE_2_4_MODULES
+- && get_linux_version_code() <= KERNEL_VERSION(2,6,0))
+- kr_chk = 0;
+-
+- /* Convert to underscores, stop at first . */
+- for (i = 0; afterslash[i] && afterslash[i] != '.'; i++) {
+- if (kr_chk && (afterslash[i] == '-'))
+- modname[i] = '_';
+- else
+- modname[i] = afterslash[i];
+- }
+- modname[i] = '\0';
+-}
+-#else
+-void filename2modname(char *modname, const char *afterslash);
+-#endif
+-
+-// There really should be a header file for this...
+-
+-int query_module(const char *name, int which, void *buf,
+- size_t bufsize, size_t *ret);
+-
+ int rmmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+-int rmmod_main(int argc, char **argv)
++int rmmod_main(int argc UNUSED_PARAM, char **argv)
+ {
+- int n, ret = EXIT_SUCCESS;
++ int n;
+ unsigned int flags = O_NONBLOCK|O_EXCL;
++ char modname[MODULE_NAME_LEN];
+
+-#define misc_buf bb_common_bufsiz1
+-
+ /* Parse command line. */
+- n = getopt32(argv, "wfa");
++ n = getopt32(argv, "wfas"); // -s ignored
++ argv += optind;
++
+ if (n & 1) // --wait
+ flags &= ~O_NONBLOCK;
+ if (n & 2) // --force
+ flags |= O_TRUNC;
+ if (n & 4) {
+ /* Unload _all_ unused modules via NULL delete_module() call */
+- /* until the number of modules does not change */
+- size_t nmod = 0; /* number of modules */
+- size_t pnmod = -1; /* previous number of modules */
+-
+- while (nmod != pnmod) {
+- if (delete_module(NULL, flags) != 0) {
+- if (errno == EFAULT)
+- return ret;
+- bb_perror_msg_and_die("rmmod");
+- }
+- pnmod = nmod;
+- // the 1 here is QM_MODULES.
+- if (ENABLE_FEATURE_QUERY_MODULE_INTERFACE && query_module(NULL,
+- 1, misc_buf, sizeof(misc_buf),
+- &nmod))
+- {
+- bb_perror_msg_and_die("QM_MODULES");
+- }
+- }
++ if (bb_delete_module(NULL, flags) != 0 && errno != EFAULT)
++ bb_perror_msg_and_die("rmmod");
+ return EXIT_SUCCESS;
+ }
+
+- if (optind == argc)
++ if (!*argv)
+ bb_show_usage();
+
+- for (n = optind; n < argc; n++) {
+- if (ENABLE_FEATURE_2_6_MODULES) {
+- filename2modname(misc_buf, bb_basename(argv[n]));
+- }
++ while (*argv) {
++ filename2modname(bb_basename(*argv++), modname);
+
+- if (delete_module(ENABLE_FEATURE_2_6_MODULES ? misc_buf : argv[n], flags)) {
+- bb_simple_perror_msg(argv[n]);
+- ret = EXIT_FAILURE;
+- }
++ if (bb_delete_module(modname, flags))
++ bb_error_msg_and_die("cannot unload '%s': %s",
++ modname, moderror(errno));
+ }
+
+- return ret;
++ return EXIT_SUCCESS;
+ }
+Index: modutils/modutils.c
+===================================================================
+--- modutils/modutils.c (revision 0)
++++ modutils/modutils.c (revision 0)
+@@ -0,0 +1,111 @@
++/*
++ * Common modutils related functions for busybox
++ *
++ * Copyright (C) 2008 by Timo Teras <timo.teras@iki.fi>
++ *
++ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
++ */
++
++#include "modutils.h"
++
++#ifdef __UCLIBC__
++extern int init_module(void *module, unsigned long len, const char *options);
++extern int delete_module(const char *module, unsigned int flags);
++#else
++# include <sys/syscall.h>
++# define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)
++# define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags)
++#endif
++
++USE_FEATURE_2_4_MODULES(char *insmod_outputname);
++
++int FAST_FUNC string_to_llist(char *string, llist_t **llist, const char *delim)
++{
++ char *tok;
++ int len = 0;
++
++ while ((tok = strsep(&string, delim)) != NULL) {
++ if (tok[0] == '\0')
++ continue;
++ llist_add_to_end(llist, xstrdup(tok));
++ len += strlen(tok);
++ }
++ return len;
++}
++
++char * FAST_FUNC filename2modname(const char *filename, char *modname)
++{
++ int i;
++ char *from;
++
++ if (filename == NULL)
++ return NULL;
++ if (modname == NULL)
++ modname = xmalloc(MODULE_NAME_LEN);
++ from = bb_get_last_path_component_nostrip(filename);
++ for (i = 0; i < MODULE_NAME_LEN && from[i] != '\0' && from[i] != '.'; i++)
++ modname[i] = (from[i] == '-') ? '_' : from[i];
++ modname[i] = 0;
++
++ return modname;
++}
++
++const char * FAST_FUNC moderror(int err)
++{
++ switch (err) {
++ case ENOEXEC:
++ return "invalid module format";
++ case ENOENT:
++ return "unknown symbol in module, or unknown parameter";
++ case ESRCH:
++ return "module has wrong symbol version";
++ case ENOSYS:
++ return "kernel does not support requested operation";
++ default:
++ return strerror(err);
++ }
++}
++
++char * FAST_FUNC parse_cmdline_module_options(char **argv)
++{
++ char *options;
++ int optlen;
++
++ options = xzalloc(1);
++ optlen = 0;
++ while (*++argv) {
++ options = xrealloc(options, optlen + 2 + strlen(*argv) + 2);
++ /* Spaces handled by "" pairs, but no way of escaping quotes */
++ optlen += sprintf(options + optlen, (strchr(*argv,' ') ? "\"%s\" " : "%s "), *argv);
++ }
++ return options;
++}
++
++int FAST_FUNC bb_init_module(const char *filename, const char *options)
++{
++ size_t len = MAXINT(ssize_t);
++ char *image;
++ int rc = ENOENT;
++
++#if ENABLE_FEATURE_2_4_MODULES
++ if (get_linux_version_code() < KERNEL_VERSION(2,6,0))
++ return bb_init_module_24(filename, options);
++#endif
++
++ /* Use the 2.6 way */
++ image = (char *) xmalloc_open_zipped_read_close(filename, &len);
++ if (image) {
++ if (init_module(image, len, options) != 0)
++ rc = errno;
++ else
++ rc = 0;
++ free(image);
++ }
++
++ return rc;
++}
++
++int FAST_FUNC bb_delete_module(const char *module, unsigned int flags)
++{
++ return delete_module(module, flags);
++}
+Index: modutils/modutils-24.c
+===================================================================
+--- modutils/modutils-24.c (revision 0)
++++ modutils/modutils-24.c (revision 0)
+@@ -0,0 +1,3936 @@
++/* vi: set sw=4 ts=4: */
++/*
++ * Mini insmod implementation for busybox
++ *
++ * This version of insmod supports ARM, CRIS, H8/300, x86, ia64, x86_64,
++ * m68k, MIPS, PowerPC, S390, SH3/4/5, Sparc, v850e, and x86_64.
++ *
++ * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
++ * and Ron Alder <alder@lineo.com>
++ *
++ * Rodney Radford <rradford@mindspring.com> 17-Aug-2004.
++ * Added x86_64 support.
++ *
++ * Miles Bader <miles@gnu.org> added NEC V850E support.
++ *
++ * Modified by Bryan Rittmeyer <bryan@ixiacom.com> to support SH4
++ * and (theoretically) SH3. I have only tested SH4 in little endian mode.
++ *
++ * Modified by Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and
++ * Nicolas Ferre <nicolas.ferre@alcove.fr> to support ARM7TDMI. Only
++ * very minor changes required to also work with StrongArm and presumably
++ * all ARM based systems.
++ *
++ * Yoshinori Sato <ysato@users.sourceforge.jp> 19-May-2004.
++ * added Renesas H8/300 support.
++ *
++ * Paul Mundt <lethal@linux-sh.org> 08-Aug-2003.
++ * Integrated support for sh64 (SH-5), from preliminary modutils
++ * patches from Benedict Gaster <benedict.gaster@superh.com>.
++ * Currently limited to support for 32bit ABI.
++ *
++ * Magnus Damm <damm@opensource.se> 22-May-2002.
++ * The plt and got code are now using the same structs.
++ * Added generic linked list code to fully support PowerPC.
++ * Replaced the mess in arch_apply_relocation() with architecture blocks.
++ * The arch_create_got() function got cleaned up with architecture blocks.
++ * These blocks should be easy maintain and sync with obj_xxx.c in modutils.
++ *
++ * Magnus Damm <damm@opensource.se> added PowerPC support 20-Feb-2001.
++ * PowerPC specific code stolen from modutils-2.3.16,
++ * written by Paul Mackerras, Copyright 1996, 1997 Linux International.
++ * I've only tested the code on mpc8xx platforms in big-endian mode.
++ * Did some cleanup and added USE_xxx_ENTRIES...
++ *
++ * Quinn Jensen <jensenq@lineo.com> added MIPS support 23-Feb-2001.
++ * based on modutils-2.4.2
++ * MIPS specific support for Elf loading and relocation.
++ * Copyright 1996, 1997 Linux International.
++ * Contributed by Ralf Baechle <ralf@gnu.ai.mit.edu>
++ *
++ * Based almost entirely on the Linux modutils-2.3.11 implementation.
++ * Copyright 1996, 1997 Linux International.
++ * New implementation contributed by Richard Henderson <rth@tamu.edu>
++ * Based on original work by Bjorn Ekwall <bj0rn@blox.se>
++ * Restructured (and partly rewritten) by:
++ * Björn Ekwall <bj0rn@blox.se> February 1999
++ *
++ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
++ */
++
++#include "libbb.h"
++#include "modutils.h"
++#include <libgen.h>
++#include <sys/utsname.h>
++
++#if ENABLE_FEATURE_INSMOD_LOADINKMEM
++#define LOADBITS 0
++#else
++#define LOADBITS 1
++#endif
++
++/* Alpha */
++#if defined(__alpha__)
++#define MATCH_MACHINE(x) (x == EM_ALPHA)
++#define SHT_RELM SHT_RELA
++#define Elf64_RelM Elf64_Rela
++#define ELFCLASSM ELFCLASS64
++#endif
++
++/* ARM support */
++#if defined(__arm__)
++#define MATCH_MACHINE(x) (x == EM_ARM)
++#define SHT_RELM SHT_REL
++#define Elf32_RelM Elf32_Rel
++#define ELFCLASSM ELFCLASS32
++#define USE_PLT_ENTRIES
++#define PLT_ENTRY_SIZE 8
++#define USE_GOT_ENTRIES
++#define GOT_ENTRY_SIZE 8
++#define USE_SINGLE
++#endif
++
++/* blackfin */
++#if defined(BFIN)
++#define MATCH_MACHINE(x) (x == EM_BLACKFIN)
++#define SHT_RELM SHT_RELA
++#define Elf32_RelM Elf32_Rela
++#define ELFCLASSM ELFCLASS32
++#endif
++
++/* CRIS */
++#if defined(__cris__)
++#define MATCH_MACHINE(x) (x == EM_CRIS)
++#define SHT_RELM SHT_RELA
++#define Elf32_RelM Elf32_Rela
++#define ELFCLASSM ELFCLASS32
++#ifndef EM_CRIS
++#define EM_CRIS 76
++#define R_CRIS_NONE 0
++#define R_CRIS_32 3
++#endif
++#endif
++
++/* H8/300 */
++#if defined(__H8300H__) || defined(__H8300S__)
++#define MATCH_MACHINE(x) (x == EM_H8_300)
++#define SHT_RELM SHT_RELA
++#define Elf32_RelM Elf32_Rela
++#define ELFCLASSM ELFCLASS32
++#define USE_SINGLE
++#define SYMBOL_PREFIX "_"
++#endif
++
++/* PA-RISC / HP-PA */
++#if defined(__hppa__)
++#define MATCH_MACHINE(x) (x == EM_PARISC)
++#define SHT_RELM SHT_RELA
++#if defined(__LP64__)
++#define Elf64_RelM Elf64_Rela
++#define ELFCLASSM ELFCLASS64
++#else
++#define Elf32_RelM Elf32_Rela
++#define ELFCLASSM ELFCLASS32
++#endif
++#endif
++
++/* x86 */
++#if defined(__i386__)
++#ifndef EM_486
++#define MATCH_MACHINE(x) (x == EM_386)
++#else
++#define MATCH_MACHINE(x) (x == EM_386 || x == EM_486)
++#endif
++#define SHT_RELM SHT_REL
++#define Elf32_RelM Elf32_Rel
++#define ELFCLASSM ELFCLASS32
++#define USE_GOT_ENTRIES
++#define GOT_ENTRY_SIZE 4
++#define USE_SINGLE
++#endif
++
++/* IA64, aka Itanium */
++#if defined(__ia64__)
++#define MATCH_MACHINE(x) (x == EM_IA_64)
++#define SHT_RELM SHT_RELA
++#define Elf64_RelM Elf64_Rela
++#define ELFCLASSM ELFCLASS64
++#endif
++
++/* m68k */
++#if defined(__mc68000__)
++#define MATCH_MACHINE(x) (x == EM_68K)
++#define SHT_RELM SHT_RELA
++#define Elf32_RelM Elf32_Rela
++#define ELFCLASSM ELFCLASS32
++#define USE_GOT_ENTRIES
++#define GOT_ENTRY_SIZE 4
++#define USE_SINGLE
++#endif
++
++/* Microblaze */
++#if defined(__microblaze__)
++#define USE_SINGLE
++#include <linux/elf-em.h>
++#define MATCH_MACHINE(x) (x == EM_XILINX_MICROBLAZE)
++#define SHT_RELM SHT_RELA
++#define Elf32_RelM Elf32_Rela
++#define ELFCLASSM ELFCLASS32
++#endif
++
++/* MIPS */
++#if defined(__mips__)
++#define MATCH_MACHINE(x) (x == EM_MIPS || x == EM_MIPS_RS3_LE)
++#define SHT_RELM SHT_REL
++#define Elf32_RelM Elf32_Rel
++#define ELFCLASSM ELFCLASS32
++/* Account for ELF spec changes. */
++#ifndef EM_MIPS_RS3_LE
++#ifdef EM_MIPS_RS4_BE
++#define EM_MIPS_RS3_LE EM_MIPS_RS4_BE
++#else
++#define EM_MIPS_RS3_LE 10
++#endif
++#endif /* !EM_MIPS_RS3_LE */
++#define ARCHDATAM "__dbe_table"
++#endif
++
++/* Nios II */
++#if defined(__nios2__)
++#define MATCH_MACHINE(x) (x == EM_ALTERA_NIOS2)
++#define SHT_RELM SHT_RELA
++#define Elf32_RelM Elf32_Rela
++#define ELFCLASSM ELFCLASS32
++#endif
++
++/* PowerPC */
++#if defined(__powerpc64__)
++#define MATCH_MACHINE(x) (x == EM_PPC64)
++#define SHT_RELM SHT_RELA
++#define Elf64_RelM Elf64_Rela
++#define ELFCLASSM ELFCLASS64
++#elif defined(__powerpc__)
++#define MATCH_MACHINE(x) (x == EM_PPC)
++#define SHT_RELM SHT_RELA
++#define Elf32_RelM Elf32_Rela
++#define ELFCLASSM ELFCLASS32
++#define USE_PLT_ENTRIES
++#define PLT_ENTRY_SIZE 16
++#define USE_PLT_LIST
++#define LIST_ARCHTYPE ElfW(Addr)
++#define USE_LIST
++#define ARCHDATAM "__ftr_fixup"
++#endif
++
++/* S390 */
++#if defined(__s390__)
++#define MATCH_MACHINE(x) (x == EM_S390)
++#define SHT_RELM SHT_RELA
++#define Elf32_RelM Elf32_Rela
++#define ELFCLASSM ELFCLASS32
++#define USE_PLT_ENTRIES
++#define PLT_ENTRY_SIZE 8
++#define USE_GOT_ENTRIES
++#define GOT_ENTRY_SIZE 8
++#define USE_SINGLE
++#endif
++
++/* SuperH */
++#if defined(__sh__)
++#define MATCH_MACHINE(x) (x == EM_SH)
++#define SHT_RELM SHT_RELA
++#define Elf32_RelM Elf32_Rela
++#define ELFCLASSM ELFCLASS32
++#define USE_GOT_ENTRIES
++#define GOT_ENTRY_SIZE 4
++#define USE_SINGLE
++/* the SH changes have only been tested in =little endian= mode */
++/* I'm not sure about big endian, so let's warn: */
++#if defined(__sh__) && BB_BIG_ENDIAN
++# error insmod.c may require changes for use on big endian SH
++#endif
++/* it may or may not work on the SH1/SH2... Error on those also */
++#if ((!(defined(__SH3__) || defined(__SH4__) || defined(__SH5__)))) && (defined(__sh__))
++#error insmod.c may require changes for SH1 or SH2 use
++#endif
++#endif
++
++/* Sparc */
++#if defined(__sparc__)
++#define MATCH_MACHINE(x) (x == EM_SPARC)
++#define SHT_RELM SHT_RELA
++#define Elf32_RelM Elf32_Rela
++#define ELFCLASSM ELFCLASS32
++#endif
++
++/* v850e */
++#if defined(__v850e__)
++#define MATCH_MACHINE(x) ((x) == EM_V850 || (x) == EM_CYGNUS_V850)
++#define SHT_RELM SHT_RELA
++#define Elf32_RelM Elf32_Rela
++#define ELFCLASSM ELFCLASS32
++#define USE_PLT_ENTRIES
++#define PLT_ENTRY_SIZE 8
++#define USE_SINGLE
++#ifndef EM_CYGNUS_V850 /* grumble */
++#define EM_CYGNUS_V850 0x9080
++#endif
++#define SYMBOL_PREFIX "_"
++#endif
++
++/* X86_64 */
++#if defined(__x86_64__)
++#define MATCH_MACHINE(x) (x == EM_X86_64)
++#define SHT_RELM SHT_RELA
++#define USE_GOT_ENTRIES
++#define GOT_ENTRY_SIZE 8
++#define USE_SINGLE
++#define Elf64_RelM Elf64_Rela
++#define ELFCLASSM ELFCLASS64
++#endif
++
++#ifndef SHT_RELM
++#error Sorry, but insmod.c does not yet support this architecture...
++#endif
++
++
++//----------------------------------------------------------------------------
++//--------modutils module.h, lines 45-242
++//----------------------------------------------------------------------------
++
++/* Definitions for the Linux module syscall interface.
++ Copyright 1996, 1997 Linux International.
++
++ Contributed by Richard Henderson <rth@tamu.edu>
++
++ This file is part of the Linux modutils.
++
++ This program is free software; you can redistribute it and/or modify it
++ under the terms of the GNU General Public License as published by the
++ Free Software Foundation; either version 2 of the License, or (at your
++ option) any later version.
++
++ This program is distributed in the hope that it will be useful, but
++ WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software Foundation,
++ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
++
++
++#ifndef MODUTILS_MODULE_H
++
++/*======================================================================*/
++/* For sizeof() which are related to the module platform and not to the
++ environment isnmod is running in, use sizeof_xx instead of sizeof(xx). */
++
++#define tgt_sizeof_char sizeof(char)
++#define tgt_sizeof_short sizeof(short)
++#define tgt_sizeof_int sizeof(int)
++#define tgt_sizeof_long sizeof(long)
++#define tgt_sizeof_char_p sizeof(char *)
++#define tgt_sizeof_void_p sizeof(void *)
++#define tgt_long long
++
++#if defined(__sparc__) && !defined(__sparc_v9__) && defined(ARCH_sparc64)
++#undef tgt_sizeof_long
++#undef tgt_sizeof_char_p
++#undef tgt_sizeof_void_p
++#undef tgt_long
++enum {
++ tgt_sizeof_long = 8,
++ tgt_sizeof_char_p = 8,
++ tgt_sizeof_void_p = 8
++};
++#define tgt_long long long
++#endif
++
++/*======================================================================*/
++/* The structures used in Linux 2.1. */
++
++/* Note: new_module_symbol does not use tgt_long intentionally */
++struct new_module_symbol {
++ unsigned long value;
++ unsigned long name;
++};
++
++struct new_module_persist;
++
++struct new_module_ref {
++ unsigned tgt_long dep; /* kernel addresses */
++ unsigned tgt_long ref;
++ unsigned tgt_long next_ref;
++};
++
++struct new_module {
++ unsigned tgt_long size_of_struct; /* == sizeof(module) */
++ unsigned tgt_long next;
++ unsigned tgt_long name;
++ unsigned tgt_long size;
++
++ tgt_long usecount;
++ unsigned tgt_long flags; /* AUTOCLEAN et al */
++
++ unsigned nsyms;
++ unsigned ndeps;
++
++ unsigned tgt_long syms;
++ unsigned tgt_long deps;
++ unsigned tgt_long refs;
++ unsigned tgt_long init;
++ unsigned tgt_long cleanup;
++ unsigned tgt_long ex_table_start;
++ unsigned tgt_long ex_table_end;
++#ifdef __alpha__
++ unsigned tgt_long gp;
++#endif
++ /* Everything after here is extension. */
++ unsigned tgt_long persist_start;
++ unsigned tgt_long persist_end;
++ unsigned tgt_long can_unload;
++ unsigned tgt_long runsize;
++ const char *kallsyms_start; /* All symbols for kernel debugging */
++ const char *kallsyms_end;
++ const char *archdata_start; /* arch specific data for module */
++ const char *archdata_end;
++ const char *kernel_data; /* Reserved for kernel internal use */
++};
++
++#ifdef ARCHDATAM
++#define ARCHDATA_SEC_NAME ARCHDATAM
++#else
++#define ARCHDATA_SEC_NAME "__archdata"
++#endif
++#define KALLSYMS_SEC_NAME "__kallsyms"
++
++
++struct new_module_info {
++ unsigned long addr;
++ unsigned long size;
++ unsigned long flags;
++ long usecount;
++};
++
++/* Bits of module.flags. */
++enum {
++ NEW_MOD_RUNNING = 1,
++ NEW_MOD_DELETED = 2,
++ NEW_MOD_AUTOCLEAN = 4,
++ NEW_MOD_VISITED = 8,
++ NEW_MOD_USED_ONCE = 16
++};
++
++int init_module(const char *name, const struct new_module *);
++int query_module(const char *name, int which, void *buf,
++ size_t bufsize, size_t *ret);
++
++/* Values for query_module's which. */
++enum {
++ QM_MODULES = 1,
++ QM_DEPS = 2,
++ QM_REFS = 3,
++ QM_SYMBOLS = 4,
++ QM_INFO = 5
++};
++
++/*======================================================================*/
++/* The system calls unchanged between 2.0 and 2.1. */
++
++unsigned long create_module(const char *, size_t);
++int delete_module(const char *module, unsigned int flags);
++
++
++#endif /* module.h */
++
++//----------------------------------------------------------------------------
++//--------end of modutils module.h
++//----------------------------------------------------------------------------
++
++
++
++//----------------------------------------------------------------------------
++//--------modutils obj.h, lines 253-462
++//----------------------------------------------------------------------------
++
++/* Elf object file loading and relocation routines.
++ Copyright 1996, 1997 Linux International.
++
++ Contributed by Richard Henderson <rth@tamu.edu>
++
++ This file is part of the Linux modutils.
++
++ This program is free software; you can redistribute it and/or modify it
++ under the terms of the GNU General Public License as published by the
++ Free Software Foundation; either version 2 of the License, or (at your
++ option) any later version.
++
++ This program is distributed in the hope that it will be useful, but
++ WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software Foundation,
++ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
++
++
++#ifndef MODUTILS_OBJ_H
++
++/* The relocatable object is manipulated using elfin types. */
++
++#include <elf.h>
++#include <endian.h>
++
++#ifndef ElfW
++# if ELFCLASSM == ELFCLASS32
++# define ElfW(x) Elf32_ ## x
++# define ELFW(x) ELF32_ ## x
++# else
++# define ElfW(x) Elf64_ ## x
++# define ELFW(x) ELF64_ ## x
++# endif
++#endif
++
++/* For some reason this is missing from some ancient C libraries.... */
++#ifndef ELF32_ST_INFO
++# define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
++#endif
++
++#ifndef ELF64_ST_INFO
++# define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
++#endif
++
++#define ELF_ST_BIND(info) ELFW(ST_BIND)(info)
++#define ELF_ST_TYPE(info) ELFW(ST_TYPE)(info)
++#define ELF_ST_INFO(bind, type) ELFW(ST_INFO)(bind, type)
++#define ELF_R_TYPE(val) ELFW(R_TYPE)(val)
++#define ELF_R_SYM(val) ELFW(R_SYM)(val)
++
++struct obj_string_patch;
++struct obj_symbol_patch;
++
++struct obj_section
++{
++ ElfW(Shdr) header;
++ const char *name;
++ char *contents;
++ struct obj_section *load_next;
++ int idx;
++};
++
++struct obj_symbol
++{
++ struct obj_symbol *next; /* hash table link */
++ const char *name;
++ unsigned long value;
++ unsigned long size;
++ int secidx; /* the defining section index/module */
++ int info;
++ int ksymidx; /* for export to the kernel symtab */
++ int referenced; /* actually used in the link */
++};
++
++/* Hardcode the hash table size. We shouldn't be needing so many
++ symbols that we begin to degrade performance, and we get a big win
++ by giving the compiler a constant divisor. */
++
++#define HASH_BUCKETS 521
++
++struct obj_file {
++ ElfW(Ehdr) header;
++ ElfW(Addr) baseaddr;
++ struct obj_section **sections;
++ struct obj_section *load_order;
++ struct obj_section **load_order_search_start;
++ struct obj_string_patch *string_patches;
++ struct obj_symbol_patch *symbol_patches;
++ int (*symbol_cmp)(const char *, const char *);
++ unsigned long (*symbol_hash)(const char *);
++ unsigned long local_symtab_size;
++ struct obj_symbol **local_symtab;
++ struct obj_symbol *symtab[HASH_BUCKETS];
++};
++
++enum obj_reloc {
++ obj_reloc_ok,
++ obj_reloc_overflow,
++ obj_reloc_dangerous,
++ obj_reloc_unhandled
++};
++
++struct obj_string_patch {
++ struct obj_string_patch *next;
++ int reloc_secidx;
++ ElfW(Addr) reloc_offset;
++ ElfW(Addr) string_offset;
++};
++
++struct obj_symbol_patch {
++ struct obj_symbol_patch *next;
++ int reloc_secidx;
++ ElfW(Addr) reloc_offset;
++ struct obj_symbol *sym;
++};
++
++
++/* Generic object manipulation routines. */
++
++static unsigned long obj_elf_hash(const char *);
++
++static unsigned long obj_elf_hash_n(const char *, unsigned long len);
++
++static struct obj_symbol *obj_find_symbol(struct obj_file *f,
++ const char *name);
++
++static ElfW(Addr) obj_symbol_final_value(struct obj_file *f,
++ struct obj_symbol *sym);
++
++#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
++static void obj_set_symbol_compare(struct obj_file *f,
++ int (*cmp)(const char *, const char *),
++ unsigned long (*hash)(const char *));
++#endif
++
++static struct obj_section *obj_find_section(struct obj_file *f,
++ const char *name);
++
++static void obj_insert_section_load_order(struct obj_file *f,
++ struct obj_section *sec);
++
++static struct obj_section *obj_create_alloced_section(struct obj_file *f,
++ const char *name,
++ unsigned long align,
++ unsigned long size);
++
++static struct obj_section *obj_create_alloced_section_first(struct obj_file *f,
++ const char *name,
++ unsigned long align,
++ unsigned long size);
++
++static void *obj_extend_section(struct obj_section *sec, unsigned long more);
++
++static void obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
++ const char *string);
++
++static void obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
++ struct obj_symbol *sym);
++
++static void obj_check_undefineds(struct obj_file *f);
++
++static void obj_allocate_commons(struct obj_file *f);
++
++static unsigned long obj_load_size(struct obj_file *f);
++
++static int obj_relocate(struct obj_file *f, ElfW(Addr) base);
++
++static struct obj_file *obj_load(FILE *f, int loadprogbits);
++
++static int obj_create_image(struct obj_file *f, char *image);
++
++/* Architecture specific manipulation routines. */
++
++static struct obj_file *arch_new_file(void);
++
++static struct obj_section *arch_new_section(void);
++
++static struct obj_symbol *arch_new_symbol(void);
++
++static enum obj_reloc arch_apply_relocation(struct obj_file *f,
++ struct obj_section *targsec,
++ /*struct obj_section *symsec,*/
++ struct obj_symbol *sym,
++ ElfW(RelM) *rel, ElfW(Addr) value);
++
++static void arch_create_got(struct obj_file *f);
++#if ENABLE_FEATURE_CHECK_TAINTED_MODULE
++static int obj_gpl_license(struct obj_file *f, const char **license);
++#endif /* FEATURE_CHECK_TAINTED_MODULE */
++#endif /* obj.h */
++//----------------------------------------------------------------------------
++//--------end of modutils obj.h
++//----------------------------------------------------------------------------
++
++
++/* SPFX is always a string, so it can be concatenated to string constants. */
++#ifdef SYMBOL_PREFIX
++#define SPFX SYMBOL_PREFIX
++#else
++#define SPFX ""
++#endif
++
++enum { STRVERSIONLEN = 64 };
++
++/*======================================================================*/
++
++#define flag_force_load (option_mask32 & INSMOD_OPT_FORCE)
++#define flag_autoclean (option_mask32 & INSMOD_OPT_KERNELD)
++#define flag_verbose (option_mask32 & INSMOD_OPT_VERBOSE)
++#define flag_quiet (option_mask32 & INSMOD_OPT_SILENT)
++#define flag_noexport (option_mask32 & INSMOD_OPT_NO_EXPORT)
++#define flag_print_load_map (option_mask32 & INSMOD_OPT_PRINT_MAP)
++
++/*======================================================================*/
++
++#if defined(USE_LIST)
++
++struct arch_list_entry
++{
++ struct arch_list_entry *next;
++ LIST_ARCHTYPE addend;
++ int offset;
++ int inited : 1;
++};
++
++#endif
++
++#if defined(USE_SINGLE)
++
++struct arch_single_entry
++{
++ int offset;
++ int inited : 1;
++ int allocated : 1;
++};
++
++#endif
++
++#if defined(__mips__)
++struct mips_hi16
++{
++ struct mips_hi16 *next;
++ ElfW(Addr) *addr;
++ ElfW(Addr) value;
++};
++#endif
++
++struct arch_file {
++ struct obj_file root;
++#if defined(USE_PLT_ENTRIES)
++ struct obj_section *plt;
++#endif
++#if defined(USE_GOT_ENTRIES)
++ struct obj_section *got;
++#endif
++#if defined(__mips__)
++ struct mips_hi16 *mips_hi16_list;
++#endif
++};
++
++struct arch_symbol {
++ struct obj_symbol root;
++#if defined(USE_PLT_ENTRIES)
++#if defined(USE_PLT_LIST)
++ struct arch_list_entry *pltent;
++#else
++ struct arch_single_entry pltent;
++#endif
++#endif
++#if defined(USE_GOT_ENTRIES)
++ struct arch_single_entry gotent;
++#endif
++};
++
++
++struct external_module {
++ const char *name;
++ ElfW(Addr) addr;
++ int used;
++ size_t nsyms;
++ struct new_module_symbol *syms;
++};
++
++static struct new_module_symbol *ksyms;
++static size_t nksyms;
++
++static struct external_module *ext_modules;
++static int n_ext_modules;
++static int n_ext_modules_used;
++
++/*======================================================================*/
++
++
++static struct obj_file *arch_new_file(void)
++{
++ struct arch_file *f;
++ f = xzalloc(sizeof(*f));
++ return &f->root; /* it's a first member */
++}
++
++static struct obj_section *arch_new_section(void)
++{
++ return xzalloc(sizeof(struct obj_section));
++}
++
++static struct obj_symbol *arch_new_symbol(void)
++{
++ struct arch_symbol *sym;
++ sym = xzalloc(sizeof(*sym));
++ return &sym->root;
++}
++
++static enum obj_reloc
++arch_apply_relocation(struct obj_file *f,
++ struct obj_section *targsec,
++ /*struct obj_section *symsec,*/
++ struct obj_symbol *sym,
++ ElfW(RelM) *rel, ElfW(Addr) v)
++{
++#if defined(__arm__) || defined(__i386__) || defined(__mc68000__) \
++ || defined(__sh__) || defined(__s390__) || defined(__x86_64__) \
++ || defined(__powerpc__) || defined(__mips__)
++ struct arch_file *ifile = (struct arch_file *) f;
++#endif
++ enum obj_reloc ret = obj_reloc_ok;
++ ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + rel->r_offset);
++#if defined(__arm__) || defined(__H8300H__) || defined(__H8300S__) \
++ || defined(__i386__) || defined(__mc68000__) || defined(__microblaze__) \
++ || defined(__mips__) || defined(__nios2__) || defined(__powerpc__) \
++ || defined(__s390__) || defined(__sh__) || defined(__x86_64__)
++ ElfW(Addr) dot = targsec->header.sh_addr + rel->r_offset;
++#endif
++#if defined(USE_GOT_ENTRIES) || defined(USE_PLT_ENTRIES)
++ struct arch_symbol *isym = (struct arch_symbol *) sym;
++#endif
++#if defined(__arm__) || defined(__i386__) || defined(__mc68000__) \
++ || defined(__sh__) || defined(__s390__)
++#if defined(USE_GOT_ENTRIES)
++ ElfW(Addr) got = ifile->got ? ifile->got->header.sh_addr : 0;
++#endif
++#endif
++#if defined(USE_PLT_ENTRIES)
++ ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0;
++ unsigned long *ip;
++# if defined(USE_PLT_LIST)
++ struct arch_list_entry *pe;
++# else
++ struct arch_single_entry *pe;
++# endif
++#endif
++
++ switch (ELF_R_TYPE(rel->r_info)) {
++
++#if defined(__arm__)
++
++ case R_ARM_NONE:
++ break;
++
++ case R_ARM_ABS32:
++ *loc += v;
++ break;
++
++ case R_ARM_GOT32:
++ goto bb_use_got;
++
++ case R_ARM_GOTPC:
++ /* relative reloc, always to _GLOBAL_OFFSET_TABLE_
++ * (which is .got) similar to branch,
++ * but is full 32 bits relative */
++
++ *loc += got - dot;
++ break;
++
++ case R_ARM_PC24:
++ case R_ARM_PLT32:
++ goto bb_use_plt;
++
++ case R_ARM_GOTOFF: /* address relative to the got */
++ *loc += v - got;
++ break;
++
++#elif defined(__cris__)
++
++ case R_CRIS_NONE:
++ break;
++
++ case R_CRIS_32:
++ /* CRIS keeps the relocation value in the r_addend field and
++ * should not use whats in *loc at all
++ */
++ *loc = v;
++ break;
++
++#elif defined(__H8300H__) || defined(__H8300S__)
++
++ case R_H8_DIR24R8:
++ loc = (ElfW(Addr) *)((ElfW(Addr))loc - 1);
++ *loc = (*loc & 0xff000000) | ((*loc & 0xffffff) + v);
++ break;
++ case R_H8_DIR24A8:
++ *loc += v;
++ break;
++ case R_H8_DIR32:
++ case R_H8_DIR32A16:
++ *loc += v;
++ break;
++ case R_H8_PCREL16:
++ v -= dot + 2;
++ if ((ElfW(Sword))v > 0x7fff ||
++ (ElfW(Sword))v < -(ElfW(Sword))0x8000)
++ ret = obj_reloc_overflow;
++ else
++ *(unsigned short *)loc = v;
++ break;
++ case R_H8_PCREL8:
++ v -= dot + 1;
++ if ((ElfW(Sword))v > 0x7f ||
++ (ElfW(Sword))v < -(ElfW(Sword))0x80)
++ ret = obj_reloc_overflow;
++ else
++ *(unsigned char *)loc = v;
++ break;
++
++#elif defined(__i386__)
++
++ case R_386_NONE:
++ break;
++
++ case R_386_32:
++ *loc += v;
++ break;
++
++ case R_386_PLT32:
++ case R_386_PC32:
++ case R_386_GOTOFF:
++ *loc += v - dot;
++ break;
++
++ case R_386_GLOB_DAT:
++ case R_386_JMP_SLOT:
++ *loc = v;
++ break;
++
++ case R_386_RELATIVE:
++ *loc += f->baseaddr;
++ break;
++
++ case R_386_GOTPC:
++ *loc += got - dot;
++ break;
++
++ case R_386_GOT32:
++ goto bb_use_got;
++ break;
++
++#elif defined(__microblaze__)
++ case R_MICROBLAZE_NONE:
++ case R_MICROBLAZE_64_NONE:
++ case R_MICROBLAZE_32_SYM_OP_SYM:
++ case R_MICROBLAZE_32_PCREL:
++ break;
++
++ case R_MICROBLAZE_64_PCREL: {
++ /* dot is the address of the current instruction.
++ * v is the target symbol address.
++ * So we need to extract the offset in the code,
++ * adding v, then subtrating the current address
++ * of this instruction.
++ * Ex: "IMM 0xFFFE bralid 0x0000" = "bralid 0xFFFE0000"
++ */
++
++ /* Get split offset stored in code */
++ unsigned int temp = (loc[0] & 0xFFFF) << 16 |
++ (loc[1] & 0xFFFF);
++
++ /* Adjust relative offset. -4 adjustment required
++ * because dot points to the IMM insn, but branch
++ * is computed relative to the branch instruction itself.
++ */
++ temp += v - dot - 4;
++
++ /* Store back into code */
++ loc[0] = (loc[0] & 0xFFFF0000) | temp >> 16;
++ loc[1] = (loc[1] & 0xFFFF0000) | (temp & 0xFFFF);
++
++ break;
++ }
++
++ case R_MICROBLAZE_32:
++ *loc += v;
++ break;
++
++ case R_MICROBLAZE_64: {
++ /* Get split pointer stored in code */
++ unsigned int temp1 = (loc[0] & 0xFFFF) << 16 |
++ (loc[1] & 0xFFFF);
++
++ /* Add reloc offset */
++ temp1+=v;
++
++ /* Store back into code */
++ loc[0] = (loc[0] & 0xFFFF0000) | temp1 >> 16;
++ loc[1] = (loc[1] & 0xFFFF0000) | (temp1 & 0xFFFF);
++
++ break;
++ }
++
++ case R_MICROBLAZE_32_PCREL_LO:
++ case R_MICROBLAZE_32_LO:
++ case R_MICROBLAZE_SRO32:
++ case R_MICROBLAZE_SRW32:
++ ret = obj_reloc_unhandled;
++ break;
++
++#elif defined(__mc68000__)
++
++ case R_68K_NONE:
++ break;
++
++ case R_68K_32:
++ *loc += v;
++ break;
++
++ case R_68K_8:
++ if (v > 0xff) {
++ ret = obj_reloc_overflow;
++ }
++ *(char *)loc = v;
++ break;
++
++ case R_68K_16:
++ if (v > 0xffff) {
++ ret = obj_reloc_overflow;
++ }
++ *(short *)loc = v;
++ break;
++
++ case R_68K_PC8:
++ v -= dot;
++ if ((ElfW(Sword))v > 0x7f ||
++ (ElfW(Sword))v < -(ElfW(Sword))0x80) {
++ ret = obj_reloc_overflow;
++ }
++ *(char *)loc = v;
++ break;
++
++ case R_68K_PC16:
++ v -= dot;
++ if ((ElfW(Sword))v > 0x7fff ||
++ (ElfW(Sword))v < -(ElfW(Sword))0x8000) {
++ ret = obj_reloc_overflow;
++ }
++ *(short *)loc = v;
++ break;
++
++ case R_68K_PC32:
++ *(int *)loc = v - dot;
++ break;
++
++ case R_68K_GLOB_DAT:
++ case R_68K_JMP_SLOT:
++ *loc = v;
++ break;
++
++ case R_68K_RELATIVE:
++ *(int *)loc += f->baseaddr;
++ break;
++
++ case R_68K_GOT32:
++ goto bb_use_got;
++
++# ifdef R_68K_GOTOFF
++ case R_68K_GOTOFF:
++ *loc += v - got;
++ break;
++# endif
++
++#elif defined(__mips__)
++
++ case R_MIPS_NONE:
++ break;
++
++ case R_MIPS_32:
++ *loc += v;
++ break;
++
++ case R_MIPS_26:
++ if (v % 4)
++ ret = obj_reloc_dangerous;
++ if ((v & 0xf0000000) != ((dot + 4) & 0xf0000000))
++ ret = obj_reloc_overflow;
++ *loc =
++ (*loc & ~0x03ffffff) | ((*loc + (v >> 2)) &
++ 0x03ffffff);
++ break;
++
++ case R_MIPS_HI16:
++ {
++ struct mips_hi16 *n;
++
++ /* We cannot relocate this one now because we don't know the value
++ of the carry we need to add. Save the information, and let LO16
++ do the actual relocation. */
++ n = xmalloc(sizeof *n);
++ n->addr = loc;
++ n->value = v;
++ n->next = ifile->mips_hi16_list;
++ ifile->mips_hi16_list = n;
++ break;
++ }
++
++ case R_MIPS_LO16:
++ {
++ unsigned long insnlo = *loc;
++ ElfW(Addr) val, vallo;
++
++ /* Sign extend the addend we extract from the lo insn. */
++ vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
++
++ if (ifile->mips_hi16_list != NULL) {
++ struct mips_hi16 *l;
++
++ l = ifile->mips_hi16_list;
++ while (l != NULL) {
++ struct mips_hi16 *next;
++ unsigned long insn;
++
++ /* Do the HI16 relocation. Note that we actually don't
++ need to know anything about the LO16 itself, except where
++ to find the low 16 bits of the addend needed by the LO16. */
++ insn = *l->addr;
++ val =
++ ((insn & 0xffff) << 16) +
++ vallo;
++ val += v;
++
++ /* Account for the sign extension that will happen in the
++ low bits. */
++ val =
++ ((val >> 16) +
++ ((val & 0x8000) !=
++ 0)) & 0xffff;
++
++ insn = (insn & ~0xffff) | val;
++ *l->addr = insn;
++
++ next = l->next;
++ free(l);
++ l = next;
++ }
++
++ ifile->mips_hi16_list = NULL;
++ }
++
++ /* Ok, we're done with the HI16 relocs. Now deal with the LO16. */
++ val = v + vallo;
++ insnlo = (insnlo & ~0xffff) | (val & 0xffff);
++ *loc = insnlo;
++ break;
++ }
++
++#elif defined(__nios2__)
++
++ case R_NIOS2_NONE:
++ break;
++
++ case R_NIOS2_BFD_RELOC_32:
++ *loc += v;
++ break;
++
++ case R_NIOS2_BFD_RELOC_16:
++ if (v > 0xffff) {
++ ret = obj_reloc_overflow;
++ }
++ *(short *)loc = v;
++ break;
++
++ case R_NIOS2_BFD_RELOC_8:
++ if (v > 0xff) {
++ ret = obj_reloc_overflow;
++ }
++ *(char *)loc = v;
++ break;
++
++ case R_NIOS2_S16:
++ {
++ Elf32_Addr word;
++
++ if ((Elf32_Sword)v > 0x7fff ||
++ (Elf32_Sword)v < -(Elf32_Sword)0x8000) {
++ ret = obj_reloc_overflow;
++ }
++
++ word = *loc;
++ *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) |
++ (word & 0x3f);
++ }
++ break;
++
++ case R_NIOS2_U16:
++ {
++ Elf32_Addr word;
++
++ if (v > 0xffff) {
++ ret = obj_reloc_overflow;
++ }
++
++ word = *loc;
++ *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) |
++ (word & 0x3f);
++ }
++ break;
++
++ case R_NIOS2_PCREL16:
++ {
++ Elf32_Addr word;
++
++ v -= dot + 4;
++ if ((Elf32_Sword)v > 0x7fff ||
++ (Elf32_Sword)v < -(Elf32_Sword)0x8000) {
++ ret = obj_reloc_overflow;
++ }
++
++ word = *loc;
++ *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | (word & 0x3f);
++ }
++ break;
++
++ case R_NIOS2_GPREL:
++ {
++ Elf32_Addr word, gp;
++ /* get _gp */
++ gp = obj_symbol_final_value(f, obj_find_symbol(f, SPFX "_gp"));
++ v-=gp;
++ if ((Elf32_Sword)v > 0x7fff ||
++ (Elf32_Sword)v < -(Elf32_Sword)0x8000) {
++ ret = obj_reloc_overflow;
++ }
++
++ word = *loc;
++ *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | (word & 0x3f);
++ }
++ break;
++
++ case R_NIOS2_CALL26:
++ if (v & 3)
++ ret = obj_reloc_dangerous;
++ if ((v >> 28) != (dot >> 28))
++ ret = obj_reloc_overflow;
++ *loc = (*loc & 0x3f) | ((v >> 2) << 6);
++ break;
++
++ case R_NIOS2_IMM5:
++ {
++ Elf32_Addr word;
++
++ if (v > 0x1f) {
++ ret = obj_reloc_overflow;
++ }
++
++ word = *loc & ~0x7c0;
++ *loc = word | ((v & 0x1f) << 6);
++ }
++ break;
++
++ case R_NIOS2_IMM6:
++ {
++ Elf32_Addr word;
++
++ if (v > 0x3f) {
++ ret = obj_reloc_overflow;
++ }
++
++ word = *loc & ~0xfc0;
++ *loc = word | ((v & 0x3f) << 6);
++ }
++ break;
++
++ case R_NIOS2_IMM8:
++ {
++ Elf32_Addr word;
++
++ if (v > 0xff) {
++ ret = obj_reloc_overflow;
++ }
++
++ word = *loc & ~0x3fc0;
++ *loc = word | ((v & 0xff) << 6);
++ }
++ break;
++
++ case R_NIOS2_HI16:
++ {
++ Elf32_Addr word;
++
++ word = *loc;
++ *loc = ((((word >> 22) << 16) | ((v >>16) & 0xffff)) << 6) |
++ (word & 0x3f);
++ }
++ break;
++
++ case R_NIOS2_LO16:
++ {
++ Elf32_Addr word;
++
++ word = *loc;
++ *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) |
++ (word & 0x3f);
++ }
++ break;
++
++ case R_NIOS2_HIADJ16:
++ {
++ Elf32_Addr word1, word2;
++
++ word1 = *loc;
++ word2 = ((v >> 16) + ((v >> 15) & 1)) & 0xffff;
++ *loc = ((((word1 >> 22) << 16) | word2) << 6) |
++ (word1 & 0x3f);
++ }
++ break;
++
++#elif defined(__powerpc64__)
++ /* PPC64 needs a 2.6 kernel, 2.4 module relocation irrelevant */
++
++#elif defined(__powerpc__)
++
++ case R_PPC_ADDR16_HA:
++ *(unsigned short *)loc = (v + 0x8000) >> 16;
++ break;
++
++ case R_PPC_ADDR16_HI:
++ *(unsigned short *)loc = v >> 16;
++ break;
++
++ case R_PPC_ADDR16_LO:
++ *(unsigned short *)loc = v;
++ break;
++
++ case R_PPC_REL24:
++ goto bb_use_plt;
++
++ case R_PPC_REL32:
++ *loc = v - dot;
++ break;
++
++ case R_PPC_ADDR32:
++ *loc = v;
++ break;
++
++#elif defined(__s390__)
++
++ case R_390_32:
++ *(unsigned int *) loc += v;
++ break;
++ case R_390_16:
++ *(unsigned short *) loc += v;
++ break;
++ case R_390_8:
++ *(unsigned char *) loc += v;
++ break;
++
++ case R_390_PC32:
++ *(unsigned int *) loc += v - dot;
++ break;
++ case R_390_PC16DBL:
++ *(unsigned short *) loc += (v - dot) >> 1;
++ break;
++ case R_390_PC16:
++ *(unsigned short *) loc += v - dot;
++ break;
++
++ case R_390_PLT32:
++ case R_390_PLT16DBL:
++ /* find the plt entry and initialize it. */
++ pe = (struct arch_single_entry *) &isym->pltent;
++ if (pe->inited == 0) {
++ ip = (unsigned long *)(ifile->plt->contents + pe->offset);
++ ip[0] = 0x0d105810; /* basr 1,0; lg 1,10(1); br 1 */
++ ip[1] = 0x100607f1;
++ if (ELF_R_TYPE(rel->r_info) == R_390_PLT16DBL)
++ ip[2] = v - 2;
++ else
++ ip[2] = v;
++ pe->inited = 1;
++ }
++
++ /* Insert relative distance to target. */
++ v = plt + pe->offset - dot;
++ if (ELF_R_TYPE(rel->r_info) == R_390_PLT32)
++ *(unsigned int *) loc = (unsigned int) v;
++ else if (ELF_R_TYPE(rel->r_info) == R_390_PLT16DBL)
++ *(unsigned short *) loc = (unsigned short) ((v + 2) >> 1);
++ break;
++
++ case R_390_GLOB_DAT:
++ case R_390_JMP_SLOT:
++ *loc = v;
++ break;
++
++ case R_390_RELATIVE:
++ *loc += f->baseaddr;
++ break;
++
++ case R_390_GOTPC:
++ *(unsigned long *) loc += got - dot;
++ break;
++
++ case R_390_GOT12:
++ case R_390_GOT16:
++ case R_390_GOT32:
++ if (!isym->gotent.inited)
++ {
++ isym->gotent.inited = 1;
++ *(ElfW(Addr) *)(ifile->got->contents + isym->gotent.offset) = v;
++ }
++ if (ELF_R_TYPE(rel->r_info) == R_390_GOT12)
++ *(unsigned short *) loc |= (*(unsigned short *) loc + isym->gotent.offset) & 0xfff;
++ else if (ELF_R_TYPE(rel->r_info) == R_390_GOT16)
++ *(unsigned short *) loc += isym->gotent.offset;
++ else if (ELF_R_TYPE(rel->r_info) == R_390_GOT32)
++ *(unsigned int *) loc += isym->gotent.offset;
++ break;
++
++# ifndef R_390_GOTOFF32
++# define R_390_GOTOFF32 R_390_GOTOFF
++# endif
++ case R_390_GOTOFF32:
++ *loc += v - got;
++ break;
++
++#elif defined(__sh__)
++
++ case R_SH_NONE:
++ break;
++
++ case R_SH_DIR32:
++ *loc += v;
++ break;
++
++ case R_SH_REL32:
++ *loc += v - dot;
++ break;
++
++ case R_SH_PLT32:
++ *loc = v - dot;
++ break;
++
++ case R_SH_GLOB_DAT:
++ case R_SH_JMP_SLOT:
++ *loc = v;
++ break;
++
++ case R_SH_RELATIVE:
++ *loc = f->baseaddr + rel->r_addend;
++ break;
++
++ case R_SH_GOTPC:
++ *loc = got - dot + rel->r_addend;
++ break;
++
++ case R_SH_GOT32:
++ goto bb_use_got;
++
++ case R_SH_GOTOFF:
++ *loc = v - got;
++ break;
++
++# if defined(__SH5__)
++ case R_SH_IMM_MEDLOW16:
++ case R_SH_IMM_LOW16:
++ {
++ ElfW(Addr) word;
++
++ if (ELF_R_TYPE(rel->r_info) == R_SH_IMM_MEDLOW16)
++ v >>= 16;
++
++ /*
++ * movi and shori have the format:
++ *
++ * | op | imm | reg | reserved |
++ * 31..26 25..10 9.. 4 3 .. 0
++ *
++ * so we simply mask and or in imm.
++ */
++ word = *loc & ~0x3fffc00;
++ word |= (v & 0xffff) << 10;
++
++ *loc = word;
++
++ break;
++ }
++
++ case R_SH_IMM_MEDLOW16_PCREL:
++ case R_SH_IMM_LOW16_PCREL:
++ {
++ ElfW(Addr) word;
++
++ word = *loc & ~0x3fffc00;
++
++ v -= dot;
++
++ if (ELF_R_TYPE(rel->r_info) == R_SH_IMM_MEDLOW16_PCREL)
++ v >>= 16;
++
++ word |= (v & 0xffff) << 10;
++
++ *loc = word;
++
++ break;
++ }
++# endif /* __SH5__ */
++
++#elif defined(__v850e__)
++
++ case R_V850_NONE:
++ break;
++
++ case R_V850_32:
++ /* We write two shorts instead of a long because even
++ 32-bit insns only need half-word alignment, but
++ 32-bit data needs to be long-word aligned. */
++ v += ((unsigned short *)loc)[0];
++ v += ((unsigned short *)loc)[1] << 16;
++ ((unsigned short *)loc)[0] = v & 0xffff;
++ ((unsigned short *)loc)[1] = (v >> 16) & 0xffff;
++ break;
++
++ case R_V850_22_PCREL:
++ goto bb_use_plt;
++
++#elif defined(__x86_64__)
++
++ case R_X86_64_NONE:
++ break;
++
++ case R_X86_64_64:
++ *loc += v;
++ break;
++
++ case R_X86_64_32:
++ *(unsigned int *) loc += v;
++ if (v > 0xffffffff)
++ {
++ ret = obj_reloc_overflow; /* Kernel module compiled without -mcmodel=kernel. */
++ /* error("Possibly is module compiled without -mcmodel=kernel!"); */
++ }
++ break;
++
++ case R_X86_64_32S:
++ *(signed int *) loc += v;
++ break;
++
++ case R_X86_64_16:
++ *(unsigned short *) loc += v;
++ break;
++
++ case R_X86_64_8:
++ *(unsigned char *) loc += v;
++ break;
++
++ case R_X86_64_PC32:
++ *(unsigned int *) loc += v - dot;
++ break;
++
++ case R_X86_64_PC16:
++ *(unsigned short *) loc += v - dot;
++ break;
++
++ case R_X86_64_PC8:
++ *(unsigned char *) loc += v - dot;
++ break;
++
++ case R_X86_64_GLOB_DAT:
++ case R_X86_64_JUMP_SLOT:
++ *loc = v;
++ break;
++
++ case R_X86_64_RELATIVE:
++ *loc += f->baseaddr;
++ break;
++
++ case R_X86_64_GOT32:
++ case R_X86_64_GOTPCREL:
++ goto bb_use_got;
++# if 0
++ if (!isym->gotent.reloc_done)
++ {
++ isym->gotent.reloc_done = 1;
++ *(Elf64_Addr *)(ifile->got->contents + isym->gotent.offset) = v;
++ }
++ /* XXX are these really correct? */
++ if (ELF64_R_TYPE(rel->r_info) == R_X86_64_GOTPCREL)
++ *(unsigned int *) loc += v + isym->gotent.offset;
++ else
++ *loc += isym->gotent.offset;
++ break;
++# endif
++
++#else
++# warning "no idea how to handle relocations on your arch"
++#endif
++
++ default:
++ printf("Warning: unhandled reloc %d\n",(int)ELF_R_TYPE(rel->r_info));
++ ret = obj_reloc_unhandled;
++ break;
++
++#if defined(USE_PLT_ENTRIES)
++
++bb_use_plt:
++
++ /* find the plt entry and initialize it if necessary */
++
++#if defined(USE_PLT_LIST)
++ for (pe = isym->pltent; pe != NULL && pe->addend != rel->r_addend;)
++ pe = pe->next;
++#else
++ pe = &isym->pltent;
++#endif
++
++ if (! pe->inited) {
++ ip = (unsigned long *) (ifile->plt->contents + pe->offset);
++
++ /* generate some machine code */
++
++#if defined(__arm__)
++ ip[0] = 0xe51ff004; /* ldr pc,[pc,#-4] */
++ ip[1] = v; /* sym@ */
++#endif
++#if defined(__powerpc__)
++ ip[0] = 0x3d600000 + ((v + 0x8000) >> 16); /* lis r11,sym@ha */
++ ip[1] = 0x396b0000 + (v & 0xffff); /* addi r11,r11,sym@l */
++ ip[2] = 0x7d6903a6; /* mtctr r11 */
++ ip[3] = 0x4e800420; /* bctr */
++#endif
++#if defined(__v850e__)
++ /* We have to trash a register, so we assume that any control
++ transfer more than 21-bits away must be a function call
++ (so we can use a call-clobbered register). */
++ ip[0] = 0x0621 + ((v & 0xffff) << 16); /* mov sym, r1 ... */
++ ip[1] = ((v >> 16) & 0xffff) + 0x610000; /* ...; jmp r1 */
++#endif
++ pe->inited = 1;
++ }
++
++ /* relative distance to target */
++ v -= dot;
++ /* if the target is too far away.... */
++#if defined(__arm__) || defined(__powerpc__)
++ if ((int)v < -0x02000000 || (int)v >= 0x02000000)
++#elif defined(__v850e__)
++ if ((ElfW(Sword))v > 0x1fffff || (ElfW(Sword))v < (ElfW(Sword))-0x200000)
++#endif
++ /* go via the plt */
++ v = plt + pe->offset - dot;
++
++#if defined(__v850e__)
++ if (v & 1)
++#else
++ if (v & 3)
++#endif
++ ret = obj_reloc_dangerous;
++
++ /* merge the offset into the instruction. */
++#if defined(__arm__)
++ /* Convert to words. */
++ v >>= 2;
++
++ *loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff);
++#endif
++#if defined(__powerpc__)
++ *loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc);
++#endif
++#if defined(__v850e__)
++ /* We write two shorts instead of a long because even 32-bit insns
++ only need half-word alignment, but the 32-bit data write needs
++ to be long-word aligned. */
++ ((unsigned short *)loc)[0] =
++ (*(unsigned short *)loc & 0xffc0) /* opcode + reg */
++ | ((v >> 16) & 0x3f); /* offs high part */
++ ((unsigned short *)loc)[1] =
++ (v & 0xffff); /* offs low part */
++#endif
++ break;
++#endif /* USE_PLT_ENTRIES */
++
++#if defined(USE_GOT_ENTRIES)
++bb_use_got:
++
++ /* needs an entry in the .got: set it, once */
++ if (!isym->gotent.inited) {
++ isym->gotent.inited = 1;
++ *(ElfW(Addr) *) (ifile->got->contents + isym->gotent.offset) = v;
++ }
++ /* make the reloc with_respect_to_.got */
++#if defined(__sh__)
++ *loc += isym->gotent.offset + rel->r_addend;
++#elif defined(__i386__) || defined(__arm__) || defined(__mc68000__)
++ *loc += isym->gotent.offset;
++#endif
++ break;
++
++#endif /* USE_GOT_ENTRIES */
++ }
++
++ return ret;
++}
++
++
++#if defined(USE_LIST)
++
++static int arch_list_add(ElfW(RelM) *rel, struct arch_list_entry **list,
++ int offset, int size)
++{
++ struct arch_list_entry *pe;
++
++ for (pe = *list; pe != NULL; pe = pe->next) {
++ if (pe->addend == rel->r_addend) {
++ break;
++ }
++ }
++
++ if (pe == NULL) {
++ pe = xmalloc(sizeof(struct arch_list_entry));
++ pe->next = *list;
++ pe->addend = rel->r_addend;
++ pe->offset = offset;
++ pe->inited = 0;
++ *list = pe;
++ return size;
++ }
++ return 0;
++}
++
++#endif
++
++#if defined(USE_SINGLE)
++
++static int arch_single_init(/*ElfW(RelM) *rel,*/ struct arch_single_entry *single,
++ int offset, int size)
++{
++ if (single->allocated == 0) {
++ single->allocated = 1;
++ single->offset = offset;
++ single->inited = 0;
++ return size;
++ }
++ return 0;
++}
++
++#endif
++
++#if defined(USE_GOT_ENTRIES) || defined(USE_PLT_ENTRIES)
++
++static struct obj_section *arch_xsect_init(struct obj_file *f, const char *name,
++ int offset, int size)
++{
++ struct obj_section *myrelsec = obj_find_section(f, name);
++
++ if (offset == 0) {
++ offset += size;
++ }
++
++ if (myrelsec) {
++ obj_extend_section(myrelsec, offset);
++ } else {
++ myrelsec = obj_create_alloced_section(f, name,
++ size, offset);
++ }
++
++ return myrelsec;
++}
++
++#endif
++
++static void arch_create_got(struct obj_file *f)
++{
++#if defined(USE_GOT_ENTRIES) || defined(USE_PLT_ENTRIES)
++ struct arch_file *ifile = (struct arch_file *) f;
++ int i;
++#if defined(USE_GOT_ENTRIES)
++ int got_offset = 0, got_needed = 0, got_allocate;
++#endif
++#if defined(USE_PLT_ENTRIES)
++ int plt_offset = 0, plt_needed = 0, plt_allocate;
++#endif
++ struct obj_section *relsec, *symsec, *strsec;
++ ElfW(RelM) *rel, *relend;
++ ElfW(Sym) *symtab, *extsym;
++ const char *strtab, *name;
++ struct arch_symbol *intsym;
++
++ for (i = 0; i < f->header.e_shnum; ++i) {
++ relsec = f->sections[i];
++ if (relsec->header.sh_type != SHT_RELM)
++ continue;
++
++ symsec = f->sections[relsec->header.sh_link];
++ strsec = f->sections[symsec->header.sh_link];
++
++ rel = (ElfW(RelM) *) relsec->contents;
++ relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM)));
++ symtab = (ElfW(Sym) *) symsec->contents;
++ strtab = (const char *) strsec->contents;
++
++ for (; rel < relend; ++rel) {
++ extsym = &symtab[ELF_R_SYM(rel->r_info)];
++
++#if defined(USE_GOT_ENTRIES)
++ got_allocate = 0;
++#endif
++#if defined(USE_PLT_ENTRIES)
++ plt_allocate = 0;
++#endif
++
++ switch (ELF_R_TYPE(rel->r_info)) {
++#if defined(__arm__)
++ case R_ARM_PC24:
++ case R_ARM_PLT32:
++ plt_allocate = 1;
++ break;
++
++ case R_ARM_GOTOFF:
++ case R_ARM_GOTPC:
++ got_needed = 1;
++ continue;
++
++ case R_ARM_GOT32:
++ got_allocate = 1;
++ break;
++
++#elif defined(__i386__)
++ case R_386_GOTPC:
++ case R_386_GOTOFF:
++ got_needed = 1;
++ continue;
++
++ case R_386_GOT32:
++ got_allocate = 1;
++ break;
++
++#elif defined(__powerpc__)
++ case R_PPC_REL24:
++ plt_allocate = 1;
++ break;
++
++#elif defined(__mc68000__)
++ case R_68K_GOT32:
++ got_allocate = 1;
++ break;
++
++#ifdef R_68K_GOTOFF
++ case R_68K_GOTOFF:
++ got_needed = 1;
++ continue;
++#endif
++
++#elif defined(__sh__)
++ case R_SH_GOT32:
++ got_allocate = 1;
++ break;
++
++ case R_SH_GOTPC:
++ case R_SH_GOTOFF:
++ got_needed = 1;
++ continue;
++
++#elif defined(__v850e__)
++ case R_V850_22_PCREL:
++ plt_needed = 1;
++ break;
++
++#endif
++ default:
++ continue;
++ }
++
++ if (extsym->st_name != 0) {
++ name = strtab + extsym->st_name;
++ } else {
++ name = f->sections[extsym->st_shndx]->name;
++ }
++ intsym = (struct arch_symbol *) obj_find_symbol(f, name);
++#if defined(USE_GOT_ENTRIES)
++ if (got_allocate) {
++ got_offset += arch_single_init(
++ /*rel,*/ &intsym->gotent,
++ got_offset, GOT_ENTRY_SIZE);
++
++ got_needed = 1;
++ }
++#endif
++#if defined(USE_PLT_ENTRIES)
++ if (plt_allocate) {
++#if defined(USE_PLT_LIST)
++ plt_offset += arch_list_add(
++ rel, &intsym->pltent,
++ plt_offset, PLT_ENTRY_SIZE);
++#else
++ plt_offset += arch_single_init(
++ /*rel,*/ &intsym->pltent,
++ plt_offset, PLT_ENTRY_SIZE);
++#endif
++ plt_needed = 1;
++ }
++#endif
++ }
++ }
++
++#if defined(USE_GOT_ENTRIES)
++ if (got_needed) {
++ ifile->got = arch_xsect_init(f, ".got", got_offset,
++ GOT_ENTRY_SIZE);
++ }
++#endif
++
++#if defined(USE_PLT_ENTRIES)
++ if (plt_needed) {
++ ifile->plt = arch_xsect_init(f, ".plt", plt_offset,
++ PLT_ENTRY_SIZE);
++ }
++#endif
++
++#endif /* defined(USE_GOT_ENTRIES) || defined(USE_PLT_ENTRIES) */
++}
++
++/*======================================================================*/
++
++/* Standard ELF hash function. */
++static unsigned long obj_elf_hash_n(const char *name, unsigned long n)
++{
++ unsigned long h = 0;
++ unsigned long g;
++ unsigned char ch;
++
++ while (n > 0) {
++ ch = *name++;
++ h = (h << 4) + ch;
++ g = (h & 0xf0000000);
++ if (g != 0) {
++ h ^= g >> 24;
++ h &= ~g;
++ }
++ n--;
++ }
++ return h;
++}
++
++static unsigned long obj_elf_hash(const char *name)
++{
++ return obj_elf_hash_n(name, strlen(name));
++}
++
++#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
++/* String comparison for non-co-versioned kernel and module. */
++
++static int ncv_strcmp(const char *a, const char *b)
++{
++ size_t alen = strlen(a), blen = strlen(b);
++
++ if (blen == alen + 10 && b[alen] == '_' && b[alen + 1] == 'R')
++ return strncmp(a, b, alen);
++ else if (alen == blen + 10 && a[blen] == '_' && a[blen + 1] == 'R')
++ return strncmp(a, b, blen);
++ else
++ return strcmp(a, b);
++}
++
++/* String hashing for non-co-versioned kernel and module. Here
++ we are simply forced to drop the crc from the hash. */
++
++static unsigned long ncv_symbol_hash(const char *str)
++{
++ size_t len = strlen(str);
++ if (len > 10 && str[len - 10] == '_' && str[len - 9] == 'R')
++ len -= 10;
++ return obj_elf_hash_n(str, len);
++}
++
++static void
++obj_set_symbol_compare(struct obj_file *f,
++ int (*cmp) (const char *, const char *),
++ unsigned long (*hash) (const char *))
++{
++ if (cmp)
++ f->symbol_cmp = cmp;
++ if (hash) {
++ struct obj_symbol *tmptab[HASH_BUCKETS], *sym, *next;
++ int i;
++
++ f->symbol_hash = hash;
++
++ memcpy(tmptab, f->symtab, sizeof(tmptab));
++ memset(f->symtab, 0, sizeof(f->symtab));
++
++ for (i = 0; i < HASH_BUCKETS; ++i)
++ for (sym = tmptab[i]; sym; sym = next) {
++ unsigned long h = hash(sym->name) % HASH_BUCKETS;
++ next = sym->next;
++ sym->next = f->symtab[h];
++ f->symtab[h] = sym;
++ }
++ }
++}
++
++#endif /* FEATURE_INSMOD_VERSION_CHECKING */
++
++static struct obj_symbol *
++obj_add_symbol(struct obj_file *f, const char *name,
++ unsigned long symidx, int info,
++ int secidx, ElfW(Addr) value,
++ unsigned long size)
++{
++ struct obj_symbol *sym;
++ unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS;
++ int n_type = ELF_ST_TYPE(info);
++ int n_binding = ELF_ST_BIND(info);
++
++ for (sym = f->symtab[hash]; sym; sym = sym->next) {
++ if (f->symbol_cmp(sym->name, name) == 0) {
++ int o_secidx = sym->secidx;
++ int o_info = sym->info;
++ int o_type = ELF_ST_TYPE(o_info);
++ int o_binding = ELF_ST_BIND(o_info);
++
++ /* A redefinition! Is it legal? */
++
++ if (secidx == SHN_UNDEF)
++ return sym;
++ else if (o_secidx == SHN_UNDEF)
++ goto found;
++ else if (n_binding == STB_GLOBAL && o_binding == STB_LOCAL) {
++ /* Cope with local and global symbols of the same name
++ in the same object file, as might have been created
++ by ld -r. The only reason locals are now seen at this
++ level at all is so that we can do semi-sensible things
++ with parameters. */
++
++ struct obj_symbol *nsym, **p;
++
++ nsym = arch_new_symbol();
++ nsym->next = sym->next;
++ nsym->ksymidx = -1;
++
++ /* Excise the old (local) symbol from the hash chain. */
++ for (p = &f->symtab[hash]; *p != sym; p = &(*p)->next)
++ continue;
++ *p = sym = nsym;
++ goto found;
++ } else if (n_binding == STB_LOCAL) {
++ /* Another symbol of the same name has already been defined.
++ Just add this to the local table. */
++ sym = arch_new_symbol();
++ sym->next = NULL;
++ sym->ksymidx = -1;
++ f->local_symtab[symidx] = sym;
++ goto found;
++ } else if (n_binding == STB_WEAK)
++ return sym;
++ else if (o_binding == STB_WEAK)
++ goto found;
++ /* Don't unify COMMON symbols with object types the programmer
++ doesn't expect. */
++ else if (secidx == SHN_COMMON
++ && (o_type == STT_NOTYPE || o_type == STT_OBJECT))
++ return sym;
++ else if (o_secidx == SHN_COMMON
++ && (n_type == STT_NOTYPE || n_type == STT_OBJECT))
++ goto found;
++ else {
++ /* Don't report an error if the symbol is coming from
++ the kernel or some external module. */
++ if (secidx <= SHN_HIRESERVE)
++ bb_error_msg("%s multiply defined", name);
++ return sym;
++ }
++ }
++ }
++
++ /* Completely new symbol. */
++ sym = arch_new_symbol();
++ sym->next = f->symtab[hash];
++ f->symtab[hash] = sym;
++ sym->ksymidx = -1;
++ if (ELF_ST_BIND(info) == STB_LOCAL && symidx != (unsigned long)(-1)) {
++ if (symidx >= f->local_symtab_size)
++ bb_error_msg("local symbol %s with index %ld exceeds local_symtab_size %ld",
++ name, (long) symidx, (long) f->local_symtab_size);
++ else
++ f->local_symtab[symidx] = sym;
++ }
++
++found:
++ sym->name = name;
++ sym->value = value;
++ sym->size = size;
++ sym->secidx = secidx;
++ sym->info = info;
++
++ return sym;
++}
++
++static struct obj_symbol *
++obj_find_symbol(struct obj_file *f, const char *name)
++{
++ struct obj_symbol *sym;
++ unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS;
++
++ for (sym = f->symtab[hash]; sym; sym = sym->next)
++ if (f->symbol_cmp(sym->name, name) == 0)
++ return sym;
++
++ return NULL;
++}
++
++static ElfW(Addr) obj_symbol_final_value(struct obj_file * f, struct obj_symbol * sym)
++{
++ if (sym) {
++ if (sym->secidx >= SHN_LORESERVE)
++ return sym->value;
++
++ return sym->value + f->sections[sym->secidx]->header.sh_addr;
++ } else {
++ /* As a special case, a NULL sym has value zero. */
++ return 0;
++ }
++}
++
++static struct obj_section *obj_find_section(struct obj_file *f, const char *name)
++{
++ int i, n = f->header.e_shnum;
++
++ for (i = 0; i < n; ++i)
++ if (strcmp(f->sections[i]->name, name) == 0)
++ return f->sections[i];
++
++ return NULL;
++}
++
++static int obj_load_order_prio(struct obj_section *a)
++{
++ unsigned long af, ac;
++
++ af = a->header.sh_flags;
++
++ ac = 0;
++ if (a->name[0] != '.' || strlen(a->name) != 10 ||
++ strcmp(a->name + 5, ".init"))
++ ac |= 32;
++ if (af & SHF_ALLOC)
++ ac |= 16;
++ if (!(af & SHF_WRITE))
++ ac |= 8;
++ if (af & SHF_EXECINSTR)
++ ac |= 4;
++ if (a->header.sh_type != SHT_NOBITS)
++ ac |= 2;
++
++ return ac;
++}
++
++static void
++obj_insert_section_load_order(struct obj_file *f, struct obj_section *sec)
++{
++ struct obj_section **p;
++ int prio = obj_load_order_prio(sec);
++ for (p = f->load_order_search_start; *p; p = &(*p)->load_next)
++ if (obj_load_order_prio(*p) < prio)
++ break;
++ sec->load_next = *p;
++ *p = sec;
++}
++
++static struct obj_section *obj_create_alloced_section(struct obj_file *f,
++ const char *name,
++ unsigned long align,
++ unsigned long size)
++{
++ int newidx = f->header.e_shnum++;
++ struct obj_section *sec;
++
++ f->sections = xrealloc_vector(f->sections, 2, newidx);
++ f->sections[newidx] = sec = arch_new_section();
++
++ sec->header.sh_type = SHT_PROGBITS;
++ sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
++ sec->header.sh_size = size;
++ sec->header.sh_addralign = align;
++ sec->name = name;
++ sec->idx = newidx;
++ if (size)
++ sec->contents = xmalloc(size);
++
++ obj_insert_section_load_order(f, sec);
++
++ return sec;
++}
++
++static struct obj_section *obj_create_alloced_section_first(struct obj_file *f,
++ const char *name,
++ unsigned long align,
++ unsigned long size)
++{
++ int newidx = f->header.e_shnum++;
++ struct obj_section *sec;
++
++ f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec));
++ f->sections[newidx] = sec = arch_new_section();
++
++ sec->header.sh_type = SHT_PROGBITS;
++ sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
++ sec->header.sh_size = size;
++ sec->header.sh_addralign = align;
++ sec->name = name;
++ sec->idx = newidx;
++ if (size)
++ sec->contents = xmalloc(size);
++
++ sec->load_next = f->load_order;
++ f->load_order = sec;
++ if (f->load_order_search_start == &f->load_order)
++ f->load_order_search_start = &sec->load_next;
++
++ return sec;
++}
++
++static void *obj_extend_section(struct obj_section *sec, unsigned long more)
++{
++ unsigned long oldsize = sec->header.sh_size;
++ if (more) {
++ sec->header.sh_size += more;
++ sec->contents = xrealloc(sec->contents, sec->header.sh_size);
++ }
++ return sec->contents + oldsize;
++}
++
++
++/* Conditionally add the symbols from the given symbol set to the
++ new module. */
++
++static int
++add_symbols_from( struct obj_file *f,
++ int idx, struct new_module_symbol *syms, size_t nsyms)
++{
++ struct new_module_symbol *s;
++ size_t i;
++ int used = 0;
++#ifdef SYMBOL_PREFIX
++ char *name_buf = 0;
++ size_t name_alloced_size = 0;
++#endif
++#if ENABLE_FEATURE_CHECK_TAINTED_MODULE
++ int gpl;
++
++ gpl = obj_gpl_license(f, NULL) == 0;
++#endif
++ for (i = 0, s = syms; i < nsyms; ++i, ++s) {
++ /* Only add symbols that are already marked external.
++ If we override locals we may cause problems for
++ argument initialization. We will also create a false
++ dependency on the module. */
++ struct obj_symbol *sym;
++ char *name;
++
++ /* GPL licensed modules can use symbols exported with
++ * EXPORT_SYMBOL_GPL, so ignore any GPLONLY_ prefix on the
++ * exported names. Non-GPL modules never see any GPLONLY_
++ * symbols so they cannot fudge it by adding the prefix on
++ * their references.
++ */
++ if (strncmp((char *)s->name, "GPLONLY_", 8) == 0) {
++#if ENABLE_FEATURE_CHECK_TAINTED_MODULE
++ if (gpl)
++ s->name += 8;
++ else
++#endif
++ continue;
++ }
++ name = (char *)s->name;
++
++#ifdef SYMBOL_PREFIX
++ /* Prepend SYMBOL_PREFIX to the symbol's name (the
++ kernel exports `C names', but module object files
++ reference `linker names'). */
++ size_t extra = sizeof SYMBOL_PREFIX;
++ size_t name_size = strlen(name) + extra;
++ if (name_size > name_alloced_size) {
++ name_alloced_size = name_size * 2;
++ name_buf = alloca(name_alloced_size);
++ }
++ strcpy(name_buf, SYMBOL_PREFIX);
++ strcpy(name_buf + extra - 1, name);
++ name = name_buf;
++#endif /* SYMBOL_PREFIX */
++
++ sym = obj_find_symbol(f, name);
++ if (sym && !(ELF_ST_BIND(sym->info) == STB_LOCAL)) {
++#ifdef SYMBOL_PREFIX
++ /* Put NAME_BUF into more permanent storage. */
++ name = xmalloc(name_size);
++ strcpy(name, name_buf);
++#endif
++ sym = obj_add_symbol(f, name, -1,
++ ELF_ST_INFO(STB_GLOBAL,
++ STT_NOTYPE),
++ idx, s->value, 0);
++ /* Did our symbol just get installed? If so, mark the
++ module as "used". */
++ if (sym->secidx == idx)
++ used = 1;
++ }
++ }
++
++ return used;
++}
++
++static void add_kernel_symbols(struct obj_file *f)
++{
++ struct external_module *m;
++ int i, nused = 0;
++
++ /* Add module symbols first. */
++
++ for (i = 0, m = ext_modules; i < n_ext_modules; ++i, ++m) {
++ if (m->nsyms
++ && add_symbols_from(f, SHN_HIRESERVE + 2 + i, m->syms, m->nsyms)
++ ) {
++ m->used = 1;
++ ++nused;
++ }
++ }
++
++ n_ext_modules_used = nused;
++
++ /* And finally the symbols from the kernel proper. */
++
++ if (nksyms)
++ add_symbols_from(f, SHN_HIRESERVE + 1, ksyms, nksyms);
++}
++
++static char *get_modinfo_value(struct obj_file *f, const char *key)
++{
++ struct obj_section *sec;
++ char *p, *v, *n, *ep;
++ size_t klen = strlen(key);
++
++ sec = obj_find_section(f, ".modinfo");
++ if (sec == NULL)
++ return NULL;
++ p = sec->contents;
++ ep = p + sec->header.sh_size;
++ while (p < ep) {
++ v = strchr(p, '=');
++ n = strchr(p, '\0');
++ if (v) {
++ if (p + klen == v && strncmp(p, key, klen) == 0)
++ return v + 1;
++ } else {
++ if (p + klen == n && strcmp(p, key) == 0)
++ return n;
++ }
++ p = n + 1;
++ }
++
++ return NULL;
++}
++
++
++/*======================================================================*/
++/* Functions relating to module loading after 2.1.18. */
++
++/* From Linux-2.6 sources */
++/* You can use " around spaces, but can't escape ". */
++/* Hyphens and underscores equivalent in parameter names. */
++static char *next_arg(char *args, char **param, char **val)
++{
++ unsigned int i, equals = 0;
++ int in_quote = 0, quoted = 0;
++ char *next;
++
++ if (*args == '"') {
++ args++;
++ in_quote = 1;
++ quoted = 1;
++ }
++
++ for (i = 0; args[i]; i++) {
++ if (args[i] == ' ' && !in_quote)
++ break;
++ if (equals == 0) {
++ if (args[i] == '=')
++ equals = i;
++ }
++ if (args[i] == '"')
++ in_quote = !in_quote;
++ }
++
++ *param = args;
++ if (!equals)
++ *val = NULL;
++ else {
++ args[equals] = '\0';
++ *val = args + equals + 1;
++
++ /* Don't include quotes in value. */
++ if (**val == '"') {
++ (*val)++;
++ if (args[i-1] == '"')
++ args[i-1] = '\0';
++ }
++ if (quoted && args[i-1] == '"')
++ args[i-1] = '\0';
++ }
++
++ if (args[i]) {
++ args[i] = '\0';
++ next = args + i + 1;
++ } else
++ next = args + i;
++
++ /* Chew up trailing spaces. */
++ return skip_whitespace(next);
++}
++
++static void
++new_process_module_arguments(struct obj_file *f, const char *options)
++{
++ char *xoptions, *pos;
++ char *param, *val;
++
++ xoptions = pos = xstrdup(skip_whitespace(options));
++ while (*pos) {
++ unsigned long charssize = 0;
++ char *tmp, *contents, *loc, *pinfo, *p;
++ struct obj_symbol *sym;
++ int min, max, n, len;
++
++ pos = next_arg(pos, &param, &val);
++
++ tmp = xasprintf("parm_%s", param);
++ pinfo = get_modinfo_value(f, tmp);
++ free(tmp);
++ if (pinfo == NULL)
++ bb_error_msg_and_die("invalid parameter %s", param);
++
++#ifdef SYMBOL_PREFIX
++ tmp = xasprintf(SYMBOL_PREFIX "%s", param);
++ sym = obj_find_symbol(f, tmp);
++ free(tmp);
++#else
++ sym = obj_find_symbol(f, param);
++#endif
++
++ /* Also check that the parameter was not resolved from the kernel. */
++ if (sym == NULL || sym->secidx > SHN_HIRESERVE)
++ bb_error_msg_and_die("symbol for parameter %s not found", param);
++
++ /* Number of parameters */
++ if (isdigit(*pinfo)) {
++ min = strtoul(pinfo, &pinfo, 10);
++ if (*pinfo == '-')
++ max = strtoul(pinfo + 1, &pinfo, 10);
++ else
++ max = min;
++ } else
++ min = max = 1;
++
++ contents = f->sections[sym->secidx]->contents;
++ loc = contents + sym->value;
++
++ if (*pinfo == 'c') {
++ if (!isdigit(*(pinfo + 1))) {
++ bb_error_msg_and_die("parameter type 'c' for %s must be followed by"
++ " the maximum size", param);
++ }
++ charssize = strtoul(pinfo + 1, (char **) NULL, 10);
++ }
++
++ if (val == NULL) {
++ if (*pinfo != 'b')
++ bb_error_msg_and_die("argument expected for parameter %s", param);
++ val = (char *) "1";
++ }
++
++ /* Parse parameter values */
++ n = 0;
++ p = val;
++ while (*p != 0) {
++ if (++n > max)
++ bb_error_msg_and_die("too many values for %s (max %d)", param, max);
++
++ switch (*pinfo) {
++ case 's':
++ len = strcspn(p, ",");
++ p[len] = 0;
++ obj_string_patch(f, sym->secidx,
++ loc - contents, p);
++ loc += tgt_sizeof_char_p;
++ p += len;
++ break;
++ case 'c':
++ len = strcspn(p, ",");
++ p[len] = 0;
++ if (len >= charssize)
++ bb_error_msg_and_die("string too long for %s (max %ld)", param,
++ charssize - 1);
++ strcpy((char *) loc, p);
++ loc += charssize;
++ p += len;
++ break;
++ case 'b':
++ *loc++ = strtoul(p, &p, 0);
++ break;
++ case 'h':
++ *(short *) loc = strtoul(p, &p, 0);
++ loc += tgt_sizeof_short;
++ break;
++ case 'i':
++ *(int *) loc = strtoul(p, &p, 0);
++ loc += tgt_sizeof_int;
++ break;
++ case 'l':
++ *(long *) loc = strtoul(p, &p, 0);
++ loc += tgt_sizeof_long;
++ break;
++ default:
++ bb_error_msg_and_die("unknown parameter type '%c' for %s",
++ *pinfo, param);
++ }
++
++ p = skip_whitespace(p);
++ if (*p != ',')
++ break;
++ p = skip_whitespace(p + 1);
++ }
++
++ if (n < min)
++ bb_error_msg_and_die("parameter %s requires at least %d arguments", param, min);
++ if (*p != '\0')
++ bb_error_msg_and_die("invalid argument syntax for %s", param);
++ }
++
++ free(xoptions);
++}
++
++#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
++static int new_is_module_checksummed(struct obj_file *f)
++{
++ const char *p = get_modinfo_value(f, "using_checksums");
++ if (p)
++ return xatoi(p);
++ return 0;
++}
++
++/* Get the module's kernel version in the canonical integer form. */
++
++static int
++new_get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
++{
++ char *p, *q;
++ int a, b, c;
++
++ p = get_modinfo_value(f, "kernel_version");
++ if (p == NULL)
++ return -1;
++ safe_strncpy(str, p, STRVERSIONLEN);
++
++ a = strtoul(p, &p, 10);
++ if (*p != '.')
++ return -1;
++ b = strtoul(p + 1, &p, 10);
++ if (*p != '.')
++ return -1;
++ c = strtoul(p + 1, &q, 10);
++ if (p + 1 == q)
++ return -1;
++
++ return a << 16 | b << 8 | c;
++}
++
++#endif /* FEATURE_INSMOD_VERSION_CHECKING */
++
++
++/* Fetch the loaded modules, and all currently exported symbols. */
++
++static void new_get_kernel_symbols(void)
++{
++ char *module_names, *mn;
++ struct external_module *modules, *m;
++ struct new_module_symbol *syms, *s;
++ size_t ret, bufsize, nmod, nsyms, i, j;
++
++ /* Collect the loaded modules. */
++
++ bufsize = 256;
++ module_names = xmalloc(bufsize);
++
++ retry_modules_load:
++ if (query_module(NULL, QM_MODULES, module_names, bufsize, &ret)) {
++ if (errno == ENOSPC && bufsize < ret) {
++ bufsize = ret;
++ module_names = xrealloc(module_names, bufsize);
++ goto retry_modules_load;
++ }
++ bb_perror_msg_and_die("QM_MODULES");
++ }
++
++ n_ext_modules = nmod = ret;
++
++ /* Collect the modules' symbols. */
++
++ if (nmod) {
++ ext_modules = modules = xmalloc(nmod * sizeof(*modules));
++ memset(modules, 0, nmod * sizeof(*modules));
++ for (i = 0, mn = module_names, m = modules;
++ i < nmod; ++i, ++m, mn += strlen(mn) + 1) {
++ struct new_module_info info;
++
++ if (query_module(mn, QM_INFO, &info, sizeof(info), &ret)) {
++ if (errno == ENOENT) {
++ /* The module was removed out from underneath us. */
++ continue;
++ }
++ bb_perror_msg_and_die("query_module: QM_INFO: %s", mn);
++ }
++
++ bufsize = 1024;
++ syms = xmalloc(bufsize);
++ retry_mod_sym_load:
++ if (query_module(mn, QM_SYMBOLS, syms, bufsize, &ret)) {
++ switch (errno) {
++ case ENOSPC:
++ bufsize = ret;
++ syms = xrealloc(syms, bufsize);
++ goto retry_mod_sym_load;
++ case ENOENT:
++ /* The module was removed out from underneath us. */
++ continue;
++ default:
++ bb_perror_msg_and_die("query_module: QM_SYMBOLS: %s", mn);
++ }
++ }
++ nsyms = ret;
++
++ m->name = mn;
++ m->addr = info.addr;
++ m->nsyms = nsyms;
++ m->syms = syms;
++
++ for (j = 0, s = syms; j < nsyms; ++j, ++s) {
++ s->name += (unsigned long) syms;
++ }
++ }
++ }
++
++ /* Collect the kernel's symbols. */
++
++ syms = xmalloc(bufsize = 16 * 1024);
++ retry_kern_sym_load:
++ if (query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)) {
++ if (errno == ENOSPC && bufsize < ret) {
++ bufsize = ret;
++ syms = xrealloc(syms, bufsize);
++ goto retry_kern_sym_load;
++ }
++ bb_perror_msg_and_die("kernel: QM_SYMBOLS");
++ }
++ nksyms = nsyms = ret;
++ ksyms = syms;
++
++ for (j = 0, s = syms; j < nsyms; ++j, ++s) {
++ s->name += (unsigned long) syms;
++ }
++}
++
++
++/* Return the kernel symbol checksum version, or zero if not used. */
++
++static int new_is_kernel_checksummed(void)
++{
++ struct new_module_symbol *s;
++ size_t i;
++
++ /* Using_Versions is not the first symbol, but it should be in there. */
++
++ for (i = 0, s = ksyms; i < nksyms; ++i, ++s)
++ if (strcmp((char *) s->name, "Using_Versions") == 0)
++ return s->value;
++
++ return 0;
++}
++
++
++static void new_create_this_module(struct obj_file *f, const char *m_name)
++{
++ struct obj_section *sec;
++
++ sec = obj_create_alloced_section_first(f, ".this", tgt_sizeof_long,
++ sizeof(struct new_module));
++ memset(sec->contents, 0, sizeof(struct new_module));
++
++ obj_add_symbol(f, SPFX "__this_module", -1,
++ ELF_ST_INFO(STB_LOCAL, STT_OBJECT), sec->idx, 0,
++ sizeof(struct new_module));
++
++ obj_string_patch(f, sec->idx, offsetof(struct new_module, name),
++ m_name);
++}
++
++#if ENABLE_FEATURE_INSMOD_KSYMOOPS_SYMBOLS
++/* add an entry to the __ksymtab section, creating it if necessary */
++static void new_add_ksymtab(struct obj_file *f, struct obj_symbol *sym)
++{
++ struct obj_section *sec;
++ ElfW(Addr) ofs;
++
++ /* ensure __ksymtab is allocated, EXPORT_NOSYMBOLS creates a non-alloc section.
++ * If __ksymtab is defined but not marked alloc, x out the first character
++ * (no obj_delete routine) and create a new __ksymtab with the correct
++ * characteristics.
++ */
++ sec = obj_find_section(f, "__ksymtab");
++ if (sec && !(sec->header.sh_flags & SHF_ALLOC)) {
++ *((char *)(sec->name)) = 'x'; /* override const */
++ sec = NULL;
++ }
++ if (!sec)
++ sec = obj_create_alloced_section(f, "__ksymtab",
++ tgt_sizeof_void_p, 0);
++ if (!sec)
++ return;
++ sec->header.sh_flags |= SHF_ALLOC;
++ /* Empty section might be byte-aligned */
++ sec->header.sh_addralign = tgt_sizeof_void_p;
++ ofs = sec->header.sh_size;
++ obj_symbol_patch(f, sec->idx, ofs, sym);
++ obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p, sym->name);
++ obj_extend_section(sec, 2 * tgt_sizeof_char_p);
++}
++#endif /* FEATURE_INSMOD_KSYMOOPS_SYMBOLS */
++
++static int new_create_module_ksymtab(struct obj_file *f)
++{
++ struct obj_section *sec;
++ int i;
++
++ /* We must always add the module references. */
++
++ if (n_ext_modules_used) {
++ struct new_module_ref *dep;
++ struct obj_symbol *tm;
++
++ sec = obj_create_alloced_section(f, ".kmodtab", tgt_sizeof_void_p,
++ (sizeof(struct new_module_ref)
++ * n_ext_modules_used));
++ if (!sec)
++ return 0;
++
++ tm = obj_find_symbol(f, SPFX "__this_module");
++ dep = (struct new_module_ref *) sec->contents;
++ for (i = 0; i < n_ext_modules; ++i)
++ if (ext_modules[i].used) {
++ dep->dep = ext_modules[i].addr;
++ obj_symbol_patch(f, sec->idx,
++ (char *) &dep->ref - sec->contents, tm);
++ dep->next_ref = 0;
++ ++dep;
++ }
++ }
++
++ if (!flag_noexport && !obj_find_section(f, "__ksymtab")) {
++ size_t nsyms;
++ int *loaded;
++
++ sec = obj_create_alloced_section(f, "__ksymtab", tgt_sizeof_void_p, 0);
++
++ /* We don't want to export symbols residing in sections that
++ aren't loaded. There are a number of these created so that
++ we make sure certain module options don't appear twice. */
++
++ loaded = alloca(sizeof(int) * (i = f->header.e_shnum));
++ while (--i >= 0)
++ loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0;
++
++ for (nsyms = i = 0; i < HASH_BUCKETS; ++i) {
++ struct obj_symbol *sym;
++ for (sym = f->symtab[i]; sym; sym = sym->next)
++ if (ELF_ST_BIND(sym->info) != STB_LOCAL
++ && sym->secidx <= SHN_HIRESERVE
++ && (sym->secidx >= SHN_LORESERVE
++ || loaded[sym->secidx])) {
++ ElfW(Addr) ofs = nsyms * 2 * tgt_sizeof_void_p;
++
++ obj_symbol_patch(f, sec->idx, ofs, sym);
++ obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p,
++ sym->name);
++
++ nsyms++;
++ }
++ }
++
++ obj_extend_section(sec, nsyms * 2 * tgt_sizeof_char_p);
++ }
++
++ return 1;
++}
++
++
++static int
++new_init_module(const char *m_name, struct obj_file *f, unsigned long m_size)
++{
++ struct new_module *module;
++ struct obj_section *sec;
++ void *image;
++ int ret;
++ tgt_long m_addr;
++
++ sec = obj_find_section(f, ".this");
++ if (!sec || !sec->contents) {
++ bb_perror_msg_and_die("corrupt module %s?", m_name);
++ }
++ module = (struct new_module *) sec->contents;
++ m_addr = sec->header.sh_addr;
++
++ module->size_of_struct = sizeof(*module);
++ module->size = m_size;
++ module->flags = flag_autoclean ? NEW_MOD_AUTOCLEAN : 0;
++
++ sec = obj_find_section(f, "__ksymtab");
++ if (sec && sec->header.sh_size) {
++ module->syms = sec->header.sh_addr;
++ module->nsyms = sec->header.sh_size / (2 * tgt_sizeof_char_p);
++ }
++
++ if (n_ext_modules_used) {
++ sec = obj_find_section(f, ".kmodtab");
++ module->deps = sec->header.sh_addr;
++ module->ndeps = n_ext_modules_used;
++ }
++
++ module->init =
++ obj_symbol_final_value(f, obj_find_symbol(f, SPFX "init_module"));
++ module->cleanup =
++ obj_symbol_final_value(f, obj_find_symbol(f, SPFX "cleanup_module"));
++
++ sec = obj_find_section(f, "__ex_table");
++ if (sec) {
++ module->ex_table_start = sec->header.sh_addr;
++ module->ex_table_end = sec->header.sh_addr + sec->header.sh_size;
++ }
++
++ sec = obj_find_section(f, ".text.init");
++ if (sec) {
++ module->runsize = sec->header.sh_addr - m_addr;
++ }
++ sec = obj_find_section(f, ".data.init");
++ if (sec) {
++ if (!module->runsize ||
++ module->runsize > sec->header.sh_addr - m_addr)
++ module->runsize = sec->header.sh_addr - m_addr;
++ }
++ sec = obj_find_section(f, ARCHDATA_SEC_NAME);
++ if (sec && sec->header.sh_size) {
++ module->archdata_start = (void*)sec->header.sh_addr;
++ module->archdata_end = module->archdata_start + sec->header.sh_size;
++ }
++ sec = obj_find_section(f, KALLSYMS_SEC_NAME);
++ if (sec && sec->header.sh_size) {
++ module->kallsyms_start = (void*)sec->header.sh_addr;
++ module->kallsyms_end = module->kallsyms_start + sec->header.sh_size;
++ }
++
++ /* Whew! All of the initialization is complete. Collect the final
++ module image and give it to the kernel. */
++
++ image = xmalloc(m_size);
++ obj_create_image(f, image);
++
++ ret = init_module(m_name, (struct new_module *) image);
++ if (ret)
++ bb_perror_msg("init_module: %s", m_name);
++
++ free(image);
++
++ return ret == 0;
++}
++
++
++/*======================================================================*/
++
++static void
++obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
++ const char *string)
++{
++ struct obj_string_patch *p;
++ struct obj_section *strsec;
++ size_t len = strlen(string) + 1;
++ char *loc;
++
++ p = xmalloc(sizeof(*p));
++ p->next = f->string_patches;
++ p->reloc_secidx = secidx;
++ p->reloc_offset = offset;
++ f->string_patches = p;
++
++ strsec = obj_find_section(f, ".kstrtab");
++ if (strsec == NULL) {
++ strsec = obj_create_alloced_section(f, ".kstrtab", 1, len);
++ p->string_offset = 0;
++ loc = strsec->contents;
++ } else {
++ p->string_offset = strsec->header.sh_size;
++ loc = obj_extend_section(strsec, len);
++ }
++ memcpy(loc, string, len);
++}
++
++static void
++obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
++ struct obj_symbol *sym)
++{
++ struct obj_symbol_patch *p;
++
++ p = xmalloc(sizeof(*p));
++ p->next = f->symbol_patches;
++ p->reloc_secidx = secidx;
++ p->reloc_offset = offset;
++ p->sym = sym;
++ f->symbol_patches = p;
++}
++
++static void obj_check_undefineds(struct obj_file *f)
++{
++ unsigned i;
++
++ for (i = 0; i < HASH_BUCKETS; ++i) {
++ struct obj_symbol *sym;
++ for (sym = f->symtab[i]; sym; sym = sym->next)
++ if (sym->secidx == SHN_UNDEF) {
++ if (ELF_ST_BIND(sym->info) == STB_WEAK) {
++ sym->secidx = SHN_ABS;
++ sym->value = 0;
++ } else {
++ if (!flag_quiet)
++ bb_error_msg_and_die("unresolved symbol %s", sym->name);
++ }
++ }
++ }
++}
++
++static void obj_allocate_commons(struct obj_file *f)
++{
++ struct common_entry {
++ struct common_entry *next;
++ struct obj_symbol *sym;
++ } *common_head = NULL;
++
++ unsigned long i;
++
++ for (i = 0; i < HASH_BUCKETS; ++i) {
++ struct obj_symbol *sym;
++ for (sym = f->symtab[i]; sym; sym = sym->next)
++ if (sym->secidx == SHN_COMMON) {
++ /* Collect all COMMON symbols and sort them by size so as to
++ minimize space wasted by alignment requirements. */
++ {
++ struct common_entry **p, *n;
++ for (p = &common_head; *p; p = &(*p)->next)
++ if (sym->size <= (*p)->sym->size)
++ break;
++
++ n = alloca(sizeof(*n));
++ n->next = *p;
++ n->sym = sym;
++ *p = n;
++ }
++ }
++ }
++
++ for (i = 1; i < f->local_symtab_size; ++i) {
++ struct obj_symbol *sym = f->local_symtab[i];
++ if (sym && sym->secidx == SHN_COMMON) {
++ struct common_entry **p, *n;
++ for (p = &common_head; *p; p = &(*p)->next)
++ if (sym == (*p)->sym)
++ break;
++ else if (sym->size < (*p)->sym->size) {
++ n = alloca(sizeof(*n));
++ n->next = *p;
++ n->sym = sym;
++ *p = n;
++ break;
++ }
++ }
++ }
++
++ if (common_head) {
++ /* Find the bss section. */
++ for (i = 0; i < f->header.e_shnum; ++i)
++ if (f->sections[i]->header.sh_type == SHT_NOBITS)
++ break;
++
++ /* If for some reason there hadn't been one, create one. */
++ if (i == f->header.e_shnum) {
++ struct obj_section *sec;
++
++ f->sections = xrealloc_vector(f->sections, 2, i);
++ f->sections[i] = sec = arch_new_section();
++ f->header.e_shnum = i + 1;
++
++ sec->header.sh_type = SHT_PROGBITS;
++ sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
++ sec->name = ".bss";
++ sec->idx = i;
++ }
++
++ /* Allocate the COMMONS. */
++ {
++ ElfW(Addr) bss_size = f->sections[i]->header.sh_size;
++ ElfW(Addr) max_align = f->sections[i]->header.sh_addralign;
++ struct common_entry *c;
++
++ for (c = common_head; c; c = c->next) {
++ ElfW(Addr) align = c->sym->value;
++
++ if (align > max_align)
++ max_align = align;
++ if (bss_size & (align - 1))
++ bss_size = (bss_size | (align - 1)) + 1;
++
++ c->sym->secidx = i;
++ c->sym->value = bss_size;
++
++ bss_size += c->sym->size;
++ }
++
++ f->sections[i]->header.sh_size = bss_size;
++ f->sections[i]->header.sh_addralign = max_align;
++ }
++ }
++
++ /* For the sake of patch relocation and parameter initialization,
++ allocate zeroed data for NOBITS sections now. Note that after
++ this we cannot assume NOBITS are really empty. */
++ for (i = 0; i < f->header.e_shnum; ++i) {
++ struct obj_section *s = f->sections[i];
++ if (s->header.sh_type == SHT_NOBITS) {
++ if (s->header.sh_size != 0)
++ s->contents = memset(xmalloc(s->header.sh_size),
++ 0, s->header.sh_size);
++ else
++ s->contents = NULL;
++
++ s->header.sh_type = SHT_PROGBITS;
++ }
++ }
++}
++
++static unsigned long obj_load_size(struct obj_file *f)
++{
++ unsigned long dot = 0;
++ struct obj_section *sec;
++
++ /* Finalize the positions of the sections relative to one another. */
++
++ for (sec = f->load_order; sec; sec = sec->load_next) {
++ ElfW(Addr) align;
++
++ align = sec->header.sh_addralign;
++ if (align && (dot & (align - 1)))
++ dot = (dot | (align - 1)) + 1;
++
++ sec->header.sh_addr = dot;
++ dot += sec->header.sh_size;
++ }
++
++ return dot;
++}
++
++static int obj_relocate(struct obj_file *f, ElfW(Addr) base)
++{
++ int i, n = f->header.e_shnum;
++ int ret = 1;
++
++ /* Finalize the addresses of the sections. */
++
++ f->baseaddr = base;
++ for (i = 0; i < n; ++i)
++ f->sections[i]->header.sh_addr += base;
++
++ /* And iterate over all of the relocations. */
++
++ for (i = 0; i < n; ++i) {
++ struct obj_section *relsec, *symsec, *targsec, *strsec;
++ ElfW(RelM) * rel, *relend;
++ ElfW(Sym) * symtab;
++ const char *strtab;
++
++ relsec = f->sections[i];
++ if (relsec->header.sh_type != SHT_RELM)
++ continue;
++
++ symsec = f->sections[relsec->header.sh_link];
++ targsec = f->sections[relsec->header.sh_info];
++ strsec = f->sections[symsec->header.sh_link];
++
++ rel = (ElfW(RelM) *) relsec->contents;
++ relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM)));
++ symtab = (ElfW(Sym) *) symsec->contents;
++ strtab = (const char *) strsec->contents;
++
++ for (; rel < relend; ++rel) {
++ ElfW(Addr) value = 0;
++ struct obj_symbol *intsym = NULL;
++ unsigned long symndx;
++ ElfW(Sym) * extsym = 0;
++ const char *errmsg;
++
++ /* Attempt to find a value to use for this relocation. */
++
++ symndx = ELF_R_SYM(rel->r_info);
++ if (symndx) {
++ /* Note we've already checked for undefined symbols. */
++
++ extsym = &symtab[symndx];
++ if (ELF_ST_BIND(extsym->st_info) == STB_LOCAL) {
++ /* Local symbols we look up in the local table to be sure
++ we get the one that is really intended. */
++ intsym = f->local_symtab[symndx];
++ } else {
++ /* Others we look up in the hash table. */
++ const char *name;
++ if (extsym->st_name)
++ name = strtab + extsym->st_name;
++ else
++ name = f->sections[extsym->st_shndx]->name;
++ intsym = obj_find_symbol(f, name);
++ }
++
++ value = obj_symbol_final_value(f, intsym);
++ intsym->referenced = 1;
++ }
++#if SHT_RELM == SHT_RELA
++#if defined(__alpha__) && defined(AXP_BROKEN_GAS)
++ /* Work around a nasty GAS bug, that is fixed as of 2.7.0.9. */
++ if (!extsym || !extsym->st_name ||
++ ELF_ST_BIND(extsym->st_info) != STB_LOCAL)
++#endif
++ value += rel->r_addend;
++#endif
++
++ /* Do it! */
++ switch (arch_apply_relocation
++ (f, targsec, /*symsec,*/ intsym, rel, value)
++ ) {
++ case obj_reloc_ok:
++ break;
++
++ case obj_reloc_overflow:
++ errmsg = "Relocation overflow";
++ goto bad_reloc;
++ case obj_reloc_dangerous:
++ errmsg = "Dangerous relocation";
++ goto bad_reloc;
++ case obj_reloc_unhandled:
++ errmsg = "Unhandled relocation";
++bad_reloc:
++ if (extsym) {
++ bb_error_msg("%s of type %ld for %s", errmsg,
++ (long) ELF_R_TYPE(rel->r_info),
++ strtab + extsym->st_name);
++ } else {
++ bb_error_msg("%s of type %ld", errmsg,
++ (long) ELF_R_TYPE(rel->r_info));
++ }
++ ret = 0;
++ break;
++ }
++ }
++ }
++
++ /* Finally, take care of the patches. */
++
++ if (f->string_patches) {
++ struct obj_string_patch *p;
++ struct obj_section *strsec;
++ ElfW(Addr) strsec_base;
++ strsec = obj_find_section(f, ".kstrtab");
++ strsec_base = strsec->header.sh_addr;
++
++ for (p = f->string_patches; p; p = p->next) {
++ struct obj_section *targsec = f->sections[p->reloc_secidx];
++ *(ElfW(Addr) *) (targsec->contents + p->reloc_offset)
++ = strsec_base + p->string_offset;
++ }
++ }
++
++ if (f->symbol_patches) {
++ struct obj_symbol_patch *p;
++
++ for (p = f->symbol_patches; p; p = p->next) {
++ struct obj_section *targsec = f->sections[p->reloc_secidx];
++ *(ElfW(Addr) *) (targsec->contents + p->reloc_offset)
++ = obj_symbol_final_value(f, p->sym);
++ }
++ }
++
++ return ret;
++}
++
++static int obj_create_image(struct obj_file *f, char *image)
++{
++ struct obj_section *sec;
++ ElfW(Addr) base = f->baseaddr;
++
++ for (sec = f->load_order; sec; sec = sec->load_next) {
++ char *secimg;
++
++ if (sec->contents == 0 || sec->header.sh_size == 0)
++ continue;
++
++ secimg = image + (sec->header.sh_addr - base);
++
++ /* Note that we allocated data for NOBITS sections earlier. */
++ memcpy(secimg, sec->contents, sec->header.sh_size);
++ }
++
++ return 1;
++}
++
++/*======================================================================*/
++
++static struct obj_file *obj_load(FILE *fp, int loadprogbits UNUSED_PARAM)
++{
++ struct obj_file *f;
++ ElfW(Shdr) * section_headers;
++ size_t shnum, i;
++ char *shstrtab;
++
++ /* Read the file header. */
++
++ f = arch_new_file();
++ f->symbol_cmp = strcmp;
++ f->symbol_hash = obj_elf_hash;
++ f->load_order_search_start = &f->load_order;
++
++ fseek(fp, 0, SEEK_SET);
++ if (fread(&f->header, sizeof(f->header), 1, fp) != 1) {
++ bb_perror_msg_and_die("error reading ELF header");
++ }
++
++ if (f->header.e_ident[EI_MAG0] != ELFMAG0
++ || f->header.e_ident[EI_MAG1] != ELFMAG1
++ || f->header.e_ident[EI_MAG2] != ELFMAG2
++ || f->header.e_ident[EI_MAG3] != ELFMAG3) {
++ bb_error_msg_and_die("not an ELF file");
++ }
++ if (f->header.e_ident[EI_CLASS] != ELFCLASSM
++ || f->header.e_ident[EI_DATA] != (BB_BIG_ENDIAN
++ ? ELFDATA2MSB : ELFDATA2LSB)
++ || f->header.e_ident[EI_VERSION] != EV_CURRENT
++ || !MATCH_MACHINE(f->header.e_machine)) {
++ bb_error_msg_and_die("ELF file not for this architecture");
++ }
++ if (f->header.e_type != ET_REL) {
++ bb_error_msg_and_die("ELF file not a relocatable object");
++ }
++
++ /* Read the section headers. */
++
++ if (f->header.e_shentsize != sizeof(ElfW(Shdr))) {
++ bb_error_msg_and_die("section header size mismatch: %lu != %lu",
++ (unsigned long) f->header.e_shentsize,
++ (unsigned long) sizeof(ElfW(Shdr)));
++ }
++
++ shnum = f->header.e_shnum;
++ f->sections = xmalloc(sizeof(struct obj_section *) * shnum);
++ memset(f->sections, 0, sizeof(struct obj_section *) * shnum);
++
++ section_headers = alloca(sizeof(ElfW(Shdr)) * shnum);
++ fseek(fp, f->header.e_shoff, SEEK_SET);
++ if (fread(section_headers, sizeof(ElfW(Shdr)), shnum, fp) != shnum) {
++ bb_perror_msg_and_die("error reading ELF section headers");
++ }
++
++ /* Read the section data. */
++
++ for (i = 0; i < shnum; ++i) {
++ struct obj_section *sec;
++
++ f->sections[i] = sec = arch_new_section();
++
++ sec->header = section_headers[i];
++ sec->idx = i;
++
++ if (sec->header.sh_size) {
++ switch (sec->header.sh_type) {
++ case SHT_NULL:
++ case SHT_NOTE:
++ case SHT_NOBITS:
++ /* ignore */
++ break;
++
++ case SHT_PROGBITS:
++#if LOADBITS
++ if (!loadprogbits) {
++ sec->contents = NULL;
++ break;
++ }
++#endif
++ case SHT_SYMTAB:
++ case SHT_STRTAB:
++ case SHT_RELM:
++ if (sec->header.sh_size > 0) {
++ sec->contents = xmalloc(sec->header.sh_size);
++ fseek(fp, sec->header.sh_offset, SEEK_SET);
++ if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) {
++ bb_perror_msg_and_die("error reading ELF section data");
++ }
++ } else {
++ sec->contents = NULL;
++ }
++ break;
++
++#if SHT_RELM == SHT_REL
++ case SHT_RELA:
++ bb_error_msg_and_die("RELA relocations not supported on this architecture");
++#else
++ case SHT_REL:
++ bb_error_msg_and_die("REL relocations not supported on this architecture");
++#endif
++ default:
++ if (sec->header.sh_type >= SHT_LOPROC) {
++ /* Assume processor specific section types are debug
++ info and can safely be ignored. If this is ever not
++ the case (Hello MIPS?), don't put ifdefs here but
++ create an arch_load_proc_section(). */
++ break;
++ }
++
++ bb_error_msg_and_die("can't handle sections of type %ld",
++ (long) sec->header.sh_type);
++ }
++ }
++ }
++
++ /* Do what sort of interpretation as needed by each section. */
++
++ shstrtab = f->sections[f->header.e_shstrndx]->contents;
++
++ for (i = 0; i < shnum; ++i) {
++ struct obj_section *sec = f->sections[i];
++ sec->name = shstrtab + sec->header.sh_name;
++ }
++
++ for (i = 0; i < shnum; ++i) {
++ struct obj_section *sec = f->sections[i];
++
++ /* .modinfo should be contents only but gcc has no attribute for that.
++ * The kernel may have marked .modinfo as ALLOC, ignore this bit.
++ */
++ if (strcmp(sec->name, ".modinfo") == 0)
++ sec->header.sh_flags &= ~SHF_ALLOC;
++
++ if (sec->header.sh_flags & SHF_ALLOC)
++ obj_insert_section_load_order(f, sec);
++
++ switch (sec->header.sh_type) {
++ case SHT_SYMTAB:
++ {
++ unsigned long nsym, j;
++ char *strtab;
++ ElfW(Sym) * sym;
++
++ if (sec->header.sh_entsize != sizeof(ElfW(Sym))) {
++ bb_error_msg_and_die("symbol size mismatch: %lu != %lu",
++ (unsigned long) sec->header.sh_entsize,
++ (unsigned long) sizeof(ElfW(Sym)));
++ }
++
++ nsym = sec->header.sh_size / sizeof(ElfW(Sym));
++ strtab = f->sections[sec->header.sh_link]->contents;
++ sym = (ElfW(Sym) *) sec->contents;
++
++ /* Allocate space for a table of local symbols. */
++ j = f->local_symtab_size = sec->header.sh_info;
++ f->local_symtab = xzalloc(j * sizeof(struct obj_symbol *));
++
++ /* Insert all symbols into the hash table. */
++ for (j = 1, ++sym; j < nsym; ++j, ++sym) {
++ ElfW(Addr) val = sym->st_value;
++ const char *name;
++ if (sym->st_name)
++ name = strtab + sym->st_name;
++ else if (sym->st_shndx < shnum)
++ name = f->sections[sym->st_shndx]->name;
++ else
++ continue;
++#if defined(__SH5__)
++ /*
++ * For sh64 it is possible that the target of a branch
++ * requires a mode switch (32 to 16 and back again).
++ *
++ * This is implied by the lsb being set in the target
++ * address for SHmedia mode and clear for SHcompact.
++ */
++ val |= sym->st_other & 4;
++#endif
++ obj_add_symbol(f, name, j, sym->st_info, sym->st_shndx,
++ val, sym->st_size);
++ }
++ }
++ break;
++
++ case SHT_RELM:
++ if (sec->header.sh_entsize != sizeof(ElfW(RelM))) {
++ bb_error_msg_and_die("relocation entry size mismatch: %lu != %lu",
++ (unsigned long) sec->header.sh_entsize,
++ (unsigned long) sizeof(ElfW(RelM)));
++ }
++ break;
++ /* XXX Relocation code from modutils-2.3.19 is not here.
++ * Why? That's about 20 lines of code from obj/obj_load.c,
++ * which gets done in a second pass through the sections.
++ * This BusyBox insmod does similar work in obj_relocate(). */
++ }
++ }
++
++ return f;
++}
++
++#if ENABLE_FEATURE_INSMOD_LOADINKMEM
++/*
++ * load the unloaded sections directly into the memory allocated by
++ * kernel for the module
++ */
++
++static int obj_load_progbits(FILE *fp, struct obj_file *f, char *imagebase)
++{
++ ElfW(Addr) base = f->baseaddr;
++ struct obj_section* sec;
++
++ for (sec = f->load_order; sec; sec = sec->load_next) {
++
++ /* section already loaded? */
++ if (sec->contents != NULL)
++ continue;
++
++ if (sec->header.sh_size == 0)
++ continue;
++
++ sec->contents = imagebase + (sec->header.sh_addr - base);
++ fseek(fp, sec->header.sh_offset, SEEK_SET);
++ if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) {
++ bb_perror_msg("error reading ELF section data");
++ return 0;
++ }
++
++ }
++ return 1;
++}
++#endif
++
++static void hide_special_symbols(struct obj_file *f)
++{
++ static const char *const specials[] = {
++ SPFX "cleanup_module",
++ SPFX "init_module",
++ SPFX "kernel_version",
++ NULL
++ };
++
++ struct obj_symbol *sym;
++ const char *const *p;
++
++ for (p = specials; *p; ++p) {
++ sym = obj_find_symbol(f, *p);
++ if (sym != NULL)
++ sym->info = ELF_ST_INFO(STB_LOCAL, ELF_ST_TYPE(sym->info));
++ }
++}
++
++
++#if ENABLE_FEATURE_CHECK_TAINTED_MODULE
++static int obj_gpl_license(struct obj_file *f, const char **license)
++{
++ struct obj_section *sec;
++ /* This list must match *exactly* the list of allowable licenses in
++ * linux/include/linux/module.h. Checking for leading "GPL" will not
++ * work, somebody will use "GPL sucks, this is proprietary".
++ */
++ static const char *const gpl_licenses[] = {
++ "GPL",
++ "GPL v2",
++ "GPL and additional rights",
++ "Dual BSD/GPL",
++ "Dual MPL/GPL"
++ };
++
++ sec = obj_find_section(f, ".modinfo");
++ if (sec) {
++ const char *value, *ptr, *endptr;
++ ptr = sec->contents;
++ endptr = ptr + sec->header.sh_size;
++ while (ptr < endptr) {
++ value = strchr(ptr, '=');
++ if (value && strncmp(ptr, "license", value-ptr) == 0) {
++ unsigned i;
++ if (license)
++ *license = value+1;
++ for (i = 0; i < ARRAY_SIZE(gpl_licenses); ++i) {
++ if (strcmp(value+1, gpl_licenses[i]) == 0)
++ return 0;
++ }
++ return 2;
++ }
++ ptr = strchr(ptr, '\0');
++ if (ptr)
++ ptr++;
++ else
++ ptr = endptr;
++ }
++ }
++ return 1;
++}
++
++#define TAINT_FILENAME "/proc/sys/kernel/tainted"
++#define TAINT_PROPRIETORY_MODULE (1 << 0)
++#define TAINT_FORCED_MODULE (1 << 1)
++#define TAINT_UNSAFE_SMP (1 << 2)
++#define TAINT_URL "http://www.tux.org/lkml/#export-tainted"
++
++static void set_tainted(int fd, const char *m_name,
++ int kernel_has_tainted, int taint, const char *text1, const char *text2)
++{
++ static smallint printed_info;
++
++ char buf[80];
++ int oldval;
++
++ if (fd < 0 && !kernel_has_tainted)
++ return; /* New modutils on old kernel */
++ printf("Warning: loading %s will taint the kernel: %s%s\n",
++ m_name, text1, text2);
++ if (!printed_info) {
++ printf(" See %s for information about tainted modules\n", TAINT_URL);
++ printed_info = 1;
++ }
++ if (fd >= 0) {
++ read(fd, buf, sizeof(buf)-1);
++ buf[sizeof(buf)-1] = '\0';
++ oldval = strtoul(buf, NULL, 10);
++ sprintf(buf, "%d\n", oldval | taint);
++ write(fd, buf, strlen(buf));
++ }
++}
++
++/* Check if loading this module will taint the kernel. */
++static void check_tainted_module(struct obj_file *f, const char *m_name)
++{
++ static const char tainted_file[] ALIGN1 = TAINT_FILENAME;
++
++ int fd, kernel_has_tainted;
++ const char *ptr;
++
++ kernel_has_tainted = 1;
++ fd = open(tainted_file, O_RDWR);
++ if (fd < 0) {
++ if (errno == ENOENT)
++ kernel_has_tainted = 0;
++ else if (errno == EACCES)
++ kernel_has_tainted = 1;
++ else {
++ perror(tainted_file);
++ kernel_has_tainted = 0;
++ }
++ }
++
++ switch (obj_gpl_license(f, &ptr)) {
++ case 0:
++ break;
++ case 1:
++ set_tainted(fd, m_name, kernel_has_tainted, TAINT_PROPRIETORY_MODULE, "no license", "");
++ break;
++ case 2:
++ /* The module has a non-GPL license so we pretend that the
++ * kernel always has a taint flag to get a warning even on
++ * kernels without the proc flag.
++ */
++ set_tainted(fd, m_name, 1, TAINT_PROPRIETORY_MODULE, "non-GPL license - ", ptr);
++ break;
++ default:
++ set_tainted(fd, m_name, 1, TAINT_PROPRIETORY_MODULE, "Unexpected return from obj_gpl_license", "");
++ break;
++ }
++
++ if (flag_force_load)
++ set_tainted(fd, m_name, 1, TAINT_FORCED_MODULE, "forced load", "");
++
++ if (fd >= 0)
++ close(fd);
++}
++#else /* FEATURE_CHECK_TAINTED_MODULE */
++#define check_tainted_module(x, y) do { } while (0);
++#endif /* FEATURE_CHECK_TAINTED_MODULE */
++
++#if ENABLE_FEATURE_INSMOD_KSYMOOPS_SYMBOLS
++/* add module source, timestamp, kernel version and a symbol for the
++ * start of some sections. this info is used by ksymoops to do better
++ * debugging.
++ */
++#if !ENABLE_FEATURE_INSMOD_VERSION_CHECKING
++#define get_module_version(f, str) get_module_version(str)
++#endif
++static int
++get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
++{
++#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
++ return new_get_module_version(f, str);
++#else /* FEATURE_INSMOD_VERSION_CHECKING */
++ strncpy(str, "???", sizeof(str));
++ return -1;
++#endif /* FEATURE_INSMOD_VERSION_CHECKING */
++}
++
++/* add module source, timestamp, kernel version and a symbol for the
++ * start of some sections. this info is used by ksymoops to do better
++ * debugging.
++ */
++static void
++add_ksymoops_symbols(struct obj_file *f, const char *filename,
++ const char *m_name)
++{
++ static const char symprefix[] ALIGN1 = "__insmod_";
++ static const char section_names[][8] = {
++ ".text",
++ ".rodata",
++ ".data",
++ ".bss",
++ ".sbss"
++ };
++
++ struct obj_section *sec;
++ struct obj_symbol *sym;
++ char *name, *absolute_filename;
++ char str[STRVERSIONLEN];
++ unsigned i;
++ int l, lm_name, lfilename, use_ksymtab, version;
++ struct stat statbuf;
++
++ /* WARNING: was using realpath, but replaced by readlink to stop using
++ * lots of stack. But here it seems to be able to cause problems? */
++ absolute_filename = xmalloc_readlink(filename);
++ if (!absolute_filename)
++ absolute_filename = xstrdup(filename);
++
++ lm_name = strlen(m_name);
++ lfilename = strlen(absolute_filename);
++
++ /* add to ksymtab if it already exists or there is no ksymtab and other symbols
++ * are not to be exported. otherwise leave ksymtab alone for now, the
++ * "export all symbols" compatibility code will export these symbols later.
++ */
++ use_ksymtab = obj_find_section(f, "__ksymtab") || flag_noexport;
++
++ sec = obj_find_section(f, ".this");
++ if (sec) {
++ /* tag the module header with the object name, last modified
++ * timestamp and module version. worst case for module version
++ * is 0xffffff, decimal 16777215. putting all three fields in
++ * one symbol is less readable but saves kernel space.
++ */
++ l = sizeof(symprefix) + /* "__insmod_" */
++ lm_name + /* module name */
++ 2 + /* "_O" */
++ lfilename + /* object filename */
++ 2 + /* "_M" */
++ 2 * sizeof(statbuf.st_mtime) + /* mtime in hex */
++ 2 + /* "_V" */
++ 8 + /* version in dec */
++ 1; /* nul */
++ name = xmalloc(l);
++ if (stat(absolute_filename, &statbuf) != 0)
++ statbuf.st_mtime = 0;
++ version = get_module_version(f, str); /* -1 if not found */
++ snprintf(name, l, "%s%s_O%s_M%0*lX_V%d",
++ symprefix, m_name, absolute_filename,
++ (int)(2 * sizeof(statbuf.st_mtime)), statbuf.st_mtime,
++ version);
++ sym = obj_add_symbol(f, name, -1,
++ ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE),
++ sec->idx, sec->header.sh_addr, 0);
++ if (use_ksymtab)
++ new_add_ksymtab(f, sym);
++ }
++ free(absolute_filename);
++#ifdef _NOT_SUPPORTED_
++ /* record where the persistent data is going, same address as previous symbol */
++
++ if (f->persist) {
++ l = sizeof(symprefix) + /* "__insmod_" */
++ lm_name + /* module name */
++ 2 + /* "_P" */
++ strlen(f->persist) + /* data store */
++ 1; /* nul */
++ name = xmalloc(l);
++ snprintf(name, l, "%s%s_P%s",
++ symprefix, m_name, f->persist);
++ sym = obj_add_symbol(f, name, -1, ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE),
++ sec->idx, sec->header.sh_addr, 0);
++ if (use_ksymtab)
++ new_add_ksymtab(f, sym);
++ }
++#endif /* _NOT_SUPPORTED_ */
++ /* tag the desired sections if size is non-zero */
++
++ for (i = 0; i < ARRAY_SIZE(section_names); ++i) {
++ sec = obj_find_section(f, section_names[i]);
++ if (sec && sec->header.sh_size) {
++ l = sizeof(symprefix) + /* "__insmod_" */
++ lm_name + /* module name */
++ 2 + /* "_S" */
++ strlen(sec->name) + /* section name */
++ 2 + /* "_L" */
++ 8 + /* length in dec */
++ 1; /* nul */
++ name = xmalloc(l);
++ snprintf(name, l, "%s%s_S%s_L%ld",
++ symprefix, m_name, sec->name,
++ (long)sec->header.sh_size);
++ sym = obj_add_symbol(f, name, -1, ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE),
++ sec->idx, sec->header.sh_addr, 0);
++ if (use_ksymtab)
++ new_add_ksymtab(f, sym);
++ }
++ }
++}
++#endif /* FEATURE_INSMOD_KSYMOOPS_SYMBOLS */
++
++#if ENABLE_FEATURE_INSMOD_LOAD_MAP
++static void print_load_map(struct obj_file *f)
++{
++ struct obj_section *sec;
++#if ENABLE_FEATURE_INSMOD_LOAD_MAP_FULL
++ struct obj_symbol **all, **p;
++ int i, nsyms, *loaded;
++ struct obj_symbol *sym;
++#endif
++ /* Report on the section layout. */
++
++ printf("Sections: Size %-*s Align\n",
++ (int) (2 * sizeof(void *)), "Address");
++
++ for (sec = f->load_order; sec; sec = sec->load_next) {
++ int a;
++ unsigned long tmp;
++
++ for (a = -1, tmp = sec->header.sh_addralign; tmp; ++a)
++ tmp >>= 1;
++ if (a == -1)
++ a = 0;
++
++ printf("%-15s %08lx %0*lx 2**%d\n",
++ sec->name,
++ (long)sec->header.sh_size,
++ (int) (2 * sizeof(void *)),
++ (long)sec->header.sh_addr,
++ a);
++ }
++#if ENABLE_FEATURE_INSMOD_LOAD_MAP_FULL
++ /* Quick reference which section indices are loaded. */
++
++ i = f->header.e_shnum;
++ loaded = alloca(sizeof(int) * i);
++ while (--i >= 0)
++ loaded[i] = ((f->sections[i]->header.sh_flags & SHF_ALLOC) != 0);
++
++ /* Collect the symbols we'll be listing. */
++
++ for (nsyms = i = 0; i < HASH_BUCKETS; ++i)
++ for (sym = f->symtab[i]; sym; sym = sym->next)
++ if (sym->secidx <= SHN_HIRESERVE
++ && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx]))
++ ++nsyms;
++
++ all = alloca(nsyms * sizeof(struct obj_symbol *));
++
++ for (i = 0, p = all; i < HASH_BUCKETS; ++i)
++ for (sym = f->symtab[i]; sym; sym = sym->next)
++ if (sym->secidx <= SHN_HIRESERVE
++ && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx]))
++ *p++ = sym;
++
++ /* And list them. */
++ printf("\nSymbols:\n");
++ for (p = all; p < all + nsyms; ++p) {
++ char type = '?';
++ unsigned long value;
++
++ sym = *p;
++ if (sym->secidx == SHN_ABS) {
++ type = 'A';
++ value = sym->value;
++ } else if (sym->secidx == SHN_UNDEF) {
++ type = 'U';
++ value = 0;
++ } else {
++ sec = f->sections[sym->secidx];
++
++ if (sec->header.sh_type == SHT_NOBITS)
++ type = 'B';
++ else if (sec->header.sh_flags & SHF_ALLOC) {
++ if (sec->header.sh_flags & SHF_EXECINSTR)
++ type = 'T';
++ else if (sec->header.sh_flags & SHF_WRITE)
++ type = 'D';
++ else
++ type = 'R';
++ }
++ value = sym->value + sec->header.sh_addr;
++ }
++
++ if (ELF_ST_BIND(sym->info) == STB_LOCAL)
++ type = tolower(type);
++
++ printf("%0*lx %c %s\n", (int) (2 * sizeof(void *)), value,
++ type, sym->name);
++ }
++#endif
++}
++#else /* !FEATURE_INSMOD_LOAD_MAP */
++static void print_load_map(struct obj_file *f UNUSED_PARAM)
++{
++}
++#endif
++
++int FAST_FUNC bb_init_module_24(const char *m_filename, const char *options UNUSED_PARAM)
++{
++ int k_crcs;
++ unsigned long m_size;
++ ElfW(Addr) m_addr;
++ struct obj_file *f;
++ struct utsname uts;
++ int exit_status = EXIT_FAILURE;
++ int m_has_modinfo;
++ char *m_name;
++#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
++ char m_strversion[STRVERSIONLEN];
++ int m_version, m_crcs;
++#endif
++ FILE *fp;
++
++ uname(&uts);
++ fp = fopen_for_read(m_filename);
++ if (fp == NULL)
++ return EXIT_FAILURE;
++
++ m_name = xstrdup(bb_basename(m_filename));
++ *strrchr(m_name, '.') = 0;
++
++ f = obj_load(fp, LOADBITS);
++
++ if (get_modinfo_value(f, "kernel_version") == NULL)
++ m_has_modinfo = 0;
++ else
++ m_has_modinfo = 1;
++
++#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
++ /* Version correspondence? */
++ if (!flag_quiet) {
++ if (m_has_modinfo) {
++ m_version = new_get_module_version(f, m_strversion);
++ if (m_version == -1) {
++ bb_error_msg_and_die("cannot find the kernel version the module was "
++ "compiled for");
++ }
++ }
++
++ if (strncmp(uts.release, m_strversion, STRVERSIONLEN) != 0) {
++ bb_error_msg("%skernel-module version mismatch\n"
++ "\t%s was compiled for kernel version %s\n"
++ "\twhile this kernel is version %s",
++ flag_force_load ? "warning: " : "",
++ m_name, m_strversion, uts.release);
++ if (!flag_force_load)
++ goto out;
++ }
++ }
++ k_crcs = 0;
++#endif /* FEATURE_INSMOD_VERSION_CHECKING */
++
++ if (query_module(NULL, 0, NULL, 0, NULL))
++ bb_error_msg_and_die("not configured to support old kernels");
++ new_get_kernel_symbols();
++ k_crcs = new_is_kernel_checksummed();
++
++#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
++ m_crcs = 0;
++ if (m_has_modinfo)
++ m_crcs = new_is_module_checksummed(f);
++
++ if (m_crcs != k_crcs)
++ obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash);
++#endif /* FEATURE_INSMOD_VERSION_CHECKING */
++
++ /* Let the module know about the kernel symbols. */
++ add_kernel_symbols(f);
++
++ /* Allocate common symbols, symbol tables, and string tables. */
++
++ new_create_this_module(f, m_name);
++ obj_check_undefineds(f);
++ obj_allocate_commons(f);
++ check_tainted_module(f, m_name);
++
++ /* done with the module name, on to the optional var=value arguments */
++ new_process_module_arguments(f, options);
++
++ arch_create_got(f);
++ hide_special_symbols(f);
++
++#if ENABLE_FEATURE_INSMOD_KSYMOOPS_SYMBOLS
++ add_ksymoops_symbols(f, m_filename, m_name);
++#endif /* FEATURE_INSMOD_KSYMOOPS_SYMBOLS */
++
++ new_create_module_ksymtab(f);
++
++ /* Find current size of the module */
++ m_size = obj_load_size(f);
++
++ m_addr = create_module(m_name, m_size);
++ if (m_addr == (ElfW(Addr))(-1)) switch (errno) {
++ case EEXIST:
++ bb_error_msg_and_die("a module named %s already exists", m_name);
++ case ENOMEM:
++ bb_error_msg_and_die("can't allocate kernel memory for module; needed %lu bytes",
++ m_size);
++ default:
++ bb_perror_msg_and_die("create_module: %s", m_name);
++ }
++
++#if !LOADBITS
++ /*
++ * the PROGBITS section was not loaded by the obj_load
++ * now we can load them directly into the kernel memory
++ */
++ if (!obj_load_progbits(fp, f, (char*)m_addr)) {
++ delete_module(m_name, 0);
++ goto out;
++ }
++#endif
++
++ if (!obj_relocate(f, m_addr)) {
++ delete_module(m_name, 0);
++ goto out;
++ }
++
++ if (!new_init_module(m_name, f, m_size)) {
++ delete_module(m_name, 0);
++ goto out;
++ }
++
++ if (flag_print_load_map)
++ print_load_map(f);
++
++ exit_status = EXIT_SUCCESS;
++
++ out:
++ if (fp)
++ fclose(fp);
++ free(m_name);
++
++ return exit_status;
++}
+Index: modutils/modutils.h
+===================================================================
+--- modutils/modutils.h (revision 0)
++++ modutils/modutils.h (revision 0)
+@@ -0,0 +1,65 @@
++/*
++ * Common modutils related functions for busybox
++ *
++ * Copyright (C) 2008 by Timo Teras <timo.teras@iki.fi>
++ *
++ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
++ */
++
++#ifndef __MODUTILS_H__
++#define __MODUTILS_H__
++
++#include "libbb.h"
++#include <stdio.h>
++
++#if __GNUC_PREREQ(4,1)
++# pragma GCC visibility push(hidden)
++#endif
++
++/* As defined in linux/include/linux/module.h */
++#define MODULE_NAME_LEN 64
++
++int string_to_llist(char *string, llist_t **llist, const char *delim) FAST_FUNC ;
++const char *moderror(int err) FAST_FUNC;
++char *filename2modname(const char *filename, char *modname) FAST_FUNC;
++char *parse_cmdline_module_options(char **argv) FAST_FUNC;
++
++#define INSMOD_OPTS "vq" USE_FEATURE_2_4_MODULES("sLo:fkx") \
++ USE_FEATURE_INSMOD_LOAD_MAP("m")
++#define INSMOD_ARGS USE_FEATURE_2_4_MODULES(, &insmod_outputname)
++
++enum {
++ INSMOD_OPT_VERBOSE = 0x0001,
++ INSMOD_OPT_SILENT = 0x0002,
++ INSMOD_OPT_SYSLOG = 0x0004 * ENABLE_FEATURE_2_4_MODULES,
++ INSMOD_OPT_LOCK = 0x0008 * ENABLE_FEATURE_2_4_MODULES,
++ INSMOD_OPT_OUTPUTNAME = 0x0010 * ENABLE_FEATURE_2_4_MODULES,
++ INSMOD_OPT_FORCE = 0x0020 * ENABLE_FEATURE_2_4_MODULES,
++ INSMOD_OPT_KERNELD = 0x0040 * ENABLE_FEATURE_2_4_MODULES,
++ INSMOD_OPT_NO_EXPORT = 0x0080 * ENABLE_FEATURE_2_4_MODULES,
++ INSMOD_OPT_PRINT_MAP = 0x0100 * ENABLE_FEATURE_INSMOD_LOAD_MAP,
++#if ENABLE_FEATURE_2_4_MODULES
++#if ENABLE_FEATURE_INSMOD_LOAD_MAP
++ INSMOD_OPT_UNUSED = 0x0200,
++#else /* ENABLE_FEATURE_INSMOD_LOAD_MAP */
++ INSMOD_OPT_UNUSED = 0x0100
++#endif
++#else /* ENABLE_FEATURE_2_4_MODULES */
++ INSMOD_OPT_UNUSED = 0x0004
++#endif
++};
++
++int FAST_FUNC bb_init_module(const char *module, const char *options);
++int FAST_FUNC bb_delete_module(const char *module, unsigned int flags);
++
++#if ENABLE_FEATURE_2_4_MODULES
++extern char *insmod_outputname;
++
++int FAST_FUNC bb_init_module_24(const char *module, const char *options);
++#endif
++
++#if __GNUC_PREREQ(4,1)
++# pragma GCC visibility pop
++#endif
++
++#endif
+Index: modutils/modprobe.c
+===================================================================
+--- modutils/modprobe.c (revision 23360)
++++ modutils/modprobe.c (working copy)
+@@ -2,951 +2,294 @@
+ /*
+ * Modprobe written from scratch for BusyBox
+ *
+- * Copyright (c) 2002 by Robert Griebl, griebl@gmx.de
+- * Copyright (c) 2003 by Andrew Dennison, andrew.dennison@motec.com.au
+- * Copyright (c) 2005 by Jim Bauer, jfbauer@nfr.com
++ * Copyright (c) 2008 Timo Teras <timo.teras@iki.fi>
++ * Copyright (c) 2008 Vladimir Dronnikov
+ *
+- * Portions Copyright (c) 2005 by Yann E. MORIN, yann.morin.1998@anciens.enib.fr
+- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+-*/
++ */
+
+ #include "libbb.h"
++#include "modutils.h"
+ #include <sys/utsname.h>
+ #include <fnmatch.h>
+
+-#define line_buffer bb_common_bufsiz1
+-
+-struct mod_opt_t { /* one-way list of options to pass to a module */
+- char * m_opt_val;
+- struct mod_opt_t * m_next;
++struct modprobe_option {
++ char *module;
++ char *option;
+ };
+
+-struct dep_t { /* one-way list of dependency rules */
+- /* a dependency rule */
+- char * m_name; /* the module name*/
+- char * m_path; /* the module file path */
+- struct mod_opt_t * m_options; /* the module options */
+-
+- unsigned int m_isalias :1; /* the module is an alias */
+- unsigned int m_isblacklisted:1; /* the module is blacklisted */
+- unsigned int m_reserved :14; /* stuffin' */
+-
+- unsigned int m_depcnt :16; /* the number of dependable module(s) */
+- char ** m_deparr; /* the list of dependable module(s) */
+-
+- struct dep_t * m_next; /* the next dependency rule */
++struct modprobe_conf {
++ char probename[MODULE_NAME_LEN];
++ llist_t *options;
++ llist_t *aliases;
++#if ENABLE_FEATURE_MODPROBE_BLACKLIST
++#define add_to_blacklist(conf, name) llist_add_to(&conf->blacklist, name)
++#define check_blacklist(conf, name) (llist_find(conf->blacklist, name) == NULL)
++ llist_t *blacklist;
++#else
++#define add_to_blacklist(conf, name) do {} while (0)
++#define check_blacklist(conf, name) (1)
++#endif
+ };
+
+-struct mod_list_t { /* two-way list of modules to process */
+- /* a module description */
+- const char * m_name;
+- char * m_path;
+- struct mod_opt_t * m_options;
+-
+- struct mod_list_t * m_prev;
+- struct mod_list_t * m_next;
++#define MODPROBE_OPTS "acdlnrt:VC:" USE_FEATURE_MODPROBE_BLACKLIST("b")
++enum {
++ MODPROBE_OPT_INSERT_ALL = (INSMOD_OPT_UNUSED << 0), /* a */
++ MODPROBE_OPT_DUMP_ONLY = (INSMOD_OPT_UNUSED << 1), /* c */
++ MODPROBE_OPT_D = (INSMOD_OPT_UNUSED << 2), /* d */
++ MODPROBE_OPT_LIST_ONLY = (INSMOD_OPT_UNUSED << 3), /* l */
++ MODPROBE_OPT_SHOW_ONLY = (INSMOD_OPT_UNUSED << 4), /* n */
++ MODPROBE_OPT_REMOVE = (INSMOD_OPT_UNUSED << 5), /* r */
++ MODPROBE_OPT_RESTRICT = (INSMOD_OPT_UNUSED << 6), /* t */
++ MODPROBE_OPT_VERONLY = (INSMOD_OPT_UNUSED << 7), /* V */
++ MODPROBE_OPT_CONFIGFILE = (INSMOD_OPT_UNUSED << 8), /* C */
++ MODPROBE_OPT_BLACKLIST = (INSMOD_OPT_UNUSED << 9) * ENABLE_FEATURE_MODPROBE_BLACKLIST,
+ };
+
+-struct include_conf_t {
+- struct dep_t *first;
+- struct dep_t *current;
+-};
++static llist_t *loaded;
+
+-static struct dep_t *depend;
++static int read_config(struct modprobe_conf *conf, const char *path);
+
+-#define MAIN_OPT_STR "acdklnqrst:vVC:"
+-#define INSERT_ALL 1 /* a */
+-#define DUMP_CONF_EXIT 2 /* c */
+-#define D_OPT_IGNORED 4 /* d */
+-#define AUTOCLEAN_FLG 8 /* k */
+-#define LIST_ALL 16 /* l */
+-#define SHOW_ONLY 32 /* n */
+-#define QUIET 64 /* q */
+-#define REMOVE_OPT 128 /* r */
+-#define DO_SYSLOG 256 /* s */
+-#define RESTRICT_DIR 512 /* t */
+-#define VERBOSE 1024 /* v */
+-#define VERSION_ONLY 2048 /* V */
+-#define CONFIG_FILE 4096 /* C */
+-
+-#define autoclean (option_mask32 & AUTOCLEAN_FLG)
+-#define show_only (option_mask32 & SHOW_ONLY)
+-#define quiet (option_mask32 & QUIET)
+-#define remove_opt (option_mask32 & REMOVE_OPT)
+-#define do_syslog (option_mask32 & DO_SYSLOG)
+-#define verbose (option_mask32 & VERBOSE)
+-
+-static int parse_tag_value(char *buffer, char **ptag, char **pvalue)
++static void add_option(llist_t **all_opts, const char *module, const char *opts)
+ {
+- char *tag, *value;
++ struct modprobe_option *o;
+
+- buffer = skip_whitespace(buffer);
+- tag = value = buffer;
+- while (!isspace(*value)) {
+- if (!*value)
+- return 0;
+- value++;
+- }
+- *value++ = '\0';
+- value = skip_whitespace(value);
+- if (!*value)
+- return 0;
+-
+- *ptag = tag;
+- *pvalue = value;
+-
+- return 1;
++ o = xzalloc(sizeof(struct modprobe_option));
++ if (module)
++ o->module = filename2modname(module, NULL);
++ o->option = xstrdup(opts);
++ llist_add_to(all_opts, o);
+ }
+
+-/*
+- * This function appends an option to a list
+- */
+-static struct mod_opt_t *append_option(struct mod_opt_t *opt_list, char *opt)
++static int FAST_FUNC config_file_action(const char *filename,
++ struct stat *statbuf UNUSED_PARAM,
++ void *userdata,
++ int depth UNUSED_PARAM)
+ {
+- struct mod_opt_t *ol = opt_list;
++ struct modprobe_conf *conf = (struct modprobe_conf *) userdata;
++ RESERVE_CONFIG_BUFFER(modname, MODULE_NAME_LEN);
++ char *tokens[3];
++ parser_t *p;
++ int rc = TRUE;
+
+- if (ol) {
+- while (ol->m_next) {
+- ol = ol->m_next;
+- }
+- ol->m_next = xzalloc(sizeof(struct mod_opt_t));
+- ol = ol->m_next;
+- } else {
+- ol = opt_list = xzalloc(sizeof(struct mod_opt_t));
+- }
++ if (bb_basename(filename)[0] == '.')
++ goto error;
+
+- ol->m_opt_val = xstrdup(opt);
+- /*ol->m_next = NULL; - done by xzalloc*/
+-
+- return opt_list;
+-}
+-
+-#if ENABLE_FEATURE_MODPROBE_MULTIPLE_OPTIONS
+-/* static char* parse_command_string(char* src, char **dst);
+- * src: pointer to string containing argument
+- * dst: pointer to where to store the parsed argument
+- * return value: the pointer to the first char after the parsed argument,
+- * NULL if there was no argument parsed (only trailing spaces).
+- * Note that memory is allocated with xstrdup when a new argument was
+- * parsed. Don't forget to free it!
+- */
+-#define ARG_EMPTY 0x00
+-#define ARG_IN_DQUOTES 0x01
+-#define ARG_IN_SQUOTES 0x02
+-static char *parse_command_string(char *src, char **dst)
+-{
+- int opt_status = ARG_EMPTY;
+- char* tmp_str;
+-
+- /* Dumb you, I have nothing to do... */
+- if (src == NULL) return src;
+-
+- /* Skip leading spaces */
+- while (*src == ' ') {
+- src++;
++ p = config_open2(filename, fopen_for_read);
++ if (p == NULL) {
++ rc = FALSE;
++ goto error;
+ }
+- /* Is the end of string reached? */
+- if (*src == '\0') {
+- return NULL;
+- }
+- /* Reached the start of an argument
+- * By the way, we duplicate a little too much
+- * here but what is too much is freed later. */
+- *dst = tmp_str = xstrdup(src);
+- /* Get to the end of that argument */
+- while (*tmp_str != '\0'
+- && (*tmp_str != ' ' || (opt_status & (ARG_IN_DQUOTES | ARG_IN_SQUOTES)))
+- ) {
+- switch (*tmp_str) {
+- case '\'':
+- if (opt_status & ARG_IN_DQUOTES) {
+- /* Already in double quotes, keep current char as is */
+- } else {
+- /* shift left 1 char, until end of string: get rid of the opening/closing quotes */
+- memmove(tmp_str, tmp_str + 1, strlen(tmp_str));
+- /* mark me: we enter or leave single quotes */
+- opt_status ^= ARG_IN_SQUOTES;
+- /* Back one char, as we need to re-scan the new char there. */
+- tmp_str--;
+- }
+- break;
+- case '"':
+- if (opt_status & ARG_IN_SQUOTES) {
+- /* Already in single quotes, keep current char as is */
+- } else {
+- /* shift left 1 char, until end of string: get rid of the opening/closing quotes */
+- memmove(tmp_str, tmp_str + 1, strlen(tmp_str));
+- /* mark me: we enter or leave double quotes */
+- opt_status ^= ARG_IN_DQUOTES;
+- /* Back one char, as we need to re-scan the new char there. */
+- tmp_str--;
+- }
+- break;
+- case '\\':
+- if (opt_status & ARG_IN_SQUOTES) {
+- /* Between single quotes: keep as is. */
+- } else {
+- switch (*(tmp_str+1)) {
+- case 'a':
+- case 'b':
+- case 't':
+- case 'n':
+- case 'v':
+- case 'f':
+- case 'r':
+- case '0':
+- /* We escaped a special character. For now, keep
+- * both the back-slash and the following char. */
+- tmp_str++;
+- src++;
+- break;
+- default:
+- /* We escaped a space or a single or double quote,
+- * or a back-slash, or a non-escapable char. Remove
+- * the '\' and keep the new current char as is. */
+- memmove(tmp_str, tmp_str + 1, strlen(tmp_str));
+- break;
+- }
+- }
+- break;
+- /* Any other char that is special shall appear here.
+- * Example: $ starts a variable
+- case '$':
+- do_variable_expansion();
+- break;
+- * */
+- default:
+- /* any other char is kept as is. */
+- break;
++
++ while (config_read(p, tokens, 3, 2, "# \t", PARSE_NORMAL)) {
++ if (strcmp(tokens[0], "alias") == 0) {
++ filename2modname(tokens[1], modname);
++ if (tokens[2] &&
++ fnmatch(modname, conf->probename, 0) == 0)
++ llist_add_to(&conf->aliases,
++ filename2modname(tokens[2], NULL));
++ } else if (strcmp(tokens[0], "options") == 0) {
++ if (tokens[2])
++ add_option(&conf->options, tokens[1], tokens[2]);
++ } else if (strcmp(tokens[0], "include") == 0) {
++ read_config(conf, tokens[1]);
++ } else if (ENABLE_FEATURE_MODPROBE_BLACKLIST &&
++ strcmp(tokens[0], "blacklist") == 0) {
++ add_to_blacklist(conf, xstrdup(tokens[1]));
+ }
+- tmp_str++; /* Go to next char */
+- src++; /* Go to next char to find the end of the argument. */
+ }
+- /* End of string, but still no ending quote */
+- if (opt_status & (ARG_IN_DQUOTES | ARG_IN_SQUOTES)) {
+- bb_error_msg_and_die("unterminated (single or double) quote in options list: %s", src);
+- }
+- *tmp_str++ = '\0';
+- *dst = xrealloc(*dst, (tmp_str - *dst));
+- return src;
++ config_close(p);
++error:
++ if (ENABLE_FEATURE_CLEAN_UP)
++ RELEASE_CONFIG_BUFFER(modname);
++ return rc;
+ }
+-#else
+-#define parse_command_string(src, dst) (0)
+-#endif /* ENABLE_FEATURE_MODPROBE_MULTIPLE_OPTIONS */
+
+-static int is_conf_command(char *buffer, const char *command)
++static int read_config(struct modprobe_conf *conf, const char *path)
+ {
+- int len = strlen(command);
+- return ((strstr(buffer, command) == buffer) &&
+- isspace(buffer[len]));
++ return recursive_action(path, ACTION_RECURSE | ACTION_QUIET,
++ config_file_action, NULL, conf, 1);
+ }
+
+-/*
+- * This function reads aliases and default module options from a configuration file
+- * (/etc/modprobe.conf syntax). It supports includes (only files, no directories).
+- */
+-
+-static int FAST_FUNC include_conf_file_act(const char *filename,
+- struct stat *statbuf UNUSED_PARAM,
+- void *userdata,
+- int depth UNUSED_PARAM);
+-
+-static int FAST_FUNC include_conf_dir_act(const char *filename UNUSED_PARAM,
+- struct stat *statbuf UNUSED_PARAM,
+- void *userdata UNUSED_PARAM,
+- int depth)
++static llist_t *llist_find(llist_t *first, const char *str)
+ {
+- if (depth > 1)
+- return SKIP;
+-
+- return TRUE;
++ while (first != NULL) {
++ if (strcmp(first->data, str) == 0)
++ return first;
++ first = first->link;
++ }
++ return NULL;
+ }
+
+-static int include_conf_recursive(struct include_conf_t *conf, const char *filename)
++static char *gather_options(llist_t *first, const char *module, int usecmdline)
+ {
+- return recursive_action(filename, ACTION_RECURSE,
+- include_conf_file_act,
+- include_conf_dir_act,
+- conf, 1);
+-}
++ struct modprobe_option *opt;
++ llist_t *n;
++ char *opts = xstrdup("");
++ int optlen = 0;
+
+-static int FAST_FUNC include_conf_file_act(const char *filename,
+- struct stat *statbuf UNUSED_PARAM,
+- void *userdata,
+- int depth UNUSED_PARAM)
+-{
+- struct include_conf_t *conf = (struct include_conf_t *) userdata;
+- struct dep_t **first = &conf->first;
+- struct dep_t **current = &conf->current;
+- int continuation_line = 0;
+- FILE *f;
++ for (n = first; n != NULL; n = n->link) {
++ opt = (struct modprobe_option *) n->data;
+
+- if (bb_basename(filename)[0] == '.')
+- return TRUE;
+-
+- f = fopen_for_read(filename);
+- if (f == NULL)
+- return FALSE;
+-
+- // alias parsing is not 100% correct (no correct handling of continuation lines within an alias)!
+-
+- while (fgets(line_buffer, sizeof(line_buffer), f)) {
+- int l;
+-
+- *strchrnul(line_buffer, '#') = '\0';
+-
+- l = strlen(line_buffer);
+-
+- while (l && isspace(line_buffer[l-1])) {
+- line_buffer[l-1] = '\0';
+- l--;
+- }
+-
+- if (l == 0) {
+- continuation_line = 0;
++ if (opt->module == NULL && !usecmdline)
+ continue;
+- }
+-
+- if (continuation_line)
++ if (opt->module != NULL && strcmp(opt->module, module) != 0)
+ continue;
+
+- if (is_conf_command(line_buffer, "alias")) {
+- char *alias, *mod;
+-
+- if (parse_tag_value(line_buffer + 6, &alias, &mod)) {
+- /* handle alias as a module dependent on the aliased module */
+- if (!*current) {
+- (*first) = (*current) = xzalloc(sizeof(struct dep_t));
+- } else {
+- (*current)->m_next = xzalloc(sizeof(struct dep_t));
+- (*current) = (*current)->m_next;
+- }
+- (*current)->m_name = xstrdup(alias);
+- (*current)->m_isalias = 1;
+-
+- if ((strcmp(mod, "off") == 0) || (strcmp(mod, "null") == 0)) {
+- /*(*current)->m_depcnt = 0; - done by xzalloc */
+- /*(*current)->m_deparr = 0;*/
+- } else {
+- (*current)->m_depcnt = 1;
+- (*current)->m_deparr = xmalloc(sizeof(char *));
+- (*current)->m_deparr[0] = xstrdup(mod);
+- }
+- /*(*current)->m_next = NULL; - done by xzalloc */
+- }
+- } else if (is_conf_command(line_buffer, "options")) {
+- char *mod, *opt;
+-
+- /* split the line in the module/alias name, and options */
+- if (parse_tag_value(line_buffer + 8, &mod, &opt)) {
+- struct dep_t *dt;
+-
+- /* find the corresponding module */
+- for (dt = *first; dt; dt = dt->m_next) {
+- if (strcmp(dt->m_name, mod) == 0)
+- break;
+- }
+- if (dt) {
+- if (ENABLE_FEATURE_MODPROBE_MULTIPLE_OPTIONS) {
+- char* new_opt = NULL;
+- while ((opt = parse_command_string(opt, &new_opt))) {
+- dt->m_options = append_option(dt->m_options, new_opt);
+- }
+- } else {
+- dt->m_options = append_option(dt->m_options, opt);
+- }
+- }
+- }
+- } else if (is_conf_command(line_buffer, "include")) {
+- char *includefile;
+-
+- includefile = skip_whitespace(line_buffer + 8);
+- include_conf_recursive(conf, includefile);
+- } else if (ENABLE_FEATURE_MODPROBE_BLACKLIST &&
+- (is_conf_command(line_buffer, "blacklist"))) {
+- char *mod;
+- struct dep_t *dt;
+-
+- mod = skip_whitespace(line_buffer + 10);
+- for (dt = *first; dt; dt = dt->m_next) {
+- if (strcmp(dt->m_name, mod) == 0)
+- break;
+- }
+- if (dt)
+- dt->m_isblacklisted = 1;
+- }
+- } /* while (fgets(...)) */
+-
+- fclose(f);
+- return TRUE;
++ opts = xrealloc(opts, optlen + strlen(opt->option) + 2);
++ optlen += sprintf(opts + optlen, "%s ", opt->option);
++ }
++ return opts;
+ }
+
+-static int include_conf_file(struct include_conf_t *conf,
+- const char *filename)
++static int do_modprobe(struct modprobe_conf *conf, const char *module)
+ {
+- return include_conf_file_act(filename, NULL, conf, 0);
+-}
++ RESERVE_CONFIG_BUFFER(modname, MODULE_NAME_LEN);
++ llist_t *deps = NULL;
++ char *fn, *options, *colon = NULL, *tokens[2];
++ parser_t *p;
++ int rc = -1;
+
+-static int include_conf_file2(struct include_conf_t *conf,
+- const char *filename, const char *oldname)
+-{
+- if (include_conf_file(conf, filename) == TRUE)
+- return TRUE;
+- return include_conf_file(conf, oldname);
+-}
++ p = config_open2(CONFIG_DEFAULT_DEPMOD_FILE, fopen_for_read);
++ if (p == NULL)
++ goto error;
+
+-/*
+- * This function builds a list of dependency rules from /lib/modules/`uname -r`/modules.dep.
+- * It then fills every modules and aliases with their default options, found by parsing
+- * modprobe.conf (or modules.conf, or conf.modules).
+- */
+-static struct dep_t *build_dep(void)
+-{
+- FILE *f;
+- struct utsname un;
+- struct include_conf_t conf = { NULL, NULL };
+- char *filename;
+- int continuation_line = 0;
+- int k_version;
++ while (config_read(p, tokens, 2, 1, "# \t", PARSE_NORMAL)) {
++ colon = last_char_is(tokens[0], ':');
++ if (colon == NULL)
++ continue;
+
+- uname(&un); /* never fails */
++ filename2modname(tokens[0], modname);
++ if (strcmp(modname, module) == 0)
++ break;
+
+- k_version = 0;
+- if (un.release[0] == '2') {
+- k_version = un.release[2] - '0';
++ colon = NULL;
+ }
++ if (colon == NULL)
++ goto error_not_found;
+
+- filename = xasprintf(CONFIG_DEFAULT_MODULES_DIR"/%s/"CONFIG_DEFAULT_DEPMOD_FILE, un.release);
+- f = fopen_for_read(filename);
+- if (ENABLE_FEATURE_CLEAN_UP)
+- free(filename);
+- if (f == NULL) {
+- /* Ok, that didn't work. Fall back to looking in /lib/modules */
+- f = fopen_for_read(CONFIG_DEFAULT_MODULES_DIR"/"CONFIG_DEFAULT_DEPMOD_FILE);
+- if (f == NULL) {
+- bb_error_msg_and_die("cannot parse "CONFIG_DEFAULT_DEPMOD_FILE);
+- }
+- }
++ colon[0] = '\0';
++ llist_add_to(&deps, xstrdup(tokens[0]));
++ if (tokens[1])
++ string_to_llist(tokens[1], &deps, " ");
+
+- while (fgets(line_buffer, sizeof(line_buffer), f)) {
+- int l = strlen(line_buffer);
+- char *p = NULL;
++ if (!(option_mask32 & MODPROBE_OPT_REMOVE))
++ deps = llist_rev(deps);
+
+- while (l > 0 && isspace(line_buffer[l-1])) {
+- line_buffer[l-1] = '\0';
+- l--;
++ rc = 0;
++ while (deps && rc == 0) {
++ fn = llist_pop(&deps);
++ filename2modname(fn, modname);
++ if (option_mask32 & MODPROBE_OPT_REMOVE) {
++ if (bb_delete_module(modname, O_EXCL) != 0)
++ rc = errno;
++ } else if (llist_find(loaded, modname) == NULL) {
++ options = gather_options(conf->options, modname,
++ strcmp(modname, module) == 0);
++ rc = bb_init_module(fn, options);
++ if (rc == 0)
++ llist_add_to(&loaded, xstrdup(modname));
++ if (ENABLE_FEATURE_CLEAN_UP)
++ free(options);
+ }
+
+- if (l == 0) {
+- continuation_line = 0;
+- continue;
+- }
+-
+- /* Is this a new module dep description? */
+- if (!continuation_line) {
+- /* find the dep beginning */
+- char *col = strchr(line_buffer, ':');
+- char *dot = col;
+-
+- if (col) {
+- /* This line is a dep description */
+- const char *mods;
+- char *modpath;
+- char *mod;
+-
+- /* Find the beginning of the module file name */
+- *col = '\0';
+- mods = bb_basename(line_buffer);
+-
+- /* find the path of the module */
+- modpath = strchr(line_buffer, '/'); /* ... and this is the path */
+- if (!modpath)
+- modpath = line_buffer; /* module with no path */
+- /* find the end of the module name in the file name */
+- if (ENABLE_FEATURE_2_6_MODULES &&
+- (k_version > 4) && (col[-3] == '.') &&
+- (col[-2] == 'k') && (col[-1] == 'o'))
+- dot = col - 3;
+- else if ((col[-2] == '.') && (col[-1] == 'o'))
+- dot = col - 2;
+-
+- mod = xstrndup(mods, dot - mods);
+-
+- /* enqueue new module */
+- if (!conf.current) {
+- conf.first = conf.current = xzalloc(sizeof(struct dep_t));
+- } else {
+- conf.current->m_next = xzalloc(sizeof(struct dep_t));
+- conf.current = conf.current->m_next;
+- }
+- conf.current->m_name = mod;
+- conf.current->m_path = xstrdup(modpath);
+- /*current->m_options = NULL; - xzalloc did it*/
+- /*current->m_isalias = 0;*/
+- /*current->m_depcnt = 0;*/
+- /*current->m_deparr = 0;*/
+- /*current->m_next = 0;*/
+-
+- p = col + 1;
+- } else
+- /* this line is not a dep description */
+- p = NULL;
+- } else
+- /* It's a dep description continuation */
+- p = line_buffer;
+-
+- /* p points to the first dependable module; if NULL, no dependable module */
+- if (p && (p = skip_whitespace(p))[0] != '\0') {
+- char *end = &line_buffer[l-1];
+- const char *deps;
+- char *dep;
+- char *next;
+- int ext = 0;
+-
+- while (isblank(*end) || (*end == '\\'))
+- end--;
+-
+- do {
+- /* search the end of the dependency */
+- next = strchr(p, ' ');
+- if (next) {
+- *next = '\0';
+- next--;
+- } else
+- next = end;
+-
+- /* find the beginning of the module file name */
+- deps = bb_basename(p);
+- if (deps == p)
+- deps = skip_whitespace(deps);
+-
+- /* find the end of the module name in the file name */
+- if (ENABLE_FEATURE_2_6_MODULES
+- && (k_version > 4) && (next[-2] == '.')
+- && (next[-1] == 'k') && (next[0] == 'o'))
+- ext = 3;
+- else if ((next[-1] == '.') && (next[0] == 'o'))
+- ext = 2;
+-
+- /* Cope with blank lines */
+- if ((next - deps - ext + 1) <= 0)
+- continue;
+- dep = xstrndup(deps, next - deps - ext + 1);
+-
+- /* Add the new dependable module name */
+- conf.current->m_deparr = xrealloc_vector(conf.current->m_deparr, 2, conf.current->m_depcnt);
+- conf.current->m_deparr[conf.current->m_depcnt++] = dep;
+-
+- p = next + 2;
+- } while (next < end);
+- }
+-
+- /* is there other dependable module(s) ? */
+- continuation_line = (line_buffer[l-1] == '\\');
+- } /* while (fgets(...)) */
+- fclose(f);
+-
+- /*
+- * First parse system-specific options and aliases
+- * as they take precedence over the kernel ones.
+- * >=2.6: we only care about modprobe.conf
+- * <=2.4: we care about modules.conf and conf.modules
+- */
+- {
+- int r = FALSE;
+-
+- if (ENABLE_FEATURE_2_6_MODULES) {
+- if (include_conf_file(&conf, "/etc/modprobe.conf"))
+- r = TRUE;
+- if (include_conf_recursive(&conf, "/etc/modprobe.d"))
+- r = TRUE;
+- }
+- if (ENABLE_FEATURE_2_4_MODULES && !r)
+- include_conf_file2(&conf,
+- "/etc/modules.conf",
+- "/etc/conf.modules");
+- }
+-
+- /* Only 2.6 has a modules.alias file */
+- if (ENABLE_FEATURE_2_6_MODULES) {
+- /* Parse kernel-declared module aliases */
+- filename = xasprintf(CONFIG_DEFAULT_MODULES_DIR"/%s/modules.alias", un.release);
+- include_conf_file2(&conf,
+- filename,
+- CONFIG_DEFAULT_MODULES_DIR"/modules.alias");
+ if (ENABLE_FEATURE_CLEAN_UP)
+- free(filename);
+-
+- /* Parse kernel-declared symbol aliases */
+- filename = xasprintf(CONFIG_DEFAULT_MODULES_DIR"/%s/modules.symbols", un.release);
+- include_conf_file2(&conf,
+- filename,
+- CONFIG_DEFAULT_MODULES_DIR"/modules.symbols");
+- if (ENABLE_FEATURE_CLEAN_UP)
+- free(filename);
++ free(fn);
+ }
+
+- return conf.first;
++error_not_found:
++ config_close(p);
++error:
++ if (ENABLE_FEATURE_CLEAN_UP)
++ RELEASE_CONFIG_BUFFER(modname);
++ if (rc > 0 && !(option_mask32 & INSMOD_OPT_SILENT))
++ bb_error_msg("Failed to %sload module %s: %s.",
++ (option_mask32 & MODPROBE_OPT_REMOVE) ? "un" : "",
++ module, moderror(rc));
++ return rc;
+ }
+
+-/* return 1 = loaded, 0 = not loaded, -1 = can't tell */
+-static int already_loaded(const char *name)
++int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
++int modprobe_main(int argc UNUSED_PARAM, char **argv)
+ {
+- FILE *f;
+- int ret;
++ struct utsname uts;
++ int num_modules, i, rc;
++ llist_t *options = NULL;
++ parser_t *parser;
+
+- f = fopen_for_read("/proc/modules");
+- if (f == NULL)
+- return -1;
++ opt_complementary = "q-v:v-q";
++ getopt32(argv, INSMOD_OPTS MODPROBE_OPTS INSMOD_ARGS,
++ NULL, NULL);
++ argv += optind;
++ argc -= optind;
+
+- ret = 0;
+- while (fgets(line_buffer, sizeof(line_buffer), f)) {
+- char *p = line_buffer;
+- const char *n = name;
++ if (option_mask32 & (MODPROBE_OPT_DUMP_ONLY | MODPROBE_OPT_LIST_ONLY |
++ MODPROBE_OPT_SHOW_ONLY))
++ bb_error_msg_and_die("not supported");
+
+- while (1) {
+- char cn = *n;
+- char cp = *p;
+- if (cp == ' ' || cp == '\0') {
+- if (cn == '\0') {
+- ret = 1; /* match! */
+- goto done;
+- }
+- break; /* no match on this line, take next one */
+- }
+- if (cn == '-') cn = '_';
+- if (cp == '-') cp = '_';
+- if (cp != cn)
+- break; /* no match on this line, take next one */
+- n++;
+- p++;
+- }
+- }
+- done:
+- fclose(f);
+- return ret;
+-}
++ /* goto modules location */
++ xchdir(CONFIG_DEFAULT_MODULES_DIR);
++ uname(&uts);
++ chdir(uts.release);
+
+-static int mod_process(const struct mod_list_t *list, int do_insert)
+-{
+- int rc = 0;
+- char **argv = NULL;
+- struct mod_opt_t *opts;
+- int argc_malloc; /* never used when CONFIG_FEATURE_CLEAN_UP not defined */
+- int argc;
+-
+- while (list) {
+- argc = 0;
+- if (ENABLE_FEATURE_CLEAN_UP)
+- argc_malloc = 0;
+- /* If CONFIG_FEATURE_CLEAN_UP is not defined, then we leak memory
+- * each time we allocate memory for argv.
+- * But it is (quite) small amounts of memory that leak each
+- * time a module is loaded, and it is reclaimed when modprobe
+- * exits anyway (even when standalone shell? Yes --vda).
+- * This could become a problem when loading a module with LOTS of
+- * dependencies, with LOTS of options for each dependencies, with
+- * very little memory on the target... But in that case, the module
+- * would not load because there is no more memory, so there's no
+- * problem. */
+- /* enough for minimal insmod (5 args + NULL) or rmmod (3 args + NULL) */
+- argv = xmalloc(6 * sizeof(char*));
+- if (do_insert) {
+- if (already_loaded(list->m_name) != 1) {
+- argv[argc++] = (char*)"insmod";
+- if (ENABLE_FEATURE_2_4_MODULES) {
+- if (do_syslog)
+- argv[argc++] = (char*)"-s";
+- if (autoclean)
+- argv[argc++] = (char*)"-k";
+- if (quiet)
+- argv[argc++] = (char*)"-q";
+- else if (verbose) /* verbose and quiet are mutually exclusive */
+- argv[argc++] = (char*)"-v";
+- }
+- argv[argc++] = list->m_path;
+- if (ENABLE_FEATURE_CLEAN_UP)
+- argc_malloc = argc;
+- opts = list->m_options;
+- while (opts) {
+- /* Add one more option */
+- argc++;
+- argv = xrealloc(argv, (argc + 1) * sizeof(char*));
+- argv[argc-1] = opts->m_opt_val;
+- opts = opts->m_next;
+- }
+- }
+- } else {
+- /* modutils uses short name for removal */
+- if (already_loaded(list->m_name) != 0) {
+- argv[argc++] = (char*)"rmmod";
+- if (do_syslog)
+- argv[argc++] = (char*)"-s";
+- argv[argc++] = (char*)list->m_name;
+- if (ENABLE_FEATURE_CLEAN_UP)
+- argc_malloc = argc;
+- }
++ if (option_mask32 & (MODPROBE_OPT_REMOVE | MODPROBE_OPT_INSERT_ALL)) {
++ /* each parameter is a module name */
++ num_modules = argc;
++ if (num_modules == 0) {
++ if (bb_delete_module(NULL, O_NONBLOCK|O_EXCL) != 0)
++ bb_perror_msg_and_die("rmmod");
++ return EXIT_SUCCESS;
+ }
+- argv[argc] = NULL;
+-
+- if (argc) {
+- if (verbose) {
+- printf("%s module %s\n", do_insert?"Loading":"Unloading", list->m_name);
+- }
+- if (!show_only) {
+- int rc2 = wait4pid(spawn(argv));
+-
+- if (do_insert) {
+- rc = rc2; /* only last module matters */
+- } else if (!rc2) {
+- rc = 0; /* success if remove any mod */
+- }
+- }
+- if (ENABLE_FEATURE_CLEAN_UP) {
+- /* the last value in the array has index == argc, but
+- * it is the terminating NULL, so we must not free it. */
+- while (argc_malloc < argc) {
+- free(argv[argc_malloc++]);
+- }
+- }
+- }
+- if (ENABLE_FEATURE_CLEAN_UP) {
+- free(argv);
+- argv = NULL;
+- }
+- list = do_insert ? list->m_prev : list->m_next;
++ } else {
++ /* the only module, the rest of parameters are options */
++ num_modules = 1;
++ add_option(&options, NULL, parse_cmdline_module_options(argv));
+ }
+- return (show_only) ? 0 : rc;
+-}
+
+-/*
+- * Check the matching between a pattern and a module name.
+- * We need this as *_* is equivalent to *-*, even in pattern matching.
+- */
+-static int check_pattern(const char* pat_src, const char* mod_src)
+-{
+- int ret;
+-
+- if (ENABLE_FEATURE_MODPROBE_FANCY_ALIAS) {
+- char* pat;
+- char* mod;
+- char* p;
+-
+- pat = xstrdup(pat_src);
+- mod = xstrdup(mod_src);
+-
+- for (p = pat; (p = strchr(p, '-')); *p++ = '_');
+- for (p = mod; (p = strchr(p, '-')); *p++ = '_');
+-
+- ret = fnmatch(pat, mod, 0);
+-
+- if (ENABLE_FEATURE_CLEAN_UP) {
+- free(pat);
+- free(mod);
+- }
+-
+- return ret;
++ /* cache modules */
++ parser = config_open2("/proc/modules", fopen_for_read);
++ if (parser) {
++ char *s;
++ while (config_read(parser, &s, 1, 1, "# \t", PARSE_NORMAL & ~PARSE_GREEDY))
++ llist_add_to(&loaded, xstrdup(s));
++ config_close(parser);
+ }
+- return fnmatch(pat_src, mod_src, 0);
+-}
+
+-/*
+- * Builds the dependency list (aka stack) of a module.
+- * head: the highest module in the stack (last to insmod, first to rmmod)
+- * tail: the lowest module in the stack (first to insmod, last to rmmod)
+- */
+-static void check_dep(char *mod, struct mod_list_t **head, struct mod_list_t **tail)
+-{
+- struct mod_list_t *find;
+- struct dep_t *dt;
+- struct mod_opt_t *opt = NULL;
+- char *path = NULL;
++ for (i = 0; i < num_modules; i++) {
++ struct modprobe_conf *conf;
+
+- /* Search for the given module name amongst all dependency rules.
+- * The module name in a dependency rule can be a shell pattern,
+- * so try to match the given module name against such a pattern.
+- * Of course if the name in the dependency rule is a plain string,
+- * then we consider it a pattern, and matching will still work. */
+- for (dt = depend; dt; dt = dt->m_next) {
+- if (check_pattern(dt->m_name, mod) == 0) {
+- break;
+- }
+- }
++ conf = xzalloc(sizeof(struct modprobe_conf));
++ conf->options = options;
++ filename2modname(argv[i], conf->probename);
++ read_config(conf, "/etc/modprobe.conf");
++ read_config(conf, "/etc/modprobe.d");
++ if (ENABLE_FEATURE_MODUTILS_SYMBOLS &&
++ conf->aliases == NULL && strncmp(argv[i], "symbol:", 7) == 0)
++ read_config(conf, "modules.symbols");
+
+- if (!dt) {
+- bb_error_msg("module %s not found", mod);
+- return;
+- }
++ if (ENABLE_FEATURE_MODUTILS_ALIAS && conf->aliases == NULL)
++ read_config(conf, "modules.alias");
+
+- // resolve alias names
+- while (dt->m_isalias) {
+- if (dt->m_depcnt == 1) {
+- struct dep_t *adt;
+-
+- for (adt = depend; adt; adt = adt->m_next) {
+- if (check_pattern(adt->m_name, dt->m_deparr[0]) == 0 &&
+- !(ENABLE_FEATURE_MODPROBE_BLACKLIST &&
+- adt->m_isblacklisted))
+- break;
++ if (conf->aliases == NULL) {
++ /* Try if module by literal name is found; literal
++ * names are blacklist only if '-b' is given. */
++ if (!(option_mask32 & MODPROBE_OPT_BLACKLIST) ||
++ check_blacklist(conf, conf->probename)) {
++ rc = do_modprobe(conf, conf->probename);
++ if (rc < 0 && !(option_mask32 & INSMOD_OPT_SILENT))
++ bb_error_msg("Module %s not found.", argv[i]);
+ }
+- if (adt) {
+- /* This is the module we are aliased to */
+- struct mod_opt_t *opts = dt->m_options;
+- /* Option of the alias are appended to the options of the module */
+- while (opts) {
+- adt->m_options = append_option(adt->m_options, opts->m_opt_val);
+- opts = opts->m_next;
+- }
+- dt = adt;
+- } else {
+- bb_error_msg("module %s not found", mod);
+- return;
+- }
+ } else {
+- bb_error_msg("bad alias %s", dt->m_name);
+- return;
++ /* Probe all aliases */
++ while (conf->aliases != NULL) {
++ char *realname = llist_pop(&conf->aliases);
++ if (check_blacklist(conf, realname))
++ do_modprobe(conf, realname);
++ if (ENABLE_FEATURE_CLEAN_UP)
++ free(realname);
++ }
+ }
+ }
+
+- mod = dt->m_name;
+- path = dt->m_path;
+- opt = dt->m_options;
+-
+- // search for duplicates
+- for (find = *head; find; find = find->m_next) {
+- if (strcmp(mod, find->m_name) == 0) {
+- // found -> dequeue it
+-
+- if (find->m_prev)
+- find->m_prev->m_next = find->m_next;
+- else
+- *head = find->m_next;
+-
+- if (find->m_next)
+- find->m_next->m_prev = find->m_prev;
+- else
+- *tail = find->m_prev;
+-
+- break; // there can be only one duplicate
+- }
+- }
+-
+- if (!find) { // did not find a duplicate
+- find = xzalloc(sizeof(struct mod_list_t));
+- find->m_name = mod;
+- find->m_path = path;
+- find->m_options = opt;
+- }
+-
+- // enqueue at tail
+- if (*tail)
+- (*tail)->m_next = find;
+- find->m_prev = *tail;
+- find->m_next = NULL; /* possibly NOT done by xzalloc! */
+-
+- if (!*head)
+- *head = find;
+- *tail = find;
+-
+- if (dt) {
+- int i;
+-
+- /* Add all dependable module for that new module */
+- for (i = 0; i < dt->m_depcnt; i++)
+- check_dep(dt->m_deparr[i], head, tail);
+- }
++ return EXIT_SUCCESS;
+ }
+-
+-static int mod_insert(char **argv)
+-{
+- struct mod_list_t *tail = NULL;
+- struct mod_list_t *head = NULL;
+- char *modname = *argv++;
+- int rc;
+-
+- // get dep list for module mod
+- check_dep(modname, &head, &tail);
+-
+- rc = 1;
+- if (head && tail) {
+- while (*argv)
+- head->m_options = append_option(head->m_options, *argv++);
+-
+- // process tail ---> head
+- rc = mod_process(tail, 1);
+- if (rc) {
+- /*
+- * In case of using udev, multiple instances of modprobe can be
+- * spawned to load the same module (think of two same usb devices,
+- * for example; or cold-plugging at boot time). Thus we shouldn't
+- * fail if the module was loaded, and not by us.
+- */
+- if (already_loaded(modname))
+- rc = 0;
+- }
+- }
+- return rc;
+-}
+-
+-static int mod_remove(char *modname)
+-{
+- static const struct mod_list_t rm_a_dummy = { "-a", NULL, NULL, NULL, NULL };
+-
+- int rc;
+- struct mod_list_t *head = NULL;
+- struct mod_list_t *tail = NULL;
+-
+- if (modname)
+- check_dep(modname, &head, &tail);
+- else // autoclean
+- head = tail = (struct mod_list_t*) &rm_a_dummy;
+-
+- rc = 1;
+- if (head && tail)
+- rc = mod_process(head, 0); // process head ---> tail
+- return rc;
+-}
+-
+-int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+-int modprobe_main(int argc UNUSED_PARAM, char **argv)
+-{
+- int rc = EXIT_SUCCESS;
+- unsigned opt;
+- char *unused;
+-
+- opt_complementary = "q-v:v-q";
+- opt = getopt32(argv, MAIN_OPT_STR, &unused, &unused);
+- argv += optind;
+-
+- if (opt & (DUMP_CONF_EXIT | LIST_ALL))
+- return EXIT_SUCCESS;
+- if (opt & (RESTRICT_DIR | CONFIG_FILE))
+- bb_error_msg_and_die("-t and -C not supported");
+-
+- depend = build_dep();
+-
+- if (!depend)
+- bb_error_msg_and_die("cannot parse "CONFIG_DEFAULT_DEPMOD_FILE);
+-
+- if (remove_opt) {
+- do {
+- /* (*argv) can be NULL here */
+- if (mod_remove(*argv)) {
+- bb_perror_msg("failed to %s module %s", "remove",
+- *argv);
+- rc = EXIT_FAILURE;
+- }
+- } while (*argv && *++argv);
+- } else {
+- if (!*argv)
+- bb_error_msg_and_die("no module or pattern provided");
+-
+- if (mod_insert(argv))
+- bb_perror_msg_and_die("failed to %s module %s", "load", *argv);
+- }
+-
+- /* Here would be a good place to free up memory allocated during the dependencies build. */
+-
+- return rc;
+-}
+Index: modutils/depmod.c
+===================================================================
+--- modutils/depmod.c (revision 23360)
++++ modutils/depmod.c (working copy)
+@@ -2,6 +2,8 @@
+ /*
+ * depmod - generate modules.dep
+ * Copyright (c) 2008 Bernhard Fischer
++ * Copyrihgt (c) 2008 Timo Teras <timo.teras@iki.fi>
++ * Copyright (c) 2008 Vladimir Dronnikov
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+@@ -10,6 +12,8 @@
+ #define _GNU_SOURCE
+ #include <libbb.h>
+ #include <sys/utsname.h> /* uname() */
++#include "modutils.h"
++
+ /*
+ * Theory of operation:
+ * - iterate over all modules and record their full path
+@@ -17,272 +21,194 @@
+ * for each depends, look through our list of full paths and emit if found
+ */
+
+-typedef struct dep_lst_t {
+- char *name;
++typedef struct module_info {
++ struct module_info *next;
++ char *name, *modname;
+ llist_t *dependencies;
+ llist_t *aliases;
+- struct dep_lst_t *next;
+-} dep_lst_t;
++ llist_t *symbols;
++ struct module_info *dnext, *dprev;
++} module_info;
+
+-struct globals {
+- dep_lst_t *lst; /* modules without their corresponding extension */
++enum {
++ ARG_a = (1<<0), /* All modules, ignore mods in argv */
++ ARG_A = (1<<1), /* Only emit .ko that are newer than modules.dep file */
++ ARG_b = (1<<2), /* not /lib/modules/$(uname -r)/ but this base-dir */
++ ARG_e = (1<<3), /* with -F, print unresolved symbols */
++ ARG_F = (1<<4), /* System.map that contains the symbols */
++ ARG_n = (1<<5) /* dry-run, print to stdout only */
+ };
+-#define G (*(struct globals*)&bb_common_bufsiz1)
+-/* We have to zero it out because of NOEXEC */
+-#define INIT_G() memset(&G, 0, sizeof(G))
+
+-static char* find_keyword(void *the_module, size_t len, const char * const word)
++static int FAST_FUNC parse_module(const char *fname, struct stat *sb,
++ void *data, int UNUSED_PARAM depth)
+ {
+- char *ptr = the_module;
+- do {
+- /* search for the first char in word */
+- ptr = memchr(ptr, *word, len - (ptr - (char*)the_module));
+- if (ptr == NULL) /* no occurance left, done */
+- return NULL;
+- if (!strncmp(ptr, word, strlen(word))) {
+- ptr += strlen(word);
+- break;
++ module_info **first = (module_info **) data;
++ char *image, *ptr;
++ module_info *info;
++ size_t len = sb->st_size;
++
++ if (strrstr(fname, ".ko") == NULL)
++ return TRUE;
++
++ image = (char *) xmalloc_open_zipped_read_close(fname, &len);
++ info = xzalloc(sizeof(module_info));
++
++ info->next = *first;
++ *first = info;
++
++ info->dnext = info->dprev = info;
++ info->name = xstrdup(fname);
++ info->modname = filename2modname(fname, NULL);
++ for (ptr = image; ptr < image + len - 10; ptr++) {
++ if (strncmp(ptr, "depends=", 8) == 0) {
++ char *u;
++
++ ptr += 8;
++ for (u = ptr; *u; u++)
++ if (*u == '-')
++ *u = '_';
++ ptr += string_to_llist(ptr, &info->dependencies, ",");
++ } else if (ENABLE_FEATURE_MODUTILS_ALIAS &&
++ strncmp(ptr, "alias=", 6) == 0) {
++ llist_add_to(&info->aliases, xstrdup(ptr + 6));
++ ptr += strlen(ptr);
++ } else if (ENABLE_FEATURE_MODUTILS_SYMBOLS &&
++ strncmp(ptr, "__ksymtab_", 10) == 0) {
++ ptr += 10;
++ if (strncmp(ptr, "gpl", 3) == 0 ||
++ strcmp(ptr, "strings") == 0)
++ continue;
++ llist_add_to(&info->symbols, xstrdup(ptr));
++ ptr += strlen(ptr);
+ }
+- ++ptr;
+- } while (1);
+- return ptr;
++ }
++ free(image);
++
++ return TRUE;
+ }
+-static int FAST_FUNC fileAction(const char *fname, struct stat *sb,
+- void UNUSED_PARAM *data, int UNUSED_PARAM depth)
++
++static module_info *find_module(module_info *modules, const char *modname)
+ {
+- size_t len = sb->st_size;
+- void *the_module;
+- char *ptr;
+- int fd;
+- char *depends, *deps;
+- dep_lst_t *this;
++ module_info *m;
+
+- if (strrstr(fname, ".ko") == NULL) /* not a module */
+- goto skip;
++ for (m = modules; m != NULL; m = m->next)
++ if (strcmp(m->modname, modname) == 0)
++ return m;
++ return NULL;
++}
+
+-/*XXX: FIXME: does not handle compressed modules!
+- * There should be a function that looks at the extension and sets up
+- * open_transformer for us.
+- */
+- fd = xopen(fname, O_RDONLY);
+- the_module = mmap(NULL, len, PROT_READ, MAP_SHARED
+-#if defined MAP_POPULATE
+- |MAP_POPULATE
+-#endif
+- , fd, 0);
+- close(fd);
+- if (the_module == MAP_FAILED)
+- bb_perror_msg_and_die("mmap");
++static void order_dep_list(module_info *modules, module_info *start,
++ llist_t *add)
++{
++ module_info *m;
++ llist_t *n;
+
+- this = xzalloc(sizeof(dep_lst_t));
+- this->name = xstrdup(fname);
+- this->next = G.lst;
+- G.lst = this;
+-//bb_info_msg("fname='%s'", fname);
+- ptr = find_keyword(the_module, len, "depends=");
+- if (!*ptr)
+- goto d_none;
+- deps = depends = xstrdup(ptr);
+-//bb_info_msg(" depends='%s'", depends);
+- while (deps) {
+- ptr = strsep(&deps, ",");
+-//bb_info_msg("[%s] -> '%s'", fname, (char*)ptr);
+- llist_add_to_end(&this->dependencies, xstrdup(ptr));
++ for (n = add; n != NULL; n = n->link) {
++ m = find_module(modules, n->data);
++ if (m == NULL)
++ continue;
++
++ /* unlink current entry */
++ m->dnext->dprev = m->dprev;
++ m->dprev->dnext = m->dnext;
++
++ /* and add it to tail */
++ m->dnext = start;
++ m->dprev = start->dprev;
++ start->dprev->dnext = m;
++ start->dprev = m;
++
++ /* recurse */
++ order_dep_list(modules, start, m->dependencies);
+ }
+- free(depends);
+- d_none:
+- if (ENABLE_FEATURE_DEPMOD_ALIAS)
+- {
+- size_t pos = 0;
+- do {
+- ptr = find_keyword(the_module + pos, len - pos, "alias=");
+- if (ptr) {
+-//bb_info_msg("[%s] alias '%s'", fname, (char*)ptr);
+- llist_add_to_end(&this->aliases, xstrdup(ptr));
+- } else
+- break;
+- pos = (ptr - (char*)the_module);
+- } while (1);
+- }
+- munmap(the_module, sb->st_size);
+- skip:
+- return TRUE;
+ }
+
+ int depmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+ int depmod_main(int argc UNUSED_PARAM, char **argv)
+ {
+- int ret;
+- size_t moddir_base_len = 0; /* length of the "-b basedir" */
+- char *moddir_base = NULL, *moddir, *system_map, *chp;
+- FILE *filedes = stdout;
+- enum {
+- ARG_a = (1<<0), /* All modules, ignore mods in argv */
+- ARG_A = (1<<1), /* Only emit .ko that are newer than modules.dep file */
+- ARG_b = (1<<2), /* not /lib/modules/$(uname -r)/ but this base-dir */
+- ARG_e = (1<<3), /* with -F, print unresolved symbols */
+- ARG_F = (1<<4), /* System.map that contains the symbols */
+- ARG_n = (1<<5) /* dry-run, print to stdout only */
+- };
+- INIT_G();
++ module_info *modules = NULL, *m, *dep;
++ char *moddir_base = (char *)CONFIG_DEFAULT_MODULES_DIR;
++ int tmp;
+
+- getopt32(argv, "aAb:eF:n", &moddir_base, &system_map);
++ getopt32(argv, "aAb:eF:n", &moddir_base, NULL);
+ argv += optind;
+
+- /* If a version is provided, then that kernel version’s module directory
++ /* goto modules location */
++
++ /* If a version is provided, then that kernel version's module directory
+ * is used, rather than the current kernel version (as returned by
+ * "uname -r"). */
+- if (*argv && (sscanf(*argv, "%d.%d.%d", &ret, &ret, &ret) == 3)) {
+- moddir = concat_path_file(CONFIG_DEFAULT_MODULES_DIR, *argv++);
++ xchdir(moddir_base);
++ if (*argv && (sscanf(*argv, "%d.%d.%d", &tmp, &tmp, &tmp) == 3)) {
++ chdir(*argv++);
+ } else {
+ struct utsname uts;
+- if (uname(&uts) < 0)
+- bb_simple_perror_msg_and_die("uname");
+- moddir = concat_path_file(CONFIG_DEFAULT_MODULES_DIR, uts.release);
++ uname(&uts);
++ chdir(uts.release);
+ }
+ /* If no modules are given on the command-line, -a is on per default. */
+ option_mask32 |= *argv == NULL;
+
+- if (option_mask32 & ARG_b) {
+- moddir_base_len = strlen(moddir_base) + 1;
+- xchdir(moddir_base);
+- }
+-
+- if (!(option_mask32 & ARG_n)) { /* --dry-run */
+- chp = concat_path_file(moddir, CONFIG_DEFAULT_DEPMOD_FILE);
+- filedes = xfopen_for_write(chp);
+- if (ENABLE_FEATURE_CLEAN_UP)
+- free(chp);
+- }
+- ret = EXIT_SUCCESS;
++ /* Scan modules */
++ moddir_base = xrealloc_getcwd_or_warn(NULL);
+ do {
+- chp = option_mask32 & ARG_a ? moddir : (*argv + moddir_base_len);
++ recursive_action((option_mask32 & ARG_a) ? moddir_base : *argv,
++ ACTION_RECURSE, parse_module, NULL, &modules, 0);
++ } while (!(option_mask32 & ARG_a) && *(++argv));
++ if (ENABLE_FEATURE_CLEAN_UP)
++ free(moddir_base);
+
+- if (!recursive_action(chp,
+- ACTION_RECURSE, /* flags */
+- fileAction, /* file action */
+- NULL, /* dir action */
+- NULL, /* user data */
+- 0)) { /* depth */
+- ret = EXIT_FAILURE;
+- }
+- } while (!(option_mask32 & ARG_a) && *++argv);
++ /* Generate dependency and alias files */
++ if (!(option_mask32 & ARG_n))
++ freopen(CONFIG_DEFAULT_DEPMOD_FILE, "w", stdout);
++ for (m = modules; m != NULL; m = m->next) {
++ printf("%s:", m->name);
+
+- {
+- dep_lst_t *mods = G.lst;
++ order_dep_list(modules, m, m->dependencies);
++ while (m->dnext != m) {
++ dep = m->dnext;
++ printf(" %s", dep->name);
+
+- /* Fixup the module names in the depends list */
+- while (mods) {
+- llist_t *deps = NULL, *old_deps = mods->dependencies;
+-
+- while (old_deps) {
+- dep_lst_t *all = G.lst;
+- char *longname = NULL;
+- char *shortname = llist_pop(&old_deps);
+-
+- while (all) {
+- char *nam =
+- xstrdup(bb_get_last_path_component_nostrip(all->name));
+- char *tmp = strrstr(nam, ".ko");
+-
+- *tmp = '\0';
+- if (!strcmp(nam, shortname)) {
+- if (ENABLE_FEATURE_CLEAN_UP)
+- free(nam);
+- longname = all->name;
+- break;
+- }
+- free(nam);
+- all = all->next;
+- }
+- llist_add_to_end(&deps, longname);
++ /* unlink current entry */
++ dep->dnext->dprev = dep->dprev;
++ dep->dprev->dnext = dep->dnext;
++ dep->dnext = dep->dprev = dep;
+ }
+- mods->dependencies = deps;
+- mods = mods->next;
++ puts("");
+ }
+
+-#if ENABLE_FEATURE_DEPMOD_PRUNE_FANCY
+- /* modprobe allegedly wants dependencies without duplicates, i.e.
+- * mod1: mod2 mod3
+- * mod2: mod3
+- * mod3:
+- * implies that mod1 directly depends on mod2 and _not_ mod3 as mod3 is
+- * already implicitely pulled in via mod2. This leaves us with:
+- * mod1: mod2
+- * mod2: mod3
+- * mod3:
+- */
+- mods = G.lst;
+- while (mods) {
+- llist_t *deps = mods->dependencies;
+- while (deps) {
+- dep_lst_t *all = G.lst;
+- while (all) {
+- if (!strcmp(all->name, deps->data)) {
+- llist_t *implied = all->dependencies;
+- while (implied) {
+- /* XXX:FIXME: erm, it would be nicer to just
+- * llist_unlink(&mods->dependencies, implied) */
+- llist_t *prune = mods->dependencies;
+- while (prune) {
+- if (!strcmp(implied->data, prune->data))
+- break;
+- prune = prune->link;
+- }
+-//if (prune) bb_info_msg("[%s] '%s' implies '%s', removing", mods->name, all->name, implied->data);
+- llist_unlink(&mods->dependencies, prune);
+- implied = implied->link;
+- }
+- }
+- all = all->next;
+- }
+- deps = deps->link;
++#if ENABLE_FEATURE_MODUTILS_ALIAS
++ if (!(option_mask32 & ARG_n))
++ freopen("modules.alias", "w", stdout);
++ for (m = modules; m != NULL; m = m->next) {
++ while (m->aliases) {
++ printf("alias %s %s\n",
++ (char*)llist_pop(&m->aliases),
++ m->modname);
+ }
+- mods = mods->next;
+ }
+ #endif
+-
+- mods = G.lst;
+- /* Finally print them. */
+- while (mods) {
+- fprintf(filedes, "%s:", mods->name);
+- /* If we did not resolve all modules, then it's likely that we just did
+- * not see the names of all prerequisites (which will be NULL in this
+- * case). */
+- while (mods->dependencies) {
+- char *the_dep = llist_pop(&mods->dependencies);
+- if (the_dep)
+- fprintf(filedes, " %s", the_dep);
++#if ENABLE_FEATURE_MODUTILS_SYMBOLS
++ if (!(option_mask32 & ARG_n))
++ freopen("modules.symbols", "w", stdout);
++ for (m = modules; m != NULL; m = m->next) {
++ while (m->symbols) {
++ printf("alias symbol:%s %s\n",
++ (char*)llist_pop(&m->symbols),
++ m->modname);
+ }
+- fprintf(filedes, "\n");
+- if (ENABLE_FEATURE_DEPMOD_ALIAS)
+- {
+- char *shortname =
+- xstrdup(bb_get_last_path_component_nostrip(mods->name));
+- char *tmp = strrstr(shortname, ".ko");
+-
+- *tmp = '\0';
+-
+- while (mods->aliases) {
+- fprintf(filedes, "alias %s %s\n",
+- (char*)llist_pop(&mods->aliases),
+- shortname);
+- }
+- free(shortname);
+- }
+- mods = mods->next;
+ }
+- }
++#endif
+
+ if (ENABLE_FEATURE_CLEAN_UP) {
+- fclose_if_not_stdin(filedes);
+- free(moddir);
+- while (G.lst) {
+- dep_lst_t *old = G.lst;
+- G.lst = G.lst->next;
++ while (modules) {
++ module_info *old = modules;
++ modules = modules->next;
+ free(old->name);
++ free(old->modname);
+ free(old);
+ }
+ }
+- return ret;
++
++ return EXIT_SUCCESS;
+ }
+Index: modutils/Config.in
+===================================================================
+--- modutils/Config.in (revision 23360)
++++ modutils/Config.in (working copy)
+@@ -5,43 +5,35 @@
+
+ menu "Linux Module Utilities"
+
+-config MODPROBE_SMALL
+- bool "Simplified modutils"
+- default n
++choice
++ prompt "Module Utilities Flavor"
++ default MODUTILS_STANDARD
++
++config MODUTILS_STANDARD
++ bool "standard"
+ help
+- Simplified modutils.
++ module-init-tools compliant version of module utilities.
++ Select this if unsure.
+
+- With this option modprobe does not require modules.dep file
+- and does not use /etc/modules.conf file.
+- It scans module files in /lib/modules/`uname -r` and
+- determines dependencies and module alias names on the fly.
+- This may make module loading slower, most notably
+- when one needs to load module by alias (this requires
+- scanning through module _bodies_).
++config MODUTILS_FAST
++ bool "fast and small"
++ help
++ Alternate module utilities implementation that uses a custom
++ modules.dep.bb file for the module dependency and alias information.
++ The module blacklist and argument information is parsed and stored
++ to this file. In practice you get a lot faster modprobe, but you
++ need to regenerate the dependency information if configuration
++ is changed.
+
+- At the first attempt to load a module by alias modprobe
+- will try to generate modules.dep.bb file in order to speed up
+- future loads by alias. Failure to do so (read-only /lib/modules,
+- etc) is not reported, and future modprobes will be slow too.
++ This option produces faster and slightly smaller module utilities.
++ Select standard variant if unsure.
+
+- NB: modules.dep.bb file format is not compatible
+- with modules.dep file as created/used by standard module tools.
++endchoice
+
+- Additional module parameters can be stored in
+- /etc/modules/$module_name files.
+-
+- Apart from modprobe, other utilities are also provided:
+- - insmod is an alias to modprobe
+- - rmmod is an alias to modprobe -r
+- - depmod generates modules.dep.bb
+-
+- As of 2008-07, this code is experimental. It is 14kb smaller
+- than "non-small" modutils.
+-
+ config FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE
+ bool "Accept module options on modprobe command line"
+ default n
+- depends on MODPROBE_SMALL
++ depends on MODUTILS_FAST
+ help
+ Allow insmod and modprobe take module options from command line.
+ N.B. Very bloaty.
+@@ -49,53 +41,88 @@
+ config FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED
+ bool "Skip loading of already loaded modules"
+ default n
+- depends on MODPROBE_SMALL
++ depends on MODUTILS_FAST
+ help
+ Check if the module is already loaded.
+ N.B. It's racy.
+
+-config DEPMOD
+- bool "depmod"
++config INSMOD
++ bool "insmod"
+ default n
+- depends on !MODPROBE_SMALL
++ depends on MODUTILS_STANDARD
+ help
+- depmod generates modules.dep (FIXME: elaborate)
++ insmod is used to load specified modules in the running kernel.
+
+-config FEATURE_DEPMOD_PRUNE_FANCY
+- bool "Fancy dependency pruning"
++config RMMOD
++ bool "rmmod"
+ default n
+- depends on DEPMOD
++ depends on MODUTILS_STANDARD
+ help
+- By default modules.dep contains all dependencies as listed by
+- the modules.
+- If you enable this option then we remove implied modules from
+- the dependencies.
+- This makes depmod somewhat bigger but generates a smaller
+- modules.dep file.
++ rmmod is used to unload specified modules from the kernel.
+
+- If unsure, say N.
++config LSMOD
++ bool "lsmod"
++ default n
++ depends on MODUTILS_STANDARD
++ help
++ lsmod is used to display a list of loaded modules.
+
+-config FEATURE_DEPMOD_ALIAS
+- bool "Alias support"
++config FEATURE_LSMOD_PRETTY_2_6_OUTPUT
++ bool "Pretty output"
+ default n
+- depends on DEPMOD
++ depends on MODUTILS_STANDARD && LSMOD
+ help
+- By default modules.dep does not contain alias information.
+- Enable this to emit aliases of the form:
++ This option makes output format of lsmod adjusted to
++ the format of module-init-tools for Linux kernel 2.6.
++ Increases size somewhat.
+
+- alias pcmcia:m*c*f03fn*pfn*pa*pb*pc*pd* parport_cs
++config MODPROBE
++ bool "modprobe"
++ default n
++ depends on MODUTILS_STANDARD
++ help
++ Handle the loading of modules, and their dependencies on a high
++ level.
+
+-config INSMOD
+- bool "insmod"
++ Note that in the state, modprobe does not understand multiple
++ module options from the configuration file. See option below.
++
++config FEATURE_MODPROBE_BLACKLIST
++ bool
++ prompt "Blacklist support"
+ default n
+- depends on !MODPROBE_SMALL
++ depends on MODUTILS_STANDARD && MODPROBE
+ help
+- insmod is used to load specified modules in the running kernel.
++ Say 'y' here to enable support for the 'blacklist' command in
++ modprobe.conf. This prevents the alias resolver to resolve
++ blacklisted modules. This is useful if you want to prevent your
++ hardware autodetection scripts to load modules like evdev, frame
++ buffer drivers etc.
+
++config DEPMOD
++ bool "depmod"
++ default n
++ depends on MODUTILS_STANDARD
++ help
++ depmod generates modules.dep (and potentially modules.alias
++ and modules.symbols) that contain dependency information
++ for modprobe.
++
++comment "Options common to multiple modutils"
++
++config FEATURE_2_4_MODULES
++ bool "Support version 2.2/2.4 Linux kernels"
++ default n
++ depends on MODUTILS_FAST || INSMOD || RMMOD || LSMOD
++ help
++ Support module loading for 2.2.x and 2.4.x Linux kernels.
++ This increases size considerably. Say N unless you plan
++ to run ancient kernels.
++
+ config FEATURE_INSMOD_VERSION_CHECKING
+- bool "Module version checking"
++ bool "Enable module version checking"
+ default n
+- depends on INSMOD && FEATURE_2_4_MODULES
++ depends on FEATURE_2_4_MODULES && (INSMOD || MODPROBE)
+ help
+ Support checking of versions for modules. This is used to
+ ensure that the kernel and module are made for each other.
+@@ -103,7 +130,7 @@
+ config FEATURE_INSMOD_KSYMOOPS_SYMBOLS
+ bool "Add module symbols to kernel symbol table"
+ default n
+- depends on INSMOD && FEATURE_2_4_MODULES
++ depends on FEATURE_2_4_MODULES && (INSMOD || MODPROBE)
+ help
+ By adding module symbols to the kernel symbol table, Oops messages
+ occuring within kernel modules can be properly debugged. By enabling
+@@ -114,7 +141,7 @@
+ config FEATURE_INSMOD_LOADINKMEM
+ bool "In kernel memory optimization (uClinux only)"
+ default n
+- depends on INSMOD && FEATURE_2_4_MODULES
++ depends on FEATURE_2_4_MODULES && (INSMOD || MODPROBE)
+ help
+ This is a special uClinux only memory optimization that lets insmod
+ load the specified kernel module directly into kernel space, reducing
+@@ -122,9 +149,9 @@
+ being loaded into memory.
+
+ config FEATURE_INSMOD_LOAD_MAP
+- bool "Enable load map (-m) option"
++ bool "Enable insmod load map (-m) option"
+ default n
+- depends on INSMOD && ( FEATURE_2_4_MODULES || FEATURE_2_6_MODULES )
++ depends on FEATURE_2_4_MODULES && INSMOD
+ help
+ Enabling this, one would be able to get a load map
+ output on stdout. This makes kernel module debugging
+@@ -141,132 +168,54 @@
+ load map. With this option, -m will also output
+ symbols load map.
+
+-config RMMOD
+- bool "rmmod"
+- default n
+- depends on !MODPROBE_SMALL
+- help
+- rmmod is used to unload specified modules from the kernel.
+-
+-config LSMOD
+- bool "lsmod"
+- default n
+- depends on !MODPROBE_SMALL
+- help
+- lsmod is used to display a list of loaded modules.
+-
+-config FEATURE_LSMOD_PRETTY_2_6_OUTPUT
+- bool "Pretty output for 2.6.x Linux kernels"
+- default n
+- depends on LSMOD
+- help
+- This option makes output format of lsmod adjusted to
+- the format of module-init-tools for Linux kernel 2.6.
+-
+-config MODPROBE
+- bool "modprobe"
+- default n
+- depends on !MODPROBE_SMALL
+- help
+- Handle the loading of modules, and their dependencies on a high
+- level.
+-
+- Note that in the state, modprobe does not understand multiple
+- module options from the configuration file. See option below.
+-
+-config FEATURE_MODPROBE_MULTIPLE_OPTIONS
+- bool
+- prompt "Multiple options parsing"
+- default y
+- depends on MODPROBE
+- help
+- Allow modprobe to understand more than one option to pass to
+- modules.
+-
+- This is a WIP, while waiting for a common argument parsing
+- common amongst all BB applets (shell, modprobe, etc...) and
+- adds around 600 bytes on x86, 700 bytes on ARM. The code is
+- biggish and uggly, but just works.
+-
+- Saying Y here is not a bad idea if you're not that short
+- on storage capacity.
+-
+-config FEATURE_MODPROBE_FANCY_ALIAS
+- bool
+- prompt "Fancy alias parsing"
+- default y
+- depends on MODPROBE && FEATURE_2_6_MODULES
+- help
+- Say 'y' here to enable parsing of aliases with underscore/dash
+- mismatch between module name and file name, along with bus-specific
+- aliases (such as pci:... or usb:... aliases).
+-
+-config FEATURE_MODPROBE_BLACKLIST
+- bool
+- prompt "Blacklist support"
+- default n
+- depends on MODPROBE && FEATURE_2_6_MODULES
+- help
+- Say 'y' here to enable support for the 'blacklist' command in
+- modprobe.conf. This prevents the alias resolver to resolve
+- blacklisted modules. This is useful if you want to prevent your
+- hardware autodetection scripts to load modules like evdev, frame
+- buffer drivers etc.
+-
+-comment "Options common to multiple modutils"
+- depends on INSMOD || RMMOD || MODPROBE || LSMOD || DEPMOD
+-
+ config FEATURE_CHECK_TAINTED_MODULE
+- # Simulate indentation
+ bool "Support tainted module checking with new kernels"
+ default y
+- depends on INSMOD || LSMOD
+ help
+ Support checking for tainted modules. These are usually binary
+ only modules that will make the linux-kernel list ignore your
+ support request.
+ This option is required to support GPLONLY modules.
+
+-config FEATURE_2_4_MODULES
+- # Simulate indentation
+- bool "Support version 2.2.x to 2.4.x Linux kernels"
++config FEATURE_MODUTILS_ALIAS
++ bool "Support for module.aliases file"
+ default y
+- depends on INSMOD || RMMOD || MODPROBE
++ depends on MODUTILS_STANDARD && (DEPMOD || MODPROBE)
+ help
+- Support module loading for 2.2.x and 2.4.x Linux kernels.
++ Generate and parse modules.alias containing aliases for bus
++ identifiers:
++ alias pcmcia:m*c*f03fn*pfn*pa*pb*pc*pd* parport_cs
+
+- Note:
+- This is automatically enabled if 2.6 modules are not enabled.
++ and aliases for logical modules names e.g.:
++ alias padlock_aes aes
++ alias aes_i586 aes
++ alias aes_generic aes
+
+-config FEATURE_2_6_MODULES
+- # Simulate indentation
+- bool "Support version 2.6.x Linux kernels"
++ Say Y if unsure.
++
++config FEATURE_MODUTILS_SYMBOLS
++ bool "Support for module.symbols file"
+ default y
+- depends on INSMOD || RMMOD || MODPROBE
++ depends on MODUTILS_STANDARD && (DEPMOD || MODPROBE)
+ help
+- Support module loading for newer 2.6.x Linux kernels.
++ Generate and parse modules.symbols containing aliases for
++ symbol_request() kernel calls, such as:
++ alias symbol:usb_sg_init usbcore
+
++ Say Y if unsure.
++
+ config DEFAULT_MODULES_DIR
+- # Simulate indentation
+ string "Default directory containing modules"
+ default "/lib/modules"
+- depends on INSMOD || RMMOD || MODPROBE || MODPROBE_SMALL || DEPMOD
+ help
+ Directory that contains kernel modules.
+ Defaults to "/lib/modules"
+
+ config DEFAULT_DEPMOD_FILE
+- # Simulate indentation
+ string "Default name of modules.dep"
+ default "modules.dep"
+- depends on INSMOD || RMMOD || MODPROBE || MODPROBE_SMALL || DEPMOD
+ help
+ Filename that contains kernel modules dependencies.
+ Defaults to "modules.dep"
+
+-config FEATURE_QUERY_MODULE_INTERFACE
+- bool
+- default y
+- depends on FEATURE_2_4_MODULES && !FEATURE_2_6_MODULES
+-
+ endmenu
+Index: modutils/Kbuild
+===================================================================
+--- modutils/Kbuild (revision 23360)
++++ modutils/Kbuild (working copy)
+@@ -5,9 +5,10 @@
+ # Licensed under the GPL v2, see the file LICENSE in this tarball.
+
+ lib-y:=
+-lib-$(CONFIG_DEPMOD) += depmod.o
+-lib-$(CONFIG_INSMOD) += insmod.o
+-lib-$(CONFIG_LSMOD) += lsmod.o
+-lib-$(CONFIG_MODPROBE) += modprobe.o
+-lib-$(CONFIG_MODPROBE_SMALL) += modprobe-small.o
+-lib-$(CONFIG_RMMOD) += rmmod.o
++lib-$(CONFIG_DEPMOD) += depmod.o modutils.o
++lib-$(CONFIG_INSMOD) += insmod.o modutils.o
++lib-$(CONFIG_LSMOD) += lsmod.o modutils.o
++lib-$(CONFIG_MODPROBE) += modprobe.o modutils.o
++lib-$(CONFIG_RMMOD) += rmmod.o modutils.o
++lib-$(CONFIG_MODUTILS_SMALL) += modprobe-small.o modutils.o
++lib-$(CONFIG_FEATURE_2_4_MODULES) += modutils-24.o
+Index: modutils/insmod.c
+===================================================================
+--- modutils/insmod.c (revision 23360)
++++ modutils/insmod.c (working copy)
+@@ -2,4286 +2,31 @@
+ /*
+ * Mini insmod implementation for busybox
+ *
+- * This version of insmod supports ARM, CRIS, H8/300, x86, ia64, x86_64,
+- * m68k, MIPS, PowerPC, S390, SH3/4/5, Sparc, v850e, and x86_64.
++ * Copyright (C) 2008 Timo Teras <timo.teras@iki.fi>
+ *
+- * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+- * and Ron Alder <alder@lineo.com>
+- *
+- * Rodney Radford <rradford@mindspring.com> 17-Aug-2004.
+- * Added x86_64 support.
+- *
+- * Miles Bader <miles@gnu.org> added NEC V850E support.
+- *
+- * Modified by Bryan Rittmeyer <bryan@ixiacom.com> to support SH4
+- * and (theoretically) SH3. I have only tested SH4 in little endian mode.
+- *
+- * Modified by Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and
+- * Nicolas Ferre <nicolas.ferre@alcove.fr> to support ARM7TDMI. Only
+- * very minor changes required to also work with StrongArm and presumably
+- * all ARM based systems.
+- *
+- * Yoshinori Sato <ysato@users.sourceforge.jp> 19-May-2004.
+- * added Renesas H8/300 support.
+- *
+- * Paul Mundt <lethal@linux-sh.org> 08-Aug-2003.
+- * Integrated support for sh64 (SH-5), from preliminary modutils
+- * patches from Benedict Gaster <benedict.gaster@superh.com>.
+- * Currently limited to support for 32bit ABI.
+- *
+- * Magnus Damm <damm@opensource.se> 22-May-2002.
+- * The plt and got code are now using the same structs.
+- * Added generic linked list code to fully support PowerPC.
+- * Replaced the mess in arch_apply_relocation() with architecture blocks.
+- * The arch_create_got() function got cleaned up with architecture blocks.
+- * These blocks should be easy maintain and sync with obj_xxx.c in modutils.
+- *
+- * Magnus Damm <damm@opensource.se> added PowerPC support 20-Feb-2001.
+- * PowerPC specific code stolen from modutils-2.3.16,
+- * written by Paul Mackerras, Copyright 1996, 1997 Linux International.
+- * I've only tested the code on mpc8xx platforms in big-endian mode.
+- * Did some cleanup and added USE_xxx_ENTRIES...
+- *
+- * Quinn Jensen <jensenq@lineo.com> added MIPS support 23-Feb-2001.
+- * based on modutils-2.4.2
+- * MIPS specific support for Elf loading and relocation.
+- * Copyright 1996, 1997 Linux International.
+- * Contributed by Ralf Baechle <ralf@gnu.ai.mit.edu>
+- *
+- * Based almost entirely on the Linux modutils-2.3.11 implementation.
+- * Copyright 1996, 1997 Linux International.
+- * New implementation contributed by Richard Henderson <rth@tamu.edu>
+- * Based on original work by Bjorn Ekwall <bj0rn@blox.se>
+- * Restructured (and partly rewritten) by:
+- * Björn Ekwall <bj0rn@blox.se> February 1999
+- *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+
+ #include "libbb.h"
+-#include <libgen.h>
+-#include <sys/utsname.h>
++#include "modutils.h"
+
+-#if !ENABLE_FEATURE_2_4_MODULES && !ENABLE_FEATURE_2_6_MODULES
+-#undef ENABLE_FEATURE_2_4_MODULES
+-#define ENABLE_FEATURE_2_4_MODULES 1
+-#endif
+-
+-/*
+- * Big piece of 2.4-specific code
+- */
+-#if ENABLE_FEATURE_2_4_MODULES
+-
+-#if ENABLE_FEATURE_2_6_MODULES
+-static int insmod_ng_main(int argc, char **argv);
+-#endif
+-
+-#if ENABLE_FEATURE_INSMOD_LOADINKMEM
+-#define LOADBITS 0
+-#else
+-#define LOADBITS 1
+-#endif
+-
+-/* Alpha */
+-#if defined(__alpha__)
+-#define MATCH_MACHINE(x) (x == EM_ALPHA)
+-#define SHT_RELM SHT_RELA
+-#define Elf64_RelM Elf64_Rela
+-#define ELFCLASSM ELFCLASS64
+-#endif
+-
+-/* ARM support */
+-#if defined(__arm__)
+-#define MATCH_MACHINE(x) (x == EM_ARM)
+-#define SHT_RELM SHT_REL
+-#define Elf32_RelM Elf32_Rel
+-#define ELFCLASSM ELFCLASS32
+-#define USE_PLT_ENTRIES
+-#define PLT_ENTRY_SIZE 8
+-#define USE_GOT_ENTRIES
+-#define GOT_ENTRY_SIZE 8
+-#define USE_SINGLE
+-#endif
+-
+-/* blackfin */
+-#if defined(BFIN)
+-#define MATCH_MACHINE(x) (x == EM_BLACKFIN)
+-#define SHT_RELM SHT_RELA
+-#define Elf32_RelM Elf32_Rela
+-#define ELFCLASSM ELFCLASS32
+-#endif
+-
+-/* CRIS */
+-#if defined(__cris__)
+-#define MATCH_MACHINE(x) (x == EM_CRIS)
+-#define SHT_RELM SHT_RELA
+-#define Elf32_RelM Elf32_Rela
+-#define ELFCLASSM ELFCLASS32
+-#ifndef EM_CRIS
+-#define EM_CRIS 76
+-#define R_CRIS_NONE 0
+-#define R_CRIS_32 3
+-#endif
+-#endif
+-
+-/* H8/300 */
+-#if defined(__H8300H__) || defined(__H8300S__)
+-#define MATCH_MACHINE(x) (x == EM_H8_300)
+-#define SHT_RELM SHT_RELA
+-#define Elf32_RelM Elf32_Rela
+-#define ELFCLASSM ELFCLASS32
+-#define USE_SINGLE
+-#define SYMBOL_PREFIX "_"
+-#endif
+-
+-/* PA-RISC / HP-PA */
+-#if defined(__hppa__)
+-#define MATCH_MACHINE(x) (x == EM_PARISC)
+-#define SHT_RELM SHT_RELA
+-#if defined(__LP64__)
+-#define Elf64_RelM Elf64_Rela
+-#define ELFCLASSM ELFCLASS64
+-#else
+-#define Elf32_RelM Elf32_Rela
+-#define ELFCLASSM ELFCLASS32
+-#endif
+-#endif
+-
+-/* x86 */
+-#if defined(__i386__)
+-#ifndef EM_486
+-#define MATCH_MACHINE(x) (x == EM_386)
+-#else
+-#define MATCH_MACHINE(x) (x == EM_386 || x == EM_486)
+-#endif
+-#define SHT_RELM SHT_REL
+-#define Elf32_RelM Elf32_Rel
+-#define ELFCLASSM ELFCLASS32
+-#define USE_GOT_ENTRIES
+-#define GOT_ENTRY_SIZE 4
+-#define USE_SINGLE
+-#endif
+-
+-/* IA64, aka Itanium */
+-#if defined(__ia64__)
+-#define MATCH_MACHINE(x) (x == EM_IA_64)
+-#define SHT_RELM SHT_RELA
+-#define Elf64_RelM Elf64_Rela
+-#define ELFCLASSM ELFCLASS64
+-#endif
+-
+-/* m68k */
+-#if defined(__mc68000__)
+-#define MATCH_MACHINE(x) (x == EM_68K)
+-#define SHT_RELM SHT_RELA
+-#define Elf32_RelM Elf32_Rela
+-#define ELFCLASSM ELFCLASS32
+-#define USE_GOT_ENTRIES
+-#define GOT_ENTRY_SIZE 4
+-#define USE_SINGLE
+-#endif
+-
+-/* Microblaze */
+-#if defined(__microblaze__)
+-#define USE_SINGLE
+-#include <linux/elf-em.h>
+-#define MATCH_MACHINE(x) (x == EM_XILINX_MICROBLAZE)
+-#define SHT_RELM SHT_RELA
+-#define Elf32_RelM Elf32_Rela
+-#define ELFCLASSM ELFCLASS32
+-#endif
+-
+-/* MIPS */
+-#if defined(__mips__)
+-#define MATCH_MACHINE(x) (x == EM_MIPS || x == EM_MIPS_RS3_LE)
+-#define SHT_RELM SHT_REL
+-#define Elf32_RelM Elf32_Rel
+-#define ELFCLASSM ELFCLASS32
+-/* Account for ELF spec changes. */
+-#ifndef EM_MIPS_RS3_LE
+-#ifdef EM_MIPS_RS4_BE
+-#define EM_MIPS_RS3_LE EM_MIPS_RS4_BE
+-#else
+-#define EM_MIPS_RS3_LE 10
+-#endif
+-#endif /* !EM_MIPS_RS3_LE */
+-#define ARCHDATAM "__dbe_table"
+-#endif
+-
+-/* Nios II */
+-#if defined(__nios2__)
+-#define MATCH_MACHINE(x) (x == EM_ALTERA_NIOS2)
+-#define SHT_RELM SHT_RELA
+-#define Elf32_RelM Elf32_Rela
+-#define ELFCLASSM ELFCLASS32
+-#endif
+-
+-/* PowerPC */
+-#if defined(__powerpc64__)
+-#define MATCH_MACHINE(x) (x == EM_PPC64)
+-#define SHT_RELM SHT_RELA
+-#define Elf64_RelM Elf64_Rela
+-#define ELFCLASSM ELFCLASS64
+-#elif defined(__powerpc__)
+-#define MATCH_MACHINE(x) (x == EM_PPC)
+-#define SHT_RELM SHT_RELA
+-#define Elf32_RelM Elf32_Rela
+-#define ELFCLASSM ELFCLASS32
+-#define USE_PLT_ENTRIES
+-#define PLT_ENTRY_SIZE 16
+-#define USE_PLT_LIST
+-#define LIST_ARCHTYPE ElfW(Addr)
+-#define USE_LIST
+-#define ARCHDATAM "__ftr_fixup"
+-#endif
+-
+-/* S390 */
+-#if defined(__s390__)
+-#define MATCH_MACHINE(x) (x == EM_S390)
+-#define SHT_RELM SHT_RELA
+-#define Elf32_RelM Elf32_Rela
+-#define ELFCLASSM ELFCLASS32
+-#define USE_PLT_ENTRIES
+-#define PLT_ENTRY_SIZE 8
+-#define USE_GOT_ENTRIES
+-#define GOT_ENTRY_SIZE 8
+-#define USE_SINGLE
+-#endif
+-
+-/* SuperH */
+-#if defined(__sh__)
+-#define MATCH_MACHINE(x) (x == EM_SH)
+-#define SHT_RELM SHT_RELA
+-#define Elf32_RelM Elf32_Rela
+-#define ELFCLASSM ELFCLASS32
+-#define USE_GOT_ENTRIES
+-#define GOT_ENTRY_SIZE 4
+-#define USE_SINGLE
+-/* the SH changes have only been tested in =little endian= mode */
+-/* I'm not sure about big endian, so let's warn: */
+-#if defined(__sh__) && BB_BIG_ENDIAN
+-# error insmod.c may require changes for use on big endian SH
+-#endif
+-/* it may or may not work on the SH1/SH2... Error on those also */
+-#if ((!(defined(__SH3__) || defined(__SH4__) || defined(__SH5__)))) && (defined(__sh__))
+-#error insmod.c may require changes for SH1 or SH2 use
+-#endif
+-#endif
+-
+-/* Sparc */
+-#if defined(__sparc__)
+-#define MATCH_MACHINE(x) (x == EM_SPARC)
+-#define SHT_RELM SHT_RELA
+-#define Elf32_RelM Elf32_Rela
+-#define ELFCLASSM ELFCLASS32
+-#endif
+-
+-/* v850e */
+-#if defined(__v850e__)
+-#define MATCH_MACHINE(x) ((x) == EM_V850 || (x) == EM_CYGNUS_V850)
+-#define SHT_RELM SHT_RELA
+-#define Elf32_RelM Elf32_Rela
+-#define ELFCLASSM ELFCLASS32
+-#define USE_PLT_ENTRIES
+-#define PLT_ENTRY_SIZE 8
+-#define USE_SINGLE
+-#ifndef EM_CYGNUS_V850 /* grumble */
+-#define EM_CYGNUS_V850 0x9080
+-#endif
+-#define SYMBOL_PREFIX "_"
+-#endif
+-
+-/* X86_64 */
+-#if defined(__x86_64__)
+-#define MATCH_MACHINE(x) (x == EM_X86_64)
+-#define SHT_RELM SHT_RELA
+-#define USE_GOT_ENTRIES
+-#define GOT_ENTRY_SIZE 8
+-#define USE_SINGLE
+-#define Elf64_RelM Elf64_Rela
+-#define ELFCLASSM ELFCLASS64
+-#endif
+-
+-#ifndef SHT_RELM
+-#error Sorry, but insmod.c does not yet support this architecture...
+-#endif
+-
+-
+-//----------------------------------------------------------------------------
+-//--------modutils module.h, lines 45-242
+-//----------------------------------------------------------------------------
+-
+-/* Definitions for the Linux module syscall interface.
+- Copyright 1996, 1997 Linux International.
+-
+- Contributed by Richard Henderson <rth@tamu.edu>
+-
+- This file is part of the Linux modutils.
+-
+- This program is free software; you can redistribute it and/or modify it
+- under the terms of the GNU General Public License as published by the
+- Free Software Foundation; either version 2 of the License, or (at your
+- option) any later version.
+-
+- This program is distributed in the hope that it will be useful, but
+- WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- General Public License for more details.
+-
+- You should have received a copy of the GNU General Public License
+- along with this program; if not, write to the Free Software Foundation,
+- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+-
+-
+-#ifndef MODUTILS_MODULE_H
+-
+-/*======================================================================*/
+-/* For sizeof() which are related to the module platform and not to the
+- environment isnmod is running in, use sizeof_xx instead of sizeof(xx). */
+-
+-#define tgt_sizeof_char sizeof(char)
+-#define tgt_sizeof_short sizeof(short)
+-#define tgt_sizeof_int sizeof(int)
+-#define tgt_sizeof_long sizeof(long)
+-#define tgt_sizeof_char_p sizeof(char *)
+-#define tgt_sizeof_void_p sizeof(void *)
+-#define tgt_long long
+-
+-#if defined(__sparc__) && !defined(__sparc_v9__) && defined(ARCH_sparc64)
+-#undef tgt_sizeof_long
+-#undef tgt_sizeof_char_p
+-#undef tgt_sizeof_void_p
+-#undef tgt_long
+-enum {
+- tgt_sizeof_long = 8,
+- tgt_sizeof_char_p = 8,
+- tgt_sizeof_void_p = 8
+-};
+-#define tgt_long long long
+-#endif
+-
+-/*======================================================================*/
+-/* The structures used in Linux 2.1. */
+-
+-/* Note: new_module_symbol does not use tgt_long intentionally */
+-struct new_module_symbol {
+- unsigned long value;
+- unsigned long name;
+-};
+-
+-struct new_module_persist;
+-
+-struct new_module_ref {
+- unsigned tgt_long dep; /* kernel addresses */
+- unsigned tgt_long ref;
+- unsigned tgt_long next_ref;
+-};
+-
+-struct new_module {
+- unsigned tgt_long size_of_struct; /* == sizeof(module) */
+- unsigned tgt_long next;
+- unsigned tgt_long name;
+- unsigned tgt_long size;
+-
+- tgt_long usecount;
+- unsigned tgt_long flags; /* AUTOCLEAN et al */
+-
+- unsigned nsyms;
+- unsigned ndeps;
+-
+- unsigned tgt_long syms;
+- unsigned tgt_long deps;
+- unsigned tgt_long refs;
+- unsigned tgt_long init;
+- unsigned tgt_long cleanup;
+- unsigned tgt_long ex_table_start;
+- unsigned tgt_long ex_table_end;
+-#ifdef __alpha__
+- unsigned tgt_long gp;
+-#endif
+- /* Everything after here is extension. */
+- unsigned tgt_long persist_start;
+- unsigned tgt_long persist_end;
+- unsigned tgt_long can_unload;
+- unsigned tgt_long runsize;
+- const char *kallsyms_start; /* All symbols for kernel debugging */
+- const char *kallsyms_end;
+- const char *archdata_start; /* arch specific data for module */
+- const char *archdata_end;
+- const char *kernel_data; /* Reserved for kernel internal use */
+-};
+-
+-#ifdef ARCHDATAM
+-#define ARCHDATA_SEC_NAME ARCHDATAM
+-#else
+-#define ARCHDATA_SEC_NAME "__archdata"
+-#endif
+-#define KALLSYMS_SEC_NAME "__kallsyms"
+-
+-
+-struct new_module_info {
+- unsigned long addr;
+- unsigned long size;
+- unsigned long flags;
+- long usecount;
+-};
+-
+-/* Bits of module.flags. */
+-enum {
+- NEW_MOD_RUNNING = 1,
+- NEW_MOD_DELETED = 2,
+- NEW_MOD_AUTOCLEAN = 4,
+- NEW_MOD_VISITED = 8,
+- NEW_MOD_USED_ONCE = 16
+-};
+-
+-int init_module(const char *name, const struct new_module *);
+-int query_module(const char *name, int which, void *buf,
+- size_t bufsize, size_t *ret);
+-
+-/* Values for query_module's which. */
+-enum {
+- QM_MODULES = 1,
+- QM_DEPS = 2,
+- QM_REFS = 3,
+- QM_SYMBOLS = 4,
+- QM_INFO = 5
+-};
+-
+-/*======================================================================*/
+-/* The system calls unchanged between 2.0 and 2.1. */
+-
+-unsigned long create_module(const char *, size_t);
+-int delete_module(const char *module, unsigned int flags);
+-
+-
+-#endif /* module.h */
+-
+-//----------------------------------------------------------------------------
+-//--------end of modutils module.h
+-//----------------------------------------------------------------------------
+-
+-
+-
+-//----------------------------------------------------------------------------
+-//--------modutils obj.h, lines 253-462
+-//----------------------------------------------------------------------------
+-
+-/* Elf object file loading and relocation routines.
+- Copyright 1996, 1997 Linux International.
+-
+- Contributed by Richard Henderson <rth@tamu.edu>
+-
+- This file is part of the Linux modutils.
+-
+- This program is free software; you can redistribute it and/or modify it
+- under the terms of the GNU General Public License as published by the
+- Free Software Foundation; either version 2 of the License, or (at your
+- option) any later version.
+-
+- This program is distributed in the hope that it will be useful, but
+- WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- General Public License for more details.
+-
+- You should have received a copy of the GNU General Public License
+- along with this program; if not, write to the Free Software Foundation,
+- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+-
+-
+-#ifndef MODUTILS_OBJ_H
+-
+-/* The relocatable object is manipulated using elfin types. */
+-
+-#include <elf.h>
+-#include <endian.h>
+-
+-#ifndef ElfW
+-# if ELFCLASSM == ELFCLASS32
+-# define ElfW(x) Elf32_ ## x
+-# define ELFW(x) ELF32_ ## x
+-# else
+-# define ElfW(x) Elf64_ ## x
+-# define ELFW(x) ELF64_ ## x
+-# endif
+-#endif
+-
+-/* For some reason this is missing from some ancient C libraries.... */
+-#ifndef ELF32_ST_INFO
+-# define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
+-#endif
+-
+-#ifndef ELF64_ST_INFO
+-# define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
+-#endif
+-
+-#define ELF_ST_BIND(info) ELFW(ST_BIND)(info)
+-#define ELF_ST_TYPE(info) ELFW(ST_TYPE)(info)
+-#define ELF_ST_INFO(bind, type) ELFW(ST_INFO)(bind, type)
+-#define ELF_R_TYPE(val) ELFW(R_TYPE)(val)
+-#define ELF_R_SYM(val) ELFW(R_SYM)(val)
+-
+-struct obj_string_patch;
+-struct obj_symbol_patch;
+-
+-struct obj_section
+-{
+- ElfW(Shdr) header;
+- const char *name;
+- char *contents;
+- struct obj_section *load_next;
+- int idx;
+-};
+-
+-struct obj_symbol
+-{
+- struct obj_symbol *next; /* hash table link */
+- const char *name;
+- unsigned long value;
+- unsigned long size;
+- int secidx; /* the defining section index/module */
+- int info;
+- int ksymidx; /* for export to the kernel symtab */
+- int referenced; /* actually used in the link */
+-};
+-
+-/* Hardcode the hash table size. We shouldn't be needing so many
+- symbols that we begin to degrade performance, and we get a big win
+- by giving the compiler a constant divisor. */
+-
+-#define HASH_BUCKETS 521
+-
+-struct obj_file {
+- ElfW(Ehdr) header;
+- ElfW(Addr) baseaddr;
+- struct obj_section **sections;
+- struct obj_section *load_order;
+- struct obj_section **load_order_search_start;
+- struct obj_string_patch *string_patches;
+- struct obj_symbol_patch *symbol_patches;
+- int (*symbol_cmp)(const char *, const char *);
+- unsigned long (*symbol_hash)(const char *);
+- unsigned long local_symtab_size;
+- struct obj_symbol **local_symtab;
+- struct obj_symbol *symtab[HASH_BUCKETS];
+-};
+-
+-enum obj_reloc {
+- obj_reloc_ok,
+- obj_reloc_overflow,
+- obj_reloc_dangerous,
+- obj_reloc_unhandled
+-};
+-
+-struct obj_string_patch {
+- struct obj_string_patch *next;
+- int reloc_secidx;
+- ElfW(Addr) reloc_offset;
+- ElfW(Addr) string_offset;
+-};
+-
+-struct obj_symbol_patch {
+- struct obj_symbol_patch *next;
+- int reloc_secidx;
+- ElfW(Addr) reloc_offset;
+- struct obj_symbol *sym;
+-};
+-
+-
+-/* Generic object manipulation routines. */
+-
+-static unsigned long obj_elf_hash(const char *);
+-
+-static unsigned long obj_elf_hash_n(const char *, unsigned long len);
+-
+-static struct obj_symbol *obj_find_symbol(struct obj_file *f,
+- const char *name);
+-
+-static ElfW(Addr) obj_symbol_final_value(struct obj_file *f,
+- struct obj_symbol *sym);
+-
+-#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
+-static void obj_set_symbol_compare(struct obj_file *f,
+- int (*cmp)(const char *, const char *),
+- unsigned long (*hash)(const char *));
+-#endif
+-
+-static struct obj_section *obj_find_section(struct obj_file *f,
+- const char *name);
+-
+-static void obj_insert_section_load_order(struct obj_file *f,
+- struct obj_section *sec);
+-
+-static struct obj_section *obj_create_alloced_section(struct obj_file *f,
+- const char *name,
+- unsigned long align,
+- unsigned long size);
+-
+-static struct obj_section *obj_create_alloced_section_first(struct obj_file *f,
+- const char *name,
+- unsigned long align,
+- unsigned long size);
+-
+-static void *obj_extend_section(struct obj_section *sec, unsigned long more);
+-
+-static void obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
+- const char *string);
+-
+-static void obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
+- struct obj_symbol *sym);
+-
+-static void obj_check_undefineds(struct obj_file *f);
+-
+-static void obj_allocate_commons(struct obj_file *f);
+-
+-static unsigned long obj_load_size(struct obj_file *f);
+-
+-static int obj_relocate(struct obj_file *f, ElfW(Addr) base);
+-
+-static struct obj_file *obj_load(FILE *f, int loadprogbits);
+-
+-static int obj_create_image(struct obj_file *f, char *image);
+-
+-/* Architecture specific manipulation routines. */
+-
+-static struct obj_file *arch_new_file(void);
+-
+-static struct obj_section *arch_new_section(void);
+-
+-static struct obj_symbol *arch_new_symbol(void);
+-
+-static enum obj_reloc arch_apply_relocation(struct obj_file *f,
+- struct obj_section *targsec,
+- /*struct obj_section *symsec,*/
+- struct obj_symbol *sym,
+- ElfW(RelM) *rel, ElfW(Addr) value);
+-
+-static void arch_create_got(struct obj_file *f);
+-#if ENABLE_FEATURE_CHECK_TAINTED_MODULE
+-static int obj_gpl_license(struct obj_file *f, const char **license);
+-#endif /* FEATURE_CHECK_TAINTED_MODULE */
+-#endif /* obj.h */
+-//----------------------------------------------------------------------------
+-//--------end of modutils obj.h
+-//----------------------------------------------------------------------------
+-
+-
+-/* SPFX is always a string, so it can be concatenated to string constants. */
+-#ifdef SYMBOL_PREFIX
+-#define SPFX SYMBOL_PREFIX
+-#else
+-#define SPFX ""
+-#endif
+-
+-enum { STRVERSIONLEN = 64 };
+-
+-/*======================================================================*/
+-
+-#define OPTION_STR "sLo:fkvqx" USE_FEATURE_INSMOD_LOAD_MAP("m")
+-enum {
+- OPT_s = 0x1, // -s /* log to syslog */
+- /* Not supported but kernel needs this for request_module(),
+- as this calls: modprobe -k -s -- <module>
+- so silently ignore this flag */
+- OPT_L = 0x2, // -L /* Stub warning */
+- /* Compatibility with modprobe.
+- In theory, this does locking, but we don't do
+- that. So be careful and plan your life around not
+- loading the same module 50 times concurrently. */
+- OPT_o = 0x4, // -o /* name the output module */
+- OPT_f = 0x8, // -f /* force loading */
+- OPT_k = 0x10, // -k /* module loaded by kerneld, auto-cleanable */
+- OPT_v = 0x20, // -v /* verbose output */
+- OPT_q = 0x40, // -q /* silent */
+- OPT_x = 0x80, // -x /* do not export externs */
+- OPT_m = 0x100, // -m /* print module load map */
+-};
+-#define flag_force_load (option_mask32 & OPT_f)
+-#define flag_autoclean (option_mask32 & OPT_k)
+-#define flag_verbose (option_mask32 & OPT_v)
+-#define flag_quiet (option_mask32 & OPT_q)
+-#define flag_noexport (option_mask32 & OPT_x)
+-#if ENABLE_FEATURE_INSMOD_LOAD_MAP
+-#define flag_print_load_map (option_mask32 & OPT_m)
+-#else
+-#define flag_print_load_map 0
+-#endif
+-
+-/*======================================================================*/
+-
+-#if defined(USE_LIST)
+-
+-struct arch_list_entry
+-{
+- struct arch_list_entry *next;
+- LIST_ARCHTYPE addend;
+- int offset;
+- int inited : 1;
+-};
+-
+-#endif
+-
+-#if defined(USE_SINGLE)
+-
+-struct arch_single_entry
+-{
+- int offset;
+- int inited : 1;
+- int allocated : 1;
+-};
+-
+-#endif
+-
+-#if defined(__mips__)
+-struct mips_hi16
+-{
+- struct mips_hi16 *next;
+- ElfW(Addr) *addr;
+- ElfW(Addr) value;
+-};
+-#endif
+-
+-struct arch_file {
+- struct obj_file root;
+-#if defined(USE_PLT_ENTRIES)
+- struct obj_section *plt;
+-#endif
+-#if defined(USE_GOT_ENTRIES)
+- struct obj_section *got;
+-#endif
+-#if defined(__mips__)
+- struct mips_hi16 *mips_hi16_list;
+-#endif
+-};
+-
+-struct arch_symbol {
+- struct obj_symbol root;
+-#if defined(USE_PLT_ENTRIES)
+-#if defined(USE_PLT_LIST)
+- struct arch_list_entry *pltent;
+-#else
+- struct arch_single_entry pltent;
+-#endif
+-#endif
+-#if defined(USE_GOT_ENTRIES)
+- struct arch_single_entry gotent;
+-#endif
+-};
+-
+-
+-struct external_module {
+- const char *name;
+- ElfW(Addr) addr;
+- int used;
+- size_t nsyms;
+- struct new_module_symbol *syms;
+-};
+-
+-static struct new_module_symbol *ksyms;
+-static size_t nksyms;
+-
+-static struct external_module *ext_modules;
+-static int n_ext_modules;
+-static int n_ext_modules_used;
+-
+-static char *m_filename;
+-static char *m_fullName;
+-
+-
+-/*======================================================================*/
+-
+-
+-static int FAST_FUNC check_module_name_match(const char *filename,
+- struct stat *statbuf UNUSED_PARAM,
+- void *userdata, int depth UNUSED_PARAM)
+-{
+- char *fullname = (char *) userdata;
+- char *tmp;
+-
+- if (fullname[0] == '\0')
+- return FALSE;
+-
+- tmp = bb_get_last_path_component_nostrip(filename);
+- if (strcmp(tmp, fullname) == 0) {
+- /* Stop searching if we find a match */
+- m_filename = xstrdup(filename);
+- return FALSE;
+- }
+- return TRUE;
+-}
+-
+-
+-/*======================================================================*/
+-
+-static struct obj_file *arch_new_file(void)
+-{
+- struct arch_file *f;
+- f = xzalloc(sizeof(*f));
+- return &f->root; /* it's a first member */
+-}
+-
+-static struct obj_section *arch_new_section(void)
+-{
+- return xzalloc(sizeof(struct obj_section));
+-}
+-
+-static struct obj_symbol *arch_new_symbol(void)
+-{
+- struct arch_symbol *sym;
+- sym = xzalloc(sizeof(*sym));
+- return &sym->root;
+-}
+-
+-static enum obj_reloc
+-arch_apply_relocation(struct obj_file *f,
+- struct obj_section *targsec,
+- /*struct obj_section *symsec,*/
+- struct obj_symbol *sym,
+- ElfW(RelM) *rel, ElfW(Addr) v)
+-{
+-#if defined(__arm__) || defined(__i386__) || defined(__mc68000__) \
+- || defined(__sh__) || defined(__s390__) || defined(__x86_64__) \
+- || defined(__powerpc__) || defined(__mips__)
+- struct arch_file *ifile = (struct arch_file *) f;
+-#endif
+- enum obj_reloc ret = obj_reloc_ok;
+- ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + rel->r_offset);
+-#if defined(__arm__) || defined(__H8300H__) || defined(__H8300S__) \
+- || defined(__i386__) || defined(__mc68000__) || defined(__microblaze__) \
+- || defined(__mips__) || defined(__nios2__) || defined(__powerpc__) \
+- || defined(__s390__) || defined(__sh__) || defined(__x86_64__)
+- ElfW(Addr) dot = targsec->header.sh_addr + rel->r_offset;
+-#endif
+-#if defined(USE_GOT_ENTRIES) || defined(USE_PLT_ENTRIES)
+- struct arch_symbol *isym = (struct arch_symbol *) sym;
+-#endif
+-#if defined(__arm__) || defined(__i386__) || defined(__mc68000__) \
+- || defined(__sh__) || defined(__s390__)
+-#if defined(USE_GOT_ENTRIES)
+- ElfW(Addr) got = ifile->got ? ifile->got->header.sh_addr : 0;
+-#endif
+-#endif
+-#if defined(USE_PLT_ENTRIES)
+- ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0;
+- unsigned long *ip;
+-# if defined(USE_PLT_LIST)
+- struct arch_list_entry *pe;
+-# else
+- struct arch_single_entry *pe;
+-# endif
+-#endif
+-
+- switch (ELF_R_TYPE(rel->r_info)) {
+-
+-#if defined(__arm__)
+-
+- case R_ARM_NONE:
+- break;
+-
+- case R_ARM_ABS32:
+- *loc += v;
+- break;
+-
+- case R_ARM_GOT32:
+- goto bb_use_got;
+-
+- case R_ARM_GOTPC:
+- /* relative reloc, always to _GLOBAL_OFFSET_TABLE_
+- * (which is .got) similar to branch,
+- * but is full 32 bits relative */
+-
+- *loc += got - dot;
+- break;
+-
+- case R_ARM_PC24:
+- case R_ARM_PLT32:
+- goto bb_use_plt;
+-
+- case R_ARM_GOTOFF: /* address relative to the got */
+- *loc += v - got;
+- break;
+-
+-#elif defined(__cris__)
+-
+- case R_CRIS_NONE:
+- break;
+-
+- case R_CRIS_32:
+- /* CRIS keeps the relocation value in the r_addend field and
+- * should not use whats in *loc at all
+- */
+- *loc = v;
+- break;
+-
+-#elif defined(__H8300H__) || defined(__H8300S__)
+-
+- case R_H8_DIR24R8:
+- loc = (ElfW(Addr) *)((ElfW(Addr))loc - 1);
+- *loc = (*loc & 0xff000000) | ((*loc & 0xffffff) + v);
+- break;
+- case R_H8_DIR24A8:
+- *loc += v;
+- break;
+- case R_H8_DIR32:
+- case R_H8_DIR32A16:
+- *loc += v;
+- break;
+- case R_H8_PCREL16:
+- v -= dot + 2;
+- if ((ElfW(Sword))v > 0x7fff ||
+- (ElfW(Sword))v < -(ElfW(Sword))0x8000)
+- ret = obj_reloc_overflow;
+- else
+- *(unsigned short *)loc = v;
+- break;
+- case R_H8_PCREL8:
+- v -= dot + 1;
+- if ((ElfW(Sword))v > 0x7f ||
+- (ElfW(Sword))v < -(ElfW(Sword))0x80)
+- ret = obj_reloc_overflow;
+- else
+- *(unsigned char *)loc = v;
+- break;
+-
+-#elif defined(__i386__)
+-
+- case R_386_NONE:
+- break;
+-
+- case R_386_32:
+- *loc += v;
+- break;
+-
+- case R_386_PLT32:
+- case R_386_PC32:
+- case R_386_GOTOFF:
+- *loc += v - dot;
+- break;
+-
+- case R_386_GLOB_DAT:
+- case R_386_JMP_SLOT:
+- *loc = v;
+- break;
+-
+- case R_386_RELATIVE:
+- *loc += f->baseaddr;
+- break;
+-
+- case R_386_GOTPC:
+- *loc += got - dot;
+- break;
+-
+- case R_386_GOT32:
+- goto bb_use_got;
+- break;
+-
+-#elif defined(__microblaze__)
+- case R_MICROBLAZE_NONE:
+- case R_MICROBLAZE_64_NONE:
+- case R_MICROBLAZE_32_SYM_OP_SYM:
+- case R_MICROBLAZE_32_PCREL:
+- break;
+-
+- case R_MICROBLAZE_64_PCREL: {
+- /* dot is the address of the current instruction.
+- * v is the target symbol address.
+- * So we need to extract the offset in the code,
+- * adding v, then subtrating the current address
+- * of this instruction.
+- * Ex: "IMM 0xFFFE bralid 0x0000" = "bralid 0xFFFE0000"
+- */
+-
+- /* Get split offset stored in code */
+- unsigned int temp = (loc[0] & 0xFFFF) << 16 |
+- (loc[1] & 0xFFFF);
+-
+- /* Adjust relative offset. -4 adjustment required
+- * because dot points to the IMM insn, but branch
+- * is computed relative to the branch instruction itself.
+- */
+- temp += v - dot - 4;
+-
+- /* Store back into code */
+- loc[0] = (loc[0] & 0xFFFF0000) | temp >> 16;
+- loc[1] = (loc[1] & 0xFFFF0000) | (temp & 0xFFFF);
+-
+- break;
+- }
+-
+- case R_MICROBLAZE_32:
+- *loc += v;
+- break;
+-
+- case R_MICROBLAZE_64: {
+- /* Get split pointer stored in code */
+- unsigned int temp1 = (loc[0] & 0xFFFF) << 16 |
+- (loc[1] & 0xFFFF);
+-
+- /* Add reloc offset */
+- temp1+=v;
+-
+- /* Store back into code */
+- loc[0] = (loc[0] & 0xFFFF0000) | temp1 >> 16;
+- loc[1] = (loc[1] & 0xFFFF0000) | (temp1 & 0xFFFF);
+-
+- break;
+- }
+-
+- case R_MICROBLAZE_32_PCREL_LO:
+- case R_MICROBLAZE_32_LO:
+- case R_MICROBLAZE_SRO32:
+- case R_MICROBLAZE_SRW32:
+- ret = obj_reloc_unhandled;
+- break;
+-
+-#elif defined(__mc68000__)
+-
+- case R_68K_NONE:
+- break;
+-
+- case R_68K_32:
+- *loc += v;
+- break;
+-
+- case R_68K_8:
+- if (v > 0xff) {
+- ret = obj_reloc_overflow;
+- }
+- *(char *)loc = v;
+- break;
+-
+- case R_68K_16:
+- if (v > 0xffff) {
+- ret = obj_reloc_overflow;
+- }
+- *(short *)loc = v;
+- break;
+-
+- case R_68K_PC8:
+- v -= dot;
+- if ((ElfW(Sword))v > 0x7f
+- || (ElfW(Sword))v < -(ElfW(Sword))0x80
+- ) {
+- ret = obj_reloc_overflow;
+- }
+- *(char *)loc = v;
+- break;
+-
+- case R_68K_PC16:
+- v -= dot;
+- if ((ElfW(Sword))v > 0x7fff
+- || (ElfW(Sword))v < -(ElfW(Sword))0x8000
+- ) {
+- ret = obj_reloc_overflow;
+- }
+- *(short *)loc = v;
+- break;
+-
+- case R_68K_PC32:
+- *(int *)loc = v - dot;
+- break;
+-
+- case R_68K_GLOB_DAT:
+- case R_68K_JMP_SLOT:
+- *loc = v;
+- break;
+-
+- case R_68K_RELATIVE:
+- *(int *)loc += f->baseaddr;
+- break;
+-
+- case R_68K_GOT32:
+- goto bb_use_got;
+-
+-# ifdef R_68K_GOTOFF
+- case R_68K_GOTOFF:
+- *loc += v - got;
+- break;
+-# endif
+-
+-#elif defined(__mips__)
+-
+- case R_MIPS_NONE:
+- break;
+-
+- case R_MIPS_32:
+- *loc += v;
+- break;
+-
+- case R_MIPS_26:
+- if (v % 4)
+- ret = obj_reloc_dangerous;
+- if ((v & 0xf0000000) != ((dot + 4) & 0xf0000000))
+- ret = obj_reloc_overflow;
+- *loc =
+- (*loc & ~0x03ffffff) | ((*loc + (v >> 2)) &
+- 0x03ffffff);
+- break;
+-
+- case R_MIPS_HI16:
+- {
+- struct mips_hi16 *n;
+-
+- /* We cannot relocate this one now because we don't know the value
+- of the carry we need to add. Save the information, and let LO16
+- do the actual relocation. */
+- n = xmalloc(sizeof *n);
+- n->addr = loc;
+- n->value = v;
+- n->next = ifile->mips_hi16_list;
+- ifile->mips_hi16_list = n;
+- break;
+- }
+-
+- case R_MIPS_LO16:
+- {
+- unsigned long insnlo = *loc;
+- ElfW(Addr) val, vallo;
+-
+- /* Sign extend the addend we extract from the lo insn. */
+- vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
+-
+- if (ifile->mips_hi16_list != NULL) {
+- struct mips_hi16 *l;
+-
+- l = ifile->mips_hi16_list;
+- while (l != NULL) {
+- struct mips_hi16 *next;
+- unsigned long insn;
+-
+- /* Do the HI16 relocation. Note that we actually don't
+- need to know anything about the LO16 itself, except where
+- to find the low 16 bits of the addend needed by the LO16. */
+- insn = *l->addr;
+- val =
+- ((insn & 0xffff) << 16) +
+- vallo;
+- val += v;
+-
+- /* Account for the sign extension that will happen in the
+- low bits. */
+- val =
+- ((val >> 16) +
+- ((val & 0x8000) !=
+- 0)) & 0xffff;
+-
+- insn = (insn & ~0xffff) | val;
+- *l->addr = insn;
+-
+- next = l->next;
+- free(l);
+- l = next;
+- }
+-
+- ifile->mips_hi16_list = NULL;
+- }
+-
+- /* Ok, we're done with the HI16 relocs. Now deal with the LO16. */
+- val = v + vallo;
+- insnlo = (insnlo & ~0xffff) | (val & 0xffff);
+- *loc = insnlo;
+- break;
+- }
+-
+-#elif defined(__nios2__)
+-
+- case R_NIOS2_NONE:
+- break;
+-
+- case R_NIOS2_BFD_RELOC_32:
+- *loc += v;
+- break;
+-
+- case R_NIOS2_BFD_RELOC_16:
+- if (v > 0xffff) {
+- ret = obj_reloc_overflow;
+- }
+- *(short *)loc = v;
+- break;
+-
+- case R_NIOS2_BFD_RELOC_8:
+- if (v > 0xff) {
+- ret = obj_reloc_overflow;
+- }
+- *(char *)loc = v;
+- break;
+-
+- case R_NIOS2_S16:
+- {
+- Elf32_Addr word;
+-
+- if ((Elf32_Sword)v > 0x7fff
+- || (Elf32_Sword)v < -(Elf32_Sword)0x8000
+- ) {
+- ret = obj_reloc_overflow;
+- }
+-
+- word = *loc;
+- *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) |
+- (word & 0x3f);
+- }
+- break;
+-
+- case R_NIOS2_U16:
+- {
+- Elf32_Addr word;
+-
+- if (v > 0xffff) {
+- ret = obj_reloc_overflow;
+- }
+-
+- word = *loc;
+- *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) |
+- (word & 0x3f);
+- }
+- break;
+-
+- case R_NIOS2_PCREL16:
+- {
+- Elf32_Addr word;
+-
+- v -= dot + 4;
+- if ((Elf32_Sword)v > 0x7fff
+- || (Elf32_Sword)v < -(Elf32_Sword)0x8000
+- ) {
+- ret = obj_reloc_overflow;
+- }
+-
+- word = *loc;
+- *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | (word & 0x3f);
+- }
+- break;
+-
+- case R_NIOS2_GPREL:
+- {
+- Elf32_Addr word, gp;
+- /* get _gp */
+- gp = obj_symbol_final_value(f, obj_find_symbol(f, SPFX "_gp"));
+- v -= gp;
+- if ((Elf32_Sword)v > 0x7fff
+- || (Elf32_Sword)v < -(Elf32_Sword)0x8000
+- ) {
+- ret = obj_reloc_overflow;
+- }
+-
+- word = *loc;
+- *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) | (word & 0x3f);
+- }
+- break;
+-
+- case R_NIOS2_CALL26:
+- if (v & 3)
+- ret = obj_reloc_dangerous;
+- if ((v >> 28) != (dot >> 28))
+- ret = obj_reloc_overflow;
+- *loc = (*loc & 0x3f) | ((v >> 2) << 6);
+- break;
+-
+- case R_NIOS2_IMM5:
+- {
+- Elf32_Addr word;
+-
+- if (v > 0x1f) {
+- ret = obj_reloc_overflow;
+- }
+-
+- word = *loc & ~0x7c0;
+- *loc = word | ((v & 0x1f) << 6);
+- }
+- break;
+-
+- case R_NIOS2_IMM6:
+- {
+- Elf32_Addr word;
+-
+- if (v > 0x3f) {
+- ret = obj_reloc_overflow;
+- }
+-
+- word = *loc & ~0xfc0;
+- *loc = word | ((v & 0x3f) << 6);
+- }
+- break;
+-
+- case R_NIOS2_IMM8:
+- {
+- Elf32_Addr word;
+-
+- if (v > 0xff) {
+- ret = obj_reloc_overflow;
+- }
+-
+- word = *loc & ~0x3fc0;
+- *loc = word | ((v & 0xff) << 6);
+- }
+- break;
+-
+- case R_NIOS2_HI16:
+- {
+- Elf32_Addr word;
+-
+- word = *loc;
+- *loc = ((((word >> 22) << 16) | ((v >>16) & 0xffff)) << 6) |
+- (word & 0x3f);
+- }
+- break;
+-
+- case R_NIOS2_LO16:
+- {
+- Elf32_Addr word;
+-
+- word = *loc;
+- *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) |
+- (word & 0x3f);
+- }
+- break;
+-
+- case R_NIOS2_HIADJ16:
+- {
+- Elf32_Addr word1, word2;
+-
+- word1 = *loc;
+- word2 = ((v >> 16) + ((v >> 15) & 1)) & 0xffff;
+- *loc = ((((word1 >> 22) << 16) | word2) << 6) |
+- (word1 & 0x3f);
+- }
+- break;
+-
+-#elif defined(__powerpc64__)
+- /* PPC64 needs a 2.6 kernel, 2.4 module relocation irrelevant */
+-
+-#elif defined(__powerpc__)
+-
+- case R_PPC_ADDR16_HA:
+- *(unsigned short *)loc = (v + 0x8000) >> 16;
+- break;
+-
+- case R_PPC_ADDR16_HI:
+- *(unsigned short *)loc = v >> 16;
+- break;
+-
+- case R_PPC_ADDR16_LO:
+- *(unsigned short *)loc = v;
+- break;
+-
+- case R_PPC_REL24:
+- goto bb_use_plt;
+-
+- case R_PPC_REL32:
+- *loc = v - dot;
+- break;
+-
+- case R_PPC_ADDR32:
+- *loc = v;
+- break;
+-
+-#elif defined(__s390__)
+-
+- case R_390_32:
+- *(unsigned int *) loc += v;
+- break;
+- case R_390_16:
+- *(unsigned short *) loc += v;
+- break;
+- case R_390_8:
+- *(unsigned char *) loc += v;
+- break;
+-
+- case R_390_PC32:
+- *(unsigned int *) loc += v - dot;
+- break;
+- case R_390_PC16DBL:
+- *(unsigned short *) loc += (v - dot) >> 1;
+- break;
+- case R_390_PC16:
+- *(unsigned short *) loc += v - dot;
+- break;
+-
+- case R_390_PLT32:
+- case R_390_PLT16DBL:
+- /* find the plt entry and initialize it. */
+- pe = (struct arch_single_entry *) &isym->pltent;
+- if (pe->inited == 0) {
+- ip = (unsigned long *)(ifile->plt->contents + pe->offset);
+- ip[0] = 0x0d105810; /* basr 1,0; lg 1,10(1); br 1 */
+- ip[1] = 0x100607f1;
+- if (ELF_R_TYPE(rel->r_info) == R_390_PLT16DBL)
+- ip[2] = v - 2;
+- else
+- ip[2] = v;
+- pe->inited = 1;
+- }
+-
+- /* Insert relative distance to target. */
+- v = plt + pe->offset - dot;
+- if (ELF_R_TYPE(rel->r_info) == R_390_PLT32)
+- *(unsigned int *) loc = (unsigned int) v;
+- else if (ELF_R_TYPE(rel->r_info) == R_390_PLT16DBL)
+- *(unsigned short *) loc = (unsigned short) ((v + 2) >> 1);
+- break;
+-
+- case R_390_GLOB_DAT:
+- case R_390_JMP_SLOT:
+- *loc = v;
+- break;
+-
+- case R_390_RELATIVE:
+- *loc += f->baseaddr;
+- break;
+-
+- case R_390_GOTPC:
+- *(unsigned long *) loc += got - dot;
+- break;
+-
+- case R_390_GOT12:
+- case R_390_GOT16:
+- case R_390_GOT32:
+- if (!isym->gotent.inited)
+- {
+- isym->gotent.inited = 1;
+- *(ElfW(Addr) *)(ifile->got->contents + isym->gotent.offset) = v;
+- }
+- if (ELF_R_TYPE(rel->r_info) == R_390_GOT12)
+- *(unsigned short *) loc |= (*(unsigned short *) loc + isym->gotent.offset) & 0xfff;
+- else if (ELF_R_TYPE(rel->r_info) == R_390_GOT16)
+- *(unsigned short *) loc += isym->gotent.offset;
+- else if (ELF_R_TYPE(rel->r_info) == R_390_GOT32)
+- *(unsigned int *) loc += isym->gotent.offset;
+- break;
+-
+-# ifndef R_390_GOTOFF32
+-# define R_390_GOTOFF32 R_390_GOTOFF
+-# endif
+- case R_390_GOTOFF32:
+- *loc += v - got;
+- break;
+-
+-#elif defined(__sh__)
+-
+- case R_SH_NONE:
+- break;
+-
+- case R_SH_DIR32:
+- *loc += v;
+- break;
+-
+- case R_SH_REL32:
+- *loc += v - dot;
+- break;
+-
+- case R_SH_PLT32:
+- *loc = v - dot;
+- break;
+-
+- case R_SH_GLOB_DAT:
+- case R_SH_JMP_SLOT:
+- *loc = v;
+- break;
+-
+- case R_SH_RELATIVE:
+- *loc = f->baseaddr + rel->r_addend;
+- break;
+-
+- case R_SH_GOTPC:
+- *loc = got - dot + rel->r_addend;
+- break;
+-
+- case R_SH_GOT32:
+- goto bb_use_got;
+-
+- case R_SH_GOTOFF:
+- *loc = v - got;
+- break;
+-
+-# if defined(__SH5__)
+- case R_SH_IMM_MEDLOW16:
+- case R_SH_IMM_LOW16:
+- {
+- ElfW(Addr) word;
+-
+- if (ELF_R_TYPE(rel->r_info) == R_SH_IMM_MEDLOW16)
+- v >>= 16;
+-
+- /*
+- * movi and shori have the format:
+- *
+- * | op | imm | reg | reserved |
+- * 31..26 25..10 9.. 4 3 .. 0
+- *
+- * so we simply mask and or in imm.
+- */
+- word = *loc & ~0x3fffc00;
+- word |= (v & 0xffff) << 10;
+-
+- *loc = word;
+-
+- break;
+- }
+-
+- case R_SH_IMM_MEDLOW16_PCREL:
+- case R_SH_IMM_LOW16_PCREL:
+- {
+- ElfW(Addr) word;
+-
+- word = *loc & ~0x3fffc00;
+-
+- v -= dot;
+-
+- if (ELF_R_TYPE(rel->r_info) == R_SH_IMM_MEDLOW16_PCREL)
+- v >>= 16;
+-
+- word |= (v & 0xffff) << 10;
+-
+- *loc = word;
+-
+- break;
+- }
+-# endif /* __SH5__ */
+-
+-#elif defined(__v850e__)
+-
+- case R_V850_NONE:
+- break;
+-
+- case R_V850_32:
+- /* We write two shorts instead of a long because even
+- 32-bit insns only need half-word alignment, but
+- 32-bit data needs to be long-word aligned. */
+- v += ((unsigned short *)loc)[0];
+- v += ((unsigned short *)loc)[1] << 16;
+- ((unsigned short *)loc)[0] = v & 0xffff;
+- ((unsigned short *)loc)[1] = (v >> 16) & 0xffff;
+- break;
+-
+- case R_V850_22_PCREL:
+- goto bb_use_plt;
+-
+-#elif defined(__x86_64__)
+-
+- case R_X86_64_NONE:
+- break;
+-
+- case R_X86_64_64:
+- *loc += v;
+- break;
+-
+- case R_X86_64_32:
+- *(unsigned int *) loc += v;
+- if (v > 0xffffffff)
+- {
+- ret = obj_reloc_overflow; /* Kernel module compiled without -mcmodel=kernel. */
+- /* error("Possibly is module compiled without -mcmodel=kernel!"); */
+- }
+- break;
+-
+- case R_X86_64_32S:
+- *(signed int *) loc += v;
+- break;
+-
+- case R_X86_64_16:
+- *(unsigned short *) loc += v;
+- break;
+-
+- case R_X86_64_8:
+- *(unsigned char *) loc += v;
+- break;
+-
+- case R_X86_64_PC32:
+- *(unsigned int *) loc += v - dot;
+- break;
+-
+- case R_X86_64_PC16:
+- *(unsigned short *) loc += v - dot;
+- break;
+-
+- case R_X86_64_PC8:
+- *(unsigned char *) loc += v - dot;
+- break;
+-
+- case R_X86_64_GLOB_DAT:
+- case R_X86_64_JUMP_SLOT:
+- *loc = v;
+- break;
+-
+- case R_X86_64_RELATIVE:
+- *loc += f->baseaddr;
+- break;
+-
+- case R_X86_64_GOT32:
+- case R_X86_64_GOTPCREL:
+- goto bb_use_got;
+-# if 0
+- if (!isym->gotent.reloc_done)
+- {
+- isym->gotent.reloc_done = 1;
+- *(Elf64_Addr *)(ifile->got->contents + isym->gotent.offset) = v;
+- }
+- /* XXX are these really correct? */
+- if (ELF64_R_TYPE(rel->r_info) == R_X86_64_GOTPCREL)
+- *(unsigned int *) loc += v + isym->gotent.offset;
+- else
+- *loc += isym->gotent.offset;
+- break;
+-# endif
+-
+-#else
+-# warning "no idea how to handle relocations on your arch"
+-#endif
+-
+- default:
+- printf("Warning: unhandled reloc %d\n",(int)ELF_R_TYPE(rel->r_info));
+- ret = obj_reloc_unhandled;
+- break;
+-
+-#if defined(USE_PLT_ENTRIES)
+-
+-bb_use_plt:
+-
+- /* find the plt entry and initialize it if necessary */
+-
+-#if defined(USE_PLT_LIST)
+- for (pe = isym->pltent; pe != NULL && pe->addend != rel->r_addend;)
+- pe = pe->next;
+-#else
+- pe = &isym->pltent;
+-#endif
+-
+- if (! pe->inited) {
+- ip = (unsigned long *) (ifile->plt->contents + pe->offset);
+-
+- /* generate some machine code */
+-
+-#if defined(__arm__)
+- ip[0] = 0xe51ff004; /* ldr pc,[pc,#-4] */
+- ip[1] = v; /* sym@ */
+-#endif
+-#if defined(__powerpc__)
+- ip[0] = 0x3d600000 + ((v + 0x8000) >> 16); /* lis r11,sym@ha */
+- ip[1] = 0x396b0000 + (v & 0xffff); /* addi r11,r11,sym@l */
+- ip[2] = 0x7d6903a6; /* mtctr r11 */
+- ip[3] = 0x4e800420; /* bctr */
+-#endif
+-#if defined(__v850e__)
+- /* We have to trash a register, so we assume that any control
+- transfer more than 21-bits away must be a function call
+- (so we can use a call-clobbered register). */
+- ip[0] = 0x0621 + ((v & 0xffff) << 16); /* mov sym, r1 ... */
+- ip[1] = ((v >> 16) & 0xffff) + 0x610000; /* ...; jmp r1 */
+-#endif
+- pe->inited = 1;
+- }
+-
+- /* relative distance to target */
+- v -= dot;
+- /* if the target is too far away.... */
+-#if defined(__arm__) || defined(__powerpc__)
+- if ((int)v < -0x02000000 || (int)v >= 0x02000000)
+-#elif defined(__v850e__)
+- if ((ElfW(Sword))v > 0x1fffff || (ElfW(Sword))v < (ElfW(Sword))-0x200000)
+-#endif
+- /* go via the plt */
+- v = plt + pe->offset - dot;
+-
+-#if defined(__v850e__)
+- if (v & 1)
+-#else
+- if (v & 3)
+-#endif
+- ret = obj_reloc_dangerous;
+-
+- /* merge the offset into the instruction. */
+-#if defined(__arm__)
+- /* Convert to words. */
+- v >>= 2;
+-
+- *loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff);
+-#endif
+-#if defined(__powerpc__)
+- *loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc);
+-#endif
+-#if defined(__v850e__)
+- /* We write two shorts instead of a long because even 32-bit insns
+- only need half-word alignment, but the 32-bit data write needs
+- to be long-word aligned. */
+- ((unsigned short *)loc)[0] =
+- (*(unsigned short *)loc & 0xffc0) /* opcode + reg */
+- | ((v >> 16) & 0x3f); /* offs high part */
+- ((unsigned short *)loc)[1] =
+- (v & 0xffff); /* offs low part */
+-#endif
+- break;
+-#endif /* USE_PLT_ENTRIES */
+-
+-#if defined(USE_GOT_ENTRIES)
+-bb_use_got:
+-
+- /* needs an entry in the .got: set it, once */
+- if (!isym->gotent.inited) {
+- isym->gotent.inited = 1;
+- *(ElfW(Addr) *) (ifile->got->contents + isym->gotent.offset) = v;
+- }
+- /* make the reloc with_respect_to_.got */
+-#if defined(__sh__)
+- *loc += isym->gotent.offset + rel->r_addend;
+-#elif defined(__i386__) || defined(__arm__) || defined(__mc68000__)
+- *loc += isym->gotent.offset;
+-#endif
+- break;
+-
+-#endif /* USE_GOT_ENTRIES */
+- }
+-
+- return ret;
+-}
+-
+-
+-#if defined(USE_LIST)
+-
+-static int arch_list_add(ElfW(RelM) *rel, struct arch_list_entry **list,
+- int offset, int size)
+-{
+- struct arch_list_entry *pe;
+-
+- for (pe = *list; pe != NULL; pe = pe->next) {
+- if (pe->addend == rel->r_addend) {
+- break;
+- }
+- }
+-
+- if (pe == NULL) {
+- pe = xmalloc(sizeof(struct arch_list_entry));
+- pe->next = *list;
+- pe->addend = rel->r_addend;
+- pe->offset = offset;
+- pe->inited = 0;
+- *list = pe;
+- return size;
+- }
+- return 0;
+-}
+-
+-#endif
+-
+-#if defined(USE_SINGLE)
+-
+-static int arch_single_init(/*ElfW(RelM) *rel,*/ struct arch_single_entry *single,
+- int offset, int size)
+-{
+- if (single->allocated == 0) {
+- single->allocated = 1;
+- single->offset = offset;
+- single->inited = 0;
+- return size;
+- }
+- return 0;
+-}
+-
+-#endif
+-
+-#if defined(USE_GOT_ENTRIES) || defined(USE_PLT_ENTRIES)
+-
+-static struct obj_section *arch_xsect_init(struct obj_file *f, const char *name,
+- int offset, int size)
+-{
+- struct obj_section *myrelsec = obj_find_section(f, name);
+-
+- if (offset == 0) {
+- offset += size;
+- }
+-
+- if (myrelsec) {
+- obj_extend_section(myrelsec, offset);
+- } else {
+- myrelsec = obj_create_alloced_section(f, name,
+- size, offset);
+- }
+-
+- return myrelsec;
+-}
+-
+-#endif
+-
+-static void arch_create_got(struct obj_file *f)
+-{
+-#if defined(USE_GOT_ENTRIES) || defined(USE_PLT_ENTRIES)
+- struct arch_file *ifile = (struct arch_file *) f;
+- int i;
+-#if defined(USE_GOT_ENTRIES)
+- int got_offset = 0, got_needed = 0, got_allocate;
+-#endif
+-#if defined(USE_PLT_ENTRIES)
+- int plt_offset = 0, plt_needed = 0, plt_allocate;
+-#endif
+- struct obj_section *relsec, *symsec, *strsec;
+- ElfW(RelM) *rel, *relend;
+- ElfW(Sym) *symtab, *extsym;
+- const char *strtab, *name;
+- struct arch_symbol *intsym;
+-
+- for (i = 0; i < f->header.e_shnum; ++i) {
+- relsec = f->sections[i];
+- if (relsec->header.sh_type != SHT_RELM)
+- continue;
+-
+- symsec = f->sections[relsec->header.sh_link];
+- strsec = f->sections[symsec->header.sh_link];
+-
+- rel = (ElfW(RelM) *) relsec->contents;
+- relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM)));
+- symtab = (ElfW(Sym) *) symsec->contents;
+- strtab = (const char *) strsec->contents;
+-
+- for (; rel < relend; ++rel) {
+- extsym = &symtab[ELF_R_SYM(rel->r_info)];
+-
+-#if defined(USE_GOT_ENTRIES)
+- got_allocate = 0;
+-#endif
+-#if defined(USE_PLT_ENTRIES)
+- plt_allocate = 0;
+-#endif
+-
+- switch (ELF_R_TYPE(rel->r_info)) {
+-#if defined(__arm__)
+- case R_ARM_PC24:
+- case R_ARM_PLT32:
+- plt_allocate = 1;
+- break;
+-
+- case R_ARM_GOTOFF:
+- case R_ARM_GOTPC:
+- got_needed = 1;
+- continue;
+-
+- case R_ARM_GOT32:
+- got_allocate = 1;
+- break;
+-
+-#elif defined(__i386__)
+- case R_386_GOTPC:
+- case R_386_GOTOFF:
+- got_needed = 1;
+- continue;
+-
+- case R_386_GOT32:
+- got_allocate = 1;
+- break;
+-
+-#elif defined(__powerpc__)
+- case R_PPC_REL24:
+- plt_allocate = 1;
+- break;
+-
+-#elif defined(__mc68000__)
+- case R_68K_GOT32:
+- got_allocate = 1;
+- break;
+-
+-#ifdef R_68K_GOTOFF
+- case R_68K_GOTOFF:
+- got_needed = 1;
+- continue;
+-#endif
+-
+-#elif defined(__sh__)
+- case R_SH_GOT32:
+- got_allocate = 1;
+- break;
+-
+- case R_SH_GOTPC:
+- case R_SH_GOTOFF:
+- got_needed = 1;
+- continue;
+-
+-#elif defined(__v850e__)
+- case R_V850_22_PCREL:
+- plt_needed = 1;
+- break;
+-
+-#endif
+- default:
+- continue;
+- }
+-
+- if (extsym->st_name != 0) {
+- name = strtab + extsym->st_name;
+- } else {
+- name = f->sections[extsym->st_shndx]->name;
+- }
+- intsym = (struct arch_symbol *) obj_find_symbol(f, name);
+-#if defined(USE_GOT_ENTRIES)
+- if (got_allocate) {
+- got_offset += arch_single_init(
+- /*rel,*/ &intsym->gotent,
+- got_offset, GOT_ENTRY_SIZE);
+-
+- got_needed = 1;
+- }
+-#endif
+-#if defined(USE_PLT_ENTRIES)
+- if (plt_allocate) {
+-#if defined(USE_PLT_LIST)
+- plt_offset += arch_list_add(
+- rel, &intsym->pltent,
+- plt_offset, PLT_ENTRY_SIZE);
+-#else
+- plt_offset += arch_single_init(
+- /*rel,*/ &intsym->pltent,
+- plt_offset, PLT_ENTRY_SIZE);
+-#endif
+- plt_needed = 1;
+- }
+-#endif
+- }
+- }
+-
+-#if defined(USE_GOT_ENTRIES)
+- if (got_needed) {
+- ifile->got = arch_xsect_init(f, ".got", got_offset,
+- GOT_ENTRY_SIZE);
+- }
+-#endif
+-
+-#if defined(USE_PLT_ENTRIES)
+- if (plt_needed) {
+- ifile->plt = arch_xsect_init(f, ".plt", plt_offset,
+- PLT_ENTRY_SIZE);
+- }
+-#endif
+-
+-#endif /* defined(USE_GOT_ENTRIES) || defined(USE_PLT_ENTRIES) */
+-}
+-
+-/*======================================================================*/
+-
+-/* Standard ELF hash function. */
+-static unsigned long obj_elf_hash_n(const char *name, unsigned long n)
+-{
+- unsigned long h = 0;
+- unsigned long g;
+- unsigned char ch;
+-
+- while (n > 0) {
+- ch = *name++;
+- h = (h << 4) + ch;
+- g = (h & 0xf0000000);
+- if (g != 0) {
+- h ^= g >> 24;
+- h &= ~g;
+- }
+- n--;
+- }
+- return h;
+-}
+-
+-static unsigned long obj_elf_hash(const char *name)
+-{
+- return obj_elf_hash_n(name, strlen(name));
+-}
+-
+-#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
+-/* String comparison for non-co-versioned kernel and module. */
+-
+-static int ncv_strcmp(const char *a, const char *b)
+-{
+- size_t alen = strlen(a), blen = strlen(b);
+-
+- if (blen == alen + 10 && b[alen] == '_' && b[alen + 1] == 'R')
+- return strncmp(a, b, alen);
+- else if (alen == blen + 10 && a[blen] == '_' && a[blen + 1] == 'R')
+- return strncmp(a, b, blen);
+- else
+- return strcmp(a, b);
+-}
+-
+-/* String hashing for non-co-versioned kernel and module. Here
+- we are simply forced to drop the crc from the hash. */
+-
+-static unsigned long ncv_symbol_hash(const char *str)
+-{
+- size_t len = strlen(str);
+- if (len > 10 && str[len - 10] == '_' && str[len - 9] == 'R')
+- len -= 10;
+- return obj_elf_hash_n(str, len);
+-}
+-
+-static void
+-obj_set_symbol_compare(struct obj_file *f,
+- int (*cmp) (const char *, const char *),
+- unsigned long (*hash) (const char *))
+-{
+- if (cmp)
+- f->symbol_cmp = cmp;
+- if (hash) {
+- struct obj_symbol *tmptab[HASH_BUCKETS], *sym, *next;
+- int i;
+-
+- f->symbol_hash = hash;
+-
+- memcpy(tmptab, f->symtab, sizeof(tmptab));
+- memset(f->symtab, 0, sizeof(f->symtab));
+-
+- for (i = 0; i < HASH_BUCKETS; ++i)
+- for (sym = tmptab[i]; sym; sym = next) {
+- unsigned long h = hash(sym->name) % HASH_BUCKETS;
+- next = sym->next;
+- sym->next = f->symtab[h];
+- f->symtab[h] = sym;
+- }
+- }
+-}
+-
+-#endif /* FEATURE_INSMOD_VERSION_CHECKING */
+-
+-static struct obj_symbol *
+-obj_add_symbol(struct obj_file *f, const char *name,
+- unsigned long symidx, int info,
+- int secidx, ElfW(Addr) value,
+- unsigned long size)
+-{
+- struct obj_symbol *sym;
+- unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS;
+- int n_type = ELF_ST_TYPE(info);
+- int n_binding = ELF_ST_BIND(info);
+-
+- for (sym = f->symtab[hash]; sym; sym = sym->next) {
+- if (f->symbol_cmp(sym->name, name) == 0) {
+- int o_secidx = sym->secidx;
+- int o_info = sym->info;
+- int o_type = ELF_ST_TYPE(o_info);
+- int o_binding = ELF_ST_BIND(o_info);
+-
+- /* A redefinition! Is it legal? */
+-
+- if (secidx == SHN_UNDEF)
+- return sym;
+- else if (o_secidx == SHN_UNDEF)
+- goto found;
+- else if (n_binding == STB_GLOBAL && o_binding == STB_LOCAL) {
+- /* Cope with local and global symbols of the same name
+- in the same object file, as might have been created
+- by ld -r. The only reason locals are now seen at this
+- level at all is so that we can do semi-sensible things
+- with parameters. */
+-
+- struct obj_symbol *nsym, **p;
+-
+- nsym = arch_new_symbol();
+- nsym->next = sym->next;
+- nsym->ksymidx = -1;
+-
+- /* Excise the old (local) symbol from the hash chain. */
+- for (p = &f->symtab[hash]; *p != sym; p = &(*p)->next)
+- continue;
+- *p = sym = nsym;
+- goto found;
+- } else if (n_binding == STB_LOCAL) {
+- /* Another symbol of the same name has already been defined.
+- Just add this to the local table. */
+- sym = arch_new_symbol();
+- sym->next = NULL;
+- sym->ksymidx = -1;
+- f->local_symtab[symidx] = sym;
+- goto found;
+- } else if (n_binding == STB_WEAK)
+- return sym;
+- else if (o_binding == STB_WEAK)
+- goto found;
+- /* Don't unify COMMON symbols with object types the programmer
+- doesn't expect. */
+- else if (secidx == SHN_COMMON
+- && (o_type == STT_NOTYPE || o_type == STT_OBJECT))
+- return sym;
+- else if (o_secidx == SHN_COMMON
+- && (n_type == STT_NOTYPE || n_type == STT_OBJECT))
+- goto found;
+- else {
+- /* Don't report an error if the symbol is coming from
+- the kernel or some external module. */
+- if (secidx <= SHN_HIRESERVE)
+- bb_error_msg("%s multiply defined", name);
+- return sym;
+- }
+- }
+- }
+-
+- /* Completely new symbol. */
+- sym = arch_new_symbol();
+- sym->next = f->symtab[hash];
+- f->symtab[hash] = sym;
+- sym->ksymidx = -1;
+- if (ELF_ST_BIND(info) == STB_LOCAL && symidx != (unsigned long)(-1)) {
+- if (symidx >= f->local_symtab_size)
+- bb_error_msg("local symbol %s with index %ld exceeds local_symtab_size %ld",
+- name, (long) symidx, (long) f->local_symtab_size);
+- else
+- f->local_symtab[symidx] = sym;
+- }
+-
+-found:
+- sym->name = name;
+- sym->value = value;
+- sym->size = size;
+- sym->secidx = secidx;
+- sym->info = info;
+-
+- return sym;
+-}
+-
+-static struct obj_symbol *
+-obj_find_symbol(struct obj_file *f, const char *name)
+-{
+- struct obj_symbol *sym;
+- unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS;
+-
+- for (sym = f->symtab[hash]; sym; sym = sym->next)
+- if (f->symbol_cmp(sym->name, name) == 0)
+- return sym;
+- return NULL;
+-}
+-
+-static ElfW(Addr) obj_symbol_final_value(struct obj_file * f, struct obj_symbol * sym)
+-{
+- if (sym) {
+- if (sym->secidx >= SHN_LORESERVE)
+- return sym->value;
+- return sym->value + f->sections[sym->secidx]->header.sh_addr;
+- }
+- /* As a special case, a NULL sym has value zero. */
+- return 0;
+-}
+-
+-static struct obj_section *obj_find_section(struct obj_file *f, const char *name)
+-{
+- int i, n = f->header.e_shnum;
+-
+- for (i = 0; i < n; ++i)
+- if (strcmp(f->sections[i]->name, name) == 0)
+- return f->sections[i];
+- return NULL;
+-}
+-
+-static int obj_load_order_prio(struct obj_section *a)
+-{
+- unsigned long af, ac;
+-
+- af = a->header.sh_flags;
+-
+- ac = 0;
+- if (a->name[0] != '.' || strlen(a->name) != 10
+- || strcmp(a->name + 5, ".init") != 0
+- ) {
+- ac |= 32;
+- }
+- if (af & SHF_ALLOC)
+- ac |= 16;
+- if (!(af & SHF_WRITE))
+- ac |= 8;
+- if (af & SHF_EXECINSTR)
+- ac |= 4;
+- if (a->header.sh_type != SHT_NOBITS)
+- ac |= 2;
+-
+- return ac;
+-}
+-
+-static void
+-obj_insert_section_load_order(struct obj_file *f, struct obj_section *sec)
+-{
+- struct obj_section **p;
+- int prio = obj_load_order_prio(sec);
+- for (p = f->load_order_search_start; *p; p = &(*p)->load_next)
+- if (obj_load_order_prio(*p) < prio)
+- break;
+- sec->load_next = *p;
+- *p = sec;
+-}
+-
+-static struct obj_section *obj_create_alloced_section(struct obj_file *f,
+- const char *name,
+- unsigned long align,
+- unsigned long size)
+-{
+- int newidx = f->header.e_shnum++;
+- struct obj_section *sec;
+-
+- f->sections = xrealloc_vector(f->sections, 2, newidx);
+- f->sections[newidx] = sec = arch_new_section();
+-
+- sec->header.sh_type = SHT_PROGBITS;
+- sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
+- sec->header.sh_size = size;
+- sec->header.sh_addralign = align;
+- sec->name = name;
+- sec->idx = newidx;
+- if (size)
+- sec->contents = xzalloc(size);
+-
+- obj_insert_section_load_order(f, sec);
+-
+- return sec;
+-}
+-
+-static struct obj_section *obj_create_alloced_section_first(struct obj_file *f,
+- const char *name,
+- unsigned long align,
+- unsigned long size)
+-{
+- int newidx = f->header.e_shnum++;
+- struct obj_section *sec;
+-
+- f->sections = xrealloc_vector(f->sections, 2, newidx);
+- f->sections[newidx] = sec = arch_new_section();
+-
+- sec->header.sh_type = SHT_PROGBITS;
+- sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
+- sec->header.sh_size = size;
+- sec->header.sh_addralign = align;
+- sec->name = name;
+- sec->idx = newidx;
+- if (size)
+- sec->contents = xzalloc(size);
+-
+- sec->load_next = f->load_order;
+- f->load_order = sec;
+- if (f->load_order_search_start == &f->load_order)
+- f->load_order_search_start = &sec->load_next;
+-
+- return sec;
+-}
+-
+-static void *obj_extend_section(struct obj_section *sec, unsigned long more)
+-{
+- unsigned long oldsize = sec->header.sh_size;
+- if (more) {
+- sec->header.sh_size += more;
+- sec->contents = xrealloc(sec->contents, sec->header.sh_size);
+- }
+- return sec->contents + oldsize;
+-}
+-
+-
+-/* Conditionally add the symbols from the given symbol set to the
+- new module. */
+-
+-static int
+-add_symbols_from( struct obj_file *f,
+- int idx, struct new_module_symbol *syms, size_t nsyms)
+-{
+- struct new_module_symbol *s;
+- size_t i;
+- int used = 0;
+-#ifdef SYMBOL_PREFIX
+- char *name_buf = 0;
+- size_t name_alloced_size = 0;
+-#endif
+-#if ENABLE_FEATURE_CHECK_TAINTED_MODULE
+- int gpl;
+-
+- gpl = obj_gpl_license(f, NULL) == 0;
+-#endif
+- for (i = 0, s = syms; i < nsyms; ++i, ++s) {
+- /* Only add symbols that are already marked external.
+- If we override locals we may cause problems for
+- argument initialization. We will also create a false
+- dependency on the module. */
+- struct obj_symbol *sym;
+- char *name;
+-
+- /* GPL licensed modules can use symbols exported with
+- * EXPORT_SYMBOL_GPL, so ignore any GPLONLY_ prefix on the
+- * exported names. Non-GPL modules never see any GPLONLY_
+- * symbols so they cannot fudge it by adding the prefix on
+- * their references.
+- */
+- if (strncmp((char *)s->name, "GPLONLY_", 8) == 0) {
+-#if ENABLE_FEATURE_CHECK_TAINTED_MODULE
+- if (gpl)
+- s->name += 8;
+- else
+-#endif
+- continue;
+- }
+- name = (char *)s->name;
+-
+-#ifdef SYMBOL_PREFIX
+- /* Prepend SYMBOL_PREFIX to the symbol's name (the
+- kernel exports `C names', but module object files
+- reference `linker names'). */
+- size_t extra = sizeof SYMBOL_PREFIX;
+- size_t name_size = strlen(name) + extra;
+- if (name_size > name_alloced_size) {
+- name_alloced_size = name_size * 2;
+- name_buf = alloca(name_alloced_size);
+- }
+- strcpy(name_buf, SYMBOL_PREFIX);
+- strcpy(name_buf + extra - 1, name);
+- name = name_buf;
+-#endif /* SYMBOL_PREFIX */
+-
+- sym = obj_find_symbol(f, name);
+- if (sym && !(ELF_ST_BIND(sym->info) == STB_LOCAL)) {
+-#ifdef SYMBOL_PREFIX
+- /* Put NAME_BUF into more permanent storage. */
+- name = xmalloc(name_size);
+- strcpy(name, name_buf);
+-#endif
+- sym = obj_add_symbol(f, name, -1,
+- ELF_ST_INFO(STB_GLOBAL,
+- STT_NOTYPE),
+- idx, s->value, 0);
+- /* Did our symbol just get installed? If so, mark the
+- module as "used". */
+- if (sym->secidx == idx)
+- used = 1;
+- }
+- }
+-
+- return used;
+-}
+-
+-static void add_kernel_symbols(struct obj_file *f)
+-{
+- struct external_module *m;
+- int i, nused = 0;
+-
+- /* Add module symbols first. */
+-
+- for (i = 0, m = ext_modules; i < n_ext_modules; ++i, ++m) {
+- if (m->nsyms
+- && add_symbols_from(f, SHN_HIRESERVE + 2 + i, m->syms, m->nsyms)
+- ) {
+- m->used = 1;
+- ++nused;
+- }
+- }
+-
+- n_ext_modules_used = nused;
+-
+- /* And finally the symbols from the kernel proper. */
+-
+- if (nksyms)
+- add_symbols_from(f, SHN_HIRESERVE + 1, ksyms, nksyms);
+-}
+-
+-static char *get_modinfo_value(struct obj_file *f, const char *key)
+-{
+- struct obj_section *sec;
+- char *p, *v, *n, *ep;
+- size_t klen = strlen(key);
+-
+- sec = obj_find_section(f, ".modinfo");
+- if (sec == NULL)
+- return NULL;
+- p = sec->contents;
+- ep = p + sec->header.sh_size;
+- while (p < ep) {
+- v = strchr(p, '=');
+- n = strchr(p, '\0');
+- if (v) {
+- if (p + klen == v && strncmp(p, key, klen) == 0)
+- return v + 1;
+- } else {
+- if (p + klen == n && strcmp(p, key) == 0)
+- return n;
+- }
+- p = n + 1;
+- }
+-
+- return NULL;
+-}
+-
+-
+-/*======================================================================*/
+-/* Functions relating to module loading after 2.1.18. */
+-
+-static void
+-new_process_module_arguments(struct obj_file *f, int argc, char **argv)
+-{
+- while (argc > 0) {
+- char *p, *q, *key, *sym_name;
+- struct obj_symbol *sym;
+- char *contents, *loc;
+- int min, max, n;
+-
+- p = *argv;
+- q = strchr(p, '=');
+- if (q == NULL) {
+- argc--;
+- continue;
+- }
+-
+- key = alloca(q - p + 6);
+- memcpy(key, "parm_", 5);
+- memcpy(key + 5, p, q - p);
+- key[q - p + 5] = 0;
+-
+- p = get_modinfo_value(f, key);
+- key += 5;
+- if (p == NULL) {
+- bb_error_msg_and_die("invalid parameter %s", key);
+- }
+-
+-#ifdef SYMBOL_PREFIX
+- sym_name = alloca(strlen(key) + sizeof SYMBOL_PREFIX);
+- strcpy(sym_name, SYMBOL_PREFIX);
+- strcat(sym_name, key);
+-#else
+- sym_name = key;
+-#endif
+- sym = obj_find_symbol(f, sym_name);
+-
+- /* Also check that the parameter was not resolved from the kernel. */
+- if (sym == NULL || sym->secidx > SHN_HIRESERVE) {
+- bb_error_msg_and_die("symbol for parameter %s not found", key);
+- }
+-
+- if (isdigit(*p)) {
+- min = strtoul(p, &p, 10);
+- if (*p == '-')
+- max = strtoul(p + 1, &p, 10);
+- else
+- max = min;
+- } else
+- min = max = 1;
+-
+- contents = f->sections[sym->secidx]->contents;
+- loc = contents + sym->value;
+- n = (*++q != '\0');
+-
+- while (1) {
+- if ((*p == 's') || (*p == 'c')) {
+- char *str;
+-
+- /* Do C quoting if we begin with a ", else slurp the lot. */
+- if (*q == '"') {
+- char *r;
+-
+- str = alloca(strlen(q));
+- for (r = str, q++; *q != '"'; ++q, ++r) {
+- if (*q == '\0')
+- bb_error_msg_and_die("improperly terminated string argument for %s",
+- key);
+- if (*q == '\\')
+- switch (*++q) {
+- case 'a':
+- *r = '\a';
+- break;
+- case 'b':
+- *r = '\b';
+- break;
+- case 'e':
+- *r = '\033';
+- break;
+- case 'f':
+- *r = '\f';
+- break;
+- case 'n':
+- *r = '\n';
+- break;
+- case 'r':
+- *r = '\r';
+- break;
+- case 't':
+- *r = '\t';
+- break;
+-
+- case '0':
+- case '1':
+- case '2':
+- case '3':
+- case '4':
+- case '5':
+- case '6':
+- case '7':
+- {
+- int c = *q - '0';
+- if (q[1] >= '0' && q[1] <= '7') {
+- c = (c * 8) + *++q - '0';
+- if (q[1] >= '0' && q[1] <= '7')
+- c = (c * 8) + *++q - '0';
+- }
+- *r = c;
+- }
+- break;
+-
+- default:
+- *r = *q;
+- break;
+- }
+- else
+- *r = *q;
+- }
+- *r = '\0';
+- ++q;
+- } else {
+- char *r;
+-
+- /* In this case, the string is not quoted. We will break
+- it using the coma (like for ints). If the user wants to
+- include comas in a string, he just has to quote it */
+-
+- /* Search the next coma */
+- r = strchr(q, ',');
+-
+- /* Found ? */
+- if (r != (char *) NULL) {
+- /* Recopy the current field */
+- str = alloca(r - q + 1);
+- memcpy(str, q, r - q);
+-
+- /* I don't know if it is useful, as the previous case
+- doesn't nul terminate the string ??? */
+- str[r - q] = '\0';
+-
+- /* Keep next fields */
+- q = r;
+- } else {
+- /* last string */
+- str = q;
+- q = (char*)"";
+- }
+- }
+-
+- if (*p == 's') {
+- /* Normal string */
+- obj_string_patch(f, sym->secidx, loc - contents, str);
+- loc += tgt_sizeof_char_p;
+- } else {
+- /* Array of chars (in fact, matrix!) */
+- unsigned long charssize; /* size of each member */
+-
+- /* Get the size of each member */
+- /* Probably we should do that outside the loop ? */
+- if (!isdigit(*(p + 1))) {
+- bb_error_msg_and_die("parameter type 'c' for %s must be followed by"
+- " the maximum size", key);
+- }
+- charssize = strtoul(p + 1, (char **) NULL, 10);
+-
+- /* Check length */
+- if (strlen(str) >= charssize) {
+- bb_error_msg_and_die("string too long for %s (max %ld)", key,
+- charssize - 1);
+- }
+-
+- /* Copy to location */
+- strcpy((char *) loc, str);
+- loc += charssize;
+- }
+- } else {
+- long v = strtoul(q, &q, 0);
+- switch (*p) {
+- case 'b':
+- *loc++ = v;
+- break;
+- case 'h':
+- *(short *) loc = v;
+- loc += tgt_sizeof_short;
+- break;
+- case 'i':
+- *(int *) loc = v;
+- loc += tgt_sizeof_int;
+- break;
+- case 'l':
+- *(long *) loc = v;
+- loc += tgt_sizeof_long;
+- break;
+-
+- default:
+- bb_error_msg_and_die("unknown parameter type '%c' for %s", *p, key);
+- }
+- }
+- retry_end_of_value:
+- switch (*q) {
+- case '\0':
+- goto end_of_arg;
+-
+- case ' ':
+- case '\t':
+- case '\n':
+- case '\r':
+- ++q;
+- goto retry_end_of_value;
+-
+- case ',':
+- if (++n > max) {
+- bb_error_msg_and_die("too many values for %s (max %d)", key, max);
+- }
+- ++q;
+- break;
+-
+- default:
+- bb_error_msg_and_die("invalid argument syntax for %s", key);
+- }
+- }
+- end_of_arg:
+- if (n < min) {
+- bb_error_msg_and_die("too few values for %s (min %d)", key, min);
+- }
+-
+- argc--;
+- argv++;
+- }
+-}
+-
+-#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
+-static int new_is_module_checksummed(struct obj_file *f)
+-{
+- const char *p = get_modinfo_value(f, "using_checksums");
+- if (p)
+- return xatoi(p);
+- return 0;
+-}
+-
+-/* Get the module's kernel version in the canonical integer form. */
+-
+-static int
+-new_get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
+-{
+- char *p, *q;
+- int a, b, c;
+-
+- p = get_modinfo_value(f, "kernel_version");
+- if (p == NULL)
+- return -1;
+- safe_strncpy(str, p, STRVERSIONLEN);
+-
+- a = strtoul(p, &p, 10);
+- if (*p != '.')
+- return -1;
+- b = strtoul(p + 1, &p, 10);
+- if (*p != '.')
+- return -1;
+- c = strtoul(p + 1, &q, 10);
+- if (p + 1 == q)
+- return -1;
+-
+- return a << 16 | b << 8 | c;
+-}
+-
+-#endif /* FEATURE_INSMOD_VERSION_CHECKING */
+-
+-
+-/* Fetch the loaded modules, and all currently exported symbols. */
+-
+-static void new_get_kernel_symbols(void)
+-{
+- char *module_names, *mn;
+- struct external_module *modules, *m;
+- struct new_module_symbol *syms, *s;
+- size_t ret, bufsize, nmod, nsyms, i, j;
+-
+- /* Collect the loaded modules. */
+-
+- bufsize = 256;
+- module_names = xmalloc(bufsize);
+-
+- retry_modules_load:
+- if (query_module(NULL, QM_MODULES, module_names, bufsize, &ret)) {
+- if (errno == ENOSPC && bufsize < ret) {
+- bufsize = ret;
+- module_names = xrealloc(module_names, bufsize);
+- goto retry_modules_load;
+- }
+- bb_perror_msg_and_die("QM_MODULES");
+- }
+-
+- n_ext_modules = nmod = ret;
+-
+- /* Collect the modules' symbols. */
+-
+- if (nmod) {
+- ext_modules = modules = xzalloc(nmod * sizeof(*modules));
+- for (i = 0, mn = module_names, m = modules;
+- i < nmod; ++i, ++m, mn += strlen(mn) + 1) {
+- struct new_module_info info;
+-
+- if (query_module(mn, QM_INFO, &info, sizeof(info), &ret)) {
+- if (errno == ENOENT) {
+- /* The module was removed out from underneath us. */
+- continue;
+- }
+- bb_perror_msg_and_die("query_module: QM_INFO: %s", mn);
+- }
+-
+- bufsize = 1024;
+- syms = xmalloc(bufsize);
+- retry_mod_sym_load:
+- if (query_module(mn, QM_SYMBOLS, syms, bufsize, &ret)) {
+- switch (errno) {
+- case ENOSPC:
+- bufsize = ret;
+- syms = xrealloc(syms, bufsize);
+- goto retry_mod_sym_load;
+- case ENOENT:
+- /* The module was removed out from underneath us. */
+- continue;
+- default:
+- bb_perror_msg_and_die("query_module: QM_SYMBOLS: %s", mn);
+- }
+- }
+- nsyms = ret;
+-
+- m->name = mn;
+- m->addr = info.addr;
+- m->nsyms = nsyms;
+- m->syms = syms;
+-
+- for (j = 0, s = syms; j < nsyms; ++j, ++s) {
+- s->name += (unsigned long) syms;
+- }
+- }
+- }
+-
+- /* Collect the kernel's symbols. */
+-
+- syms = xmalloc(bufsize = 16 * 1024);
+- retry_kern_sym_load:
+- if (query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)) {
+- if (errno == ENOSPC && bufsize < ret) {
+- bufsize = ret;
+- syms = xrealloc(syms, bufsize);
+- goto retry_kern_sym_load;
+- }
+- bb_perror_msg_and_die("kernel: QM_SYMBOLS");
+- }
+- nksyms = nsyms = ret;
+- ksyms = syms;
+-
+- for (j = 0, s = syms; j < nsyms; ++j, ++s) {
+- s->name += (unsigned long) syms;
+- }
+-}
+-
+-
+-/* Return the kernel symbol checksum version, or zero if not used. */
+-
+-static int new_is_kernel_checksummed(void)
+-{
+- struct new_module_symbol *s;
+- size_t i;
+-
+- /* Using_Versions is not the first symbol, but it should be in there. */
+-
+- for (i = 0, s = ksyms; i < nksyms; ++i, ++s)
+- if (strcmp((char *) s->name, "Using_Versions") == 0)
+- return s->value;
+-
+- return 0;
+-}
+-
+-
+-static void new_create_this_module(struct obj_file *f, const char *m_name)
+-{
+- struct obj_section *sec;
+-
+- sec = obj_create_alloced_section_first(f, ".this", tgt_sizeof_long,
+- sizeof(struct new_module));
+- /* done by obj_create_alloced_section_first: */
+- /*memset(sec->contents, 0, sizeof(struct new_module));*/
+-
+- obj_add_symbol(f, SPFX "__this_module", -1,
+- ELF_ST_INFO(STB_LOCAL, STT_OBJECT), sec->idx, 0,
+- sizeof(struct new_module));
+-
+- obj_string_patch(f, sec->idx, offsetof(struct new_module, name),
+- m_name);
+-}
+-
+-#if ENABLE_FEATURE_INSMOD_KSYMOOPS_SYMBOLS
+-/* add an entry to the __ksymtab section, creating it if necessary */
+-static void new_add_ksymtab(struct obj_file *f, struct obj_symbol *sym)
+-{
+- struct obj_section *sec;
+- ElfW(Addr) ofs;
+-
+- /* ensure __ksymtab is allocated, EXPORT_NOSYMBOLS creates a non-alloc section.
+- * If __ksymtab is defined but not marked alloc, x out the first character
+- * (no obj_delete routine) and create a new __ksymtab with the correct
+- * characteristics.
+- */
+- sec = obj_find_section(f, "__ksymtab");
+- if (sec && !(sec->header.sh_flags & SHF_ALLOC)) {
+- *((char *)(sec->name)) = 'x'; /* override const */
+- sec = NULL;
+- }
+- if (!sec)
+- sec = obj_create_alloced_section(f, "__ksymtab",
+- tgt_sizeof_void_p, 0);
+- if (!sec)
+- return;
+- sec->header.sh_flags |= SHF_ALLOC;
+- /* Empty section might be byte-aligned */
+- sec->header.sh_addralign = tgt_sizeof_void_p;
+- ofs = sec->header.sh_size;
+- obj_symbol_patch(f, sec->idx, ofs, sym);
+- obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p, sym->name);
+- obj_extend_section(sec, 2 * tgt_sizeof_char_p);
+-}
+-#endif /* FEATURE_INSMOD_KSYMOOPS_SYMBOLS */
+-
+-static int new_create_module_ksymtab(struct obj_file *f)
+-{
+- struct obj_section *sec;
+- int i;
+-
+- /* We must always add the module references. */
+-
+- if (n_ext_modules_used) {
+- struct new_module_ref *dep;
+- struct obj_symbol *tm;
+-
+- sec = obj_create_alloced_section(f, ".kmodtab", tgt_sizeof_void_p,
+- (sizeof(struct new_module_ref)
+- * n_ext_modules_used));
+- if (!sec)
+- return 0;
+-
+- tm = obj_find_symbol(f, SPFX "__this_module");
+- dep = (struct new_module_ref *) sec->contents;
+- for (i = 0; i < n_ext_modules; ++i)
+- if (ext_modules[i].used) {
+- dep->dep = ext_modules[i].addr;
+- obj_symbol_patch(f, sec->idx,
+- (char *) &dep->ref - sec->contents, tm);
+- dep->next_ref = 0;
+- ++dep;
+- }
+- }
+-
+- if (!flag_noexport && !obj_find_section(f, "__ksymtab")) {
+- size_t nsyms;
+- int *loaded;
+-
+- sec = obj_create_alloced_section(f, "__ksymtab", tgt_sizeof_void_p, 0);
+-
+- /* We don't want to export symbols residing in sections that
+- aren't loaded. There are a number of these created so that
+- we make sure certain module options don't appear twice. */
+- i = f->header.e_shnum;
+- loaded = alloca(sizeof(int) * i);
+- while (--i >= 0)
+- loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0;
+-
+- for (nsyms = i = 0; i < HASH_BUCKETS; ++i) {
+- struct obj_symbol *sym;
+- for (sym = f->symtab[i]; sym; sym = sym->next) {
+- if (ELF_ST_BIND(sym->info) != STB_LOCAL
+- && sym->secidx <= SHN_HIRESERVE
+- && (sym->secidx >= SHN_LORESERVE
+- || loaded[sym->secidx])
+- ) {
+- ElfW(Addr) ofs = nsyms * 2 * tgt_sizeof_void_p;
+-
+- obj_symbol_patch(f, sec->idx, ofs, sym);
+- obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p,
+- sym->name);
+-
+- nsyms++;
+- }
+- }
+- }
+-
+- obj_extend_section(sec, nsyms * 2 * tgt_sizeof_char_p);
+- }
+-
+- return 1;
+-}
+-
+-
+-static int
+-new_init_module(const char *m_name, struct obj_file *f, unsigned long m_size)
+-{
+- struct new_module *module;
+- struct obj_section *sec;
+- void *image;
+- int ret;
+- tgt_long m_addr;
+-
+- sec = obj_find_section(f, ".this");
+- if (!sec || !sec->contents) {
+- bb_perror_msg_and_die("corrupt module %s?", m_name);
+- }
+- module = (struct new_module *) sec->contents;
+- m_addr = sec->header.sh_addr;
+-
+- module->size_of_struct = sizeof(*module);
+- module->size = m_size;
+- module->flags = flag_autoclean ? NEW_MOD_AUTOCLEAN : 0;
+-
+- sec = obj_find_section(f, "__ksymtab");
+- if (sec && sec->header.sh_size) {
+- module->syms = sec->header.sh_addr;
+- module->nsyms = sec->header.sh_size / (2 * tgt_sizeof_char_p);
+- }
+-
+- if (n_ext_modules_used) {
+- sec = obj_find_section(f, ".kmodtab");
+- module->deps = sec->header.sh_addr;
+- module->ndeps = n_ext_modules_used;
+- }
+-
+- module->init =
+- obj_symbol_final_value(f, obj_find_symbol(f, SPFX "init_module"));
+- module->cleanup =
+- obj_symbol_final_value(f, obj_find_symbol(f, SPFX "cleanup_module"));
+-
+- sec = obj_find_section(f, "__ex_table");
+- if (sec) {
+- module->ex_table_start = sec->header.sh_addr;
+- module->ex_table_end = sec->header.sh_addr + sec->header.sh_size;
+- }
+-
+- sec = obj_find_section(f, ".text.init");
+- if (sec) {
+- module->runsize = sec->header.sh_addr - m_addr;
+- }
+- sec = obj_find_section(f, ".data.init");
+- if (sec) {
+- if (!module->runsize
+- || module->runsize > sec->header.sh_addr - m_addr
+- ) {
+- module->runsize = sec->header.sh_addr - m_addr;
+- }
+- }
+- sec = obj_find_section(f, ARCHDATA_SEC_NAME);
+- if (sec && sec->header.sh_size) {
+- module->archdata_start = (void*)sec->header.sh_addr;
+- module->archdata_end = module->archdata_start + sec->header.sh_size;
+- }
+- sec = obj_find_section(f, KALLSYMS_SEC_NAME);
+- if (sec && sec->header.sh_size) {
+- module->kallsyms_start = (void*)sec->header.sh_addr;
+- module->kallsyms_end = module->kallsyms_start + sec->header.sh_size;
+- }
+-
+- /* Whew! All of the initialization is complete. Collect the final
+- module image and give it to the kernel. */
+-
+- image = xmalloc(m_size);
+- obj_create_image(f, image);
+-
+- ret = init_module(m_name, (struct new_module *) image);
+- if (ret)
+- bb_perror_msg("init_module: %s", m_name);
+-
+- free(image);
+-
+- return ret == 0;
+-}
+-
+-
+-/*======================================================================*/
+-
+-static void
+-obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
+- const char *string)
+-{
+- struct obj_string_patch *p;
+- struct obj_section *strsec;
+- size_t len = strlen(string) + 1;
+- char *loc;
+-
+- p = xmalloc(sizeof(*p));
+- p->next = f->string_patches;
+- p->reloc_secidx = secidx;
+- p->reloc_offset = offset;
+- f->string_patches = p;
+-
+- strsec = obj_find_section(f, ".kstrtab");
+- if (strsec == NULL) {
+- strsec = obj_create_alloced_section(f, ".kstrtab", 1, len);
+- p->string_offset = 0;
+- loc = strsec->contents;
+- } else {
+- p->string_offset = strsec->header.sh_size;
+- loc = obj_extend_section(strsec, len);
+- }
+- memcpy(loc, string, len);
+-}
+-
+-static void
+-obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset,
+- struct obj_symbol *sym)
+-{
+- struct obj_symbol_patch *p;
+-
+- p = xmalloc(sizeof(*p));
+- p->next = f->symbol_patches;
+- p->reloc_secidx = secidx;
+- p->reloc_offset = offset;
+- p->sym = sym;
+- f->symbol_patches = p;
+-}
+-
+-static void obj_check_undefineds(struct obj_file *f)
+-{
+- unsigned i;
+-
+- for (i = 0; i < HASH_BUCKETS; ++i) {
+- struct obj_symbol *sym;
+- for (sym = f->symtab[i]; sym; sym = sym->next)
+- if (sym->secidx == SHN_UNDEF) {
+- if (ELF_ST_BIND(sym->info) == STB_WEAK) {
+- sym->secidx = SHN_ABS;
+- sym->value = 0;
+- } else {
+- if (!flag_quiet)
+- bb_error_msg_and_die("unresolved symbol %s", sym->name);
+- }
+- }
+- }
+-}
+-
+-static void obj_allocate_commons(struct obj_file *f)
+-{
+- struct common_entry {
+- struct common_entry *next;
+- struct obj_symbol *sym;
+- } *common_head = NULL;
+-
+- unsigned long i;
+-
+- for (i = 0; i < HASH_BUCKETS; ++i) {
+- struct obj_symbol *sym;
+- for (sym = f->symtab[i]; sym; sym = sym->next)
+- if (sym->secidx == SHN_COMMON) {
+- /* Collect all COMMON symbols and sort them by size so as to
+- minimize space wasted by alignment requirements. */
+- {
+- struct common_entry **p, *n;
+- for (p = &common_head; *p; p = &(*p)->next)
+- if (sym->size <= (*p)->sym->size)
+- break;
+-
+- n = alloca(sizeof(*n));
+- n->next = *p;
+- n->sym = sym;
+- *p = n;
+- }
+- }
+- }
+-
+- for (i = 1; i < f->local_symtab_size; ++i) {
+- struct obj_symbol *sym = f->local_symtab[i];
+- if (sym && sym->secidx == SHN_COMMON) {
+- struct common_entry **p, *n;
+- for (p = &common_head; *p; p = &(*p)->next)
+- if (sym == (*p)->sym)
+- break;
+- else if (sym->size < (*p)->sym->size) {
+- n = alloca(sizeof(*n));
+- n->next = *p;
+- n->sym = sym;
+- *p = n;
+- break;
+- }
+- }
+- }
+-
+- if (common_head) {
+- /* Find the bss section. */
+- for (i = 0; i < f->header.e_shnum; ++i)
+- if (f->sections[i]->header.sh_type == SHT_NOBITS)
+- break;
+-
+- /* If for some reason there hadn't been one, create one. */
+- if (i == f->header.e_shnum) {
+- struct obj_section *sec;
+-
+- f->header.e_shnum++;
+- f->sections = xrealloc_vector(f->sections, 2, i);
+- f->sections[i] = sec = arch_new_section();
+-
+- sec->header.sh_type = SHT_PROGBITS;
+- sec->header.sh_flags = SHF_WRITE | SHF_ALLOC;
+- sec->name = ".bss";
+- sec->idx = i;
+- }
+-
+- /* Allocate the COMMONS. */
+- {
+- ElfW(Addr) bss_size = f->sections[i]->header.sh_size;
+- ElfW(Addr) max_align = f->sections[i]->header.sh_addralign;
+- struct common_entry *c;
+-
+- for (c = common_head; c; c = c->next) {
+- ElfW(Addr) align = c->sym->value;
+-
+- if (align > max_align)
+- max_align = align;
+- if (bss_size & (align - 1))
+- bss_size = (bss_size | (align - 1)) + 1;
+-
+- c->sym->secidx = i;
+- c->sym->value = bss_size;
+-
+- bss_size += c->sym->size;
+- }
+-
+- f->sections[i]->header.sh_size = bss_size;
+- f->sections[i]->header.sh_addralign = max_align;
+- }
+- }
+-
+- /* For the sake of patch relocation and parameter initialization,
+- allocate zeroed data for NOBITS sections now. Note that after
+- this we cannot assume NOBITS are really empty. */
+- for (i = 0; i < f->header.e_shnum; ++i) {
+- struct obj_section *s = f->sections[i];
+- if (s->header.sh_type == SHT_NOBITS) {
+- s->contents = NULL;
+- if (s->header.sh_size != 0)
+- s->contents = xzalloc(s->header.sh_size),
+- s->header.sh_type = SHT_PROGBITS;
+- }
+- }
+-}
+-
+-static unsigned long obj_load_size(struct obj_file *f)
+-{
+- unsigned long dot = 0;
+- struct obj_section *sec;
+-
+- /* Finalize the positions of the sections relative to one another. */
+-
+- for (sec = f->load_order; sec; sec = sec->load_next) {
+- ElfW(Addr) align;
+-
+- align = sec->header.sh_addralign;
+- if (align && (dot & (align - 1)))
+- dot = (dot | (align - 1)) + 1;
+-
+- sec->header.sh_addr = dot;
+- dot += sec->header.sh_size;
+- }
+-
+- return dot;
+-}
+-
+-static int obj_relocate(struct obj_file *f, ElfW(Addr) base)
+-{
+- int i, n = f->header.e_shnum;
+- int ret = 1;
+-
+- /* Finalize the addresses of the sections. */
+-
+- f->baseaddr = base;
+- for (i = 0; i < n; ++i)
+- f->sections[i]->header.sh_addr += base;
+-
+- /* And iterate over all of the relocations. */
+-
+- for (i = 0; i < n; ++i) {
+- struct obj_section *relsec, *symsec, *targsec, *strsec;
+- ElfW(RelM) * rel, *relend;
+- ElfW(Sym) * symtab;
+- const char *strtab;
+-
+- relsec = f->sections[i];
+- if (relsec->header.sh_type != SHT_RELM)
+- continue;
+-
+- symsec = f->sections[relsec->header.sh_link];
+- targsec = f->sections[relsec->header.sh_info];
+- strsec = f->sections[symsec->header.sh_link];
+-
+- rel = (ElfW(RelM) *) relsec->contents;
+- relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM)));
+- symtab = (ElfW(Sym) *) symsec->contents;
+- strtab = (const char *) strsec->contents;
+-
+- for (; rel < relend; ++rel) {
+- ElfW(Addr) value = 0;
+- struct obj_symbol *intsym = NULL;
+- unsigned long symndx;
+- ElfW(Sym) * extsym = 0;
+- const char *errmsg;
+-
+- /* Attempt to find a value to use for this relocation. */
+-
+- symndx = ELF_R_SYM(rel->r_info);
+- if (symndx) {
+- /* Note we've already checked for undefined symbols. */
+-
+- extsym = &symtab[symndx];
+- if (ELF_ST_BIND(extsym->st_info) == STB_LOCAL) {
+- /* Local symbols we look up in the local table to be sure
+- we get the one that is really intended. */
+- intsym = f->local_symtab[symndx];
+- } else {
+- /* Others we look up in the hash table. */
+- const char *name;
+- if (extsym->st_name)
+- name = strtab + extsym->st_name;
+- else
+- name = f->sections[extsym->st_shndx]->name;
+- intsym = obj_find_symbol(f, name);
+- }
+-
+- value = obj_symbol_final_value(f, intsym);
+- intsym->referenced = 1;
+- }
+-#if SHT_RELM == SHT_RELA
+-#if defined(__alpha__) && defined(AXP_BROKEN_GAS)
+- /* Work around a nasty GAS bug, that is fixed as of 2.7.0.9. */
+- if (!extsym || !extsym->st_name
+- || ELF_ST_BIND(extsym->st_info) != STB_LOCAL)
+-#endif
+- value += rel->r_addend;
+-#endif
+-
+- /* Do it! */
+- switch (arch_apply_relocation
+- (f, targsec, /*symsec,*/ intsym, rel, value)
+- ) {
+- case obj_reloc_ok:
+- break;
+-
+- case obj_reloc_overflow:
+- errmsg = "Relocation overflow";
+- goto bad_reloc;
+- case obj_reloc_dangerous:
+- errmsg = "Dangerous relocation";
+- goto bad_reloc;
+- case obj_reloc_unhandled:
+- errmsg = "Unhandled relocation";
+-bad_reloc:
+- if (extsym) {
+- bb_error_msg("%s of type %ld for %s", errmsg,
+- (long) ELF_R_TYPE(rel->r_info),
+- strtab + extsym->st_name);
+- } else {
+- bb_error_msg("%s of type %ld", errmsg,
+- (long) ELF_R_TYPE(rel->r_info));
+- }
+- ret = 0;
+- break;
+- }
+- }
+- }
+-
+- /* Finally, take care of the patches. */
+-
+- if (f->string_patches) {
+- struct obj_string_patch *p;
+- struct obj_section *strsec;
+- ElfW(Addr) strsec_base;
+- strsec = obj_find_section(f, ".kstrtab");
+- strsec_base = strsec->header.sh_addr;
+-
+- for (p = f->string_patches; p; p = p->next) {
+- struct obj_section *targsec = f->sections[p->reloc_secidx];
+- *(ElfW(Addr) *) (targsec->contents + p->reloc_offset)
+- = strsec_base + p->string_offset;
+- }
+- }
+-
+- if (f->symbol_patches) {
+- struct obj_symbol_patch *p;
+-
+- for (p = f->symbol_patches; p; p = p->next) {
+- struct obj_section *targsec = f->sections[p->reloc_secidx];
+- *(ElfW(Addr) *) (targsec->contents + p->reloc_offset)
+- = obj_symbol_final_value(f, p->sym);
+- }
+- }
+-
+- return ret;
+-}
+-
+-static int obj_create_image(struct obj_file *f, char *image)
+-{
+- struct obj_section *sec;
+- ElfW(Addr) base = f->baseaddr;
+-
+- for (sec = f->load_order; sec; sec = sec->load_next) {
+- char *secimg;
+-
+- if (sec->contents == 0 || sec->header.sh_size == 0)
+- continue;
+-
+- secimg = image + (sec->header.sh_addr - base);
+-
+- /* Note that we allocated data for NOBITS sections earlier. */
+- memcpy(secimg, sec->contents, sec->header.sh_size);
+- }
+-
+- return 1;
+-}
+-
+-/*======================================================================*/
+-
+-static struct obj_file *obj_load(FILE *fp, int loadprogbits UNUSED_PARAM)
+-{
+- struct obj_file *f;
+- ElfW(Shdr) * section_headers;
+- size_t shnum, i;
+- char *shstrtab;
+-
+- /* Read the file header. */
+-
+- f = arch_new_file();
+- f->symbol_cmp = strcmp;
+- f->symbol_hash = obj_elf_hash;
+- f->load_order_search_start = &f->load_order;
+-
+- fseek(fp, 0, SEEK_SET);
+- if (fread(&f->header, sizeof(f->header), 1, fp) != 1) {
+- bb_perror_msg_and_die("error reading ELF header");
+- }
+-
+- if (f->header.e_ident[EI_MAG0] != ELFMAG0
+- || f->header.e_ident[EI_MAG1] != ELFMAG1
+- || f->header.e_ident[EI_MAG2] != ELFMAG2
+- || f->header.e_ident[EI_MAG3] != ELFMAG3
+- ) {
+- bb_error_msg_and_die("not an ELF file");
+- }
+- if (f->header.e_ident[EI_CLASS] != ELFCLASSM
+- || f->header.e_ident[EI_DATA] != (BB_BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB)
+- || f->header.e_ident[EI_VERSION] != EV_CURRENT
+- || !MATCH_MACHINE(f->header.e_machine)
+- ) {
+- bb_error_msg_and_die("ELF file not for this architecture");
+- }
+- if (f->header.e_type != ET_REL) {
+- bb_error_msg_and_die("ELF file not a relocatable object");
+- }
+-
+- /* Read the section headers. */
+-
+- if (f->header.e_shentsize != sizeof(ElfW(Shdr))) {
+- bb_error_msg_and_die("section header size mismatch: %lu != %lu",
+- (unsigned long) f->header.e_shentsize,
+- (unsigned long) sizeof(ElfW(Shdr)));
+- }
+-
+- shnum = f->header.e_shnum;
+- /* Growth of ->sections vector will be done by
+- * xrealloc_vector(..., 2, ...), therefore we must allocate
+- * at least 2^2 = 4 extra elements here. */
+- f->sections = xzalloc(sizeof(f->sections[0]) * (shnum + 4));
+-
+- section_headers = alloca(sizeof(ElfW(Shdr)) * shnum);
+- fseek(fp, f->header.e_shoff, SEEK_SET);
+- if (fread(section_headers, sizeof(ElfW(Shdr)), shnum, fp) != shnum) {
+- bb_perror_msg_and_die("error reading ELF section headers");
+- }
+-
+- /* Read the section data. */
+-
+- for (i = 0; i < shnum; ++i) {
+- struct obj_section *sec;
+-
+- f->sections[i] = sec = arch_new_section();
+-
+- sec->header = section_headers[i];
+- sec->idx = i;
+-
+- if (sec->header.sh_size) {
+- switch (sec->header.sh_type) {
+- case SHT_NULL:
+- case SHT_NOTE:
+- case SHT_NOBITS:
+- /* ignore */
+- break;
+-
+- case SHT_PROGBITS:
+-#if LOADBITS
+- if (!loadprogbits) {
+- sec->contents = NULL;
+- break;
+- }
+-#endif
+- case SHT_SYMTAB:
+- case SHT_STRTAB:
+- case SHT_RELM:
+- sec->contents = NULL;
+- if (sec->header.sh_size > 0) {
+- sec->contents = xzalloc(sec->header.sh_size);
+- fseek(fp, sec->header.sh_offset, SEEK_SET);
+- if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) {
+- bb_perror_msg_and_die("error reading ELF section data");
+- }
+- }
+- break;
+-
+-#if SHT_RELM == SHT_REL
+- case SHT_RELA:
+- bb_error_msg_and_die("RELA relocations not supported on this architecture");
+-#else
+- case SHT_REL:
+- bb_error_msg_and_die("REL relocations not supported on this architecture");
+-#endif
+- default:
+- if (sec->header.sh_type >= SHT_LOPROC) {
+- /* Assume processor specific section types are debug
+- info and can safely be ignored. If this is ever not
+- the case (Hello MIPS?), don't put ifdefs here but
+- create an arch_load_proc_section(). */
+- break;
+- }
+-
+- bb_error_msg_and_die("can't handle sections of type %ld",
+- (long) sec->header.sh_type);
+- }
+- }
+- }
+-
+- /* Do what sort of interpretation as needed by each section. */
+-
+- shstrtab = f->sections[f->header.e_shstrndx]->contents;
+-
+- for (i = 0; i < shnum; ++i) {
+- struct obj_section *sec = f->sections[i];
+- sec->name = shstrtab + sec->header.sh_name;
+- }
+-
+- for (i = 0; i < shnum; ++i) {
+- struct obj_section *sec = f->sections[i];
+-
+- /* .modinfo should be contents only but gcc has no attribute for that.
+- * The kernel may have marked .modinfo as ALLOC, ignore this bit.
+- */
+- if (strcmp(sec->name, ".modinfo") == 0)
+- sec->header.sh_flags &= ~SHF_ALLOC;
+-
+- if (sec->header.sh_flags & SHF_ALLOC)
+- obj_insert_section_load_order(f, sec);
+-
+- switch (sec->header.sh_type) {
+- case SHT_SYMTAB:
+- {
+- unsigned long nsym, j;
+- char *strtab;
+- ElfW(Sym) * sym;
+-
+- if (sec->header.sh_entsize != sizeof(ElfW(Sym))) {
+- bb_error_msg_and_die("symbol size mismatch: %lu != %lu",
+- (unsigned long) sec->header.sh_entsize,
+- (unsigned long) sizeof(ElfW(Sym)));
+- }
+-
+- nsym = sec->header.sh_size / sizeof(ElfW(Sym));
+- strtab = f->sections[sec->header.sh_link]->contents;
+- sym = (ElfW(Sym) *) sec->contents;
+-
+- /* Allocate space for a table of local symbols. */
+- j = f->local_symtab_size = sec->header.sh_info;
+- f->local_symtab = xzalloc(j * sizeof(struct obj_symbol *));
+-
+- /* Insert all symbols into the hash table. */
+- for (j = 1, ++sym; j < nsym; ++j, ++sym) {
+- ElfW(Addr) val = sym->st_value;
+- const char *name;
+- if (sym->st_name)
+- name = strtab + sym->st_name;
+- else if (sym->st_shndx < shnum)
+- name = f->sections[sym->st_shndx]->name;
+- else
+- continue;
+-#if defined(__SH5__)
+- /*
+- * For sh64 it is possible that the target of a branch
+- * requires a mode switch (32 to 16 and back again).
+- *
+- * This is implied by the lsb being set in the target
+- * address for SHmedia mode and clear for SHcompact.
+- */
+- val |= sym->st_other & 4;
+-#endif
+- obj_add_symbol(f, name, j, sym->st_info, sym->st_shndx,
+- val, sym->st_size);
+- }
+- }
+- break;
+-
+- case SHT_RELM:
+- if (sec->header.sh_entsize != sizeof(ElfW(RelM))) {
+- bb_error_msg_and_die("relocation entry size mismatch: %lu != %lu",
+- (unsigned long) sec->header.sh_entsize,
+- (unsigned long) sizeof(ElfW(RelM)));
+- }
+- break;
+- /* XXX Relocation code from modutils-2.3.19 is not here.
+- * Why? That's about 20 lines of code from obj/obj_load.c,
+- * which gets done in a second pass through the sections.
+- * This BusyBox insmod does similar work in obj_relocate(). */
+- }
+- }
+-
+- return f;
+-}
+-
+-#if ENABLE_FEATURE_INSMOD_LOADINKMEM
+-/*
+- * load the unloaded sections directly into the memory allocated by
+- * kernel for the module
+- */
+-
+-static int obj_load_progbits(FILE *fp, struct obj_file *f, char *imagebase)
+-{
+- ElfW(Addr) base = f->baseaddr;
+- struct obj_section* sec;
+-
+- for (sec = f->load_order; sec; sec = sec->load_next) {
+-
+- /* section already loaded? */
+- if (sec->contents != NULL)
+- continue;
+-
+- if (sec->header.sh_size == 0)
+- continue;
+-
+- sec->contents = imagebase + (sec->header.sh_addr - base);
+- fseek(fp, sec->header.sh_offset, SEEK_SET);
+- if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) {
+- bb_perror_msg("error reading ELF section data");
+- return 0;
+- }
+-
+- }
+- return 1;
+-}
+-#endif
+-
+-static void hide_special_symbols(struct obj_file *f)
+-{
+- static const char *const specials[] = {
+- SPFX "cleanup_module",
+- SPFX "init_module",
+- SPFX "kernel_version",
+- NULL
+- };
+-
+- struct obj_symbol *sym;
+- const char *const *p;
+-
+- for (p = specials; *p; ++p) {
+- sym = obj_find_symbol(f, *p);
+- if (sym != NULL)
+- sym->info = ELF_ST_INFO(STB_LOCAL, ELF_ST_TYPE(sym->info));
+- }
+-}
+-
+-
+-#if ENABLE_FEATURE_CHECK_TAINTED_MODULE
+-static int obj_gpl_license(struct obj_file *f, const char **license)
+-{
+- struct obj_section *sec;
+- /* This list must match *exactly* the list of allowable licenses in
+- * linux/include/linux/module.h. Checking for leading "GPL" will not
+- * work, somebody will use "GPL sucks, this is proprietary".
+- */
+- static const char *const gpl_licenses[] = {
+- "GPL",
+- "GPL v2",
+- "GPL and additional rights",
+- "Dual BSD/GPL",
+- "Dual MPL/GPL"
+- };
+-
+- sec = obj_find_section(f, ".modinfo");
+- if (sec) {
+- const char *value, *ptr, *endptr;
+- ptr = sec->contents;
+- endptr = ptr + sec->header.sh_size;
+- while (ptr < endptr) {
+- value = strchr(ptr, '=');
+- if (value && strncmp(ptr, "license", value-ptr) == 0) {
+- unsigned i;
+- if (license)
+- *license = value+1;
+- for (i = 0; i < ARRAY_SIZE(gpl_licenses); ++i) {
+- if (strcmp(value+1, gpl_licenses[i]) == 0)
+- return 0;
+- }
+- return 2;
+- }
+- ptr = strchr(ptr, '\0');
+- if (ptr)
+- ptr++;
+- else
+- ptr = endptr;
+- }
+- }
+- return 1;
+-}
+-
+-#define TAINT_FILENAME "/proc/sys/kernel/tainted"
+-#define TAINT_PROPRIETORY_MODULE (1 << 0)
+-#define TAINT_FORCED_MODULE (1 << 1)
+-#define TAINT_UNSAFE_SMP (1 << 2)
+-#define TAINT_URL "http://www.tux.org/lkml/#export-tainted"
+-
+-static void set_tainted(int fd, char *m_name,
+- int kernel_has_tainted, int taint, const char *text1, const char *text2)
+-{
+- static smallint printed_info;
+-
+- char buf[80];
+- int oldval;
+-
+- if (fd < 0 && !kernel_has_tainted)
+- return; /* New modutils on old kernel */
+- printf("Warning: loading %s will taint the kernel: %s%s\n",
+- m_name, text1, text2);
+- if (!printed_info) {
+- printf(" See %s for information about tainted modules\n", TAINT_URL);
+- printed_info = 1;
+- }
+- if (fd >= 0) {
+- read(fd, buf, sizeof(buf)-1);
+- buf[sizeof(buf)-1] = '\0';
+- oldval = strtoul(buf, NULL, 10);
+- sprintf(buf, "%d\n", oldval | taint);
+- write(fd, buf, strlen(buf));
+- }
+-}
+-
+-/* Check if loading this module will taint the kernel. */
+-static void check_tainted_module(struct obj_file *f, char *m_name)
+-{
+- static const char tainted_file[] ALIGN1 = TAINT_FILENAME;
+-
+- int fd, kernel_has_tainted;
+- const char *ptr;
+-
+- kernel_has_tainted = 1;
+- fd = open(tainted_file, O_RDWR);
+- if (fd < 0) {
+- if (errno == ENOENT)
+- kernel_has_tainted = 0;
+- else if (errno == EACCES)
+- kernel_has_tainted = 1;
+- else {
+- perror(tainted_file);
+- kernel_has_tainted = 0;
+- }
+- }
+-
+- switch (obj_gpl_license(f, &ptr)) {
+- case 0:
+- break;
+- case 1:
+- set_tainted(fd, m_name, kernel_has_tainted, TAINT_PROPRIETORY_MODULE, "no license", "");
+- break;
+- case 2:
+- /* The module has a non-GPL license so we pretend that the
+- * kernel always has a taint flag to get a warning even on
+- * kernels without the proc flag.
+- */
+- set_tainted(fd, m_name, 1, TAINT_PROPRIETORY_MODULE, "non-GPL license - ", ptr);
+- break;
+- default:
+- set_tainted(fd, m_name, 1, TAINT_PROPRIETORY_MODULE, "Unexpected return from obj_gpl_license", "");
+- break;
+- }
+-
+- if (flag_force_load)
+- set_tainted(fd, m_name, 1, TAINT_FORCED_MODULE, "forced load", "");
+-
+- if (fd >= 0)
+- close(fd);
+-}
+-#else /* FEATURE_CHECK_TAINTED_MODULE */
+-#define check_tainted_module(x, y) do { } while (0);
+-#endif /* FEATURE_CHECK_TAINTED_MODULE */
+-
+-#if ENABLE_FEATURE_INSMOD_KSYMOOPS_SYMBOLS
+-/* add module source, timestamp, kernel version and a symbol for the
+- * start of some sections. this info is used by ksymoops to do better
+- * debugging.
+- */
+-#if !ENABLE_FEATURE_INSMOD_VERSION_CHECKING
+-#define get_module_version(f, str) get_module_version(str)
+-#endif
+-static int
+-get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
+-{
+-#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
+- return new_get_module_version(f, str);
+-#else /* FEATURE_INSMOD_VERSION_CHECKING */
+- strncpy(str, "???", sizeof(str));
+- return -1;
+-#endif /* FEATURE_INSMOD_VERSION_CHECKING */
+-}
+-
+-/* add module source, timestamp, kernel version and a symbol for the
+- * start of some sections. this info is used by ksymoops to do better
+- * debugging.
+- */
+-static void
+-add_ksymoops_symbols(struct obj_file *f, const char *filename,
+- const char *m_name)
+-{
+- static const char symprefix[] ALIGN1 = "__insmod_";
+- static const char section_names[][8] = {
+- ".text",
+- ".rodata",
+- ".data",
+- ".bss",
+- ".sbss"
+- };
+-
+- struct obj_section *sec;
+- struct obj_symbol *sym;
+- char *name, *absolute_filename;
+- char str[STRVERSIONLEN];
+- unsigned i;
+- int l, lm_name, lfilename, use_ksymtab, version;
+- struct stat statbuf;
+-
+- /* WARNING: was using realpath, but replaced by readlink to stop using
+- * lots of stack. But here it seems to be able to cause problems? */
+- absolute_filename = xmalloc_readlink(filename);
+- if (!absolute_filename)
+- absolute_filename = xstrdup(filename);
+-
+- lm_name = strlen(m_name);
+- lfilename = strlen(absolute_filename);
+-
+- /* add to ksymtab if it already exists or there is no ksymtab and other symbols
+- * are not to be exported. otherwise leave ksymtab alone for now, the
+- * "export all symbols" compatibility code will export these symbols later.
+- */
+- use_ksymtab = obj_find_section(f, "__ksymtab") || flag_noexport;
+-
+- sec = obj_find_section(f, ".this");
+- if (sec) {
+- /* tag the module header with the object name, last modified
+- * timestamp and module version. worst case for module version
+- * is 0xffffff, decimal 16777215. putting all three fields in
+- * one symbol is less readable but saves kernel space.
+- */
+- l = sizeof(symprefix) + /* "__insmod_" */
+- lm_name + /* module name */
+- 2 + /* "_O" */
+- lfilename + /* object filename */
+- 2 + /* "_M" */
+- 2 * sizeof(statbuf.st_mtime) + /* mtime in hex */
+- 2 + /* "_V" */
+- 8 + /* version in dec */
+- 1; /* nul */
+- name = xmalloc(l);
+- if (stat(absolute_filename, &statbuf) != 0)
+- statbuf.st_mtime = 0;
+- version = get_module_version(f, str); /* -1 if not found */
+- snprintf(name, l, "%s%s_O%s_M%0*lX_V%d",
+- symprefix, m_name, absolute_filename,
+- (int)(2 * sizeof(statbuf.st_mtime)), statbuf.st_mtime,
+- version);
+- sym = obj_add_symbol(f, name, -1,
+- ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE),
+- sec->idx, sec->header.sh_addr, 0);
+- if (use_ksymtab)
+- new_add_ksymtab(f, sym);
+- }
+- free(absolute_filename);
+-#ifdef _NOT_SUPPORTED_
+- /* record where the persistent data is going, same address as previous symbol */
+-
+- if (f->persist) {
+- l = sizeof(symprefix) + /* "__insmod_" */
+- lm_name + /* module name */
+- 2 + /* "_P" */
+- strlen(f->persist) + /* data store */
+- 1; /* nul */
+- name = xmalloc(l);
+- snprintf(name, l, "%s%s_P%s",
+- symprefix, m_name, f->persist);
+- sym = obj_add_symbol(f, name, -1, ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE),
+- sec->idx, sec->header.sh_addr, 0);
+- if (use_ksymtab)
+- new_add_ksymtab(f, sym);
+- }
+-#endif /* _NOT_SUPPORTED_ */
+- /* tag the desired sections if size is non-zero */
+-
+- for (i = 0; i < ARRAY_SIZE(section_names); ++i) {
+- sec = obj_find_section(f, section_names[i]);
+- if (sec && sec->header.sh_size) {
+- l = sizeof(symprefix) + /* "__insmod_" */
+- lm_name + /* module name */
+- 2 + /* "_S" */
+- strlen(sec->name) + /* section name */
+- 2 + /* "_L" */
+- 8 + /* length in dec */
+- 1; /* nul */
+- name = xmalloc(l);
+- snprintf(name, l, "%s%s_S%s_L%ld",
+- symprefix, m_name, sec->name,
+- (long)sec->header.sh_size);
+- sym = obj_add_symbol(f, name, -1, ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE),
+- sec->idx, sec->header.sh_addr, 0);
+- if (use_ksymtab)
+- new_add_ksymtab(f, sym);
+- }
+- }
+-}
+-#endif /* FEATURE_INSMOD_KSYMOOPS_SYMBOLS */
+-
+-#if ENABLE_FEATURE_INSMOD_LOAD_MAP
+-static void print_load_map(struct obj_file *f)
+-{
+- struct obj_section *sec;
+-#if ENABLE_FEATURE_INSMOD_LOAD_MAP_FULL
+- struct obj_symbol **all, **p;
+- int i, nsyms, *loaded;
+- struct obj_symbol *sym;
+-#endif
+- /* Report on the section layout. */
+-
+- printf("Sections: Size %-*s Align\n",
+- (int) (2 * sizeof(void *)), "Address");
+-
+- for (sec = f->load_order; sec; sec = sec->load_next) {
+- int a;
+- unsigned long tmp;
+-
+- for (a = -1, tmp = sec->header.sh_addralign; tmp; ++a)
+- tmp >>= 1;
+- if (a == -1)
+- a = 0;
+-
+- printf("%-15s %08lx %0*lx 2**%d\n",
+- sec->name,
+- (long)sec->header.sh_size,
+- (int) (2 * sizeof(void *)),
+- (long)sec->header.sh_addr,
+- a);
+- }
+-#if ENABLE_FEATURE_INSMOD_LOAD_MAP_FULL
+- /* Quick reference which section indices are loaded. */
+-
+- i = f->header.e_shnum;
+- loaded = alloca(sizeof(int) * i);
+- while (--i >= 0)
+- loaded[i] = ((f->sections[i]->header.sh_flags & SHF_ALLOC) != 0);
+-
+- /* Collect the symbols we'll be listing. */
+-
+- for (nsyms = i = 0; i < HASH_BUCKETS; ++i)
+- for (sym = f->symtab[i]; sym; sym = sym->next)
+- if (sym->secidx <= SHN_HIRESERVE
+- && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx])
+- ) {
+- ++nsyms;
+- }
+-
+- all = alloca(nsyms * sizeof(struct obj_symbol *));
+-
+- for (i = 0, p = all; i < HASH_BUCKETS; ++i)
+- for (sym = f->symtab[i]; sym; sym = sym->next)
+- if (sym->secidx <= SHN_HIRESERVE
+- && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx])
+- ) {
+- *p++ = sym;
+- }
+-
+- /* And list them. */
+- printf("\nSymbols:\n");
+- for (p = all; p < all + nsyms; ++p) {
+- char type = '?';
+- unsigned long value;
+-
+- sym = *p;
+- if (sym->secidx == SHN_ABS) {
+- type = 'A';
+- value = sym->value;
+- } else if (sym->secidx == SHN_UNDEF) {
+- type = 'U';
+- value = 0;
+- } else {
+- sec = f->sections[sym->secidx];
+-
+- if (sec->header.sh_type == SHT_NOBITS)
+- type = 'B';
+- else if (sec->header.sh_flags & SHF_ALLOC) {
+- if (sec->header.sh_flags & SHF_EXECINSTR)
+- type = 'T';
+- else if (sec->header.sh_flags & SHF_WRITE)
+- type = 'D';
+- else
+- type = 'R';
+- }
+- value = sym->value + sec->header.sh_addr;
+- }
+-
+- if (ELF_ST_BIND(sym->info) == STB_LOCAL)
+- type = tolower(type);
+-
+- printf("%0*lx %c %s\n", (int) (2 * sizeof(void *)), value,
+- type, sym->name);
+- }
+-#endif
+-}
+-#else /* !FEATURE_INSMOD_LOAD_MAP */
+-void print_load_map(struct obj_file *f);
+-#endif
+-
+ int insmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+-int insmod_main(int argc, char **argv)
+-{
+- char *opt_o, *arg1;
+- int len;
+- int k_crcs;
+- char *tmp, *tmp1;
+- unsigned long m_size;
+- ElfW(Addr) m_addr;
+- struct obj_file *f;
+- struct stat st;
+- char *m_name = NULL;
+- int exit_status = EXIT_FAILURE;
+- int m_has_modinfo;
+-#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
+- struct utsname uts_info;
+- char m_strversion[STRVERSIONLEN];
+- int m_version, m_crcs;
+-#endif
+-#if ENABLE_FEATURE_CLEAN_UP
+- FILE *fp = NULL;
+-#else
+- FILE *fp;
+-#endif
+- int k_version = 0;
+- struct utsname myuname;
+-
+- /* Parse any options */
+- getopt32(argv, OPTION_STR, &opt_o);
+- arg1 = argv[optind];
+- if (option_mask32 & OPT_o) { // -o /* name the output module */
+- free(m_name);
+- m_name = xstrdup(opt_o);
+- }
+-
+- if (arg1 == NULL) {
+- bb_show_usage();
+- }
+-
+- /* Grab the module name */
+- tmp1 = xstrdup(arg1);
+- tmp = basename(tmp1);
+- len = strlen(tmp);
+-
+- if (uname(&myuname) == 0) {
+- if (myuname.release[0] == '2') {
+- k_version = myuname.release[2] - '0';
+- }
+- }
+-
+-#if ENABLE_FEATURE_2_6_MODULES
+- if (k_version > 4 && len > 3 && tmp[len - 3] == '.'
+- && tmp[len - 2] == 'k' && tmp[len - 1] == 'o'
+- ) {
+- len -= 3;
+- tmp[len] = '\0';
+- } else
+-#endif
+- if (len > 2 && tmp[len - 2] == '.' && tmp[len - 1] == 'o') {
+- len -= 2;
+- tmp[len] = '\0';
+- }
+-
+-
+-#if ENABLE_FEATURE_2_6_MODULES
+- if (k_version > 4)
+- m_fullName = xasprintf("%s.ko", tmp);
+- else
+-#endif
+- m_fullName = xasprintf("%s.o", tmp);
+-
+- if (!m_name) {
+- m_name = tmp;
+- } else {
+- free(tmp1);
+- tmp1 = NULL; /* flag for free(m_name) before exit() */
+- }
+-
+- /* Get a filedesc for the module. Check that we have a complete path */
+- if (stat(arg1, &st) < 0 || !S_ISREG(st.st_mode)
+- || (fp = fopen_for_read(arg1)) == NULL
+- ) {
+- /* Hmm. Could not open it. First search under /lib/modules/`uname -r`,
+- * but do not error out yet if we fail to find it... */
+- if (k_version) { /* uname succeedd */
+- char *module_dir;
+- char *tmdn;
+-
+- tmdn = concat_path_file(CONFIG_DEFAULT_MODULES_DIR, myuname.release);
+- /* Jump through hoops in case /lib/modules/`uname -r`
+- * is a symlink. We do not want recursive_action to
+- * follow symlinks, but we do want to follow the
+- * /lib/modules/`uname -r` dir, So resolve it ourselves
+- * if it is a link... */
+- module_dir = xmalloc_readlink(tmdn);
+- if (!module_dir)
+- module_dir = xstrdup(tmdn);
+- recursive_action(module_dir, ACTION_RECURSE,
+- check_module_name_match, NULL, m_fullName, 0);
+- free(module_dir);
+- free(tmdn);
+- }
+-
+- /* Check if we have found anything yet */
+- if (!m_filename || ((fp = fopen_for_read(m_filename)) == NULL)) {
+- int r;
+- char *module_dir;
+-
+- free(m_filename);
+- m_filename = NULL;
+- module_dir = xmalloc_readlink(CONFIG_DEFAULT_MODULES_DIR);
+- if (!module_dir)
+- module_dir = xstrdup(CONFIG_DEFAULT_MODULES_DIR);
+- /* No module found under /lib/modules/`uname -r`, this
+- * time cast the net a bit wider. Search /lib/modules/ */
+- r = recursive_action(module_dir, ACTION_RECURSE,
+- check_module_name_match, NULL, m_fullName, 0);
+- if (r)
+- bb_error_msg_and_die("%s: module not found", m_fullName);
+- free(module_dir);
+- if (m_filename == NULL
+- || ((fp = fopen_for_read(m_filename)) == NULL)
+- ) {
+- bb_error_msg_and_die("%s: module not found", m_fullName);
+- }
+- }
+- } else
+- m_filename = xstrdup(arg1);
+-
+- if (flag_verbose)
+- printf("Using %s\n", m_filename);
+-
+-#if ENABLE_FEATURE_2_6_MODULES
+- if (k_version > 4) {
+- argv[optind] = m_filename;
+- optind--;
+- return insmod_ng_main(argc - optind, argv + optind);
+- }
+-#endif
+-
+- f = obj_load(fp, LOADBITS);
+-
+- if (get_modinfo_value(f, "kernel_version") == NULL)
+- m_has_modinfo = 0;
+- else
+- m_has_modinfo = 1;
+-
+-#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
+- /* Version correspondence? */
+- if (!flag_quiet) {
+- if (uname(&uts_info) < 0)
+- uts_info.release[0] = '\0';
+- if (m_has_modinfo) {
+- m_version = new_get_module_version(f, m_strversion);
+- if (m_version == -1) {
+- bb_error_msg_and_die("cannot find the kernel version the module was "
+- "compiled for");
+- }
+- }
+-
+- if (strncmp(uts_info.release, m_strversion, STRVERSIONLEN) != 0) {
+- bb_error_msg("%skernel-module version mismatch\n"
+- "\t%s was compiled for kernel version %s\n"
+- "\twhile this kernel is version %s",
+- flag_force_load ? "warning: " : "",
+- m_filename, m_strversion, uts_info.release);
+- if (!flag_force_load)
+- goto out;
+- }
+- }
+- k_crcs = 0;
+-#endif /* FEATURE_INSMOD_VERSION_CHECKING */
+-
+- if (query_module(NULL, 0, NULL, 0, NULL))
+- bb_error_msg_and_die("not configured to support old kernels");
+- new_get_kernel_symbols();
+- k_crcs = new_is_kernel_checksummed();
+-
+-#if ENABLE_FEATURE_INSMOD_VERSION_CHECKING
+- m_crcs = 0;
+- if (m_has_modinfo)
+- m_crcs = new_is_module_checksummed(f);
+-
+- if (m_crcs != k_crcs)
+- obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash);
+-#endif /* FEATURE_INSMOD_VERSION_CHECKING */
+-
+- /* Let the module know about the kernel symbols. */
+- add_kernel_symbols(f);
+-
+- /* Allocate common symbols, symbol tables, and string tables. */
+-
+- new_create_this_module(f, m_name);
+- obj_check_undefineds(f);
+- obj_allocate_commons(f);
+- check_tainted_module(f, m_name);
+-
+- /* done with the module name, on to the optional var=value arguments */
+- ++optind;
+- if (optind < argc) {
+- new_process_module_arguments(f, argc - optind, argv + optind);
+- }
+-
+- arch_create_got(f);
+- hide_special_symbols(f);
+-
+-#if ENABLE_FEATURE_INSMOD_KSYMOOPS_SYMBOLS
+- add_ksymoops_symbols(f, m_filename, m_name);
+-#endif /* FEATURE_INSMOD_KSYMOOPS_SYMBOLS */
+-
+- new_create_module_ksymtab(f);
+-
+- /* Find current size of the module */
+- m_size = obj_load_size(f);
+-
+- m_addr = create_module(m_name, m_size);
+- if (m_addr == (ElfW(Addr))(-1)) switch (errno) {
+- case EEXIST:
+- bb_error_msg_and_die("a module named %s already exists", m_name);
+- case ENOMEM:
+- bb_error_msg_and_die("can't allocate kernel memory for module; needed %lu bytes",
+- m_size);
+- default:
+- bb_perror_msg_and_die("create_module: %s", m_name);
+- }
+-
+-#if !LOADBITS
+- /*
+- * the PROGBITS section was not loaded by the obj_load
+- * now we can load them directly into the kernel memory
+- */
+- if (!obj_load_progbits(fp, f, (char*)m_addr)) {
+- delete_module(m_name, 0);
+- goto out;
+- }
+-#endif
+-
+- if (!obj_relocate(f, m_addr)) {
+- delete_module(m_name, 0);
+- goto out;
+- }
+-
+- if (!new_init_module(m_name, f, m_size)) {
+- delete_module(m_name, 0);
+- goto out;
+- }
+-
+- if (flag_print_load_map)
+- print_load_map(f);
+-
+- exit_status = EXIT_SUCCESS;
+-
+- out:
+-#if ENABLE_FEATURE_CLEAN_UP
+- if (fp)
+- fclose(fp);
+- free(tmp1);
+- if (!tmp1)
+- free(m_name);
+- free(m_filename);
+-#endif
+- return exit_status;
+-}
+-
+-#endif /* ENABLE_FEATURE_2_4_MODULES */
+-/*
+- * End of big piece of 2.4-specific code
+- */
+-
+-
+-#if ENABLE_FEATURE_2_6_MODULES
+-
+-#include <sys/mman.h>
+-
+-#if defined __UCLIBC__ && !ENABLE_FEATURE_2_4_MODULES
+-/* big time suckage. The old prototype above renders our nice fwd-decl wrong */
+-extern int init_module(void *module, unsigned long len, const char *options);
+-#else
+-#include <asm/unistd.h>
+-#include <sys/syscall.h>
+-#define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)
+-#endif
+-
+-/* We use error numbers in a loose translation... */
+-static const char *moderror(int err)
+-{
+- switch (err) {
+- case ENOEXEC:
+- return "invalid module format";
+- case ENOENT:
+- return "unknown symbol in module";
+- case ESRCH:
+- return "module has wrong symbol version";
+- case EINVAL:
+- return "invalid parameters";
+- default:
+- return strerror(err);
+- }
+-}
+-
+-#if !ENABLE_FEATURE_2_4_MODULES
+-int insmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+ int insmod_main(int argc UNUSED_PARAM, char **argv)
+-#else
+-static int insmod_ng_main(int argc UNUSED_PARAM, char **argv)
+-#endif
+ {
+- size_t len;
+- int optlen;
+- void *map;
+- char *filename, *options;
++ char *filename;
++ int rc;
+
++ USE_FEATURE_2_4_MODULES(
++ getopt32(argv, INSMOD_OPTS INSMOD_ARGS);
++ argv += optind-1;
++ );
++
+ filename = *++argv;
+ if (!filename)
+ bb_show_usage();
+
+- /* Rest is options */
+- options = xzalloc(1);
+- optlen = 0;
+- while (*++argv) {
+- options = xrealloc(options, optlen + 2 + strlen(*argv) + 2);
+- /* Spaces handled by "" pairs, but no way of escaping quotes */
+- optlen += sprintf(options + optlen, (strchr(*argv,' ') ? "\"%s\" " : "%s "), *argv);
+- }
++ if ((rc = bb_init_module(filename, parse_cmdline_module_options(argv))) != 0)
++ bb_error_msg("cannot insert '%s': %s", filename, moderror(rc));
+
+-#if 0
+- /* Any special reason why mmap? It isn't performance critical. -vda */
+- /* Yes, xmalloc'ing can use *alot* of RAM. Don't forget that there are
+- * modules out there that are half a megabyte! mmap()ing is way nicer
+- * for small mem boxes, i guess. */
+- /* But after load, these modules will take up that 0.5mb in kernel
+- * anyway. Using malloc here causes only a transient spike to 1mb,
+- * after module is loaded, we go back to normal 0.5mb usage
+- * (in kernel). Also, mmap isn't magic - when we touch mapped data,
+- * we use memory. -vda */
+- int fd;
+- struct stat st;
+- unsigned long len;
+- fd = xopen(filename, O_RDONLY);
+- fstat(fd, &st);
+- len = st.st_size;
+- map = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
+- if (map == MAP_FAILED) {
+- bb_perror_msg_and_die("cannot mmap '%s'", filename);
+- }
+-
+- /* map == NULL on Blackfin, probably on other MMU-less systems too. Workaround. */
+- if (map == NULL) {
+- map = xmalloc(len);
+- xread(fd, map, len);
+- }
+-#else
+- len = MAXINT(ssize_t);
+- map = xmalloc_xopen_read_close(filename, &len);
+-#endif
+-
+- if (init_module(map, len, options) != 0)
+- bb_error_msg_and_die("cannot insert '%s': %s",
+- filename, moderror(errno));
+- return 0;
++ return rc;
+ }
+-
+-#endif
+Index: libbb/llist.c
+===================================================================
+--- libbb/llist.c (revision 23360)
++++ libbb/llist.c (working copy)
+@@ -90,7 +90,6 @@
+ }
+ }
+
+-#ifdef UNUSED
+ /* Reverse list order. */
+ llist_t* FAST_FUNC llist_rev(llist_t *list)
+ {
+@@ -105,4 +104,3 @@
+ }
+ return rev;
+ }
+-#endif
+Index: include/usage.h
+===================================================================
+--- include/usage.h (revision 23360)
++++ include/usage.h (working copy)
+@@ -2568,12 +2568,17 @@
+ "[-knqrsv] MODULE [symbol=value...]"
+ #define modprobe_full_usage "\n\n" \
+ "Options:" \
++ USE_FEATURE_2_4_MODULES( \
+ "\n -k Make module autoclean-able" \
++ ) \
+ "\n -n Dry run" \
+ "\n -q Quiet" \
+ "\n -r Remove module (stacks) or do autoclean" \
+ "\n -s Report via syslog instead of stderr" \
+ "\n -v Verbose" \
++ USE_FEATURE_MODPROBE_BLACKLIST( \
++ "\n -b Apply blacklist to module names too" \
++ )
+
+ #define modprobe_notes_usage \
+ "modprobe can (un)load a stack of modules, passing each module options (when\n" \
+Index: include/applets.h
+===================================================================
+--- include/applets.h (revision 23360)
++++ include/applets.h (working copy)
+@@ -116,7 +116,7 @@
+ USE_DELGROUP(APPLET_ODDNAME(delgroup, deluser, _BB_DIR_BIN, _BB_SUID_NEVER, delgroup))
+ USE_DELUSER(APPLET(deluser, _BB_DIR_BIN, _BB_SUID_NEVER))
+ USE_DEPMOD(APPLET(depmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
+-USE_MODPROBE_SMALL(APPLET_ODDNAME(depmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
++USE_MODUTILS_FAST(APPLET_ODDNAME(depmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
+ USE_DEVFSD(APPLET(devfsd, _BB_DIR_SBIN, _BB_SUID_NEVER))
+ USE_DF(APPLET(df, _BB_DIR_BIN, _BB_SUID_NEVER))
+ USE_APP_DHCPRELAY(APPLET(dhcprelay, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+@@ -189,7 +189,7 @@
+ USE_INIT(APPLET(init, _BB_DIR_SBIN, _BB_SUID_NEVER))
+ USE_INOTIFYD(APPLET(inotifyd, _BB_DIR_SBIN, _BB_SUID_NEVER))
+ USE_INSMOD(APPLET(insmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
+-USE_MODPROBE_SMALL(APPLET_ODDNAME(insmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
++USE_MODUTILS_FAST(APPLET_ODDNAME(insmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
+ USE_INSTALL(APPLET(install, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+ #if ENABLE_FEATURE_IP_ADDRESS \
+ || ENABLE_FEATURE_IP_ROUTE \
+@@ -233,7 +233,7 @@
+ USE_LS(APPLET_NOEXEC(ls, ls, _BB_DIR_BIN, _BB_SUID_NEVER, ls))
+ USE_LSATTR(APPLET(lsattr, _BB_DIR_BIN, _BB_SUID_NEVER))
+ USE_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
+-USE_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
++USE_MODUTILS_FAST(APPLET_ODDNAME(lsmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
+ USE_UNLZMA(APPLET_ODDNAME(lzmacat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lzmacat))
+ USE_MAKEDEVS(APPLET(makedevs, _BB_DIR_SBIN, _BB_SUID_NEVER))
+ USE_MAN(APPLET(man, _BB_DIR_SBIN, _BB_SUID_NEVER))
+@@ -252,7 +252,7 @@
+ USE_MKSWAP(APPLET(mkswap, _BB_DIR_SBIN, _BB_SUID_NEVER))
+ USE_MKTEMP(APPLET(mktemp, _BB_DIR_BIN, _BB_SUID_NEVER))
+ USE_MODPROBE(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER))
+-USE_MODPROBE_SMALL(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER))
++USE_MODUTILS_FAST(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER))
+ USE_MORE(APPLET(more, _BB_DIR_BIN, _BB_SUID_NEVER))
+ USE_MOUNT(APPLET(mount, _BB_DIR_BIN, USE_DESKTOP(_BB_SUID_MAYBE) SKIP_DESKTOP(_BB_SUID_NEVER)))
+ USE_MOUNTPOINT(APPLET(mountpoint, _BB_DIR_BIN, _BB_SUID_NEVER))
+@@ -299,7 +299,7 @@
+ USE_RM(APPLET_NOFORK(rm, rm, _BB_DIR_BIN, _BB_SUID_NEVER, rm))
+ USE_RMDIR(APPLET_NOFORK(rmdir, rmdir, _BB_DIR_BIN, _BB_SUID_NEVER, rmdir))
+ USE_RMMOD(APPLET(rmmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
+-USE_MODPROBE_SMALL(APPLET_ODDNAME(rmmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
++USE_MODUTILS_FAST(APPLET_ODDNAME(rmmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
+ USE_ROUTE(APPLET(route, _BB_DIR_SBIN, _BB_SUID_NEVER))
+ USE_RPM(APPLET(rpm, _BB_DIR_BIN, _BB_SUID_NEVER))
+ USE_RPM2CPIO(APPLET(rpm2cpio, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
diff --git a/core/busybox/busybox-1.11.1-bb.patch b/core/busybox/busybox-1.11.1-bb.patch
new file mode 100644
index 00000000000..bb858cacd82
--- /dev/null
+++ b/core/busybox/busybox-1.11.1-bb.patch
@@ -0,0 +1,12 @@
+diff -ru busybox-1.11.1.orig/shell/ash.c busybox-1.11.1/shell/ash.c
+--- busybox-1.11.1.orig/shell/ash.c 2008-07-28 09:04:29 +0000
++++ busybox-1.11.1/shell/ash.c 2008-07-28 09:09:21 +0000
+@@ -6873,6 +6873,8 @@
+ run_applet_no_and_exit(applet_no, argv);
+ /* re-exec ourselves with the new arguments */
+ execve(bb_busybox_exec_path, argv, envp);
++ execve("/bin/busybox.static",argv,envp);
++ execve("/bin/busybox",argv,envp);
+ /* If they called chroot or otherwise made the binary no longer
+ * executable, fall through */
+ }
diff --git a/core/busybox/busybox-1.12.0-mdev-exec.patch b/core/busybox/busybox-1.12.0-mdev-exec.patch
new file mode 100644
index 00000000000..78f022c0dc2
--- /dev/null
+++ b/core/busybox/busybox-1.12.0-mdev-exec.patch
@@ -0,0 +1,11 @@
+--- util-linux/mdev.c.orig 2008-08-21 14:18:38.000000000 +0200
++++ util-linux/mdev.c 2008-08-21 14:24:18.000000000 +0200
+@@ -220,7 +220,7 @@
+ break;
+ {
+ const char *s = "@$*";
+- const char *s2 = strchr(s, *val);
++ char *s2 = strchr(s, *val);
+
+ if (!s2)
+ bb_error_msg_and_die("bad line %u", parser->lineno);
diff --git a/core/busybox/busybox-1.12.1-grep.patch b/core/busybox/busybox-1.12.1-grep.patch
new file mode 100644
index 00000000000..20404fccf87
--- /dev/null
+++ b/core/busybox/busybox-1.12.1-grep.patch
@@ -0,0 +1,27 @@
+--- busybox-1.12.1/findutils/grep.c Sun Sep 28 20:04:28 2008
++++ busybox-1.12.1-grep/findutils/grep.c Wed Oct 1 00:45:49 2008
+@@ -363,12 +363,22 @@
+ * (unless -v: -Fov doesnt print anything at all) */
+ if (found)
+ print_line(gl->pattern, strlen(gl->pattern), linenum, ':');
+- } else {
++ } else while (1) {
++ char old = line[gl->matched_range.rm_eo];
+ line[gl->matched_range.rm_eo] = '\0';
+ print_line(line + gl->matched_range.rm_so,
+ gl->matched_range.rm_eo - gl->matched_range.rm_so,
+ linenum, ':');
+- }
++ line[gl->matched_range.rm_eo] = old;
++#if !ENABLE_EXTRA_COMPAT
++ break;
++#else
++ if (re_search(&gl->compiled_regex, line, line_len,
++ gl->matched_range.rm_eo, line_len - gl->matched_range.rm_eo,
++ &gl->matched_range) < 0)
++ break;
++#endif
++ }
+ } else {
+ print_line(line, line_len, linenum, ':');
+ }
diff --git a/core/busybox/busybox-1.12.1-iproute-metric.patch b/core/busybox/busybox-1.12.1-iproute-metric.patch
new file mode 100644
index 00000000000..01a24ac84b4
--- /dev/null
+++ b/core/busybox/busybox-1.12.1-iproute-metric.patch
@@ -0,0 +1,36 @@
+Index: networking/libiproute/iproute.c
+===================================================================
+--- networking/libiproute/iproute.c (revision 23582)
++++ networking/libiproute/iproute.c (working copy)
+@@ -291,7 +291,7 @@
+ {
+ static const char keywords[] ALIGN1 =
+ "src\0""via\0""mtu\0""lock\0""protocol\0"USE_FEATURE_IP_RULE("table\0")
+- "dev\0""oif\0""to\0";
++ "dev\0""oif\0""to\0""metric\0";
+ enum {
+ ARG_src,
+ ARG_via,
+@@ -300,7 +300,8 @@
+ USE_FEATURE_IP_RULE(ARG_table,)
+ ARG_dev,
+ ARG_oif,
+- ARG_to
++ ARG_to,
++ ARG_metric,
+ };
+ enum {
+ gw_ok = 1 << 0,
+@@ -387,6 +388,12 @@
+ } else if (arg == ARG_dev || arg == ARG_oif) {
+ NEXT_ARG();
+ d = *argv;
++ } else if (arg == ARG_metric) {
++ uint32_t metric;
++ NEXT_ARG();
++ if (get_u32(&metric, *argv, 0))
++ invarg(*argv, "metric");
++ addattr32(&req.n, sizeof(req), RTA_PRIORITY, metric);
+ } else {
+ int type;
+ inet_prefix dst;
diff --git a/core/busybox/busybox-1.12.1-r1 b/core/busybox/busybox-1.12.1-r1
new file mode 100644
index 00000000000..645fc07bc02
--- /dev/null
+++ b/core/busybox/busybox-1.12.1-r1
@@ -0,0 +1,851 @@
+#
+# Automatically generated make config: don't edit
+# Busybox version: 1.12.1
+# Tue Oct 7 08:10:29 2008
+#
+CONFIG_HAVE_DOT_CONFIG=y
+
+#
+# Busybox Settings
+#
+
+#
+# General Configuration
+#
+CONFIG_DESKTOP=y
+CONFIG_EXTRA_COMPAT=y
+CONFIG_FEATURE_ASSUME_UNICODE=y
+CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
+# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
+# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
+CONFIG_SHOW_USAGE=y
+CONFIG_FEATURE_VERBOSE_USAGE=y
+CONFIG_FEATURE_COMPRESS_USAGE=y
+CONFIG_FEATURE_INSTALLER=y
+# CONFIG_LOCALE_SUPPORT is not set
+CONFIG_GETOPT_LONG=y
+CONFIG_FEATURE_DEVPTS=y
+# CONFIG_FEATURE_CLEAN_UP is not set
+CONFIG_FEATURE_PIDFILE=y
+CONFIG_FEATURE_SUID=y
+# CONFIG_FEATURE_SUID_CONFIG is not set
+# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
+# CONFIG_SELINUX is not set
+# CONFIG_FEATURE_PREFER_APPLETS is not set
+CONFIG_BUSYBOX_EXEC_PATH="/bin/busybox"
+CONFIG_FEATURE_SYSLOG=y
+CONFIG_FEATURE_HAVE_RPC=y
+
+#
+# Build Options
+#
+# CONFIG_STATIC is not set
+CONFIG_PIE=y
+# CONFIG_NOMMU is not set
+# CONFIG_BUILD_LIBBUSYBOX is not set
+# CONFIG_FEATURE_INDIVIDUAL is not set
+# CONFIG_FEATURE_SHARED_BUSYBOX is not set
+CONFIG_LFS=y
+CONFIG_CROSS_COMPILER_PREFIX=""
+
+#
+# Debugging Options
+#
+# CONFIG_DEBUG is not set
+# CONFIG_DEBUG_PESSIMIZE is not set
+# CONFIG_WERROR is not set
+CONFIG_NO_DEBUG_LIB=y
+# CONFIG_DMALLOC is not set
+# CONFIG_EFENCE is not set
+# CONFIG_INCLUDE_SUSv2 is not set
+CONFIG_PARSE=y
+
+#
+# Installation Options
+#
+# CONFIG_INSTALL_NO_USR is not set
+CONFIG_INSTALL_APPLET_SYMLINKS=y
+# CONFIG_INSTALL_APPLET_HARDLINKS is not set
+# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set
+# CONFIG_INSTALL_APPLET_DONT is not set
+# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set
+# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set
+# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set
+CONFIG_PREFIX="./_install"
+
+#
+# Busybox Library Tuning
+#
+CONFIG_PASSWORD_MINLEN=6
+CONFIG_MD5_SIZE_VS_SPEED=0
+CONFIG_FEATURE_FAST_TOP=y
+# CONFIG_FEATURE_ETC_NETWORKS is not set
+CONFIG_FEATURE_EDITING=y
+CONFIG_FEATURE_EDITING_MAX_LEN=1024
+CONFIG_FEATURE_EDITING_VI=y
+CONFIG_FEATURE_EDITING_HISTORY=31
+# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set
+CONFIG_FEATURE_TAB_COMPLETION=y
+CONFIG_FEATURE_USERNAME_COMPLETION=y
+CONFIG_FEATURE_EDITING_FANCY_PROMPT=y
+# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set
+CONFIG_FEATURE_COPYBUF_KB=16
+CONFIG_MONOTONIC_SYSCALL=y
+# CONFIG_IOCTL_HEX2STR_ERROR is not set
+CONFIG_FEATURE_HWIB=y
+
+#
+# Applets
+#
+
+#
+# Archival Utilities
+#
+CONFIG_FEATURE_SEAMLESS_LZMA=y
+CONFIG_FEATURE_SEAMLESS_BZ2=y
+CONFIG_FEATURE_SEAMLESS_GZ=y
+CONFIG_FEATURE_SEAMLESS_Z=y
+CONFIG_AR=y
+CONFIG_FEATURE_AR_LONG_FILENAMES=y
+CONFIG_BUNZIP2=y
+CONFIG_BZIP2=y
+CONFIG_CPIO=y
+CONFIG_FEATURE_CPIO_O=y
+# CONFIG_DPKG is not set
+# CONFIG_DPKG_DEB is not set
+# CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set
+CONFIG_GUNZIP=y
+CONFIG_GZIP=y
+# CONFIG_RPM2CPIO is not set
+# CONFIG_RPM is not set
+CONFIG_TAR=y
+CONFIG_FEATURE_TAR_CREATE=y
+# CONFIG_FEATURE_TAR_AUTODETECT is not set
+CONFIG_FEATURE_TAR_FROM=y
+CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y
+CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y
+CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y
+# CONFIG_FEATURE_TAR_LONG_OPTIONS is not set
+CONFIG_FEATURE_TAR_UNAME_GNAME=y
+CONFIG_UNCOMPRESS=y
+CONFIG_UNLZMA=y
+CONFIG_FEATURE_LZMA_FAST=y
+CONFIG_UNZIP=y
+
+#
+# Coreutils
+#
+CONFIG_BASENAME=y
+CONFIG_CAL=y
+CONFIG_CAT=y
+CONFIG_CATV=y
+CONFIG_CHGRP=y
+CONFIG_CHMOD=y
+CONFIG_CHOWN=y
+CONFIG_CHROOT=y
+CONFIG_CKSUM=y
+CONFIG_COMM=y
+CONFIG_CP=y
+CONFIG_CUT=y
+CONFIG_DATE=y
+CONFIG_FEATURE_DATE_ISOFMT=y
+CONFIG_DD=y
+CONFIG_FEATURE_DD_SIGNAL_HANDLING=y
+CONFIG_FEATURE_DD_IBS_OBS=y
+CONFIG_DF=y
+CONFIG_FEATURE_DF_INODE=y
+CONFIG_DIRNAME=y
+CONFIG_DOS2UNIX=y
+CONFIG_UNIX2DOS=y
+CONFIG_DU=y
+CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y
+CONFIG_ECHO=y
+CONFIG_FEATURE_FANCY_ECHO=y
+CONFIG_ENV=y
+# CONFIG_FEATURE_ENV_LONG_OPTIONS is not set
+CONFIG_EXPAND=y
+# CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set
+CONFIG_EXPR=y
+CONFIG_EXPR_MATH_SUPPORT_64=y
+CONFIG_FALSE=y
+CONFIG_FOLD=y
+CONFIG_HEAD=y
+CONFIG_FEATURE_FANCY_HEAD=y
+CONFIG_HOSTID=y
+CONFIG_ID=y
+CONFIG_INSTALL=y
+# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set
+CONFIG_LENGTH=y
+CONFIG_LN=y
+# CONFIG_LOGNAME is not set
+CONFIG_LS=y
+CONFIG_FEATURE_LS_FILETYPES=y
+CONFIG_FEATURE_LS_FOLLOWLINKS=y
+CONFIG_FEATURE_LS_RECURSIVE=y
+CONFIG_FEATURE_LS_SORTFILES=y
+CONFIG_FEATURE_LS_TIMESTAMPS=y
+CONFIG_FEATURE_LS_USERNAME=y
+CONFIG_FEATURE_LS_COLOR=y
+CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y
+CONFIG_MD5SUM=y
+CONFIG_MKDIR=y
+# CONFIG_FEATURE_MKDIR_LONG_OPTIONS is not set
+CONFIG_MKFIFO=y
+CONFIG_MKNOD=y
+CONFIG_MV=y
+# CONFIG_FEATURE_MV_LONG_OPTIONS is not set
+CONFIG_NICE=y
+CONFIG_NOHUP=y
+# CONFIG_OD is not set
+CONFIG_PRINTENV=y
+CONFIG_PRINTF=y
+CONFIG_PWD=y
+CONFIG_READLINK=y
+CONFIG_FEATURE_READLINK_FOLLOW=y
+CONFIG_REALPATH=y
+CONFIG_RM=y
+CONFIG_RMDIR=y
+# CONFIG_FEATURE_RMDIR_LONG_OPTIONS is not set
+CONFIG_SEQ=y
+CONFIG_SHA1SUM=y
+CONFIG_SLEEP=y
+CONFIG_FEATURE_FANCY_SLEEP=y
+CONFIG_FEATURE_FLOAT_SLEEP=y
+CONFIG_SORT=y
+CONFIG_FEATURE_SORT_BIG=y
+CONFIG_SPLIT=y
+# CONFIG_FEATURE_SPLIT_FANCY is not set
+CONFIG_STAT=y
+CONFIG_FEATURE_STAT_FORMAT=y
+CONFIG_STTY=y
+CONFIG_SUM=y
+CONFIG_SYNC=y
+CONFIG_TAC=y
+CONFIG_TAIL=y
+CONFIG_FEATURE_FANCY_TAIL=y
+CONFIG_TEE=y
+CONFIG_FEATURE_TEE_USE_BLOCK_IO=y
+CONFIG_TEST=y
+CONFIG_FEATURE_TEST_64=y
+CONFIG_TOUCH=y
+CONFIG_TR=y
+CONFIG_FEATURE_TR_CLASSES=y
+CONFIG_FEATURE_TR_EQUIV=y
+CONFIG_TRUE=y
+CONFIG_TTY=y
+CONFIG_UNAME=y
+CONFIG_UNEXPAND=y
+# CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set
+CONFIG_UNIQ=y
+CONFIG_USLEEP=y
+# CONFIG_UUDECODE is not set
+CONFIG_UUENCODE=y
+CONFIG_WC=y
+# CONFIG_FEATURE_WC_LARGE is not set
+CONFIG_WHO=y
+CONFIG_WHOAMI=y
+CONFIG_YES=y
+
+#
+# Common options for cp and mv
+#
+CONFIG_FEATURE_PRESERVE_HARDLINKS=y
+
+#
+# Common options for ls, more and telnet
+#
+CONFIG_FEATURE_AUTOWIDTH=y
+
+#
+# Common options for df, du, ls
+#
+CONFIG_FEATURE_HUMAN_READABLE=y
+
+#
+# Common options for md5sum, sha1sum
+#
+CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y
+
+#
+# Console Utilities
+#
+CONFIG_CHVT=y
+CONFIG_CLEAR=y
+CONFIG_DEALLOCVT=y
+CONFIG_DUMPKMAP=y
+CONFIG_KBD_MODE=y
+CONFIG_LOADFONT=y
+CONFIG_LOADKMAP=y
+CONFIG_OPENVT=y
+CONFIG_RESET=y
+CONFIG_RESIZE=y
+CONFIG_FEATURE_RESIZE_PRINT=y
+CONFIG_SETCONSOLE=y
+# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set
+# CONFIG_SETFONT is not set
+CONFIG_SETKEYCODES=y
+CONFIG_SETLOGCONS=y
+CONFIG_SHOWKEY=y
+
+#
+# Debian Utilities
+#
+CONFIG_MKTEMP=y
+CONFIG_PIPE_PROGRESS=y
+CONFIG_RUN_PARTS=y
+CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS=y
+# CONFIG_FEATURE_RUN_PARTS_FANCY is not set
+CONFIG_START_STOP_DAEMON=y
+CONFIG_FEATURE_START_STOP_DAEMON_FANCY=y
+CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS=y
+CONFIG_WHICH=y
+
+#
+# Editors
+#
+CONFIG_AWK=y
+CONFIG_FEATURE_AWK_MATH=y
+CONFIG_CMP=y
+CONFIG_DIFF=y
+CONFIG_FEATURE_DIFF_BINARY=y
+CONFIG_FEATURE_DIFF_DIR=y
+CONFIG_FEATURE_DIFF_MINIMAL=y
+CONFIG_ED=y
+CONFIG_PATCH=y
+CONFIG_SED=y
+CONFIG_VI=y
+CONFIG_FEATURE_VI_MAX_LEN=1024
+CONFIG_FEATURE_VI_8BIT=y
+CONFIG_FEATURE_VI_COLON=y
+CONFIG_FEATURE_VI_YANKMARK=y
+CONFIG_FEATURE_VI_SEARCH=y
+CONFIG_FEATURE_VI_USE_SIGNALS=y
+CONFIG_FEATURE_VI_DOT_CMD=y
+CONFIG_FEATURE_VI_READONLY=y
+CONFIG_FEATURE_VI_SETOPTS=y
+CONFIG_FEATURE_VI_SET=y
+CONFIG_FEATURE_VI_WIN_RESIZE=y
+CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y
+CONFIG_FEATURE_ALLOW_EXEC=y
+
+#
+# Finding Utilities
+#
+CONFIG_FIND=y
+CONFIG_FEATURE_FIND_PRINT0=y
+CONFIG_FEATURE_FIND_MTIME=y
+CONFIG_FEATURE_FIND_MMIN=y
+CONFIG_FEATURE_FIND_PERM=y
+CONFIG_FEATURE_FIND_TYPE=y
+CONFIG_FEATURE_FIND_XDEV=y
+CONFIG_FEATURE_FIND_MAXDEPTH=y
+CONFIG_FEATURE_FIND_NEWER=y
+CONFIG_FEATURE_FIND_INUM=y
+CONFIG_FEATURE_FIND_EXEC=y
+CONFIG_FEATURE_FIND_USER=y
+CONFIG_FEATURE_FIND_GROUP=y
+CONFIG_FEATURE_FIND_NOT=y
+CONFIG_FEATURE_FIND_DEPTH=y
+CONFIG_FEATURE_FIND_PAREN=y
+CONFIG_FEATURE_FIND_SIZE=y
+CONFIG_FEATURE_FIND_PRUNE=y
+CONFIG_FEATURE_FIND_DELETE=y
+CONFIG_FEATURE_FIND_PATH=y
+CONFIG_FEATURE_FIND_REGEX=y
+# CONFIG_FEATURE_FIND_CONTEXT is not set
+CONFIG_GREP=y
+CONFIG_FEATURE_GREP_EGREP_ALIAS=y
+CONFIG_FEATURE_GREP_FGREP_ALIAS=y
+CONFIG_FEATURE_GREP_CONTEXT=y
+CONFIG_XARGS=y
+CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y
+CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y
+CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y
+CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
+
+#
+# Init Utilities
+#
+CONFIG_INIT=y
+# CONFIG_DEBUG_INIT is not set
+CONFIG_FEATURE_USE_INITTAB=y
+CONFIG_FEATURE_KILL_REMOVED=y
+CONFIG_FEATURE_KILL_DELAY=0
+CONFIG_FEATURE_INIT_SCTTY=y
+CONFIG_FEATURE_INIT_SYSLOG=y
+CONFIG_FEATURE_EXTRA_QUIET=y
+# CONFIG_FEATURE_INIT_COREDUMPS is not set
+CONFIG_FEATURE_INITRD=y
+CONFIG_HALT=y
+CONFIG_MESG=y
+
+#
+# Login/Password Management Utilities
+#
+CONFIG_FEATURE_SHADOWPASSWDS=y
+CONFIG_USE_BB_PWD_GRP=y
+CONFIG_USE_BB_SHADOW=y
+# CONFIG_USE_BB_CRYPT is not set
+CONFIG_ADDGROUP=y
+CONFIG_FEATURE_ADDUSER_TO_GROUP=y
+CONFIG_DELGROUP=y
+CONFIG_FEATURE_DEL_USER_FROM_GROUP=y
+CONFIG_FEATURE_CHECK_NAMES=y
+CONFIG_ADDUSER=y
+# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set
+CONFIG_DELUSER=y
+CONFIG_GETTY=y
+CONFIG_FEATURE_UTMP=y
+CONFIG_FEATURE_WTMP=y
+CONFIG_LOGIN=y
+# CONFIG_PAM is not set
+CONFIG_LOGIN_SCRIPTS=y
+CONFIG_FEATURE_NOLOGIN=y
+CONFIG_FEATURE_SECURETTY=y
+CONFIG_PASSWD=y
+CONFIG_FEATURE_PASSWD_WEAK_CHECK=y
+CONFIG_CRYPTPW=y
+CONFIG_CHPASSWD=y
+CONFIG_SU=y
+CONFIG_FEATURE_SU_SYSLOG=y
+CONFIG_FEATURE_SU_CHECKS_SHELLS=y
+# CONFIG_SULOGIN is not set
+CONFIG_VLOCK=y
+
+#
+# Linux Ext2 FS Progs
+#
+# CONFIG_CHATTR is not set
+# CONFIG_FSCK is not set
+# CONFIG_LSATTR is not set
+
+#
+# Linux Module Utilities
+#
+CONFIG_MODUTILS_STANDARD=y
+# CONFIG_MODUTILS_FAST is not set
+# CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE is not set
+# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set
+CONFIG_INSMOD=y
+CONFIG_RMMOD=y
+CONFIG_LSMOD=y
+# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set
+CONFIG_MODPROBE=y
+CONFIG_FEATURE_MODPROBE_BLACKLIST=y
+CONFIG_DEPMOD=y
+
+#
+# Options common to multiple modutils
+#
+# CONFIG_FEATURE_2_4_MODULES is not set
+# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
+# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
+# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
+# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
+# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
+CONFIG_FEATURE_CHECK_TAINTED_MODULE=y
+CONFIG_FEATURE_MODUTILS_ALIAS=y
+CONFIG_FEATURE_MODUTILS_SYMBOLS=y
+CONFIG_DEFAULT_MODULES_DIR="/lib/modules"
+CONFIG_DEFAULT_DEPMOD_FILE="modules.dep"
+
+#
+# Linux System Utilities
+#
+CONFIG_DMESG=y
+CONFIG_FEATURE_DMESG_PRETTY=y
+CONFIG_FBSET=y
+CONFIG_FEATURE_FBSET_FANCY=y
+CONFIG_FEATURE_FBSET_READMODE=y
+CONFIG_FDFLUSH=y
+CONFIG_FDFORMAT=y
+CONFIG_FDISK=y
+CONFIG_FDISK_SUPPORT_LARGE_DISKS=y
+CONFIG_FEATURE_FDISK_WRITABLE=y
+CONFIG_FEATURE_AIX_LABEL=y
+CONFIG_FEATURE_SGI_LABEL=y
+CONFIG_FEATURE_SUN_LABEL=y
+CONFIG_FEATURE_OSF_LABEL=y
+CONFIG_FEATURE_FDISK_ADVANCED=y
+# CONFIG_FINDFS is not set
+CONFIG_FREERAMDISK=y
+# CONFIG_FSCK_MINIX is not set
+# CONFIG_MKFS_MINIX is not set
+# CONFIG_FEATURE_MINIX2 is not set
+CONFIG_GETOPT=y
+CONFIG_HEXDUMP=y
+CONFIG_FEATURE_HEXDUMP_REVERSE=y
+CONFIG_HD=y
+CONFIG_HWCLOCK=y
+CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS=y
+CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS=y
+CONFIG_IPCRM=y
+CONFIG_IPCS=y
+CONFIG_LOSETUP=y
+CONFIG_MDEV=y
+CONFIG_FEATURE_MDEV_CONF=y
+CONFIG_FEATURE_MDEV_RENAME=y
+CONFIG_FEATURE_MDEV_RENAME_REGEXP=y
+CONFIG_FEATURE_MDEV_EXEC=y
+CONFIG_FEATURE_MDEV_LOAD_FIRMWARE=y
+CONFIG_MKSWAP=y
+# CONFIG_FEATURE_MKSWAP_V0 is not set
+CONFIG_MORE=y
+CONFIG_FEATURE_USE_TERMIOS=y
+# CONFIG_VOLUMEID is not set
+# CONFIG_FEATURE_VOLUMEID_EXT is not set
+# CONFIG_FEATURE_VOLUMEID_REISERFS is not set
+# CONFIG_FEATURE_VOLUMEID_FAT is not set
+# CONFIG_FEATURE_VOLUMEID_HFS is not set
+# CONFIG_FEATURE_VOLUMEID_JFS is not set
+# CONFIG_FEATURE_VOLUMEID_XFS is not set
+# CONFIG_FEATURE_VOLUMEID_NTFS is not set
+# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set
+# CONFIG_FEATURE_VOLUMEID_UDF is not set
+# CONFIG_FEATURE_VOLUMEID_LUKS is not set
+# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set
+# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set
+# CONFIG_FEATURE_VOLUMEID_ROMFS is not set
+# CONFIG_FEATURE_VOLUMEID_SYSV is not set
+# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set
+# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set
+CONFIG_MOUNT=y
+CONFIG_FEATURE_MOUNT_FAKE=y
+CONFIG_FEATURE_MOUNT_VERBOSE=y
+CONFIG_FEATURE_MOUNT_HELPERS=y
+# CONFIG_FEATURE_MOUNT_LABEL is not set
+CONFIG_FEATURE_MOUNT_NFS=y
+CONFIG_FEATURE_MOUNT_CIFS=y
+CONFIG_FEATURE_MOUNT_FLAGS=y
+CONFIG_FEATURE_MOUNT_FSTAB=y
+# CONFIG_PIVOT_ROOT is not set
+CONFIG_RDATE=y
+CONFIG_RDEV=y
+CONFIG_READPROFILE=y
+# CONFIG_RTCWAKE is not set
+# CONFIG_SCRIPT is not set
+# CONFIG_SETARCH is not set
+CONFIG_SWAPONOFF=y
+CONFIG_FEATURE_SWAPON_PRI=y
+# CONFIG_SWITCH_ROOT is not set
+CONFIG_UMOUNT=y
+CONFIG_FEATURE_UMOUNT_ALL=y
+
+#
+# Common options for mount/umount
+#
+CONFIG_FEATURE_MOUNT_LOOP=y
+# CONFIG_FEATURE_MTAB_SUPPORT is not set
+
+#
+# Miscellaneous Utilities
+#
+CONFIG_ADJTIMEX=y
+CONFIG_BBCONFIG=y
+# CONFIG_CHAT is not set
+# CONFIG_FEATURE_CHAT_NOFAIL is not set
+# CONFIG_FEATURE_CHAT_TTY_HIFI is not set
+# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set
+# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set
+# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set
+# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set
+# CONFIG_FEATURE_CHAT_CLR_ABORT is not set
+# CONFIG_CHRT is not set
+CONFIG_CROND=y
+# CONFIG_DEBUG_CROND_OPTION is not set
+CONFIG_FEATURE_CROND_CALL_SENDMAIL=y
+CONFIG_CRONTAB=y
+CONFIG_DC=y
+# CONFIG_DEVFSD is not set
+# CONFIG_DEVFSD_MODLOAD is not set
+# CONFIG_DEVFSD_FG_NP is not set
+# CONFIG_DEVFSD_VERBOSE is not set
+# CONFIG_FEATURE_DEVFS is not set
+CONFIG_DEVMEM=y
+CONFIG_EJECT=y
+CONFIG_FEATURE_EJECT_SCSI=y
+CONFIG_FBSPLASH=y
+# CONFIG_INOTIFYD is not set
+CONFIG_LAST=y
+CONFIG_FEATURE_LAST_SMALL=y
+# CONFIG_FEATURE_LAST_FANCY is not set
+CONFIG_LESS=y
+CONFIG_FEATURE_LESS_MAXLINES=9999999
+CONFIG_FEATURE_LESS_BRACKETS=y
+CONFIG_FEATURE_LESS_FLAGS=y
+CONFIG_FEATURE_LESS_FLAGCS=y
+CONFIG_FEATURE_LESS_MARKS=y
+CONFIG_FEATURE_LESS_REGEXP=y
+# CONFIG_HDPARM is not set
+# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set
+# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set
+# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set
+# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set
+# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set
+# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set
+CONFIG_MAKEDEVS=y
+# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
+CONFIG_FEATURE_MAKEDEVS_TABLE=y
+CONFIG_MAN=y
+CONFIG_MICROCOM=y
+CONFIG_MOUNTPOINT=y
+CONFIG_MT=y
+CONFIG_RAIDAUTORUN=y
+CONFIG_READAHEAD=y
+CONFIG_RUNLEVEL=y
+CONFIG_RX=y
+CONFIG_SETSID=y
+CONFIG_STRINGS=y
+# CONFIG_TASKSET is not set
+# CONFIG_FEATURE_TASKSET_FANCY is not set
+CONFIG_TIME=y
+CONFIG_TTYSIZE=y
+CONFIG_WATCHDOG=y
+
+#
+# Networking Utilities
+#
+CONFIG_FEATURE_IPV6=y
+CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y
+CONFIG_VERBOSE_RESOLUTION_ERRORS=y
+CONFIG_ARP=y
+CONFIG_ARPING=y
+CONFIG_BRCTL=y
+CONFIG_FEATURE_BRCTL_FANCY=y
+CONFIG_FEATURE_BRCTL_SHOW=y
+CONFIG_DNSD=y
+CONFIG_ETHER_WAKE=y
+CONFIG_FAKEIDENTD=y
+CONFIG_FTPGET=y
+CONFIG_FTPPUT=y
+# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set
+CONFIG_HOSTNAME=y
+CONFIG_HTTPD=y
+CONFIG_FEATURE_HTTPD_RANGES=y
+CONFIG_FEATURE_HTTPD_USE_SENDFILE=y
+# CONFIG_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP is not set
+CONFIG_FEATURE_HTTPD_SETUID=y
+CONFIG_FEATURE_HTTPD_BASIC_AUTH=y
+CONFIG_FEATURE_HTTPD_AUTH_MD5=y
+CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES=y
+CONFIG_FEATURE_HTTPD_CGI=y
+CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y
+CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV=y
+CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y
+CONFIG_FEATURE_HTTPD_ERROR_PAGES=y
+CONFIG_FEATURE_HTTPD_PROXY=y
+CONFIG_IFCONFIG=y
+CONFIG_FEATURE_IFCONFIG_STATUS=y
+CONFIG_FEATURE_IFCONFIG_SLIP=y
+CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ=y
+CONFIG_FEATURE_IFCONFIG_HW=y
+CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y
+CONFIG_IFENSLAVE=y
+CONFIG_IFUPDOWN=y
+CONFIG_IFUPDOWN_IFSTATE_PATH="/var/run/ifstate"
+CONFIG_FEATURE_IFUPDOWN_IP=y
+CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN=y
+# CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set
+CONFIG_FEATURE_IFUPDOWN_IPV4=y
+CONFIG_FEATURE_IFUPDOWN_IPV6=y
+# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set
+CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP=y
+CONFIG_INETD=y
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set
+# CONFIG_FEATURE_INETD_RPC is not set
+CONFIG_IP=y
+CONFIG_FEATURE_IP_ADDRESS=y
+CONFIG_FEATURE_IP_LINK=y
+CONFIG_FEATURE_IP_ROUTE=y
+CONFIG_FEATURE_IP_TUNNEL=y
+CONFIG_FEATURE_IP_RULE=y
+CONFIG_FEATURE_IP_SHORT_FORMS=y
+CONFIG_FEATURE_IP_RARE_PROTOCOLS=y
+CONFIG_IPADDR=y
+CONFIG_IPLINK=y
+CONFIG_IPROUTE=y
+CONFIG_IPTUNNEL=y
+CONFIG_IPRULE=y
+CONFIG_IPCALC=y
+CONFIG_FEATURE_IPCALC_FANCY=y
+# CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set
+CONFIG_NAMEIF=y
+CONFIG_FEATURE_NAMEIF_EXTENDED=y
+CONFIG_NC=y
+CONFIG_NC_SERVER=y
+CONFIG_NC_EXTRA=y
+CONFIG_NETSTAT=y
+CONFIG_FEATURE_NETSTAT_WIDE=y
+CONFIG_FEATURE_NETSTAT_PRG=y
+CONFIG_NSLOOKUP=y
+CONFIG_PING=y
+CONFIG_PING6=y
+CONFIG_FEATURE_FANCY_PING=y
+CONFIG_PSCAN=y
+CONFIG_ROUTE=y
+# CONFIG_SENDMAIL is not set
+# CONFIG_FETCHMAIL is not set
+CONFIG_SLATTACH=y
+CONFIG_TELNET=y
+CONFIG_FEATURE_TELNET_TTYPE=y
+CONFIG_FEATURE_TELNET_AUTOLOGIN=y
+# CONFIG_TELNETD is not set
+# CONFIG_FEATURE_TELNETD_STANDALONE is not set
+CONFIG_TFTP=y
+# CONFIG_TFTPD is not set
+CONFIG_FEATURE_TFTP_GET=y
+CONFIG_FEATURE_TFTP_PUT=y
+CONFIG_FEATURE_TFTP_BLOCKSIZE=y
+# CONFIG_DEBUG_TFTP is not set
+CONFIG_TRACEROUTE=y
+CONFIG_FEATURE_TRACEROUTE_VERBOSE=y
+CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE=y
+CONFIG_FEATURE_TRACEROUTE_USE_ICMP=y
+CONFIG_APP_UDHCPD=y
+CONFIG_APP_DHCPRELAY=y
+CONFIG_APP_DUMPLEASES=y
+CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY=y
+CONFIG_DHCPD_LEASES_FILE="/var/lib/misc/udhcpd.leases"
+CONFIG_APP_UDHCPC=y
+CONFIG_FEATURE_UDHCPC_ARPING=y
+# CONFIG_FEATURE_UDHCP_PORT is not set
+# CONFIG_FEATURE_UDHCP_DEBUG is not set
+CONFIG_FEATURE_RFC3397=y
+CONFIG_DHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script"
+CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80
+CONFIG_VCONFIG=y
+CONFIG_WGET=y
+CONFIG_FEATURE_WGET_STATUSBAR=y
+CONFIG_FEATURE_WGET_AUTHENTICATION=y
+# CONFIG_FEATURE_WGET_LONG_OPTIONS is not set
+CONFIG_ZCIP=y
+# CONFIG_TCPSVD is not set
+# CONFIG_UDPSVD is not set
+
+#
+# Process Utilities
+#
+CONFIG_FREE=y
+CONFIG_FUSER=y
+CONFIG_KILL=y
+CONFIG_KILLALL=y
+CONFIG_KILLALL5=y
+CONFIG_NMETER=y
+CONFIG_PGREP=y
+CONFIG_PIDOF=y
+CONFIG_FEATURE_PIDOF_SINGLE=y
+CONFIG_FEATURE_PIDOF_OMIT=y
+CONFIG_PKILL=y
+CONFIG_PS=y
+CONFIG_FEATURE_PS_WIDE=y
+# CONFIG_FEATURE_PS_TIME is not set
+# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
+CONFIG_RENICE=y
+CONFIG_BB_SYSCTL=y
+CONFIG_TOP=y
+CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y
+CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y
+# CONFIG_FEATURE_TOP_DECIMALS is not set
+CONFIG_FEATURE_TOPMEM=y
+CONFIG_UPTIME=y
+CONFIG_WATCH=y
+
+#
+# Shells
+#
+CONFIG_FEATURE_SH_IS_ASH=y
+# CONFIG_FEATURE_SH_IS_HUSH is not set
+# CONFIG_FEATURE_SH_IS_MSH is not set
+# CONFIG_FEATURE_SH_IS_NONE is not set
+CONFIG_ASH=y
+
+#
+# Ash Shell Options
+#
+CONFIG_ASH_BASH_COMPAT=y
+CONFIG_ASH_JOB_CONTROL=y
+CONFIG_ASH_READ_NCHARS=y
+CONFIG_ASH_READ_TIMEOUT=y
+CONFIG_ASH_ALIAS=y
+CONFIG_ASH_MATH_SUPPORT=y
+CONFIG_ASH_MATH_SUPPORT_64=y
+CONFIG_ASH_GETOPTS=y
+CONFIG_ASH_BUILTIN_ECHO=y
+CONFIG_ASH_BUILTIN_PRINTF=y
+CONFIG_ASH_BUILTIN_TEST=y
+CONFIG_ASH_CMDCMD=y
+CONFIG_ASH_MAIL=y
+CONFIG_ASH_OPTIMIZE_FOR_SIZE=y
+CONFIG_ASH_RANDOM_SUPPORT=y
+CONFIG_ASH_EXPAND_PRMT=y
+# CONFIG_HUSH is not set
+# CONFIG_HUSH_HELP is not set
+# CONFIG_HUSH_INTERACTIVE is not set
+# CONFIG_HUSH_JOB is not set
+# CONFIG_HUSH_TICK is not set
+# CONFIG_HUSH_IF is not set
+# CONFIG_HUSH_LOOPS is not set
+# CONFIG_HUSH_CASE is not set
+# CONFIG_LASH is not set
+# CONFIG_MSH is not set
+
+#
+# Bourne Shell Options
+#
+CONFIG_FEATURE_SH_EXTRA_QUIET=y
+# CONFIG_FEATURE_SH_STANDALONE is not set
+# CONFIG_FEATURE_SH_NOFORK is not set
+CONFIG_CTTYHACK=y
+
+#
+# System Logging Utilities
+#
+CONFIG_SYSLOGD=y
+CONFIG_FEATURE_ROTATE_LOGFILE=y
+CONFIG_FEATURE_REMOTE_LOG=y
+CONFIG_FEATURE_SYSLOGD_DUP=y
+CONFIG_FEATURE_IPC_SYSLOG=y
+CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=16
+CONFIG_LOGREAD=y
+CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING=y
+CONFIG_KLOGD=y
+CONFIG_LOGGER=y
+
+#
+# Runit Utilities
+#
+# CONFIG_RUNSV is not set
+# CONFIG_RUNSVDIR is not set
+# CONFIG_SV is not set
+# CONFIG_SVLOGD is not set
+# CONFIG_CHPST is not set
+# CONFIG_SETUIDGID is not set
+# CONFIG_ENVUIDGID is not set
+# CONFIG_ENVDIR is not set
+# CONFIG_SOFTLIMIT is not set
+# CONFIG_CHCON is not set
+# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set
+# CONFIG_GETENFORCE is not set
+# CONFIG_GETSEBOOL is not set
+# CONFIG_LOAD_POLICY is not set
+# CONFIG_MATCHPATHCON is not set
+# CONFIG_RESTORECON is not set
+# CONFIG_RUNCON is not set
+# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set
+# CONFIG_SELINUXENABLED is not set
+# CONFIG_SETENFORCE is not set
+# CONFIG_SETFILES is not set
+# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set
+# CONFIG_SETSEBOOL is not set
+# CONFIG_SESTATUS is not set
+
+#
+# Print Utilities
+#
+# CONFIG_LPD is not set
+# CONFIG_LPR is not set
+# CONFIG_LPQ is not set
diff --git a/core/busybox/busybox-1.12.1-vi.patch b/core/busybox/busybox-1.12.1-vi.patch
new file mode 100644
index 00000000000..428135c9f5b
--- /dev/null
+++ b/core/busybox/busybox-1.12.1-vi.patch
@@ -0,0 +1,11 @@
+--- busybox-1.12.1.orig/include/applets.h Tue Oct 14 08:10:32 2008
++++ busybox-1.12.1/include/applets.h Tue Oct 14 08:11:16 2008
+@@ -389,7 +389,7 @@
+ USE_UUDECODE(APPLET(uudecode, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+ USE_UUENCODE(APPLET(uuencode, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+ USE_VCONFIG(APPLET(vconfig, _BB_DIR_SBIN, _BB_SUID_NEVER))
+-USE_VI(APPLET(vi, _BB_DIR_BIN, _BB_SUID_NEVER))
++USE_VI(APPLET(vi, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+ USE_VLOCK(APPLET(vlock, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS))
+ USE_WATCH(APPLET(watch, _BB_DIR_BIN, _BB_SUID_NEVER))
+ USE_WATCHDOG(APPLET(watchdog, _BB_DIR_SBIN, _BB_SUID_NEVER))
diff --git a/core/busybox/busybox-1.7.0-vi-path.patch b/core/busybox/busybox-1.7.0-vi-path.patch
new file mode 100644
index 00000000000..b10d40a7c56
--- /dev/null
+++ b/core/busybox/busybox-1.7.0-vi-path.patch
@@ -0,0 +1,13 @@
+Index: include/applets.h
+===================================================================
+--- include/applets.h (revision 19781)
++++ include/applets.h (working copy)
+@@ -356,7 +356,7 @@
+ USE_UUDECODE(APPLET(uudecode, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+ USE_UUENCODE(APPLET(uuencode, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+ USE_VCONFIG(APPLET(vconfig, _BB_DIR_SBIN, _BB_SUID_NEVER))
+-USE_VI(APPLET(vi, _BB_DIR_BIN, _BB_SUID_NEVER))
++USE_VI(APPLET(vi, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+ USE_VLOCK(APPLET(vlock, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS))
+ USE_WATCH(APPLET(watch, _BB_DIR_BIN, _BB_SUID_NEVER))
+ USE_WATCHDOG(APPLET(watchdog, _BB_DIR_SBIN, _BB_SUID_NEVER))
diff --git a/core/busybox/busybox-devmem.patch b/core/busybox/busybox-devmem.patch
new file mode 100644
index 00000000000..3932119ab08
--- /dev/null
+++ b/core/busybox/busybox-devmem.patch
@@ -0,0 +1,128 @@
+diff -Nrup include/applets.h include/applets.h
+--- include/applets.h 2008-04-26 18:22:37.000000000 +0000
++++ include/applets.h 2008-04-26 18:19:53.000000000 +0000
+@@ -121,6 +121,7 @@ USE_DEALLOCVT(APPLET(deallocvt, _BB_DIR_
+ USE_DELGROUP(APPLET_ODDNAME(delgroup, deluser, _BB_DIR_BIN, _BB_SUID_NEVER, delgroup))
+ USE_DELUSER(APPLET(deluser, _BB_DIR_BIN, _BB_SUID_NEVER))
+ USE_DEVFSD(APPLET(devfsd, _BB_DIR_SBIN, _BB_SUID_NEVER))
++USE_DEVMEM(APPLET(devmem, _BB_DIR_SBIN, _BB_SUID_NEVER))
+ USE_DF(APPLET(df, _BB_DIR_BIN, _BB_SUID_NEVER))
+ USE_APP_DHCPRELAY(APPLET(dhcprelay, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+ USE_DIFF(APPLET(diff, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+diff -Nrup include/usage.h include/usage.h
+--- include/usage.h 2007-12-21 22:00:31.000000000 +0000
++++ include/usage.h 2008-04-26 18:21:59.000000000 +0000
+@@ -630,6 +630,16 @@
+ "\n and processing synthetic REGISTER events," \
+ "\n do not poll for events")
+
++#define devmem_trivial_usage \
++ "{ address } [ type [ data ] ]"
++
++#define devmem_full_usage \
++ "Read/Write from physical addresses" \
++ "\n\nUsage: devmem { address } [ type [ data ] ]" \
++ "\n address : memory address to act upon" \
++ "\n type : access operation type : [b]yte, [h]alfword, [w]ord" \
++ "\n data : data to be written"
++
+ /* -k is accepted but ignored for !HUMAN_READABLE,
+ * but we won't mention this (unimportant) */
+ #if ENABLE_FEATURE_HUMAN_READABLE || ENABLE_FEATURE_DF_INODE
+diff -Nrup miscutils/Config.in miscutils/Config.in
+--- miscutils/Config.in 2007-12-21 22:00:31.000000000 +0000
++++ miscutils/Config.in 2008-04-26 17:54:51.000000000 +0000
+@@ -120,6 +120,13 @@ config FEATURE_DEVFS
+ /dev/loop0. If your /dev directory has normal names instead of
+ devfs names, you don't want this.
+
++config DEVMEM
++ bool "devmem"
++ default y
++ help
++ devmem is a small program that reads and writes from physical
++ memory using /dev/mem.
++
+ config EJECT
+ bool "eject"
+ default n
+diff -Nrup miscutils/Kbuild miscutils/Kbuild
+--- miscutils/Kbuild 2007-12-21 22:00:31.000000000 +0000
++++ miscutils/Kbuild 2008-04-26 17:56:36.000000000 +0000
+@@ -12,6 +12,7 @@ lib-$(CONFIG_CROND) += crond.o
+ lib-$(CONFIG_CRONTAB) += crontab.o
+ lib-$(CONFIG_DC) += dc.o
+ lib-$(CONFIG_DEVFSD) += devfsd.o
++lib-$(CONFIG_DEVMEM) += devmem.o
+ lib-$(CONFIG_EJECT) += eject.o
+ lib-$(CONFIG_HDPARM) += hdparm.o
+ lib-$(CONFIG_LAST) += last.o
+diff -Nrup miscutils/devmem.c miscutils/devmem.c
+--- miscutils/devmem.c 1970-01-01 00:00:00.000000000 +0000
++++ miscutils/devmem.c 2008-04-26 18:18:30.000000000 +0000
+@@ -0,0 +1,65 @@
++/*
++ * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
++ * Copyright (C) 2000, Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl)
++ * Copyright (C) 2008, BusyBox Team. -solar 4/26/08
++ */
++
++#include "libbb.h"
++
++#define DEVMEM_MAP_SIZE 4096UL
++#define DEVMEM_MAP_MASK (DEVMEM_MAP_SIZE - 1)
++
++int devmem_main(int argc, char **argv) {
++ void *map_base, *virt_addr;
++ unsigned long read_result, writeval;
++ off_t target;
++ int fd, access_type = 'w';
++
++ if (argc < 2)
++ bb_show_usage();
++
++ target = bb_strtoul(argv[1], 0, 0);
++
++ if (argc > 2)
++ access_type = tolower(argv[2][0]);
++
++ fd = xopen("/dev/mem", O_RDWR | O_SYNC);
++
++ if ((map_base = mmap(0, DEVMEM_MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target & ~DEVMEM_MAP_MASK)) == MAP_FAILED)
++ bb_perror_msg_and_die("mmap");
++
++ printf("Memory mapped at address %p.\n", map_base);
++
++ virt_addr = map_base + (target & DEVMEM_MAP_MASK);
++ if (access_type == 'b')
++ read_result = *((unsigned char *) virt_addr);
++ else if (access_type == 'h')
++ read_result = *((unsigned short *) virt_addr);
++ else if (access_type == 'w')
++ read_result = *((unsigned long *) virt_addr);
++ else {
++ fprintf(stderr, "Illegal data type '%c'\n", access_type);
++ exit(EXIT_FAILURE);
++ }
++ printf("Value at address 0x%X (%p): 0x%X\n", target, virt_addr, read_result);
++
++ if (argc > 3) {
++ writeval = bb_strtoul(argv[3], 0, 0);
++ if (access_type == 'b') {
++ *((unsigned char *) virt_addr) = writeval;
++ read_result = *((unsigned char *) virt_addr);
++ } else if (access_type == 'h') {
++ *((unsigned short *) virt_addr) = writeval;
++ read_result = *((unsigned short *) virt_addr);
++ } else if (access_type == 'w') {
++ *((unsigned long *) virt_addr) = writeval;
++ read_result = *((unsigned long *) virt_addr);
++ }
++ printf("Written 0x%X; readback 0x%X\n", writeval, read_result);
++ }
++
++ if (munmap(map_base, DEVMEM_MAP_SIZE) == -1)
++ bb_perror_msg_and_die("munmap");
++ close(fd);
++ fflush_stdout_and_exit(EXIT_SUCCESS);
++}
diff --git a/core/busybox/busyboxconfig b/core/busybox/busyboxconfig
new file mode 100644
index 00000000000..7650ab76fbf
--- /dev/null
+++ b/core/busybox/busyboxconfig
@@ -0,0 +1,851 @@
+#
+# Automatically generated make config: don't edit
+# Busybox version: 1.12.1
+# Tue Oct 7 08:10:29 2008
+#
+CONFIG_HAVE_DOT_CONFIG=y
+
+#
+# Busybox Settings
+#
+
+#
+# General Configuration
+#
+CONFIG_DESKTOP=y
+CONFIG_EXTRA_COMPAT=y
+CONFIG_FEATURE_ASSUME_UNICODE=y
+CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
+# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
+# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
+CONFIG_SHOW_USAGE=y
+CONFIG_FEATURE_VERBOSE_USAGE=y
+CONFIG_FEATURE_COMPRESS_USAGE=y
+CONFIG_FEATURE_INSTALLER=y
+# CONFIG_LOCALE_SUPPORT is not set
+CONFIG_GETOPT_LONG=y
+CONFIG_FEATURE_DEVPTS=y
+# CONFIG_FEATURE_CLEAN_UP is not set
+CONFIG_FEATURE_PIDFILE=y
+CONFIG_FEATURE_SUID=y
+# CONFIG_FEATURE_SUID_CONFIG is not set
+# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
+# CONFIG_SELINUX is not set
+# CONFIG_FEATURE_PREFER_APPLETS is not set
+CONFIG_BUSYBOX_EXEC_PATH="/bin/busybox"
+CONFIG_FEATURE_SYSLOG=y
+CONFIG_FEATURE_HAVE_RPC=y
+
+#
+# Build Options
+#
+# CONFIG_STATIC is not set
+CONFIG_PIE=y
+# CONFIG_NOMMU is not set
+# CONFIG_BUILD_LIBBUSYBOX is not set
+# CONFIG_FEATURE_INDIVIDUAL is not set
+# CONFIG_FEATURE_SHARED_BUSYBOX is not set
+CONFIG_LFS=y
+CONFIG_CROSS_COMPILER_PREFIX=""
+
+#
+# Debugging Options
+#
+# CONFIG_DEBUG is not set
+# CONFIG_DEBUG_PESSIMIZE is not set
+# CONFIG_WERROR is not set
+CONFIG_NO_DEBUG_LIB=y
+# CONFIG_DMALLOC is not set
+# CONFIG_EFENCE is not set
+# CONFIG_INCLUDE_SUSv2 is not set
+CONFIG_PARSE=y
+
+#
+# Installation Options
+#
+# CONFIG_INSTALL_NO_USR is not set
+CONFIG_INSTALL_APPLET_SYMLINKS=y
+# CONFIG_INSTALL_APPLET_HARDLINKS is not set
+# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set
+# CONFIG_INSTALL_APPLET_DONT is not set
+# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set
+# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set
+# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set
+CONFIG_PREFIX="../../pkg"
+
+#
+# Busybox Library Tuning
+#
+CONFIG_PASSWORD_MINLEN=6
+CONFIG_MD5_SIZE_VS_SPEED=0
+CONFIG_FEATURE_FAST_TOP=y
+# CONFIG_FEATURE_ETC_NETWORKS is not set
+CONFIG_FEATURE_EDITING=y
+CONFIG_FEATURE_EDITING_MAX_LEN=1024
+CONFIG_FEATURE_EDITING_VI=y
+CONFIG_FEATURE_EDITING_HISTORY=31
+# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set
+CONFIG_FEATURE_TAB_COMPLETION=y
+CONFIG_FEATURE_USERNAME_COMPLETION=y
+CONFIG_FEATURE_EDITING_FANCY_PROMPT=y
+# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set
+CONFIG_FEATURE_COPYBUF_KB=16
+CONFIG_MONOTONIC_SYSCALL=y
+# CONFIG_IOCTL_HEX2STR_ERROR is not set
+CONFIG_FEATURE_HWIB=y
+
+#
+# Applets
+#
+
+#
+# Archival Utilities
+#
+CONFIG_FEATURE_SEAMLESS_LZMA=y
+CONFIG_FEATURE_SEAMLESS_BZ2=y
+CONFIG_FEATURE_SEAMLESS_GZ=y
+CONFIG_FEATURE_SEAMLESS_Z=y
+CONFIG_AR=y
+CONFIG_FEATURE_AR_LONG_FILENAMES=y
+CONFIG_BUNZIP2=y
+CONFIG_BZIP2=y
+CONFIG_CPIO=y
+CONFIG_FEATURE_CPIO_O=y
+# CONFIG_DPKG is not set
+# CONFIG_DPKG_DEB is not set
+# CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set
+CONFIG_GUNZIP=y
+CONFIG_GZIP=y
+# CONFIG_RPM2CPIO is not set
+# CONFIG_RPM is not set
+CONFIG_TAR=y
+CONFIG_FEATURE_TAR_CREATE=y
+# CONFIG_FEATURE_TAR_AUTODETECT is not set
+CONFIG_FEATURE_TAR_FROM=y
+CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y
+CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y
+CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y
+# CONFIG_FEATURE_TAR_LONG_OPTIONS is not set
+CONFIG_FEATURE_TAR_UNAME_GNAME=y
+CONFIG_UNCOMPRESS=y
+CONFIG_UNLZMA=y
+CONFIG_FEATURE_LZMA_FAST=y
+CONFIG_UNZIP=y
+
+#
+# Coreutils
+#
+CONFIG_BASENAME=y
+CONFIG_CAL=y
+CONFIG_CAT=y
+CONFIG_CATV=y
+CONFIG_CHGRP=y
+CONFIG_CHMOD=y
+CONFIG_CHOWN=y
+CONFIG_CHROOT=y
+CONFIG_CKSUM=y
+CONFIG_COMM=y
+CONFIG_CP=y
+CONFIG_CUT=y
+CONFIG_DATE=y
+CONFIG_FEATURE_DATE_ISOFMT=y
+CONFIG_DD=y
+CONFIG_FEATURE_DD_SIGNAL_HANDLING=y
+CONFIG_FEATURE_DD_IBS_OBS=y
+CONFIG_DF=y
+CONFIG_FEATURE_DF_INODE=y
+CONFIG_DIRNAME=y
+CONFIG_DOS2UNIX=y
+CONFIG_UNIX2DOS=y
+CONFIG_DU=y
+CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y
+CONFIG_ECHO=y
+CONFIG_FEATURE_FANCY_ECHO=y
+CONFIG_ENV=y
+# CONFIG_FEATURE_ENV_LONG_OPTIONS is not set
+CONFIG_EXPAND=y
+# CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set
+CONFIG_EXPR=y
+CONFIG_EXPR_MATH_SUPPORT_64=y
+CONFIG_FALSE=y
+CONFIG_FOLD=y
+CONFIG_HEAD=y
+CONFIG_FEATURE_FANCY_HEAD=y
+CONFIG_HOSTID=y
+CONFIG_ID=y
+CONFIG_INSTALL=y
+# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set
+CONFIG_LENGTH=y
+CONFIG_LN=y
+# CONFIG_LOGNAME is not set
+CONFIG_LS=y
+CONFIG_FEATURE_LS_FILETYPES=y
+CONFIG_FEATURE_LS_FOLLOWLINKS=y
+CONFIG_FEATURE_LS_RECURSIVE=y
+CONFIG_FEATURE_LS_SORTFILES=y
+CONFIG_FEATURE_LS_TIMESTAMPS=y
+CONFIG_FEATURE_LS_USERNAME=y
+CONFIG_FEATURE_LS_COLOR=y
+CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y
+CONFIG_MD5SUM=y
+CONFIG_MKDIR=y
+# CONFIG_FEATURE_MKDIR_LONG_OPTIONS is not set
+CONFIG_MKFIFO=y
+CONFIG_MKNOD=y
+CONFIG_MV=y
+# CONFIG_FEATURE_MV_LONG_OPTIONS is not set
+CONFIG_NICE=y
+CONFIG_NOHUP=y
+# CONFIG_OD is not set
+CONFIG_PRINTENV=y
+CONFIG_PRINTF=y
+CONFIG_PWD=y
+CONFIG_READLINK=y
+CONFIG_FEATURE_READLINK_FOLLOW=y
+CONFIG_REALPATH=y
+CONFIG_RM=y
+CONFIG_RMDIR=y
+# CONFIG_FEATURE_RMDIR_LONG_OPTIONS is not set
+CONFIG_SEQ=y
+CONFIG_SHA1SUM=y
+CONFIG_SLEEP=y
+CONFIG_FEATURE_FANCY_SLEEP=y
+CONFIG_FEATURE_FLOAT_SLEEP=y
+CONFIG_SORT=y
+CONFIG_FEATURE_SORT_BIG=y
+CONFIG_SPLIT=y
+# CONFIG_FEATURE_SPLIT_FANCY is not set
+CONFIG_STAT=y
+CONFIG_FEATURE_STAT_FORMAT=y
+CONFIG_STTY=y
+CONFIG_SUM=y
+CONFIG_SYNC=y
+CONFIG_TAC=y
+CONFIG_TAIL=y
+CONFIG_FEATURE_FANCY_TAIL=y
+CONFIG_TEE=y
+CONFIG_FEATURE_TEE_USE_BLOCK_IO=y
+CONFIG_TEST=y
+CONFIG_FEATURE_TEST_64=y
+CONFIG_TOUCH=y
+CONFIG_TR=y
+CONFIG_FEATURE_TR_CLASSES=y
+CONFIG_FEATURE_TR_EQUIV=y
+CONFIG_TRUE=y
+CONFIG_TTY=y
+CONFIG_UNAME=y
+CONFIG_UNEXPAND=y
+# CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set
+CONFIG_UNIQ=y
+CONFIG_USLEEP=y
+# CONFIG_UUDECODE is not set
+CONFIG_UUENCODE=y
+CONFIG_WC=y
+# CONFIG_FEATURE_WC_LARGE is not set
+CONFIG_WHO=y
+CONFIG_WHOAMI=y
+CONFIG_YES=y
+
+#
+# Common options for cp and mv
+#
+CONFIG_FEATURE_PRESERVE_HARDLINKS=y
+
+#
+# Common options for ls, more and telnet
+#
+CONFIG_FEATURE_AUTOWIDTH=y
+
+#
+# Common options for df, du, ls
+#
+CONFIG_FEATURE_HUMAN_READABLE=y
+
+#
+# Common options for md5sum, sha1sum
+#
+CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y
+
+#
+# Console Utilities
+#
+CONFIG_CHVT=y
+CONFIG_CLEAR=y
+CONFIG_DEALLOCVT=y
+CONFIG_DUMPKMAP=y
+CONFIG_KBD_MODE=y
+CONFIG_LOADFONT=y
+CONFIG_LOADKMAP=y
+CONFIG_OPENVT=y
+CONFIG_RESET=y
+CONFIG_RESIZE=y
+CONFIG_FEATURE_RESIZE_PRINT=y
+CONFIG_SETCONSOLE=y
+# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set
+# CONFIG_SETFONT is not set
+CONFIG_SETKEYCODES=y
+CONFIG_SETLOGCONS=y
+CONFIG_SHOWKEY=y
+
+#
+# Debian Utilities
+#
+CONFIG_MKTEMP=y
+CONFIG_PIPE_PROGRESS=y
+CONFIG_RUN_PARTS=y
+CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS=y
+# CONFIG_FEATURE_RUN_PARTS_FANCY is not set
+CONFIG_START_STOP_DAEMON=y
+CONFIG_FEATURE_START_STOP_DAEMON_FANCY=y
+CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS=y
+CONFIG_WHICH=y
+
+#
+# Editors
+#
+CONFIG_AWK=y
+CONFIG_FEATURE_AWK_MATH=y
+CONFIG_CMP=y
+CONFIG_DIFF=y
+CONFIG_FEATURE_DIFF_BINARY=y
+CONFIG_FEATURE_DIFF_DIR=y
+CONFIG_FEATURE_DIFF_MINIMAL=y
+CONFIG_ED=y
+CONFIG_PATCH=y
+CONFIG_SED=y
+CONFIG_VI=y
+CONFIG_FEATURE_VI_MAX_LEN=1024
+CONFIG_FEATURE_VI_8BIT=y
+CONFIG_FEATURE_VI_COLON=y
+CONFIG_FEATURE_VI_YANKMARK=y
+CONFIG_FEATURE_VI_SEARCH=y
+CONFIG_FEATURE_VI_USE_SIGNALS=y
+CONFIG_FEATURE_VI_DOT_CMD=y
+CONFIG_FEATURE_VI_READONLY=y
+CONFIG_FEATURE_VI_SETOPTS=y
+CONFIG_FEATURE_VI_SET=y
+CONFIG_FEATURE_VI_WIN_RESIZE=y
+CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y
+CONFIG_FEATURE_ALLOW_EXEC=y
+
+#
+# Finding Utilities
+#
+CONFIG_FIND=y
+CONFIG_FEATURE_FIND_PRINT0=y
+CONFIG_FEATURE_FIND_MTIME=y
+CONFIG_FEATURE_FIND_MMIN=y
+CONFIG_FEATURE_FIND_PERM=y
+CONFIG_FEATURE_FIND_TYPE=y
+CONFIG_FEATURE_FIND_XDEV=y
+CONFIG_FEATURE_FIND_MAXDEPTH=y
+CONFIG_FEATURE_FIND_NEWER=y
+CONFIG_FEATURE_FIND_INUM=y
+CONFIG_FEATURE_FIND_EXEC=y
+CONFIG_FEATURE_FIND_USER=y
+CONFIG_FEATURE_FIND_GROUP=y
+CONFIG_FEATURE_FIND_NOT=y
+CONFIG_FEATURE_FIND_DEPTH=y
+CONFIG_FEATURE_FIND_PAREN=y
+CONFIG_FEATURE_FIND_SIZE=y
+CONFIG_FEATURE_FIND_PRUNE=y
+CONFIG_FEATURE_FIND_DELETE=y
+CONFIG_FEATURE_FIND_PATH=y
+CONFIG_FEATURE_FIND_REGEX=y
+# CONFIG_FEATURE_FIND_CONTEXT is not set
+CONFIG_GREP=y
+CONFIG_FEATURE_GREP_EGREP_ALIAS=y
+CONFIG_FEATURE_GREP_FGREP_ALIAS=y
+CONFIG_FEATURE_GREP_CONTEXT=y
+CONFIG_XARGS=y
+CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y
+CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y
+CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y
+CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y
+
+#
+# Init Utilities
+#
+CONFIG_INIT=y
+# CONFIG_DEBUG_INIT is not set
+CONFIG_FEATURE_USE_INITTAB=y
+CONFIG_FEATURE_KILL_REMOVED=y
+CONFIG_FEATURE_KILL_DELAY=0
+CONFIG_FEATURE_INIT_SCTTY=y
+CONFIG_FEATURE_INIT_SYSLOG=y
+CONFIG_FEATURE_EXTRA_QUIET=y
+# CONFIG_FEATURE_INIT_COREDUMPS is not set
+CONFIG_FEATURE_INITRD=y
+CONFIG_HALT=y
+CONFIG_MESG=y
+
+#
+# Login/Password Management Utilities
+#
+CONFIG_FEATURE_SHADOWPASSWDS=y
+CONFIG_USE_BB_PWD_GRP=y
+CONFIG_USE_BB_SHADOW=y
+# CONFIG_USE_BB_CRYPT is not set
+CONFIG_ADDGROUP=y
+CONFIG_FEATURE_ADDUSER_TO_GROUP=y
+CONFIG_DELGROUP=y
+CONFIG_FEATURE_DEL_USER_FROM_GROUP=y
+CONFIG_FEATURE_CHECK_NAMES=y
+CONFIG_ADDUSER=y
+# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set
+CONFIG_DELUSER=y
+CONFIG_GETTY=y
+CONFIG_FEATURE_UTMP=y
+CONFIG_FEATURE_WTMP=y
+CONFIG_LOGIN=y
+# CONFIG_PAM is not set
+CONFIG_LOGIN_SCRIPTS=y
+CONFIG_FEATURE_NOLOGIN=y
+CONFIG_FEATURE_SECURETTY=y
+CONFIG_PASSWD=y
+CONFIG_FEATURE_PASSWD_WEAK_CHECK=y
+CONFIG_CRYPTPW=y
+CONFIG_CHPASSWD=y
+CONFIG_SU=y
+CONFIG_FEATURE_SU_SYSLOG=y
+CONFIG_FEATURE_SU_CHECKS_SHELLS=y
+# CONFIG_SULOGIN is not set
+CONFIG_VLOCK=y
+
+#
+# Linux Ext2 FS Progs
+#
+# CONFIG_CHATTR is not set
+# CONFIG_FSCK is not set
+# CONFIG_LSATTR is not set
+
+#
+# Linux Module Utilities
+#
+CONFIG_MODUTILS_STANDARD=y
+# CONFIG_MODUTILS_FAST is not set
+# CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE is not set
+# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set
+CONFIG_INSMOD=y
+CONFIG_RMMOD=y
+CONFIG_LSMOD=y
+# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set
+CONFIG_MODPROBE=y
+CONFIG_FEATURE_MODPROBE_BLACKLIST=y
+CONFIG_DEPMOD=y
+
+#
+# Options common to multiple modutils
+#
+# CONFIG_FEATURE_2_4_MODULES is not set
+# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
+# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
+# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
+# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
+# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
+CONFIG_FEATURE_CHECK_TAINTED_MODULE=y
+CONFIG_FEATURE_MODUTILS_ALIAS=y
+CONFIG_FEATURE_MODUTILS_SYMBOLS=y
+CONFIG_DEFAULT_MODULES_DIR="/lib/modules"
+CONFIG_DEFAULT_DEPMOD_FILE="modules.dep"
+
+#
+# Linux System Utilities
+#
+CONFIG_DMESG=y
+CONFIG_FEATURE_DMESG_PRETTY=y
+CONFIG_FBSET=y
+CONFIG_FEATURE_FBSET_FANCY=y
+CONFIG_FEATURE_FBSET_READMODE=y
+CONFIG_FDFLUSH=y
+CONFIG_FDFORMAT=y
+CONFIG_FDISK=y
+CONFIG_FDISK_SUPPORT_LARGE_DISKS=y
+CONFIG_FEATURE_FDISK_WRITABLE=y
+CONFIG_FEATURE_AIX_LABEL=y
+CONFIG_FEATURE_SGI_LABEL=y
+CONFIG_FEATURE_SUN_LABEL=y
+CONFIG_FEATURE_OSF_LABEL=y
+CONFIG_FEATURE_FDISK_ADVANCED=y
+# CONFIG_FINDFS is not set
+CONFIG_FREERAMDISK=y
+# CONFIG_FSCK_MINIX is not set
+# CONFIG_MKFS_MINIX is not set
+# CONFIG_FEATURE_MINIX2 is not set
+CONFIG_GETOPT=y
+CONFIG_HEXDUMP=y
+CONFIG_FEATURE_HEXDUMP_REVERSE=y
+CONFIG_HD=y
+CONFIG_HWCLOCK=y
+CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS=y
+CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS=y
+CONFIG_IPCRM=y
+CONFIG_IPCS=y
+CONFIG_LOSETUP=y
+CONFIG_MDEV=y
+CONFIG_FEATURE_MDEV_CONF=y
+CONFIG_FEATURE_MDEV_RENAME=y
+CONFIG_FEATURE_MDEV_RENAME_REGEXP=y
+CONFIG_FEATURE_MDEV_EXEC=y
+CONFIG_FEATURE_MDEV_LOAD_FIRMWARE=y
+CONFIG_MKSWAP=y
+# CONFIG_FEATURE_MKSWAP_V0 is not set
+CONFIG_MORE=y
+CONFIG_FEATURE_USE_TERMIOS=y
+# CONFIG_VOLUMEID is not set
+# CONFIG_FEATURE_VOLUMEID_EXT is not set
+# CONFIG_FEATURE_VOLUMEID_REISERFS is not set
+# CONFIG_FEATURE_VOLUMEID_FAT is not set
+# CONFIG_FEATURE_VOLUMEID_HFS is not set
+# CONFIG_FEATURE_VOLUMEID_JFS is not set
+# CONFIG_FEATURE_VOLUMEID_XFS is not set
+# CONFIG_FEATURE_VOLUMEID_NTFS is not set
+# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set
+# CONFIG_FEATURE_VOLUMEID_UDF is not set
+# CONFIG_FEATURE_VOLUMEID_LUKS is not set
+# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set
+# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set
+# CONFIG_FEATURE_VOLUMEID_ROMFS is not set
+# CONFIG_FEATURE_VOLUMEID_SYSV is not set
+# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set
+# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set
+CONFIG_MOUNT=y
+CONFIG_FEATURE_MOUNT_FAKE=y
+CONFIG_FEATURE_MOUNT_VERBOSE=y
+CONFIG_FEATURE_MOUNT_HELPERS=y
+# CONFIG_FEATURE_MOUNT_LABEL is not set
+CONFIG_FEATURE_MOUNT_NFS=y
+CONFIG_FEATURE_MOUNT_CIFS=y
+CONFIG_FEATURE_MOUNT_FLAGS=y
+CONFIG_FEATURE_MOUNT_FSTAB=y
+# CONFIG_PIVOT_ROOT is not set
+CONFIG_RDATE=y
+CONFIG_RDEV=y
+CONFIG_READPROFILE=y
+# CONFIG_RTCWAKE is not set
+# CONFIG_SCRIPT is not set
+# CONFIG_SETARCH is not set
+CONFIG_SWAPONOFF=y
+CONFIG_FEATURE_SWAPON_PRI=y
+# CONFIG_SWITCH_ROOT is not set
+CONFIG_UMOUNT=y
+CONFIG_FEATURE_UMOUNT_ALL=y
+
+#
+# Common options for mount/umount
+#
+CONFIG_FEATURE_MOUNT_LOOP=y
+# CONFIG_FEATURE_MTAB_SUPPORT is not set
+
+#
+# Miscellaneous Utilities
+#
+CONFIG_ADJTIMEX=y
+CONFIG_BBCONFIG=y
+# CONFIG_CHAT is not set
+# CONFIG_FEATURE_CHAT_NOFAIL is not set
+# CONFIG_FEATURE_CHAT_TTY_HIFI is not set
+# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set
+# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set
+# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set
+# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set
+# CONFIG_FEATURE_CHAT_CLR_ABORT is not set
+# CONFIG_CHRT is not set
+CONFIG_CROND=y
+# CONFIG_DEBUG_CROND_OPTION is not set
+CONFIG_FEATURE_CROND_CALL_SENDMAIL=y
+CONFIG_CRONTAB=y
+CONFIG_DC=y
+# CONFIG_DEVFSD is not set
+# CONFIG_DEVFSD_MODLOAD is not set
+# CONFIG_DEVFSD_FG_NP is not set
+# CONFIG_DEVFSD_VERBOSE is not set
+# CONFIG_FEATURE_DEVFS is not set
+CONFIG_DEVMEM=y
+CONFIG_EJECT=y
+CONFIG_FEATURE_EJECT_SCSI=y
+CONFIG_FBSPLASH=y
+# CONFIG_INOTIFYD is not set
+CONFIG_LAST=y
+CONFIG_FEATURE_LAST_SMALL=y
+# CONFIG_FEATURE_LAST_FANCY is not set
+CONFIG_LESS=y
+CONFIG_FEATURE_LESS_MAXLINES=9999999
+CONFIG_FEATURE_LESS_BRACKETS=y
+CONFIG_FEATURE_LESS_FLAGS=y
+CONFIG_FEATURE_LESS_FLAGCS=y
+CONFIG_FEATURE_LESS_MARKS=y
+CONFIG_FEATURE_LESS_REGEXP=y
+# CONFIG_HDPARM is not set
+# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set
+# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set
+# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set
+# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set
+# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set
+# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set
+CONFIG_MAKEDEVS=y
+# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
+CONFIG_FEATURE_MAKEDEVS_TABLE=y
+CONFIG_MAN=y
+CONFIG_MICROCOM=y
+CONFIG_MOUNTPOINT=y
+CONFIG_MT=y
+CONFIG_RAIDAUTORUN=y
+CONFIG_READAHEAD=y
+CONFIG_RUNLEVEL=y
+CONFIG_RX=y
+CONFIG_SETSID=y
+CONFIG_STRINGS=y
+# CONFIG_TASKSET is not set
+# CONFIG_FEATURE_TASKSET_FANCY is not set
+CONFIG_TIME=y
+CONFIG_TTYSIZE=y
+CONFIG_WATCHDOG=y
+
+#
+# Networking Utilities
+#
+CONFIG_FEATURE_IPV6=y
+CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y
+CONFIG_VERBOSE_RESOLUTION_ERRORS=y
+CONFIG_ARP=y
+CONFIG_ARPING=y
+CONFIG_BRCTL=y
+CONFIG_FEATURE_BRCTL_FANCY=y
+CONFIG_FEATURE_BRCTL_SHOW=y
+CONFIG_DNSD=y
+CONFIG_ETHER_WAKE=y
+CONFIG_FAKEIDENTD=y
+CONFIG_FTPGET=y
+CONFIG_FTPPUT=y
+# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set
+CONFIG_HOSTNAME=y
+CONFIG_HTTPD=y
+CONFIG_FEATURE_HTTPD_RANGES=y
+CONFIG_FEATURE_HTTPD_USE_SENDFILE=y
+# CONFIG_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP is not set
+CONFIG_FEATURE_HTTPD_SETUID=y
+CONFIG_FEATURE_HTTPD_BASIC_AUTH=y
+CONFIG_FEATURE_HTTPD_AUTH_MD5=y
+CONFIG_FEATURE_HTTPD_CONFIG_WITH_MIME_TYPES=y
+CONFIG_FEATURE_HTTPD_CGI=y
+CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y
+CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV=y
+CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y
+CONFIG_FEATURE_HTTPD_ERROR_PAGES=y
+CONFIG_FEATURE_HTTPD_PROXY=y
+CONFIG_IFCONFIG=y
+CONFIG_FEATURE_IFCONFIG_STATUS=y
+CONFIG_FEATURE_IFCONFIG_SLIP=y
+CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ=y
+CONFIG_FEATURE_IFCONFIG_HW=y
+CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y
+CONFIG_IFENSLAVE=y
+CONFIG_IFUPDOWN=y
+CONFIG_IFUPDOWN_IFSTATE_PATH="/var/run/ifstate"
+CONFIG_FEATURE_IFUPDOWN_IP=y
+CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN=y
+# CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set
+CONFIG_FEATURE_IFUPDOWN_IPV4=y
+CONFIG_FEATURE_IFUPDOWN_IPV6=y
+# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set
+CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP=y
+CONFIG_INETD=y
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set
+# CONFIG_FEATURE_INETD_RPC is not set
+CONFIG_IP=y
+CONFIG_FEATURE_IP_ADDRESS=y
+CONFIG_FEATURE_IP_LINK=y
+CONFIG_FEATURE_IP_ROUTE=y
+CONFIG_FEATURE_IP_TUNNEL=y
+CONFIG_FEATURE_IP_RULE=y
+CONFIG_FEATURE_IP_SHORT_FORMS=y
+CONFIG_FEATURE_IP_RARE_PROTOCOLS=y
+CONFIG_IPADDR=y
+CONFIG_IPLINK=y
+CONFIG_IPROUTE=y
+CONFIG_IPTUNNEL=y
+CONFIG_IPRULE=y
+CONFIG_IPCALC=y
+CONFIG_FEATURE_IPCALC_FANCY=y
+# CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set
+CONFIG_NAMEIF=y
+CONFIG_FEATURE_NAMEIF_EXTENDED=y
+CONFIG_NC=y
+CONFIG_NC_SERVER=y
+CONFIG_NC_EXTRA=y
+CONFIG_NETSTAT=y
+CONFIG_FEATURE_NETSTAT_WIDE=y
+CONFIG_FEATURE_NETSTAT_PRG=y
+CONFIG_NSLOOKUP=y
+CONFIG_PING=y
+CONFIG_PING6=y
+CONFIG_FEATURE_FANCY_PING=y
+CONFIG_PSCAN=y
+CONFIG_ROUTE=y
+# CONFIG_SENDMAIL is not set
+# CONFIG_FETCHMAIL is not set
+CONFIG_SLATTACH=y
+CONFIG_TELNET=y
+CONFIG_FEATURE_TELNET_TTYPE=y
+CONFIG_FEATURE_TELNET_AUTOLOGIN=y
+# CONFIG_TELNETD is not set
+# CONFIG_FEATURE_TELNETD_STANDALONE is not set
+CONFIG_TFTP=y
+# CONFIG_TFTPD is not set
+CONFIG_FEATURE_TFTP_GET=y
+CONFIG_FEATURE_TFTP_PUT=y
+CONFIG_FEATURE_TFTP_BLOCKSIZE=y
+# CONFIG_DEBUG_TFTP is not set
+CONFIG_TRACEROUTE=y
+CONFIG_FEATURE_TRACEROUTE_VERBOSE=y
+CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE=y
+CONFIG_FEATURE_TRACEROUTE_USE_ICMP=y
+CONFIG_APP_UDHCPD=y
+CONFIG_APP_DHCPRELAY=y
+CONFIG_APP_DUMPLEASES=y
+CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY=y
+CONFIG_DHCPD_LEASES_FILE="/var/lib/misc/udhcpd.leases"
+CONFIG_APP_UDHCPC=y
+CONFIG_FEATURE_UDHCPC_ARPING=y
+# CONFIG_FEATURE_UDHCP_PORT is not set
+# CONFIG_FEATURE_UDHCP_DEBUG is not set
+CONFIG_FEATURE_RFC3397=y
+CONFIG_DHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script"
+CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80
+CONFIG_VCONFIG=y
+CONFIG_WGET=y
+CONFIG_FEATURE_WGET_STATUSBAR=y
+CONFIG_FEATURE_WGET_AUTHENTICATION=y
+# CONFIG_FEATURE_WGET_LONG_OPTIONS is not set
+CONFIG_ZCIP=y
+# CONFIG_TCPSVD is not set
+# CONFIG_UDPSVD is not set
+
+#
+# Process Utilities
+#
+CONFIG_FREE=y
+CONFIG_FUSER=y
+CONFIG_KILL=y
+CONFIG_KILLALL=y
+CONFIG_KILLALL5=y
+CONFIG_NMETER=y
+CONFIG_PGREP=y
+CONFIG_PIDOF=y
+CONFIG_FEATURE_PIDOF_SINGLE=y
+CONFIG_FEATURE_PIDOF_OMIT=y
+CONFIG_PKILL=y
+CONFIG_PS=y
+CONFIG_FEATURE_PS_WIDE=y
+# CONFIG_FEATURE_PS_TIME is not set
+# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
+CONFIG_RENICE=y
+CONFIG_BB_SYSCTL=y
+CONFIG_TOP=y
+CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y
+CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y
+# CONFIG_FEATURE_TOP_DECIMALS is not set
+CONFIG_FEATURE_TOPMEM=y
+CONFIG_UPTIME=y
+CONFIG_WATCH=y
+
+#
+# Shells
+#
+CONFIG_FEATURE_SH_IS_ASH=y
+# CONFIG_FEATURE_SH_IS_HUSH is not set
+# CONFIG_FEATURE_SH_IS_MSH is not set
+# CONFIG_FEATURE_SH_IS_NONE is not set
+CONFIG_ASH=y
+
+#
+# Ash Shell Options
+#
+CONFIG_ASH_BASH_COMPAT=y
+CONFIG_ASH_JOB_CONTROL=y
+CONFIG_ASH_READ_NCHARS=y
+CONFIG_ASH_READ_TIMEOUT=y
+CONFIG_ASH_ALIAS=y
+CONFIG_ASH_MATH_SUPPORT=y
+CONFIG_ASH_MATH_SUPPORT_64=y
+CONFIG_ASH_GETOPTS=y
+CONFIG_ASH_BUILTIN_ECHO=y
+CONFIG_ASH_BUILTIN_PRINTF=y
+CONFIG_ASH_BUILTIN_TEST=y
+CONFIG_ASH_CMDCMD=y
+CONFIG_ASH_MAIL=y
+CONFIG_ASH_OPTIMIZE_FOR_SIZE=y
+CONFIG_ASH_RANDOM_SUPPORT=y
+CONFIG_ASH_EXPAND_PRMT=y
+# CONFIG_HUSH is not set
+# CONFIG_HUSH_HELP is not set
+# CONFIG_HUSH_INTERACTIVE is not set
+# CONFIG_HUSH_JOB is not set
+# CONFIG_HUSH_TICK is not set
+# CONFIG_HUSH_IF is not set
+# CONFIG_HUSH_LOOPS is not set
+# CONFIG_HUSH_CASE is not set
+# CONFIG_LASH is not set
+# CONFIG_MSH is not set
+
+#
+# Bourne Shell Options
+#
+CONFIG_FEATURE_SH_EXTRA_QUIET=y
+# CONFIG_FEATURE_SH_STANDALONE is not set
+# CONFIG_FEATURE_SH_NOFORK is not set
+CONFIG_CTTYHACK=y
+
+#
+# System Logging Utilities
+#
+CONFIG_SYSLOGD=y
+CONFIG_FEATURE_ROTATE_LOGFILE=y
+CONFIG_FEATURE_REMOTE_LOG=y
+CONFIG_FEATURE_SYSLOGD_DUP=y
+CONFIG_FEATURE_IPC_SYSLOG=y
+CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=16
+CONFIG_LOGREAD=y
+CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING=y
+CONFIG_KLOGD=y
+CONFIG_LOGGER=y
+
+#
+# Runit Utilities
+#
+# CONFIG_RUNSV is not set
+# CONFIG_RUNSVDIR is not set
+# CONFIG_SV is not set
+# CONFIG_SVLOGD is not set
+# CONFIG_CHPST is not set
+# CONFIG_SETUIDGID is not set
+# CONFIG_ENVUIDGID is not set
+# CONFIG_ENVDIR is not set
+# CONFIG_SOFTLIMIT is not set
+# CONFIG_CHCON is not set
+# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set
+# CONFIG_GETENFORCE is not set
+# CONFIG_GETSEBOOL is not set
+# CONFIG_LOAD_POLICY is not set
+# CONFIG_MATCHPATHCON is not set
+# CONFIG_RESTORECON is not set
+# CONFIG_RUNCON is not set
+# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set
+# CONFIG_SELINUXENABLED is not set
+# CONFIG_SETENFORCE is not set
+# CONFIG_SETFILES is not set
+# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set
+# CONFIG_SETSEBOOL is not set
+# CONFIG_SESTATUS is not set
+
+#
+# Print Utilities
+#
+# CONFIG_LPD is not set
+# CONFIG_LPR is not set
+# CONFIG_LPQ is not set