From 645531103b2ee8ef54d53a58eca3b52f7d3fb9ac Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Sat, 18 Oct 2008 09:16:29 +0000 Subject: added busybox --- core/busybox/APKBUILD | 43 + core/busybox/bb-modprobe-v9.diff | 10876 +++++++++++++++++++++ core/busybox/busybox-1.11.1-bb.patch | 12 + core/busybox/busybox-1.12.0-mdev-exec.patch | 11 + core/busybox/busybox-1.12.1-grep.patch | 27 + core/busybox/busybox-1.12.1-iproute-metric.patch | 36 + core/busybox/busybox-1.12.1-r1 | 851 ++ core/busybox/busybox-1.12.1-vi.patch | 11 + core/busybox/busybox-1.7.0-vi-path.patch | 13 + core/busybox/busybox-devmem.patch | 128 + core/busybox/busyboxconfig | 851 ++ 11 files changed, 12859 insertions(+) create mode 100644 core/busybox/APKBUILD create mode 100644 core/busybox/bb-modprobe-v9.diff create mode 100644 core/busybox/busybox-1.11.1-bb.patch create mode 100644 core/busybox/busybox-1.12.0-mdev-exec.patch create mode 100644 core/busybox/busybox-1.12.1-grep.patch create mode 100644 core/busybox/busybox-1.12.1-iproute-metric.patch create mode 100644 core/busybox/busybox-1.12.1-r1 create mode 100644 core/busybox/busybox-1.12.1-vi.patch create mode 100644 core/busybox/busybox-1.7.0-vi-path.patch create mode 100644 core/busybox/busybox-devmem.patch create mode 100644 core/busybox/busyboxconfig (limited to 'core/busybox') 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 ++ * Copyright (C) 2008 by Vladimir Dronnikov + * +- * Modified by Alcove, Julien Gaulmin and +- * Nicolas Ferre 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 ++ * Copyright (C) 2008 Timo Teras + * + * 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 +-# 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 ++ * ++ * 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 ++# 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 ++ * and Ron Alder ++ * ++ * Rodney Radford 17-Aug-2004. ++ * Added x86_64 support. ++ * ++ * Miles Bader added NEC V850E support. ++ * ++ * Modified by Bryan Rittmeyer to support SH4 ++ * and (theoretically) SH3. I have only tested SH4 in little endian mode. ++ * ++ * Modified by Alcove, Julien Gaulmin and ++ * Nicolas Ferre to support ARM7TDMI. Only ++ * very minor changes required to also work with StrongArm and presumably ++ * all ARM based systems. ++ * ++ * Yoshinori Sato 19-May-2004. ++ * added Renesas H8/300 support. ++ * ++ * Paul Mundt 08-Aug-2003. ++ * Integrated support for sh64 (SH-5), from preliminary modutils ++ * patches from Benedict Gaster . ++ * Currently limited to support for 32bit ABI. ++ * ++ * Magnus Damm 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 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 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 ++ * ++ * Based almost entirely on the Linux modutils-2.3.11 implementation. ++ * Copyright 1996, 1997 Linux International. ++ * New implementation contributed by Richard Henderson ++ * Based on original work by Bjorn Ekwall ++ * Restructured (and partly rewritten) by: ++ * Björn Ekwall February 1999 ++ * ++ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. ++ */ ++ ++#include "libbb.h" ++#include "modutils.h" ++#include ++#include ++ ++#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 ++#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 ++ ++ 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 ++ ++ 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 ++#include ++ ++#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, ¶m, &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 ++ * ++ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. ++ */ ++ ++#ifndef __MODUTILS_H__ ++#define __MODUTILS_H__ ++ ++#include "libbb.h" ++#include ++ ++#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 ++ * 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 + #include + +-#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 ++ * 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 + #include /* 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 + * +- * Copyright (C) 1999-2004 by Erik Andersen +- * and Ron Alder +- * +- * Rodney Radford 17-Aug-2004. +- * Added x86_64 support. +- * +- * Miles Bader added NEC V850E support. +- * +- * Modified by Bryan Rittmeyer to support SH4 +- * and (theoretically) SH3. I have only tested SH4 in little endian mode. +- * +- * Modified by Alcove, Julien Gaulmin and +- * Nicolas Ferre to support ARM7TDMI. Only +- * very minor changes required to also work with StrongArm and presumably +- * all ARM based systems. +- * +- * Yoshinori Sato 19-May-2004. +- * added Renesas H8/300 support. +- * +- * Paul Mundt 08-Aug-2003. +- * Integrated support for sh64 (SH-5), from preliminary modutils +- * patches from Benedict Gaster . +- * Currently limited to support for 32bit ABI. +- * +- * Magnus Damm 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 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 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 +- * +- * Based almost entirely on the Linux modutils-2.3.11 implementation. +- * Copyright 1996, 1997 Linux International. +- * New implementation contributed by Richard Henderson +- * Based on original work by Bjorn Ekwall +- * Restructured (and partly rewritten) by: +- * Björn Ekwall February 1999 +- * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + + #include "libbb.h" +-#include +-#include ++#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 +-#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 +- +- 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 +- +- 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 +-#include +- +-#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 -- +- 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 +- +-#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 +-#include +-#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 -- cgit v1.2.3