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