ash: do not let EXIT trap to fire in `trap`
[oweals/busybox.git] / modutils / modprobe-small.c
index 63be9aadb8ba56d54021cdbd147b8658775b7900..e2359d042259c16c31510dcf18685c85bf7509b2 100644 (file)
@@ -3,13 +3,13 @@
  * simplified modprobe
  *
  * Copyright (c) 2008 Vladimir Dronnikov
- * Copyright (c) 2008 Bernhard Fischer (initial depmod code)
+ * Copyright (c) 2008 Bernhard Reutner-Fischer (initial depmod code)
  *
  * Licensed under GPLv2, see file LICENSE in this tarball for details.
  */
 
 #include "libbb.h"
-
+/* After libbb.h, since it needs sys/types.h on some systems */
 #include <sys/utsname.h> /* uname() */
 #include <fnmatch.h>
 
@@ -44,11 +44,13 @@ struct globals {
        char *module_load_options;
        smallint dep_bb_seen;
        smallint wrote_dep_bb_ok;
-       int module_count;
+       unsigned module_count;
        int module_found_idx;
-       int stringbuf_idx;
-       char stringbuf[32 * 1024]; /* some modules have lots of stuff */
+       unsigned stringbuf_idx;
+       unsigned stringbuf_size;
+       char *stringbuf; /* some modules have lots of stuff */
        /* for example, drivers/media/video/saa7134/saa7134.ko */
+       /* therefore having a fixed biggish buffer is not wise */
 };
 #define G (*ptr_to_globals)
 #define modinfo             (G.modinfo            )
@@ -58,16 +60,29 @@ struct globals {
 #define module_found_idx    (G.module_found_idx   )
 #define module_load_options (G.module_load_options)
 #define stringbuf_idx       (G.stringbuf_idx      )
+#define stringbuf_size      (G.stringbuf_size     )
 #define stringbuf           (G.stringbuf          )
 #define INIT_G() do { \
        SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
 } while (0)
 
+static void append(const char *s)
+{
+       unsigned len = strlen(s);
+       if (stringbuf_idx + len + 15 > stringbuf_size) {
+               stringbuf_size = stringbuf_idx + len + 127;
+               dbg2_error_msg("grow stringbuf to %u", stringbuf_size);
+               stringbuf = xrealloc(stringbuf, stringbuf_size);
+       }
+       memcpy(stringbuf + stringbuf_idx, s, len);
+       stringbuf_idx += len;
+}
 
 static void appendc(char c)
 {
-       if (stringbuf_idx < sizeof(stringbuf))
-               stringbuf[stringbuf_idx++] = c;
+       /* We appendc() only after append(), + 15 trick in append()
+        * makes it unnecessary to check for overflow here */
+       stringbuf[stringbuf_idx++] = c;
 }
 
 static void bksp(void)
@@ -76,15 +91,6 @@ static void bksp(void)
                stringbuf_idx--;
 }
 
-static void append(const char *s)
-{
-       size_t len = strlen(s);
-       if (stringbuf_idx + len < sizeof(stringbuf)) {
-               memcpy(stringbuf + stringbuf_idx, s, len);
-               stringbuf_idx += len;
-       }
-}
-
 static void reset_stringbuf(void)
 {
        stringbuf_idx = 0;
@@ -92,7 +98,7 @@ static void reset_stringbuf(void)
 
 static char* copy_stringbuf(void)
 {
-       char *copy = xmalloc(stringbuf_idx);
+       char *copy = xzalloc(stringbuf_idx + 1); /* terminating NUL */
        return memcpy(copy, stringbuf, stringbuf_idx);
 }
 
@@ -100,7 +106,7 @@ static char* find_keyword(char *ptr, size_t len, const char *word)
 {
        int wlen;
 
-       if (!ptr) /* happens if read_module cannot read it */
+       if (!ptr) /* happens if xmalloc_open_zipped_read_close cannot read it */
                return NULL;
 
        wlen = strlen(word);
@@ -141,12 +147,6 @@ static char* str_2_list(const char *str)
        return dst;
 }
 
-#if ENABLE_FEATURE_MODPROBE_SMALL_ZIPPED
-# define read_module xmalloc_open_zipped_read_close
-#else
-# define read_module xmalloc_open_read_close
-#endif
-
 /* We use error numbers in a loose translation... */
 static const char *moderror(int err)
 {
@@ -173,7 +173,7 @@ static int load_module(const char *fname, const char *options)
        char *module_image;
        dbg1_error_msg("load_module('%s','%s')", fname, options);
 
-       module_image = read_module(fname, &len);
+       module_image = xmalloc_open_zipped_read_close(fname, &len);
        r = (!module_image || init_module(module_image, len, options ? options : "") != 0);
        free(module_image);
        dbg1_error_msg("load_module:%d", r);
@@ -195,7 +195,7 @@ static void parse_module(module_info *info, const char *pathname)
 
        /* Read (possibly compressed) module */
        len = 64 * 1024 * 1024; /* 64 Mb at most */
-       module_image = read_module(pathname, &len);
+       module_image = xmalloc_open_zipped_read_close(pathname, &len);
 //TODO: optimize redundant module body reads
 
        /* "alias1 symbol:sym1 alias2 symbol:sym2" */
@@ -222,8 +222,8 @@ static void parse_module(module_info *info, const char *pathname)
                pos = (ptr - module_image);
        }
        bksp(); /* remove last ' ' */
-       appendc('\0');
        info->aliases = copy_stringbuf();
+       replace(info->aliases, '-', '_');
 
        /* "dependency1 depandency2" */
        reset_stringbuf();
@@ -234,7 +234,6 @@ static void parse_module(module_info *info, const char *pathname)
                dbg2_error_msg("dep:'%s'", ptr);
                append(ptr);
        }
-       appendc('\0');
        info->deps = copy_stringbuf();
 
        free(module_image);
@@ -270,10 +269,9 @@ static FAST_FUNC int fileAction(const char *pathname,
 
        cur = module_count++;
        modinfo = xrealloc_vector(modinfo, 12, cur);
-//TODO: use zeroing version of xrealloc_vector?
        modinfo[cur].pathname = xstrdup(pathname);
-       modinfo[cur].aliases = NULL;
-       modinfo[cur+1].pathname = NULL;
+       /*modinfo[cur].aliases = NULL; - xrealloc_vector did it */
+       /*modinfo[cur+1].pathname = NULL;*/
 
        if (!pathname_matches_modname(fname, modname_to_match)) {
                dbg1_error_msg("'%s' module name doesn't match", pathname);
@@ -321,6 +319,7 @@ static int load_dep_bb(void)
 
        while ((line = xmalloc_fgetline(fp)) != NULL) {
                char* space;
+               char* linebuf;
                int cur;
 
                if (!line[0]) {
@@ -330,13 +329,13 @@ static int load_dep_bb(void)
                space = strchrnul(line, ' ');
                cur = module_count++;
                modinfo = xrealloc_vector(modinfo, 12, cur);
-//TODO: use zeroing version of xrealloc_vector?
-               modinfo[cur+1].pathname = NULL;
+               /*modinfo[cur+1].pathname = NULL; - xrealloc_vector did it */
                modinfo[cur].pathname = line; /* we take ownership of malloced block here */
                if (*space)
                        *space++ = '\0';
                modinfo[cur].aliases = space;
-               modinfo[cur].deps = xmalloc_fgetline(fp) ? : xzalloc(1);
+               linebuf = xmalloc_fgetline(fp);
+               modinfo[cur].deps = linebuf ? linebuf : xzalloc(1);
                if (modinfo[cur].deps[0]) {
                        /* deps are not "", so next line must be empty */
                        line = xmalloc_fgetline(fp);
@@ -452,8 +451,10 @@ static module_info* find_alias(const char *alias)
                if (!modinfo[i].aliases) {
                        parse_module(&modinfo[i], modinfo[i].pathname);
                }
-               if (result)
+               if (result) {
+                       i++;
                        continue;
+               }
                /* "alias1 symbol:sym1 alias2 symbol:sym2" */
                desc = str_2_list(modinfo[i].aliases);
                /* Does matching substring exist? */
@@ -605,19 +606,23 @@ static void process_module(char *name, const char *cmdline_options)
        }
        free(deps);
 
-       /* insmod -> load it */
+       /* modprobe -> load it */
        if (!is_rmmod) {
-               errno = 0;
-               if (load_module(info->pathname, options) != 0) {
-                       if (EEXIST != errno) {
-                               bb_error_msg("'%s': %s",
+               if (!options || strstr(options, "blacklist") == NULL) {
+                       errno = 0;
+                       if (load_module(info->pathname, options) != 0) {
+                               if (EEXIST != errno) {
+                                       bb_error_msg("'%s': %s",
                                                info->pathname,
                                                moderror(errno));
-                       } else {
-                               dbg1_error_msg("'%s': %s",
+                               } else {
+                                       dbg1_error_msg("'%s': %s",
                                                info->pathname,
                                                moderror(errno));
+                               }
                        }
+               } else {
+                       dbg1_error_msg("'%s': blacklisted", info->pathname);
                }
        }
  ret:
@@ -642,7 +647,7 @@ Usage: rmmod [-fhswvV] modulename ...
  -s (or --syslog) says use syslog, not stderr
  -v (or --verbose) enables more messages
  -V (or --version) prints the version code
- -w (or --wait) begins module removal even if it is used
+ -w (or --wait) begins module removal even if it is used
     and will stop new users from accessing the module (so it
     should eventually fall to zero).
 
@@ -658,21 +663,22 @@ depmod -[aA] [-n -e -v -q -V -r -u]
       [-b basedirectory] [forced_version]
 depmod [-n -e -v -q -r -u] [-F kernelsyms] module1.ko module2.ko ...
 If no arguments (except options) are given, "depmod -a" is assumed.
-depmod will output a dependancy list suitable for the modprobe utility.
+depmod will output a dependency list suitable for the modprobe utility.
 Options:
-    -a, --all            Probe all modules
-    -A, --quick          Only does the work if there's a new module
-    -n, --show           Write the dependency file on stdout only
-    -e, --errsyms        Report not supplied symbols
-    -V, --version        Print the release version
-    -v, --verbose        Enable verbose mode
-    -h, --help           Print this usage message
+    -a, --all           Probe all modules
+    -A, --quick         Only does the work if there's a new module
+    -n, --show          Write the dependency file on stdout only
+    -e, --errsyms       Report not supplied symbols
+    -V, --version       Print the release version
+    -v, --verbose       Enable verbose mode
+    -h, --help          Print this usage message
 The following options are useful for people managing distributions:
     -b basedirectory
-        --basedir basedirectory    Use an image of a module tree.
+    --basedir basedirectory
+                        Use an image of a module tree
     -F kernelsyms
-        --filesyms kernelsyms      Use the file instead of the
-                                   current kernel symbols.
+    --filesyms kernelsyms
+                        Use the file instead of the current kernel symbols
 */
 
 int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -680,7 +686,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
 {
        struct utsname uts;
        char applet0 = applet_name[0];
-       USE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(char *options;)
+       IF_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(char *options;)
 
        /* are we lsmod? -> just dump /proc/modules */
        if ('l' == applet0) {
@@ -693,8 +699,10 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
        /* Prevent ugly corner cases with no modules at all */
        modinfo = xzalloc(sizeof(modinfo[0]));
 
-       /* Goto modules directory */
-       xchdir(CONFIG_DEFAULT_MODULES_DIR);
+       if ('i' != applet0) { /* not insmod */
+               /* Goto modules directory */
+               xchdir(CONFIG_DEFAULT_MODULES_DIR);
+       }
        uname(&uts); /* never fails */
 
        /* depmod? */
@@ -741,8 +749,10 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
                option_mask32 |= OPT_r;
        }
 
-       /* Goto $VERSION directory */
-       xchdir(uts.release);
+       if ('i' != applet0) { /* not insmod */
+               /* Goto $VERSION directory */
+               xchdir(uts.release);
+       }
 
 #if ENABLE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE
        /* If not rmmod, parse possible module options given on command line.
@@ -763,17 +773,32 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
                argv[1] = NULL;
 #endif
 
+       if ('i' == applet0) { /* insmod */
+               size_t len;
+               void *map;
+
+               len = MAXINT(ssize_t);
+               map = xmalloc_xopen_read_close(*argv, &len);
+               if (init_module(map, len,
+                       IF_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(options ? options : "")
+                       IF_NOT_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE("")
+                               ) != 0)
+                       bb_error_msg_and_die("can't insert '%s': %s",
+                                       *argv, moderror(errno));
+               return 0;
+       }
+
        /* Try to load modprobe.dep.bb */
        load_dep_bb();
 
        /* Load/remove modules.
-        * Only rmmod loops here, insmod/modprobe has only argv[0] */
+        * Only rmmod loops here, modprobe has only argv[0] */
        do {
                process_module(*argv++, options);
        } while (*argv);
 
        if (ENABLE_FEATURE_CLEAN_UP) {
-               USE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(free(options);)
+               IF_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(free(options);)
        }
        return EXIT_SUCCESS;
 }