busybox/modutils/modutils.c
<<
>>
Prefs
   1/*
   2 * Common modutils related functions for busybox
   3 *
   4 * Copyright (C) 2008 by Timo Teras <timo.teras@iki.fi>
   5 *
   6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
   7 */
   8#include "modutils.h"
   9
  10#ifdef __UCLIBC__
  11extern int init_module(void *module, unsigned long len, const char *options);
  12extern int delete_module(const char *module, unsigned int flags);
  13#else
  14# include <sys/syscall.h>
  15# define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)
  16# define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags)
  17#endif
  18
  19void FAST_FUNC replace(char *s, char what, char with)
  20{
  21        while (*s) {
  22                if (what == *s)
  23                        *s = with;
  24                ++s;
  25        }
  26}
  27
  28char* FAST_FUNC replace_underscores(char *s)
  29{
  30        replace(s, '-', '_');
  31        return s;
  32}
  33
  34int FAST_FUNC string_to_llist(char *string, llist_t **llist, const char *delim)
  35{
  36        char *tok;
  37        int len = 0;
  38
  39        while ((tok = strsep(&string, delim)) != NULL) {
  40                if (tok[0] == '\0')
  41                        continue;
  42                llist_add_to_end(llist, xstrdup(tok));
  43                len += strlen(tok);
  44        }
  45        return len;
  46}
  47
  48char* FAST_FUNC filename2modname(const char *filename, char *modname)
  49{
  50        char local_modname[MODULE_NAME_LEN];
  51        int i;
  52        const char *from;
  53
  54        if (filename == NULL)
  55                return NULL;
  56        if (modname == NULL)
  57                modname = local_modname;
  58        // Disabled since otherwise "modprobe dir/name" would work
  59        // as if it is "modprobe name". It is unclear why
  60        // 'basenamization' was here in the first place.
  61        //from = bb_get_last_path_component_nostrip(filename);
  62        from = filename;
  63        for (i = 0; i < (MODULE_NAME_LEN-1) && from[i] != '\0' && from[i] != '.'; i++)
  64                modname[i] = (from[i] == '-') ? '_' : from[i];
  65        modname[i] = '\0';
  66
  67        if (modname == local_modname)
  68                return xstrdup(modname);
  69
  70        return modname;
  71}
  72
  73char* FAST_FUNC parse_cmdline_module_options(char **argv, int quote_spaces)
  74{
  75        char *options;
  76        int optlen;
  77
  78        options = xzalloc(1);
  79        optlen = 0;
  80        while (*++argv) {
  81                const char *fmt;
  82                const char *var;
  83                const char *val;
  84
  85                var = *argv;
  86                options = xrealloc(options, optlen + 2 + strlen(var) + 2);
  87                fmt = "%.*s%s ";
  88                val = strchrnul(var, '=');
  89                if (quote_spaces) {
  90                        /*
  91                         * modprobe (module-init-tools version 3.11.1) compat:
  92                         * quote only value:
  93                         * var="val with spaces", not "var=val with spaces"
  94                         * (note: var *name* is not checked for spaces!)
  95                         */
  96                        if (*val) { /* has var=val format. skip '=' */
  97                                val++;
  98                                if (strchr(val, ' '))
  99                                        fmt = "%.*s\"%s\" ";
 100                        }
 101                }
 102                optlen += sprintf(options + optlen, fmt, (int)(val - var), var, val);
 103        }
 104        /* Remove trailing space. Disabled */
 105        /* if (optlen != 0) options[optlen-1] = '\0'; */
 106        return options;
 107}
 108
 109#if ENABLE_FEATURE_INSMOD_TRY_MMAP
 110void* FAST_FUNC try_to_mmap_module(const char *filename, size_t *image_size_p)
 111{
 112        /* We have user reports of failure to load 3MB module
 113         * on a 16MB RAM machine. Apparently even a transient
 114         * memory spike to 6MB during module load
 115         * is too big for that system. */
 116        void *image;
 117        struct stat st;
 118        int fd;
 119
 120        fd = xopen(filename, O_RDONLY);
 121        fstat(fd, &st);
 122        image = NULL;
 123        /* st.st_size is off_t, we can't just pass it to mmap */
 124        if (st.st_size <= *image_size_p) {
 125                size_t image_size = st.st_size;
 126                image = mmap(NULL, image_size, PROT_READ, MAP_PRIVATE, fd, 0);
 127                if (image == MAP_FAILED) {
 128                        image = NULL;
 129                } else if (*(uint32_t*)image != SWAP_BE32(0x7f454C46)) {
 130                        /* No ELF signature. Compressed module? */
 131                        munmap(image, image_size);
 132                        image = NULL;
 133                } else {
 134                        /* Success. Report the size */
 135                        *image_size_p = image_size;
 136                }
 137        }
 138        close(fd);
 139        return image;
 140}
 141#endif
 142
 143/* Return:
 144 * 0 on success,
 145 * -errno on open/read error,
 146 * errno on init_module() error
 147 */
 148int FAST_FUNC bb_init_module(const char *filename, const char *options)
 149{
 150        size_t image_size;
 151        char *image;
 152        int rc;
 153        bool mmaped;
 154
 155        if (!options)
 156                options = "";
 157
 158//TODO: audit bb_init_module_24 to match error code convention
 159#if ENABLE_FEATURE_2_4_MODULES
 160        if (get_linux_version_code() < KERNEL_VERSION(2,6,0))
 161                return bb_init_module_24(filename, options);
 162#endif
 163
 164        image_size = INT_MAX - 4095;
 165        mmaped = 0;
 166        image = try_to_mmap_module(filename, &image_size);
 167        if (image) {
 168                mmaped = 1;
 169        } else {
 170                errno = ENOMEM; /* may be changed by e.g. open errors below */
 171                image = xmalloc_open_zipped_read_close(filename, &image_size);
 172                if (!image)
 173                        return -errno;
 174        }
 175
 176        errno = 0;
 177        init_module(image, image_size, options);
 178        rc = errno;
 179        if (mmaped)
 180                munmap(image, image_size);
 181        else
 182                free(image);
 183        return rc;
 184}
 185
 186int FAST_FUNC bb_delete_module(const char *module, unsigned int flags)
 187{
 188        errno = 0;
 189        delete_module(module, flags);
 190        return errno;
 191}
 192
 193const char* FAST_FUNC moderror(int err)
 194{
 195        switch (err) {
 196        case -1: /* btw: it's -EPERM */
 197                return "no such module";
 198        case ENOEXEC:
 199                return "invalid module format";
 200        case ENOENT:
 201                return "unknown symbol in module, or unknown parameter";
 202        case ESRCH:
 203                return "module has wrong symbol version";
 204        case ENOSYS:
 205                return "kernel does not support requested operation";
 206        }
 207        if (err < 0) /* should always be */
 208                err = -err;
 209        return strerror(err);
 210}
 211