* 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.
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/
-#undef _GNU_SOURCE
-#define _GNU_SOURCE
-#include <libbb.h>
-#include <sys/utsname.h> /* uname() */
+//applet:IF_DEPMOD(APPLET(depmod, BB_DIR_SBIN, BB_SUID_DROP))
+
+#include "libbb.h"
#include "modutils.h"
+#include <sys/utsname.h> /* uname() */
/*
* Theory of operation:
struct module_info *dnext, *dprev;
} module_info;
-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), /* base directory when modules are in staging area */
- 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 */
-};
-
-static int FAST_FUNC parse_module(const char *fname, struct stat *sb,
- void *data, int UNUSED_PARAM depth)
+static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARAM,
+ void *data, int depth UNUSED_PARAM)
{
+ char modname[MODULE_NAME_LEN];
module_info **first = (module_info **) data;
char *image, *ptr;
module_info *info;
- size_t len = sb->st_size;
+ /* Arbitrary. Was sb->st_size, but that breaks .gz etc */
+ size_t len = (64*1024*1024 - 4096);
if (strrstr(fname, ".ko") == NULL)
return TRUE;
image = xmalloc_open_zipped_read_close(fname, &len);
- info = xzalloc(sizeof(module_info));
+ info = xzalloc(sizeof(*info));
info->next = *first;
*first = info;
info->dnext = info->dprev = info;
- info->name = xasprintf("/%s", fname);
- info->modname = filename2modname(fname, NULL);
+ info->name = xstrdup(fname + 2); /* skip "./" */
+ info->modname = xstrdup(filename2modname(fname, modname));
for (ptr = image; ptr < image + len - 10; ptr++) {
if (strncmp(ptr, "depends=", 8) == 0) {
char *u;
if (*u == '-')
*u = '_';
ptr += string_to_llist(ptr, &info->dependencies, ",");
- } else if (ENABLE_FEATURE_MODUTILS_ALIAS &&
- strncmp(ptr, "alias=", 6) == 0) {
+ } 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) {
+ } else if (ENABLE_FEATURE_MODUTILS_SYMBOLS
+ && strncmp(ptr, "__ksymtab_", 10) == 0
+ ) {
ptr += 10;
- if (strncmp(ptr, "gpl", 3) == 0 ||
- strcmp(ptr, "strings") == 0)
+ if (strncmp(ptr, "gpl", 3) == 0
+ || strcmp(ptr, "strings") == 0
+ ) {
continue;
+ }
llist_add_to(&info->symbols, xstrdup(ptr));
ptr += strlen(ptr);
}
}
static void order_dep_list(module_info *modules, module_info *start,
- llist_t *add)
+ llist_t *add)
{
module_info *m;
llist_t *n;
bb_perror_msg_and_die("can't open '%s'", file);
}
+//usage:#if !ENABLE_MODPROBE_SMALL
+//usage:#define depmod_trivial_usage "[-n] [-b BASE] [VERSION] [MODFILES]..."
+//usage:#define depmod_full_usage "\n\n"
+//usage: "Generate modules.dep, alias, and symbols files"
+//usage: "\n"
+//usage: "\n -b BASE Use BASE/lib/modules/VERSION"
+//usage: "\n -n Dry run: print files to stdout"
+//usage:#endif
+
+/* Upstream usage:
+ * [-aAenv] [-C FILE or DIR] [-b BASE] [-F System.map] [VERSION] [MODFILES]...
+ * -a --all
+ * Probe all modules. Default if no MODFILES.
+ * -A --quick
+ * Check modules.dep's mtime against module files' mtimes.
+ * -b --basedir BASE
+ * Use $BASE/lib/modules/VERSION
+ * -C --config FILE or DIR
+ * Path to /etc/depmod.conf or /etc/depmod.d/
+ * -e --errsyms
+ * When combined with the -F option, this reports any symbols
+ * which are not supplied by other modules or kernel.
+ * -F --filesyms System.map
+ * -n --dry-run
+ * Print modules.dep etc to standard output
+ * -v --verbose
+ * Print to stdout all the symbols each module depends on
+ * and the module's file name which provides that symbol.
+ * -r No-op
+ * -u No-op
+ * -q No-op
+ *
+ * So far we only support: [-n] [-b BASE] [VERSION] [MODFILES]...
+ * Accepted but ignored:
+ * -aAe
+ * -F System.map
+ * -C FILE/DIR
+ *
+ * Not accepted: -v
+ */
+enum {
+ //OPT_a = (1 << 0), /* All modules, ignore mods in argv */
+ //OPT_A = (1 << 1), /* Only emit .ko that are newer than modules.dep file */
+ OPT_b = (1 << 2), /* base directory when modules are in staging area */
+ //OPT_e = (1 << 3), /* with -F, print unresolved symbols */
+ //OPT_F = (1 << 4), /* System.map that contains the symbols */
+ OPT_n = (1 << 5), /* dry-run, print to stdout only */
+ OPT_r = (1 << 6), /* Compat dummy. Linux Makefile uses it */
+ OPT_u = (1 << 7), /* -u,--unresolved-error: ignored */
+ OPT_q = (1 << 8), /* -q,--quiet: ignored */
+ OPT_C = (1 << 9), /* -C,--config etc_modules_conf: ignored */
+};
+
int depmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int depmod_main(int argc UNUSED_PARAM, char **argv)
{
- module_info *modules = NULL, *m, *dep;
+ module_info *modules, *m, *dep;
const char *moddir_base = "/";
char *moddir, *version;
struct utsname uts;
int tmp;
- getopt32(argv, "aAb:eF:n", &moddir_base, NULL);
+ getopt32(argv, "aAb:eF:nruqC:", &moddir_base, NULL, NULL);
argv += optind;
/* 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", &tmp, &tmp, &tmp) == 3) {
+ if (*argv && sscanf(*argv, "%u.%u.%u", &tmp, &tmp, &tmp) == 3) {
version = *argv++;
} else {
uname(&uts);
version = uts.release;
}
moddir = concat_path_file(&CONFIG_DEFAULT_MODULES_DIR[1], version);
+ xchdir(moddir);
+ if (ENABLE_FEATURE_CLEAN_UP)
+ free(moddir);
/* Scan modules */
+ modules = NULL;
if (*argv) {
- char *modfile;
- struct stat sb;
do {
- modfile = concat_path_file(moddir, *argv);
- xstat(modfile, &sb);
- parse_module(modfile, &sb, &modules, 0);
- free(modfile);
- } while (*(++argv));
+ parse_module(*argv, /*sb (unused):*/ NULL, &modules, 0);
+ } while (*++argv);
} else {
- recursive_action(moddir, ACTION_RECURSE,
- parse_module, NULL, &modules, 0);
+ recursive_action(".", ACTION_RECURSE,
+ parse_module, NULL, &modules, 0);
}
- /* Prepare for writing out the dep files */
- xchdir(moddir);
- if (ENABLE_FEATURE_CLEAN_UP)
- free(moddir);
-
/* Generate dependency and alias files */
- if (!(option_mask32 & ARG_n))
+ if (!(option_mask32 & OPT_n))
xfreopen_write(CONFIG_DEFAULT_DEPMOD_FILE, stdout);
for (m = modules; m != NULL; m = m->next) {
printf("%s:", m->name);
}
#if ENABLE_FEATURE_MODUTILS_ALIAS
- if (!(option_mask32 & ARG_n))
+ if (!(option_mask32 & OPT_n))
xfreopen_write("modules.alias", stdout);
for (m = modules; m != NULL; m = m->next) {
+ const char *fname = bb_basename(m->name);
+ int fnlen = strchrnul(fname, '.') - fname;
while (m->aliases) {
- printf("alias %s %s\n",
+ /* Last word can well be m->modname instead,
+ * but depmod from module-init-tools 3.4
+ * uses module basename, i.e., no s/-/_/g.
+ * (pathname and .ko.* are still stripped)
+ * Mimicking that... */
+ printf("alias %s %.*s\n",
(char*)llist_pop(&m->aliases),
- m->modname);
+ fnlen, fname);
}
}
#endif
#if ENABLE_FEATURE_MODUTILS_SYMBOLS
- if (!(option_mask32 & ARG_n))
+ if (!(option_mask32 & OPT_n))
xfreopen_write("modules.symbols", stdout);
for (m = modules; m != NULL; m = m->next) {
+ const char *fname = bb_basename(m->name);
+ int fnlen = strchrnul(fname, '.') - fname;
while (m->symbols) {
- printf("alias symbol:%s %s\n",
+ printf("alias symbol:%s %.*s\n",
(char*)llist_pop(&m->symbols),
- m->modname);
+ fnlen, fname);
}
}
#endif