busybox/modutils/modinfo.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * modinfo - retrieve module info
   4 * Copyright (c) 2008 Pascal Bellard
   5 *
   6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
   7 */
   8//config:config MODINFO
   9//config:       bool "modinfo (24 kb)"
  10//config:       default y
  11//config:       select PLATFORM_LINUX
  12//config:       help
  13//config:       Show information about a Linux Kernel module
  14
  15//applet:IF_MODINFO(APPLET_NOEXEC(modinfo, modinfo, BB_DIR_SBIN, BB_SUID_DROP, modinfo))
  16
  17//kbuild:lib-$(CONFIG_MODINFO) += modinfo.o modutils.o
  18
  19#include <fnmatch.h>
  20#include <sys/utsname.h> /* uname() */
  21#include "libbb.h"
  22#include "modutils.h"
  23
  24static const char *const shortcuts[] = {
  25        "filename",     // -n
  26        "author",       // -a
  27        "description",  // -d
  28        "license",      // -l
  29        "parm",         // -p
  30        "version",      // the rest has no shortcut options
  31        "alias",
  32        "srcversion",
  33        "depends",
  34        "uts_release",
  35        "intree",
  36        "vermagic",
  37        "firmware",
  38};
  39
  40enum {
  41        OPT_0 = (1 << 0), /* \0 as separator */
  42        OPT_F = (1 << 1), /* field name */
  43        /* first bits are for -nadlp options, the rest are for
  44         * fields not selectable with "shortcut" options
  45         */
  46        OPT_n = (1 << 2),
  47        OPT_TAGS = ((1 << ARRAY_SIZE(shortcuts)) - 1) << 2,
  48};
  49
  50static void display(const char *data, const char *pattern)
  51{
  52        int flag = option_mask32 >> 1; /* shift out -0 bit */
  53        if (flag & (flag-1)) {
  54                /* more than one field to show: print "FIELD:" pfx */
  55                int n = printf("%s:", pattern);
  56                while (n++ < 16)
  57                        bb_putchar(' ');
  58        }
  59        printf("%s%c", data, (option_mask32 & OPT_0) ? '\0' : '\n');
  60}
  61
  62static void modinfo(const char *path, const char *version,
  63                        const char *field)
  64{
  65        size_t len;
  66        int j;
  67        char *ptr, *the_module;
  68        char *allocated;
  69        int tags = option_mask32;
  70
  71        allocated = NULL;
  72        len = MAXINT(ssize_t);
  73        the_module = xmalloc_open_zipped_read_close(path, &len);
  74        if (!the_module) {
  75                if (path[0] == '/')
  76                        return;
  77                /* Newer depmod puts relative paths in modules.dep */
  78                path = allocated = xasprintf("%s/%s/%s", CONFIG_DEFAULT_MODULES_DIR, version, path);
  79                the_module = xmalloc_open_zipped_read_close(path, &len);
  80                if (!the_module) {
  81                        bb_error_msg("module '%s' not found", path);
  82                        goto ret;
  83                }
  84        }
  85
  86        for (j = 1; (1<<j) & (OPT_TAGS|OPT_F); j++) {
  87                const char *pattern;
  88
  89                if (!((1<<j) & tags))
  90                        continue;
  91
  92                pattern = field;
  93                if ((1<<j) & OPT_TAGS)
  94                        pattern = shortcuts[j-2];
  95
  96                if (strcmp(pattern, shortcuts[0]) == 0) {
  97                        /* "-n" or "-F filename" */
  98                        display(path, shortcuts[0]);
  99                        continue;
 100                }
 101
 102                ptr = the_module;
 103                while (1) {
 104                        char *after_pattern;
 105
 106                        ptr = memchr(ptr, *pattern, len - (ptr - (char*)the_module));
 107                        if (ptr == NULL) /* no occurrence left, done */
 108                                break;
 109                        after_pattern = is_prefixed_with(ptr, pattern);
 110                        if (after_pattern && *after_pattern == '=') {
 111                                /* field prefixes are 0x80 or 0x00 */
 112                                if ((ptr[-1] & 0x7F) == 0x00) {
 113                                        ptr = after_pattern + 1;
 114                                        display(ptr, pattern);
 115                                        ptr += strlen(ptr);
 116                                }
 117                        }
 118                        ++ptr;
 119                }
 120        }
 121        free(the_module);
 122 ret:
 123        free(allocated);
 124}
 125
 126//usage:#define modinfo_trivial_usage
 127//usage:       "[-adlpn0] [-F keyword] MODULE"
 128//usage:#define modinfo_full_usage "\n\n"
 129//usage:       "        -a              Shortcut for '-F author'"
 130//usage:     "\n        -d              Shortcut for '-F description'"
 131//usage:     "\n        -l              Shortcut for '-F license'"
 132//usage:     "\n        -p              Shortcut for '-F parm'"
 133////usage:     "\n      -n              Shortcut for '-F filename'"
 134//usage:     "\n        -F keyword      Keyword to look for"
 135//usage:     "\n        -0              Separate output with NULs"
 136//usage:#define modinfo_example_usage
 137//usage:       "$ modinfo -F vermagic loop\n"
 138
 139int modinfo_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 140int modinfo_main(int argc UNUSED_PARAM, char **argv)
 141{
 142        const char *field;
 143        char name[MODULE_NAME_LEN];
 144        struct utsname uts;
 145        parser_t *parser;
 146        char *colon, *tokens[2];
 147        unsigned opts;
 148        unsigned i;
 149
 150        field = NULL;
 151        opts = getopt32(argv, "^" "0F:nadlp" "\0" "-1"/*minimum one arg*/, &field);
 152        /* If no field selected, show all */
 153        if (!(opts & (OPT_TAGS|OPT_F)))
 154                option_mask32 |= OPT_TAGS;
 155        argv += optind;
 156
 157        uname(&uts);
 158        parser = config_open2(
 159                xasprintf("%s/%s/%s", CONFIG_DEFAULT_MODULES_DIR, uts.release, CONFIG_DEFAULT_DEPMOD_FILE),
 160                xfopen_for_read
 161        );
 162
 163        while (config_read(parser, tokens, 2, 1, "# \t", PARSE_NORMAL)) {
 164                colon = last_char_is(tokens[0], ':');
 165                if (colon == NULL)
 166                        continue;
 167                *colon = '\0';
 168                filename2modname(bb_basename(tokens[0]), name);
 169                for (i = 0; argv[i]; i++) {
 170                        if (fnmatch(argv[i], name, 0) == 0) {
 171                                modinfo(tokens[0], uts.release, field);
 172                                argv[i] = (char *) "";
 173                        }
 174                }
 175        }
 176        if (ENABLE_FEATURE_CLEAN_UP)
 177                config_close(parser);
 178
 179        for (i = 0; argv[i]; i++) {
 180                if (argv[i][0]) {
 181                        modinfo(argv[i], uts.release, field);
 182                }
 183        }
 184
 185        return 0;
 186}
 187