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