modutils/*: rewrite by Timo Teras <timo.teras AT iki.fi>

- a lot faster (linear algorithmic complexity, smaller memory foot print)
- a lot smaller (the old code was overly complicated)
- loading of aliases is now module-init-tools compliant
- blacklisting is done correctly (-b option added)
- module argument quoting done right
- depmod now correctly generates modules.symbols and modules.alias

add/remove: 16/21 grow/shrink: 4/6 up/down: 6930/-9316 Total: -2386 bytes
   text    data     bss     dec     hex filename
 806039     592    6680  813311   c68ff busybox_old
 803498     592    6676  810766   c5f0e busybox_unstripped
This commit is contained in:
Denis Vlasenko 2008-09-13 14:59:38 +00:00
parent 4f3209b9d4
commit ba1315d0fb
12 changed files with 4730 additions and 5777 deletions

View File

@ -2569,12 +2569,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" \

View File

@ -90,7 +90,6 @@ void FAST_FUNC llist_free(llist_t *elm, void (*freeit) (void *data))
}
}
#ifdef UNUSED
/* Reverse list order. */
llist_t* FAST_FUNC llist_rev(llist_t *list)
{
@ -105,4 +104,3 @@ llist_t* FAST_FUNC llist_rev(llist_t *list)
}
return rev;
}
#endif

View File

@ -5,6 +5,20 @@
menu "Linux Module Utilities"
config DEFAULT_MODULES_DIR
string "Default directory containing modules"
default "/lib/modules"
help
Directory that contains kernel modules.
Defaults to "/lib/modules"
config DEFAULT_DEPMOD_FILE
string "Default name of modules.dep"
default "modules.dep"
help
Filename that contains kernel modules dependencies.
Defaults to "modules.dep"
config MODPROBE_SMALL
bool "Simplified modutils"
default n
@ -54,37 +68,6 @@ config FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED
Check if the module is already loaded.
N.B. It's racy.
config DEPMOD
bool "depmod"
default n
depends on !MODPROBE_SMALL
help
depmod generates modules.dep (FIXME: elaborate)
config FEATURE_DEPMOD_PRUNE_FANCY
bool "Fancy dependency pruning"
default n
depends on DEPMOD
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.
If unsure, say N.
config FEATURE_DEPMOD_ALIAS
bool "Alias support"
default n
depends on DEPMOD
help
By default modules.dep does not contain alias information.
Enable this to emit aliases of the form:
alias pcmcia:m*c*f03fn*pfn*pa*pb*pc*pd* parport_cs
config INSMOD
bool "insmod"
default n
@ -92,55 +75,6 @@ config INSMOD
help
insmod is used to load specified modules in the running kernel.
config FEATURE_INSMOD_VERSION_CHECKING
bool "Module version checking"
default n
depends on INSMOD && FEATURE_2_4_MODULES
help
Support checking of versions for modules. This is used to
ensure that the kernel and module are made for each other.
config FEATURE_INSMOD_KSYMOOPS_SYMBOLS
bool "Add module symbols to kernel symbol table"
default n
depends on INSMOD && FEATURE_2_4_MODULES
help
By adding module symbols to the kernel symbol table, Oops messages
occuring within kernel modules can be properly debugged. By enabling
this feature, module symbols will always be added to the kernel symbol
table for properly debugging support. If you are not interested in
Oops messages from kernel modules, say N.
config FEATURE_INSMOD_LOADINKMEM
bool "In kernel memory optimization (uClinux only)"
default n
depends on INSMOD && FEATURE_2_4_MODULES
help
This is a special uClinux only memory optimization that lets insmod
load the specified kernel module directly into kernel space, reducing
memory usage by preventing the need for two copies of the module
being loaded into memory.
config FEATURE_INSMOD_LOAD_MAP
bool "Enable load map (-m) option"
default n
depends on INSMOD && ( FEATURE_2_4_MODULES || FEATURE_2_6_MODULES )
help
Enabling this, one would be able to get a load map
output on stdout. This makes kernel module debugging
easier.
If you don't plan to debug kernel modules, you
don't need this option.
config FEATURE_INSMOD_LOAD_MAP_FULL
bool "Symbols in load map"
default y
depends on FEATURE_INSMOD_LOAD_MAP
help
Without this option, -m will only output section
load map. With this option, -m will also output
symbols load map.
config RMMOD
bool "rmmod"
default n
@ -156,12 +90,13 @@ config LSMOD
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"
bool "Pretty output"
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.
Increases size somewhat.
config MODPROBE
bool "modprobe"
@ -174,38 +109,11 @@ config MODPROBE
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
depends on MODPROBE
help
Say 'y' here to enable support for the 'blacklist' command in
modprobe.conf. This prevents the alias resolver to resolve
@ -213,60 +121,110 @@ config FEATURE_MODPROBE_BLACKLIST
hardware autodetection scripts to load modules like evdev, frame
buffer drivers etc.
config DEPMOD
bool "depmod"
default n
depends on !MODPROBE_SMALL
help
depmod generates modules.dep (and potentially modules.alias
and modules.symbols) that contain dependency information
for modprobe.
comment "Options common to multiple modutils"
depends on INSMOD || RMMOD || MODPROBE || LSMOD || DEPMOD
config FEATURE_2_4_MODULES
bool "Support version 2.2/2.4 Linux kernels"
default n
depends on 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 "Enable module version checking"
default n
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.
config FEATURE_INSMOD_KSYMOOPS_SYMBOLS
bool "Add module symbols to kernel symbol table"
default n
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
this feature, module symbols will always be added to the kernel symbol
table for properly debugging support. If you are not interested in
Oops messages from kernel modules, say N.
config FEATURE_INSMOD_LOADINKMEM
bool "In kernel memory optimization (uClinux only)"
default n
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
memory usage by preventing the need for two copies of the module
being loaded into memory.
config FEATURE_INSMOD_LOAD_MAP
bool "Enable insmod load map (-m) option"
default n
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
easier.
If you don't plan to debug kernel modules, you
don't need this option.
config FEATURE_INSMOD_LOAD_MAP_FULL
bool "Symbols in load map"
default y
depends on FEATURE_INSMOD_LOAD_MAP && !MODPROBE_SMALL
help
Without this option, -m will only output section
load map. With this option, -m will also output
symbols load map.
config FEATURE_CHECK_TAINTED_MODULE
# Simulate indentation
bool "Support tainted module checking with new kernels"
default y
depends on INSMOD || LSMOD
depends on !MODPROBE_SMALL
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 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 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
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
Say Y if unsure.
endmenu

View File

@ -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_MODPROBE_SMALL) += modprobe-small.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_FEATURE_2_4_MODULES) += modutils-24.o

View File

@ -2,6 +2,8 @@
/*
* depmod - generate modules.dep
* Copyright (c) 2008 Bernhard Fischer
* Copyrihgt (c) 2008 Timo Teras <timo.teras@iki.fi>
* Copyright (c) 2008 Vladimir Dronnikov
*
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
@ -10,6 +12,8 @@
#define _GNU_SOURCE
#include <libbb.h>
#include <sys/utsname.h> /* uname() */
#include "modutils.h"
/*
* Theory of operation:
* - iterate over all modules and record their full path
@ -17,272 +21,194 @@
* for each depends, look through our list of full paths and emit if found
*/
typedef struct dep_lst_t {
char *name;
typedef struct module_info {
struct module_info *next;
char *name, *modname;
llist_t *dependencies;
llist_t *aliases;
struct dep_lst_t *next;
} dep_lst_t;
llist_t *symbols;
struct module_info *dnext, *dprev;
} module_info;
struct globals {
dep_lst_t *lst; /* modules without their corresponding extension */
enum {
ARG_a = (1<<0), /* All modules, ignore mods in argv */
ARG_A = (1<<1), /* Only emit .ko that are newer than modules.dep file */
ARG_b = (1<<2), /* not /lib/modules/$(uname -r)/ but this base-dir */
ARG_e = (1<<3), /* with -F, print unresolved symbols */
ARG_F = (1<<4), /* System.map that contains the symbols */
ARG_n = (1<<5) /* dry-run, print to stdout only */
};
#define G (*(struct globals*)&bb_common_bufsiz1)
/* We have to zero it out because of NOEXEC */
#define INIT_G() memset(&G, 0, sizeof(G))
static char* find_keyword(void *the_module, size_t len, const char * const word)
{
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;
}
++ptr;
} while (1);
return ptr;
}
static int FAST_FUNC fileAction(const char *fname, struct stat *sb,
void UNUSED_PARAM *data, int UNUSED_PARAM depth)
static int FAST_FUNC parse_module(const char *fname, struct stat *sb,
void *data, int UNUSED_PARAM depth)
{
module_info **first = (module_info **) data;
char *image, *ptr;
module_info *info;
size_t len = sb->st_size;
void *the_module;
char *ptr;
int fd;
char *depends, *deps;
dep_lst_t *this;
if (strrstr(fname, ".ko") == NULL) /* not a module */
goto skip;
if (strrstr(fname, ".ko") == NULL)
return TRUE;
/*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");
image = (char *) xmalloc_open_zipped_read_close(fname, &len);
info = xzalloc(sizeof(module_info));
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));
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);
}
}
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:
free(image);
return TRUE;
}
static module_info *find_module(module_info *modules, const char *modname)
{
module_info *m;
for (m = modules; m != NULL; m = m->next)
if (strcmp(m->modname, modname) == 0)
return m;
return NULL;
}
static void order_dep_list(module_info *modules, module_info *start,
llist_t *add)
{
module_info *m;
llist_t *n;
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);
}
}
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 versions 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)) {
xchdir(*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);
xchdir(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;
/* 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);
order_dep_list(modules, m, m->dependencies);
while (m->dnext != m) {
dep = m->dnext;
printf(" %s", dep->name);
/* unlink current entry */
dep->dnext->dprev = dep->dprev;
dep->dprev->dnext = dep->dnext;
dep->dnext = dep->dprev = dep;
}
} while (!(option_mask32 & ARG_a) && *++argv);
{
dep_lst_t *mods = G.lst;
/* 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);
}
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);
}
}
#endif
#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);
}
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);
}
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;
}
}
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;
}

File diff suppressed because it is too large Load Diff

View File

@ -3,192 +3,77 @@
* Mini lsmod implementation for busybox
*
* Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
*
* Modified by Alcove, Julien Gaulmin <julien.gaulmin@alcove.fr> and
* Nicolas Ferre <nicolas.ferre@alcove.fr> to support pre 2.1 kernels
* (which lack the query_module() interface).
* Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
*
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
#include "libbb.h"
#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)
#if ENABLE_FEATURE_CHECK_TAINTED_MODULE
enum {
TAINT_PROPRIETORY_MODULE = (1 << 0),
TAINT_FORCED_MODULE = (1 << 1),
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");
}
}
#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");
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);
}
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);
}
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);
}
#else
xprint_and_close_file(file);
#endif /* CONFIG_FEATURE_2_6_MODULES */
static void check_tainted(void) { putchar('\n'); }
#endif
int lsmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int lsmod_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
{
#if ENABLE_FEATURE_LSMOD_PRETTY_2_6_OUTPUT
char *token[4];
parser_t *parser = config_open("/proc/modules");
printf("Module Size Used by"); //vda!
check_tainted();
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]);
}
} 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]);
}
}
if (ENABLE_FEATURE_CLEAN_UP)
config_close(parser);
#else
check_tainted();
xprint_and_close_file(xfopen_for_read("/proc/modules"));
#endif
return EXIT_SUCCESS;
}
#endif /* CONFIG_FEATURE_QUERY_MODULE_INTERFACE */

File diff suppressed because it is too large Load Diff

3936
modutils/modutils-24.c Normal file

File diff suppressed because it is too large Load Diff

141
modutils/modutils.c Normal file
View File

@ -0,0 +1,141 @@
/*
* Common modutils related functions for busybox
*
* Copyright (C) 2008 by Timo Teras <timo.teras@iki.fi>
*
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
#include "modutils.h"
#ifdef __UCLIBC__
extern int init_module(void *module, unsigned long len, const char *options);
extern int delete_module(const char *module, unsigned int flags);
#else
# include <sys/syscall.h>
# define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)
# define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags)
#endif
USE_FEATURE_2_4_MODULES(char *insmod_outputname);
/*
a libbb candidate from ice age!
*/
llist_t FAST_FUNC *llist_find(llist_t *first, const char *str)
{
while (first != NULL) {
if (strcmp(first->data, str) == 0)
return first;
first = first->link;
}
return NULL;
}
void FAST_FUNC replace(char *s, char what, char with)
{
while (*s) {
if (what == *s)
*s = with;
++s;
}
}
char * FAST_FUNC replace_underscores(char *s)
{
replace(s, '-', '_');
return s;
}
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 -1:
return "no such module";
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);
}

68
modutils/modutils.h Normal file
View File

@ -0,0 +1,68 @@
/*
* Common modutils related functions for busybox
*
* Copyright (C) 2008 by Timo Teras <timo.teras@iki.fi>
*
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
#ifndef __MODUTILS_H__
#define __MODUTILS_H__
#include "libbb.h"
#include <stdio.h>
#if __GNUC_PREREQ(4,1)
# pragma GCC visibility push(hidden)
#endif
/* As defined in linux/include/linux/module.h */
#define MODULE_NAME_LEN 64
const char *moderror(int err) FAST_FUNC;
llist_t *llist_find(llist_t *first, const char *str) FAST_FUNC;
void replace(char *s, char what, char with) FAST_FUNC;
char *replace_underscores(char *s) FAST_FUNC;
int string_to_llist(char *string, llist_t **llist, const char *delim) 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

View File

@ -3,98 +3,45 @@
* Mini rmmod implementation for busybox
*
* Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
* Copyright (C) 2008 Timo Teras <timo.teras@iki.fi>
*
* Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
#include "libbb.h"
#ifdef __UCLIBC__
extern int delete_module(const char *module, unsigned int flags);
#else
# include <sys/syscall.h>
# define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags)
#endif
#if ENABLE_FEATURE_2_6_MODULES
static void filename2modname(char *modname, const char *afterslash)
{
unsigned int i;
int kr_chk = 1;
if (ENABLE_FEATURE_2_4_MODULES
&& get_linux_version_code() <= KERNEL_VERSION(2,6,0))
kr_chk = 0;
/* Convert to underscores, stop at first . */
for (i = 0; afterslash[i] && afterslash[i] != '.'; i++) {
if (kr_chk && (afterslash[i] == '-'))
modname[i] = '_';
else
modname[i] = afterslash[i];
}
modname[i] = '\0';
}
#else
void filename2modname(char *modname, const char *afterslash);
#endif
// There really should be a header file for this...
int query_module(const char *name, int which, void *buf,
size_t bufsize, size_t *ret);
#include "modutils.h"
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;
#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]));
}
if (delete_module(ENABLE_FEATURE_2_6_MODULES ? misc_buf : argv[n], flags)) {
bb_simple_perror_msg(argv[n]);
ret = EXIT_FAILURE;
}
while (*argv) {
char modname[MODULE_NAME_LEN];
filename2modname(bb_basename(*argv++), modname);
if (bb_delete_module(modname, flags))
bb_error_msg_and_die("cannot unload '%s': %s",
modname, moderror(errno));
}
return ret;
return EXIT_SUCCESS;
}