diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2009-06-17 18:46:06 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2009-06-17 18:46:06 +0200 |
commit | ee47f6e44f1a33146e26c7410ade10a98f78ead1 (patch) | |
tree | 0d86e43e6c6162dbf64f9bf01374abaffec3179b | |
parent | a5bdbe10877e2e53aaba051eddfd5d47520657f5 (diff) | |
download | busybox-w32-ee47f6e44f1a33146e26c7410ade10a98f78ead1.tar.gz busybox-w32-ee47f6e44f1a33146e26c7410ade10a98f78ead1.tar.bz2 busybox-w32-ee47f6e44f1a33146e26c7410ade10a98f78ead1.zip |
modprobe: correct exitcode handling and error messages with respect to -q
function old new delta
do_modprobe 319 339 +20
bb_delete_module 10 26 +16
moderror 62 71 +9
bb_init_module 112 119 +7
modprobe_main 488 494 +6
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 5/0 up/down: 58/0) Total: 58 bytes
Signed-off-by: Gilles Espinasse <g.esp@free.fr>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | modutils/modprobe.c | 159 | ||||
-rw-r--r-- | modutils/modutils.c | 65 | ||||
-rw-r--r-- | modutils/modutils.h | 12 |
3 files changed, 143 insertions, 93 deletions
diff --git a/modutils/modprobe.c b/modutils/modprobe.c index d000c9123..cfc16cb34 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c | |||
@@ -9,10 +9,9 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | /* Note that unlike older versions of modules.dep/depmod (busybox and m-i-t), | 11 | /* Note that unlike older versions of modules.dep/depmod (busybox and m-i-t), |
12 | * we expect the full dependency list to be specified in modules.dep. Older | 12 | * we expect the full dependency list to be specified in modules.dep. |
13 | * versions would only export the direct dependency list. | 13 | * Older versions would only export the direct dependency list. |
14 | */ | 14 | */ |
15 | |||
16 | #include "libbb.h" | 15 | #include "libbb.h" |
17 | #include "modutils.h" | 16 | #include "modutils.h" |
18 | #include <sys/utsname.h> | 17 | #include <sys/utsname.h> |
@@ -21,11 +20,11 @@ | |||
21 | //#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__) | 20 | //#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__) |
22 | #define DBG(...) ((void)0) | 21 | #define DBG(...) ((void)0) |
23 | 22 | ||
24 | #define MODULE_FLAG_LOADED 0x0001 | 23 | #define MODULE_FLAG_LOADED 0x0001 |
25 | #define MODULE_FLAG_NEED_DEPS 0x0002 | 24 | #define MODULE_FLAG_NEED_DEPS 0x0002 |
26 | /* "was seen in modules.dep": */ | 25 | /* "was seen in modules.dep": */ |
27 | #define MODULE_FLAG_FOUND_IN_MODDEP 0x0004 | 26 | #define MODULE_FLAG_FOUND_IN_MODDEP 0x0004 |
28 | #define MODULE_FLAG_BLACKLISTED 0x0008 | 27 | #define MODULE_FLAG_BLACKLISTED 0x0008 |
29 | 28 | ||
30 | struct module_entry { /* I'll call it ME. */ | 29 | struct module_entry { /* I'll call it ME. */ |
31 | unsigned flags; | 30 | unsigned flags; |
@@ -38,18 +37,30 @@ struct module_entry { /* I'll call it ME. */ | |||
38 | llist_t *deps; /* strings. modules we depend on */ | 37 | llist_t *deps; /* strings. modules we depend on */ |
39 | }; | 38 | }; |
40 | 39 | ||
40 | /* NB: INSMOD_OPT_SILENT bit suppresses ONLY non-existent modules, | ||
41 | * not deleted ones (those are still listed in modules.dep). | ||
42 | * module-init-tools version 3.4: | ||
43 | * # modprobe bogus | ||
44 | * FATAL: Module bogus not found. [exitcode 1] | ||
45 | * # modprobe -q bogus [silent, exitcode still 1] | ||
46 | * but: | ||
47 | * # rm kernel/drivers/net/dummy.ko | ||
48 | * # modprobe -q dummy | ||
49 | * FATAL: Could not open '/lib/modules/xxx/kernel/drivers/net/dummy.ko': No such file or directory | ||
50 | * [exitcode 1] | ||
51 | */ | ||
41 | #define MODPROBE_OPTS "acdlnrt:VC:" IF_FEATURE_MODPROBE_BLACKLIST("b") | 52 | #define MODPROBE_OPTS "acdlnrt:VC:" IF_FEATURE_MODPROBE_BLACKLIST("b") |
42 | enum { | 53 | enum { |
43 | MODPROBE_OPT_INSERT_ALL = (INSMOD_OPT_UNUSED << 0), /* a */ | 54 | MODPROBE_OPT_INSERT_ALL = (INSMOD_OPT_UNUSED << 0), /* a */ |
44 | MODPROBE_OPT_DUMP_ONLY = (INSMOD_OPT_UNUSED << 1), /* c */ | 55 | MODPROBE_OPT_DUMP_ONLY = (INSMOD_OPT_UNUSED << 1), /* c */ |
45 | MODPROBE_OPT_D = (INSMOD_OPT_UNUSED << 2), /* d */ | 56 | MODPROBE_OPT_D = (INSMOD_OPT_UNUSED << 2), /* d */ |
46 | MODPROBE_OPT_LIST_ONLY = (INSMOD_OPT_UNUSED << 3), /* l */ | 57 | MODPROBE_OPT_LIST_ONLY = (INSMOD_OPT_UNUSED << 3), /* l */ |
47 | MODPROBE_OPT_SHOW_ONLY = (INSMOD_OPT_UNUSED << 4), /* n */ | 58 | MODPROBE_OPT_SHOW_ONLY = (INSMOD_OPT_UNUSED << 4), /* n */ |
48 | MODPROBE_OPT_REMOVE = (INSMOD_OPT_UNUSED << 5), /* r */ | 59 | MODPROBE_OPT_REMOVE = (INSMOD_OPT_UNUSED << 5), /* r */ |
49 | MODPROBE_OPT_RESTRICT = (INSMOD_OPT_UNUSED << 6), /* t */ | 60 | MODPROBE_OPT_RESTRICT = (INSMOD_OPT_UNUSED << 6), /* t */ |
50 | MODPROBE_OPT_VERONLY = (INSMOD_OPT_UNUSED << 7), /* V */ | 61 | MODPROBE_OPT_VERONLY = (INSMOD_OPT_UNUSED << 7), /* V */ |
51 | MODPROBE_OPT_CONFIGFILE = (INSMOD_OPT_UNUSED << 8), /* C */ | 62 | MODPROBE_OPT_CONFIGFILE = (INSMOD_OPT_UNUSED << 8), /* C */ |
52 | MODPROBE_OPT_BLACKLIST = (INSMOD_OPT_UNUSED << 9) * ENABLE_FEATURE_MODPROBE_BLACKLIST, | 63 | MODPROBE_OPT_BLACKLIST = (INSMOD_OPT_UNUSED << 9) * ENABLE_FEATURE_MODPROBE_BLACKLIST, |
53 | }; | 64 | }; |
54 | 65 | ||
55 | struct globals { | 66 | struct globals { |
@@ -140,7 +151,7 @@ static int FAST_FUNC config_file_action(const char *filename, | |||
140 | { | 151 | { |
141 | char *tokens[3]; | 152 | char *tokens[3]; |
142 | parser_t *p; | 153 | parser_t *p; |
143 | struct module_entry *m; | 154 | struct module_entry *m; |
144 | int rc = TRUE; | 155 | int rc = TRUE; |
145 | 156 | ||
146 | if (bb_basename(filename)[0] == '.') | 157 | if (bb_basename(filename)[0] == '.') |
@@ -199,7 +210,7 @@ static int FAST_FUNC config_file_action(const char *filename, | |||
199 | } | 210 | } |
200 | } | 211 | } |
201 | config_close(p); | 212 | config_close(p); |
202 | error: | 213 | error: |
203 | return rc; | 214 | return rc; |
204 | } | 215 | } |
205 | 216 | ||
@@ -209,6 +220,11 @@ static int read_config(const char *path) | |||
209 | config_file_action, NULL, NULL, 1); | 220 | config_file_action, NULL, NULL, 1); |
210 | } | 221 | } |
211 | 222 | ||
223 | /* Return: similar to bb_init_module: | ||
224 | * 0 on success, | ||
225 | * -errno on open/read error, | ||
226 | * errno on init_module() error | ||
227 | */ | ||
212 | static int do_modprobe(struct module_entry *m) | 228 | static int do_modprobe(struct module_entry *m) |
213 | { | 229 | { |
214 | struct module_entry *m2 = m2; /* for compiler */ | 230 | struct module_entry *m2 = m2; /* for compiler */ |
@@ -217,7 +233,8 @@ static int do_modprobe(struct module_entry *m) | |||
217 | llist_t *l; | 233 | llist_t *l; |
218 | 234 | ||
219 | if (!(m->flags & MODULE_FLAG_FOUND_IN_MODDEP)) { | 235 | if (!(m->flags & MODULE_FLAG_FOUND_IN_MODDEP)) { |
220 | DBG("skipping %s, not found in modules.dep", m->modname); | 236 | if (!(option_mask32 & INSMOD_OPT_SILENT)) |
237 | bb_error_msg("module %s not found in modules.dep", m->probed_name); | ||
221 | return -ENOENT; | 238 | return -ENOENT; |
222 | } | 239 | } |
223 | DBG("do_modprob'ing %s", m->modname); | 240 | DBG("do_modprob'ing %s", m->modname); |
@@ -230,43 +247,52 @@ static int do_modprobe(struct module_entry *m) | |||
230 | 247 | ||
231 | first = 1; | 248 | first = 1; |
232 | rc = 0; | 249 | rc = 0; |
233 | while (m->deps && rc == 0) { | 250 | while (m->deps) { |
234 | fn = llist_pop(&m->deps); | 251 | rc = 0; |
252 | fn = llist_pop(&m->deps); /* we leak it */ | ||
235 | m2 = get_or_add_modentry(fn); | 253 | m2 = get_or_add_modentry(fn); |
254 | |||
236 | if (option_mask32 & MODPROBE_OPT_REMOVE) { | 255 | if (option_mask32 & MODPROBE_OPT_REMOVE) { |
256 | /* modprobe -r */ | ||
237 | if (m2->flags & MODULE_FLAG_LOADED) { | 257 | if (m2->flags & MODULE_FLAG_LOADED) { |
238 | if (bb_delete_module(m2->modname, O_EXCL) != 0) { | 258 | rc = bb_delete_module(m2->modname, O_EXCL); |
239 | if (first) | 259 | if (rc) { |
240 | rc = errno; | 260 | if (first) { |
261 | bb_error_msg("failed to unload module %s: %s", | ||
262 | m2->probed_name ? m2->probed_name : m2->modname, | ||
263 | moderror(rc)); | ||
264 | break; | ||
265 | } | ||
241 | } else { | 266 | } else { |
242 | m2->flags &= ~MODULE_FLAG_LOADED; | 267 | m2->flags &= ~MODULE_FLAG_LOADED; |
243 | } | 268 | } |
244 | } | 269 | } |
245 | /* do not error out if *deps* fail to unload */ | 270 | /* do not error out if *deps* fail to unload */ |
246 | first = 0; | 271 | first = 0; |
247 | } else if (!(m2->flags & MODULE_FLAG_LOADED)) { | 272 | continue; |
248 | options = m2->options; | ||
249 | m2->options = NULL; | ||
250 | if (m == m2) | ||
251 | options = gather_options_str(options, G.cmdline_mopts); | ||
252 | rc = bb_init_module(fn, options); | ||
253 | DBG("loaded %s '%s', rc:%d", fn, options, rc); | ||
254 | if (rc == 0) | ||
255 | m2->flags |= MODULE_FLAG_LOADED; | ||
256 | free(options); | ||
257 | } else { | ||
258 | DBG("%s is already loaded, skipping", fn); | ||
259 | } | 273 | } |
260 | 274 | ||
261 | free(fn); | 275 | if (m2->flags & MODULE_FLAG_LOADED) { |
262 | } | 276 | DBG("%s is already loaded, skipping", fn); |
277 | continue; | ||
278 | } | ||
263 | 279 | ||
264 | if (rc && !(option_mask32 & INSMOD_OPT_SILENT)) { | 280 | options = m2->options; |
265 | bb_error_msg("failed to %sload module %s: %s", | 281 | m2->options = NULL; |
266 | (option_mask32 & MODPROBE_OPT_REMOVE) ? "un" : "", | 282 | if (m == m2) |
283 | options = gather_options_str(options, G.cmdline_mopts); | ||
284 | rc = bb_init_module(fn, options); | ||
285 | DBG("loaded %s '%s', rc:%d", fn, options, rc); | ||
286 | free(options); | ||
287 | if (rc) { | ||
288 | bb_error_msg("failed to load module %s (%s): %s", | ||
267 | m2->probed_name ? m2->probed_name : m2->modname, | 289 | m2->probed_name ? m2->probed_name : m2->modname, |
268 | moderror(rc) | 290 | fn, |
269 | ); | 291 | moderror(rc) |
292 | ); | ||
293 | break; | ||
294 | } | ||
295 | m2->flags |= MODULE_FLAG_LOADED; | ||
270 | } | 296 | } |
271 | 297 | ||
272 | return rc; | 298 | return rc; |
@@ -278,7 +304,7 @@ static void load_modules_dep(void) | |||
278 | char *colon, *tokens[2]; | 304 | char *colon, *tokens[2]; |
279 | parser_t *p; | 305 | parser_t *p; |
280 | 306 | ||
281 | /* Modprobe does not work at all without modprobe.dep, | 307 | /* Modprobe does not work at all without modules.dep, |
282 | * even if the full module name is given. Returning error here | 308 | * even if the full module name is given. Returning error here |
283 | * was making us later confuse user with this message: | 309 | * was making us later confuse user with this message: |
284 | * "module /full/path/to/existing/file/module.ko not found". | 310 | * "module /full/path/to/existing/file/module.ko not found". |
@@ -387,35 +413,40 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) | |||
387 | load_modules_dep(); | 413 | load_modules_dep(); |
388 | } | 414 | } |
389 | 415 | ||
416 | rc = 0; | ||
390 | while ((me = llist_pop(&G.probes)) != NULL) { | 417 | while ((me = llist_pop(&G.probes)) != NULL) { |
391 | if (me->realnames == NULL) { | 418 | if (me->realnames == NULL) { |
419 | DBG("probing by module name"); | ||
392 | /* This is not an alias. Literal names are blacklisted | 420 | /* This is not an alias. Literal names are blacklisted |
393 | * only if '-b' is given. | 421 | * only if '-b' is given. |
394 | */ | 422 | */ |
395 | if (!(opt & MODPROBE_OPT_BLACKLIST) | 423 | if (!(opt & MODPROBE_OPT_BLACKLIST) |
396 | || !(me->flags & MODULE_FLAG_BLACKLISTED) | 424 | || !(me->flags & MODULE_FLAG_BLACKLISTED) |
397 | ) { | 425 | ) { |
398 | rc = do_modprobe(me); | 426 | rc |= do_modprobe(me); |
399 | //FIXME: what if rc > 0? | ||
400 | if (rc < 0 && !(opt & INSMOD_OPT_SILENT)) | ||
401 | bb_error_msg("module %s not found", | ||
402 | me->probed_name); | ||
403 | } | 427 | } |
404 | } else { | 428 | continue; |
405 | /* Probe all realnames */ | ||
406 | do { | ||
407 | char *realname = llist_pop(&me->realnames); | ||
408 | struct module_entry *m2; | ||
409 | |||
410 | DBG("probing %s by realname %s", me->modname, realname); | ||
411 | m2 = get_or_add_modentry(realname); | ||
412 | if (!(m2->flags & MODULE_FLAG_BLACKLISTED)) | ||
413 | do_modprobe(m2); | ||
414 | //FIXME: error check? | ||
415 | free(realname); | ||
416 | } while (me->realnames != NULL); | ||
417 | } | 429 | } |
430 | |||
431 | /* Probe all real names for the alias */ | ||
432 | do { | ||
433 | char *realname = llist_pop(&me->realnames); | ||
434 | struct module_entry *m2; | ||
435 | |||
436 | DBG("probing alias %s by realname %s", me->modname, realname); | ||
437 | m2 = get_or_add_modentry(realname); | ||
438 | if (!(m2->flags & MODULE_FLAG_BLACKLISTED) | ||
439 | && (!(m2->flags & MODULE_FLAG_LOADED) | ||
440 | || (opt & MODPROBE_OPT_REMOVE)) | ||
441 | ) { | ||
442 | //TODO: we can pass "me" as 2nd param to do_modprobe, | ||
443 | //and make do_modprobe emit more meaningful error messages | ||
444 | //with alias name included, not just module name alias resolves to. | ||
445 | rc |= do_modprobe(m2); | ||
446 | } | ||
447 | free(realname); | ||
448 | } while (me->realnames != NULL); | ||
418 | } | 449 | } |
419 | 450 | ||
420 | return EXIT_SUCCESS; | 451 | return (rc != 0); |
421 | } | 452 | } |
diff --git a/modutils/modutils.c b/modutils/modutils.c index f437a9829..969926db9 100644 --- a/modutils/modutils.c +++ b/modutils/modutils.c | |||
@@ -25,7 +25,7 @@ void FAST_FUNC replace(char *s, char what, char with) | |||
25 | } | 25 | } |
26 | } | 26 | } |
27 | 27 | ||
28 | char * FAST_FUNC replace_underscores(char *s) | 28 | char* FAST_FUNC replace_underscores(char *s) |
29 | { | 29 | { |
30 | replace(s, '-', '_'); | 30 | replace(s, '-', '_'); |
31 | return s; | 31 | return s; |
@@ -45,7 +45,7 @@ int FAST_FUNC string_to_llist(char *string, llist_t **llist, const char *delim) | |||
45 | return len; | 45 | return len; |
46 | } | 46 | } |
47 | 47 | ||
48 | char * FAST_FUNC filename2modname(const char *filename, char *modname) | 48 | char* FAST_FUNC filename2modname(const char *filename, char *modname) |
49 | { | 49 | { |
50 | int i; | 50 | int i; |
51 | char *from; | 51 | char *from; |
@@ -62,24 +62,6 @@ char * FAST_FUNC filename2modname(const char *filename, char *modname) | |||
62 | return modname; | 62 | return modname; |
63 | } | 63 | } |
64 | 64 | ||
65 | const char * FAST_FUNC moderror(int err) | ||
66 | { | ||
67 | switch (err) { | ||
68 | case -1: | ||
69 | return "no such module"; | ||
70 | case ENOEXEC: | ||
71 | return "invalid module format"; | ||
72 | case ENOENT: | ||
73 | return "unknown symbol in module, or unknown parameter"; | ||
74 | case ESRCH: | ||
75 | return "module has wrong symbol version"; | ||
76 | case ENOSYS: | ||
77 | return "kernel does not support requested operation"; | ||
78 | default: | ||
79 | return strerror(err); | ||
80 | } | ||
81 | } | ||
82 | |||
83 | char * FAST_FUNC parse_cmdline_module_options(char **argv) | 65 | char * FAST_FUNC parse_cmdline_module_options(char **argv) |
84 | { | 66 | { |
85 | char *options; | 67 | char *options; |
@@ -95,6 +77,11 @@ char * FAST_FUNC parse_cmdline_module_options(char **argv) | |||
95 | return options; | 77 | return options; |
96 | } | 78 | } |
97 | 79 | ||
80 | /* Return: | ||
81 | * 0 on success, | ||
82 | * -errno on open/read error, | ||
83 | * errno on init_module() error | ||
84 | */ | ||
98 | int FAST_FUNC bb_init_module(const char *filename, const char *options) | 85 | int FAST_FUNC bb_init_module(const char *filename, const char *options) |
99 | { | 86 | { |
100 | size_t len; | 87 | size_t len; |
@@ -104,6 +91,7 @@ int FAST_FUNC bb_init_module(const char *filename, const char *options) | |||
104 | if (!options) | 91 | if (!options) |
105 | options = ""; | 92 | options = ""; |
106 | 93 | ||
94 | //TODO: audit bb_init_module_24 to match error code convention | ||
107 | #if ENABLE_FEATURE_2_4_MODULES | 95 | #if ENABLE_FEATURE_2_4_MODULES |
108 | if (get_linux_version_code() < KERNEL_VERSION(2,6,0)) | 96 | if (get_linux_version_code() < KERNEL_VERSION(2,6,0)) |
109 | return bb_init_module_24(filename, options); | 97 | return bb_init_module_24(filename, options); |
@@ -111,19 +99,40 @@ int FAST_FUNC bb_init_module(const char *filename, const char *options) | |||
111 | 99 | ||
112 | /* Use the 2.6 way */ | 100 | /* Use the 2.6 way */ |
113 | len = INT_MAX - 4095; | 101 | len = INT_MAX - 4095; |
114 | rc = ENOENT; | 102 | errno = ENOMEM; /* may be changed by e.g. open errors below */ |
115 | image = xmalloc_open_zipped_read_close(filename, &len); | 103 | image = xmalloc_open_zipped_read_close(filename, &len); |
116 | if (image) { | 104 | if (!image) |
117 | rc = 0; | 105 | return -errno; |
118 | if (init_module(image, len, options) != 0) | ||
119 | rc = errno; | ||
120 | free(image); | ||
121 | } | ||
122 | 106 | ||
107 | errno = 0; | ||
108 | init_module(image, len, options); | ||
109 | rc = errno; | ||
110 | free(image); | ||
123 | return rc; | 111 | return rc; |
124 | } | 112 | } |
125 | 113 | ||
126 | int FAST_FUNC bb_delete_module(const char *module, unsigned int flags) | 114 | int FAST_FUNC bb_delete_module(const char *module, unsigned int flags) |
127 | { | 115 | { |
128 | return delete_module(module, flags); | 116 | errno = 0; |
117 | delete_module(module, flags); | ||
118 | return errno; | ||
119 | } | ||
120 | |||
121 | const char* FAST_FUNC moderror(int err) | ||
122 | { | ||
123 | switch (err) { | ||
124 | case -1: /* btw: it's -EPERM */ | ||
125 | return "no such module"; | ||
126 | case ENOEXEC: | ||
127 | return "invalid module format"; | ||
128 | case ENOENT: | ||
129 | return "unknown symbol in module, or unknown parameter"; | ||
130 | case ESRCH: | ||
131 | return "module has wrong symbol version"; | ||
132 | case ENOSYS: | ||
133 | return "kernel does not support requested operation"; | ||
134 | } | ||
135 | if (err < 0) /* should always be */ | ||
136 | err = -err; | ||
137 | return strerror(err); | ||
129 | } | 138 | } |
diff --git a/modutils/modutils.h b/modutils/modutils.h index 8cca5ccfe..1cf4bba95 100644 --- a/modutils/modutils.h +++ b/modutils/modutils.h | |||
@@ -17,7 +17,6 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN | |||
17 | * internally for the maximum alias name length, which can be quite long */ | 17 | * internally for the maximum alias name length, which can be quite long */ |
18 | #define MODULE_NAME_LEN 256 | 18 | #define MODULE_NAME_LEN 256 |
19 | 19 | ||
20 | const char *moderror(int err) FAST_FUNC; | ||
21 | void replace(char *s, char what, char with) FAST_FUNC; | 20 | void replace(char *s, char what, char with) FAST_FUNC; |
22 | char *replace_underscores(char *s) FAST_FUNC; | 21 | char *replace_underscores(char *s) FAST_FUNC; |
23 | int string_to_llist(char *string, llist_t **llist, const char *delim) FAST_FUNC; | 22 | int string_to_llist(char *string, llist_t **llist, const char *delim) FAST_FUNC; |
@@ -52,8 +51,19 @@ enum { | |||
52 | #endif | 51 | #endif |
53 | }; | 52 | }; |
54 | 53 | ||
54 | /* Return: | ||
55 | * 0 on success, | ||
56 | * -errno on open/read error, | ||
57 | * errno on init_module() error | ||
58 | */ | ||
55 | int FAST_FUNC bb_init_module(const char *module, const char *options); | 59 | int FAST_FUNC bb_init_module(const char *module, const char *options); |
60 | /* Return: | ||
61 | * 0 on success, | ||
62 | * errno on init_module() error | ||
63 | */ | ||
56 | int FAST_FUNC bb_delete_module(const char *module, unsigned int flags); | 64 | int FAST_FUNC bb_delete_module(const char *module, unsigned int flags); |
65 | /* Translates error return to a string */ | ||
66 | const char *moderror(int err) FAST_FUNC; | ||
57 | 67 | ||
58 | #if ENABLE_FEATURE_2_4_MODULES | 68 | #if ENABLE_FEATURE_2_4_MODULES |
59 | int FAST_FUNC bb_init_module_24(const char *module, const char *options); | 69 | int FAST_FUNC bb_init_module_24(const char *module, const char *options); |