source: MondoRescue/branches/3.3/mindi-busybox/modutils/modutils.c@ 3865

Last change on this file since 3865 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 6.2 KB
RevLine 
[2725]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
[3621]19static module_entry *helper_get_module(module_db *db, const char *module, int create)
20{
21 char modname[MODULE_NAME_LEN];
22 struct module_entry *e;
23 unsigned i, hash;
24
25 filename2modname(module, modname);
26
27 hash = 0;
28 for (i = 0; modname[i]; i++)
29 hash = ((hash << 5) + hash) + modname[i];
30 hash %= MODULE_HASH_SIZE;
31
32 for (e = db->buckets[hash]; e; e = e->next)
33 if (strcmp(e->modname, modname) == 0)
34 return e;
35 if (!create)
36 return NULL;
37
38 e = xzalloc(sizeof(*e));
39 e->modname = xstrdup(modname);
40 e->next = db->buckets[hash];
41 db->buckets[hash] = e;
42 IF_DEPMOD(e->dnext = e->dprev = e;)
43
44 return e;
45}
46module_entry* FAST_FUNC moddb_get(module_db *db, const char *module)
47{
48 return helper_get_module(db, module, 0);
49}
50module_entry* FAST_FUNC moddb_get_or_create(module_db *db, const char *module)
51{
52 return helper_get_module(db, module, 1);
53}
54
55void FAST_FUNC moddb_free(module_db *db)
56{
57 module_entry *e, *n;
58 unsigned i;
59
60 for (i = 0; i < MODULE_HASH_SIZE; i++) {
61 for (e = db->buckets[i]; e; e = n) {
62 n = e->next;
63 free(e->name);
64 free(e->modname);
65 free(e);
66 }
67 }
68}
69
[2725]70void FAST_FUNC replace(char *s, char what, char with)
71{
72 while (*s) {
73 if (what == *s)
74 *s = with;
75 ++s;
76 }
77}
78
79char* FAST_FUNC replace_underscores(char *s)
80{
81 replace(s, '-', '_');
82 return s;
83}
84
85int FAST_FUNC string_to_llist(char *string, llist_t **llist, const char *delim)
86{
87 char *tok;
88 int len = 0;
89
90 while ((tok = strsep(&string, delim)) != NULL) {
91 if (tok[0] == '\0')
92 continue;
93 llist_add_to_end(llist, xstrdup(tok));
94 len += strlen(tok);
95 }
96 return len;
97}
98
99char* FAST_FUNC filename2modname(const char *filename, char *modname)
100{
[3621]101 char local_modname[MODULE_NAME_LEN];
[2725]102 int i;
[3621]103 const char *from;
[2725]104
105 if (filename == NULL)
106 return NULL;
107 if (modname == NULL)
[3621]108 modname = local_modname;
109 // Disabled since otherwise "modprobe dir/name" would work
110 // as if it is "modprobe name". It is unclear why
111 // 'basenamization' was here in the first place.
112 //from = bb_get_last_path_component_nostrip(filename);
113 from = filename;
[2725]114 for (i = 0; i < (MODULE_NAME_LEN-1) && from[i] != '\0' && from[i] != '.'; i++)
115 modname[i] = (from[i] == '-') ? '_' : from[i];
116 modname[i] = '\0';
117
[3621]118 if (modname == local_modname)
119 return xstrdup(modname);
120
[2725]121 return modname;
122}
123
[3232]124char* FAST_FUNC parse_cmdline_module_options(char **argv, int quote_spaces)
[2725]125{
126 char *options;
127 int optlen;
128
129 options = xzalloc(1);
130 optlen = 0;
131 while (*++argv) {
[3232]132 const char *fmt;
133 const char *var;
134 const char *val;
135
136 var = *argv;
137 options = xrealloc(options, optlen + 2 + strlen(var) + 2);
138 fmt = "%.*s%s ";
139 val = strchrnul(var, '=');
140 if (quote_spaces) {
141 /*
142 * modprobe (module-init-tools version 3.11.1) compat:
143 * quote only value:
144 * var="val with spaces", not "var=val with spaces"
145 * (note: var *name* is not checked for spaces!)
146 */
147 if (*val) { /* has var=val format. skip '=' */
148 val++;
149 if (strchr(val, ' '))
150 fmt = "%.*s\"%s\" ";
151 }
152 }
153 optlen += sprintf(options + optlen, fmt, (int)(val - var), var, val);
[2725]154 }
[3232]155 /* Remove trailing space. Disabled */
156 /* if (optlen != 0) options[optlen-1] = '\0'; */
[2725]157 return options;
158}
159
160#if ENABLE_FEATURE_INSMOD_TRY_MMAP
161void* FAST_FUNC try_to_mmap_module(const char *filename, size_t *image_size_p)
162{
163 /* We have user reports of failure to load 3MB module
164 * on a 16MB RAM machine. Apparently even a transient
165 * memory spike to 6MB during module load
166 * is too big for that system. */
167 void *image;
168 struct stat st;
169 int fd;
170
171 fd = xopen(filename, O_RDONLY);
172 fstat(fd, &st);
173 image = NULL;
174 /* st.st_size is off_t, we can't just pass it to mmap */
175 if (st.st_size <= *image_size_p) {
176 size_t image_size = st.st_size;
177 image = mmap(NULL, image_size, PROT_READ, MAP_PRIVATE, fd, 0);
178 if (image == MAP_FAILED) {
179 image = NULL;
180 } else if (*(uint32_t*)image != SWAP_BE32(0x7f454C46)) {
181 /* No ELF signature. Compressed module? */
182 munmap(image, image_size);
183 image = NULL;
184 } else {
185 /* Success. Report the size */
186 *image_size_p = image_size;
187 }
188 }
189 close(fd);
190 return image;
191}
192#endif
193
194/* Return:
195 * 0 on success,
196 * -errno on open/read error,
197 * errno on init_module() error
198 */
199int FAST_FUNC bb_init_module(const char *filename, const char *options)
200{
201 size_t image_size;
202 char *image;
203 int rc;
204 bool mmaped;
205
206 if (!options)
207 options = "";
208
209//TODO: audit bb_init_module_24 to match error code convention
210#if ENABLE_FEATURE_2_4_MODULES
211 if (get_linux_version_code() < KERNEL_VERSION(2,6,0))
212 return bb_init_module_24(filename, options);
213#endif
214
215 image_size = INT_MAX - 4095;
216 mmaped = 0;
217 image = try_to_mmap_module(filename, &image_size);
218 if (image) {
219 mmaped = 1;
220 } else {
221 errno = ENOMEM; /* may be changed by e.g. open errors below */
222 image = xmalloc_open_zipped_read_close(filename, &image_size);
223 if (!image)
224 return -errno;
225 }
226
227 errno = 0;
228 init_module(image, image_size, options);
229 rc = errno;
230 if (mmaped)
231 munmap(image, image_size);
232 else
233 free(image);
234 return rc;
235}
236
237int FAST_FUNC bb_delete_module(const char *module, unsigned int flags)
238{
239 errno = 0;
240 delete_module(module, flags);
241 return errno;
242}
243
[3621]244/* Note: not suitable for delete_module() errnos.
245 * For them, probably only EWOULDBLOCK needs explaining:
246 * "Other modules depend on us". So far we don't do such
247 * translation and don't use moderror() for removal errors.
248 */
[2725]249const char* FAST_FUNC moderror(int err)
250{
251 switch (err) {
252 case -1: /* btw: it's -EPERM */
253 return "no such module";
254 case ENOEXEC:
255 return "invalid module format";
256 case ENOENT:
257 return "unknown symbol in module, or unknown parameter";
258 case ESRCH:
259 return "module has wrong symbol version";
260 case ENOSYS:
261 return "kernel does not support requested operation";
262 }
263 if (err < 0) /* should always be */
264 err = -err;
265 return strerror(err);
266}
Note: See TracBrowser for help on using the repository browser.