udhcpc: fix a problem with binary-encoded options #2
[oweals/busybox.git] / modutils / modinfo.c
index 321ad78f42f8db8ec676ff568be957636efe550e..7c978d1da50ad68a4eb66d3e0dcc1ff20f9e56d7 100644 (file)
@@ -3,16 +3,17 @@
  * modinfo - retrieve module info
  * Copyright (c) 2008 Pascal Bellard
  *
- * 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.
  */
 
-//applet:IF_MODINFO(APPLET(modinfo, _BB_DIR_SBIN, _BB_SUID_DROP))
+//applet:IF_MODINFO(APPLET(modinfo, BB_DIR_SBIN, BB_SUID_DROP))
 
 //kbuild:lib-$(CONFIG_MODINFO) += modinfo.o modutils.o
 
 //config:config MODINFO
 //config:      bool "modinfo"
 //config:      default y
+//config:      select PLATFORM_LINUX
 //config:      help
 //config:        Show information about a Linux Kernel module
 
@@ -23,9 +24,9 @@
 
 
 enum {
-       OPT_TAGS = (1 << 6) - 1,
-       OPT_F = (1 << 6), /* field name */
-       OPT_0 = (1 << 7),  /* \0 as separator */
+       OPT_TAGS = (1 << 12) - 1, /* shortcut count */
+       OPT_F = (1 << 12), /* field name */
+       OPT_0 = (1 << 13), /* \0 as separator */
 };
 
 struct modinfo_env {
@@ -43,15 +44,22 @@ static int display(const char *data, const char *pattern, int flag)
        return printf("%s%c", data, (option_mask32 & OPT_0) ? '\0' : '\n');
 }
 
-static void modinfo(const char *path, struct modinfo_env *env)
+static void modinfo(const char *path, const char *version,
+                       const struct modinfo_env *env)
 {
        static const char *const shortcuts[] = {
                "filename",
-               "description",
-               "author",
                "license",
+               "author",
+               "description",
+               "version",
+               "alias",
+               "srcversion",
+               "depends",
+               "uts_release",
                "vermagic",
                "parm",
+               "firmware",
        };
        size_t len;
        int j, length;
@@ -62,18 +70,30 @@ static void modinfo(const char *path, struct modinfo_env *env)
        if (tags & 1) { /* filename */
                display(path, shortcuts[0], 1 != tags);
        }
+
        len = MAXINT(ssize_t);
        the_module = xmalloc_open_zipped_read_close(path, &len);
-       if (!the_module)
-               return;
+       if (!the_module) {
+               if (path[0] == '/')
+                       return;
+               /* Newer depmod puts relative paths in modules.dep */
+               path = xasprintf("%s/%s/%s", CONFIG_DEFAULT_MODULES_DIR, version, path);
+               the_module = xmalloc_open_zipped_read_close(path, &len);
+               free((char*)path);
+               if (!the_module)
+                       return;
+       }
+
        if (field)
                tags |= OPT_F;
        for (j = 1; (1<<j) & (OPT_TAGS + OPT_F); j++) {
-               const char *pattern = field;
-               if ((1<<j) & OPT_TAGS)
-                       pattern = shortcuts[j];
+               const char *pattern;
+
                if (!((1<<j) & tags))
                        continue;
+               pattern = field;
+               if ((1<<j) & OPT_TAGS)
+                       pattern = shortcuts[j];
                length = strlen(pattern);
                ptr = the_module;
                while (1) {
@@ -81,8 +101,11 @@ static void modinfo(const char *path, struct modinfo_env *env)
                        if (ptr == NULL) /* no occurance left, done */
                                break;
                        if (strncmp(ptr, pattern, length) == 0 && ptr[length] == '=') {
-                               ptr += length + 1;
-                               ptr += display(ptr, pattern, (1<<j) != tags);
+                               /* field prefixes are 0x80 or 0x00 */
+                               if ((ptr[-1] & 0x7F) == '\0') {
+                                       ptr += length + 1;
+                                       ptr += display(ptr, pattern, (1<<j) != tags);
+                               }
                        }
                        ++ptr;
                }
@@ -93,8 +116,7 @@ static void modinfo(const char *path, struct modinfo_env *env)
 //usage:#define modinfo_trivial_usage
 //usage:       "[-adlp0] [-F keyword] MODULE"
 //usage:#define modinfo_full_usage "\n\n"
-//usage:       "Options:"
-//usage:     "\n       -a              Shortcut for '-F author'"
+//usage:       "       -a              Shortcut for '-F author'"
 //usage:     "\n       -d              Shortcut for '-F description'"
 //usage:     "\n       -l              Shortcut for '-F license'"
 //usage:     "\n       -p              Shortcut for '-F parm'"
@@ -109,26 +131,24 @@ int modinfo_main(int argc UNUSED_PARAM, char **argv)
        struct modinfo_env env;
        char name[MODULE_NAME_LEN];
        struct utsname uts;
-       parser_t *p;
+       parser_t *parser;
        char *colon, *tokens[2];
        unsigned opts;
        unsigned i;
 
        env.field = NULL;
        opt_complementary = "-1"; /* minimum one param */
-       opts = getopt32(argv, "fdalvpF:0", &env.field);
+       opts = getopt32(argv, "nladvAsDumpF:0", &env.field);
        env.tags = opts & OPT_TAGS ? opts & OPT_TAGS : OPT_TAGS;
        argv += optind;
 
        uname(&uts);
-       p = config_open2(
-               concat_path_file(
-                       concat_path_file(CONFIG_DEFAULT_MODULES_DIR, uts.release),
-                       CONFIG_DEFAULT_DEPMOD_FILE),
+       parser = config_open2(
+               xasprintf("%s/%s/%s", CONFIG_DEFAULT_MODULES_DIR, uts.release, CONFIG_DEFAULT_DEPMOD_FILE),
                xfopen_for_read
        );
 
-       while (config_read(p, tokens, 2, 1, "# \t", PARSE_NORMAL)) {
+       while (config_read(parser, tokens, 2, 1, "# \t", PARSE_NORMAL)) {
                colon = last_char_is(tokens[0], ':');
                if (colon == NULL)
                        continue;
@@ -136,15 +156,19 @@ int modinfo_main(int argc UNUSED_PARAM, char **argv)
                filename2modname(tokens[0], name);
                for (i = 0; argv[i]; i++) {
                        if (fnmatch(argv[i], name, 0) == 0) {
-                               modinfo(tokens[0], &env);
+                               modinfo(tokens[0], uts.release, &env);
                                argv[i] = (char *) "";
                        }
                }
        }
+       if (ENABLE_FEATURE_CLEAN_UP)
+               config_close(parser);
+
        for (i = 0; argv[i]; i++) {
                if (argv[i][0]) {
-                       modinfo(argv[i], &env);
+                       modinfo(argv[i], uts.release, &env);
                }
        }
+
        return 0;
 }