aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2009-06-17 18:46:06 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2009-06-17 18:46:06 +0200
commitee47f6e44f1a33146e26c7410ade10a98f78ead1 (patch)
tree0d86e43e6c6162dbf64f9bf01374abaffec3179b
parenta5bdbe10877e2e53aaba051eddfd5d47520657f5 (diff)
downloadbusybox-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.c159
-rw-r--r--modutils/modutils.c65
-rw-r--r--modutils/modutils.h12
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
30struct module_entry { /* I'll call it ME. */ 29struct 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")
42enum { 53enum {
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
55struct globals { 66struct 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);
202error: 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 */
212static int do_modprobe(struct module_entry *m) 228static 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
28char * FAST_FUNC replace_underscores(char *s) 28char* 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
48char * FAST_FUNC filename2modname(const char *filename, char *modname) 48char* 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
65const 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
83char * FAST_FUNC parse_cmdline_module_options(char **argv) 65char * 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 */
98int FAST_FUNC bb_init_module(const char *filename, const char *options) 85int 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
126int FAST_FUNC bb_delete_module(const char *module, unsigned int flags) 114int 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
121const 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
20const char *moderror(int err) FAST_FUNC;
21void replace(char *s, char what, char with) FAST_FUNC; 20void replace(char *s, char what, char with) FAST_FUNC;
22char *replace_underscores(char *s) FAST_FUNC; 21char *replace_underscores(char *s) FAST_FUNC;
23int string_to_llist(char *string, llist_t **llist, const char *delim) FAST_FUNC; 22int 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 */
55int FAST_FUNC bb_init_module(const char *module, const char *options); 59int FAST_FUNC bb_init_module(const char *module, const char *options);
60/* Return:
61 * 0 on success,
62 * errno on init_module() error
63 */
56int FAST_FUNC bb_delete_module(const char *module, unsigned int flags); 64int FAST_FUNC bb_delete_module(const char *module, unsigned int flags);
65/* Translates error return to a string */
66const char *moderror(int err) FAST_FUNC;
57 67
58#if ENABLE_FEATURE_2_4_MODULES 68#if ENABLE_FEATURE_2_4_MODULES
59int FAST_FUNC bb_init_module_24(const char *module, const char *options); 69int FAST_FUNC bb_init_module_24(const char *module, const char *options);