blob: 431b8aeb23a702afb8022db4c6f333e337733035 [file] [log] [blame]
Denis Vlasenko671691c2008-07-04 10:25:44 +00001/* vi: set sw=4 ts=4: */
2/*
3 * simplified modprobe
4 *
5 * Copyright (c) 2008 Vladimir Dronnikov
Bernhard Reutner-Fischer6c4dade2008-09-25 12:13:34 +00006 * Copyright (c) 2008 Bernhard Reutner-Fischer (initial depmod code)
Denis Vlasenko671691c2008-07-04 10:25:44 +00007 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02008 * Licensed under GPLv2, see file LICENSE in this source tree.
Denis Vlasenko671691c2008-07-04 10:25:44 +00009 */
Denys Vlasenko326edc32016-12-22 14:36:49 +010010
Kang-Che Sung415cc422017-02-01 19:43:54 +080011/* modprobe-small configs are defined in Config.src to ensure better
12 * "make config" order */
Denis Vlasenko671691c2008-07-04 10:25:44 +000013
Kang-Che Sungfdfd7162017-01-31 17:06:43 +080014//applet:IF_LSMOD( IF_MODPROBE_SMALL(APPLET(lsmod, BB_DIR_SBIN, BB_SUID_DROP)))
Denys Vlasenkoa1cd0d92016-12-23 15:12:27 +010015//applet:IF_MODPROBE(IF_MODPROBE_SMALL(APPLET(modprobe, BB_DIR_SBIN, BB_SUID_DROP)))
Denys Vlasenko205d48e2017-01-29 14:57:33 +010016// APPLET_ODDNAME:name main location suid_type help
Denys Vlasenkoa1cd0d92016-12-23 15:12:27 +010017//applet:IF_DEPMOD(IF_MODPROBE_SMALL(APPLET_ODDNAME(depmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, depmod)))
18//applet:IF_INSMOD(IF_MODPROBE_SMALL(APPLET_ODDNAME(insmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, insmod)))
Kang-Che Sungfdfd7162017-01-31 17:06:43 +080019//applet:IF_RMMOD( IF_MODPROBE_SMALL(APPLET_ODDNAME(rmmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, rmmod)))
Denys Vlasenkoc15613c2010-10-15 11:29:02 +020020
Denys Vlasenkoe32b64c2016-11-23 07:54:52 +010021//kbuild:lib-$(CONFIG_MODPROBE_SMALL) += modprobe-small.o
22
Denis Vlasenko671691c2008-07-04 10:25:44 +000023#include "libbb.h"
Denys Vlasenko043b1e52009-09-06 12:47:55 +020024/* After libbb.h, since it needs sys/types.h on some systems */
Denis Vlasenko671691c2008-07-04 10:25:44 +000025#include <sys/utsname.h> /* uname() */
26#include <fnmatch.h>
Mike Frysinger3a45b872016-09-15 12:16:33 +020027#include <sys/syscall.h>
Denis Vlasenko671691c2008-07-04 10:25:44 +000028
Waldemar Brodkorb9c083f52016-12-26 20:07:59 +010029#define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)
30#define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags)
Mike Frysinger3a45b872016-09-15 12:16:33 +020031#ifdef __NR_finit_module
32# define finit_module(fd, uargs, flags) syscall(__NR_finit_module, fd, uargs, flags)
33#endif
Denys Vlasenko07e55552014-04-21 16:59:36 +020034/* linux/include/linux/module.h has limit of 64 chars on module names */
35#undef MODULE_NAME_LEN
36#define MODULE_NAME_LEN 64
Denis Vlasenko24a131e2008-07-09 15:30:57 +000037
38
Denys Vlasenko5b3151c2010-09-25 14:37:06 +020039#if 1
40# define dbg1_error_msg(...) ((void)0)
41# define dbg2_error_msg(...) ((void)0)
42#else
43# define dbg1_error_msg(...) bb_error_msg(__VA_ARGS__)
44# define dbg2_error_msg(...) bb_error_msg(__VA_ARGS__)
45#endif
Denis Vlasenko671691c2008-07-04 10:25:44 +000046
Denis Vlasenko24a131e2008-07-09 15:30:57 +000047#define DEPFILE_BB CONFIG_DEFAULT_DEPMOD_FILE".bb"
Denis Vlasenko671691c2008-07-04 10:25:44 +000048
Kang-Che Sungfdfd7162017-01-31 17:06:43 +080049//usage:#if ENABLE_MODPROBE_SMALL
50
51//usage:#define lsmod_trivial_usage
52//usage: ""
53//usage:#define lsmod_full_usage "\n\n"
54//usage: "List loaded kernel modules"
55
56//usage:#endif
57
58#if ENABLE_LSMOD
59int lsmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
60int lsmod_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
61{
62 xprint_and_close_file(xfopen_for_read("/proc/modules"));
63 return EXIT_SUCCESS;
64}
65#endif
66
67/* Num of applets that use modprobe_main() entry point. */
68/* lsmod is not here. */
69#define MOD_APPLET_CNT (ENABLE_MODPROBE + ENABLE_DEPMOD + ENABLE_INSMOD + ENABLE_RMMOD)
Denys Vlasenkoe7b54d02017-01-09 16:31:21 +010070
71/* Do not bother if MODPROBE_SMALL=y but no applets selected. */
72/* The rest of the file is in this if block. */
73#if MOD_APPLET_CNT > 0
74
75#define ONLY_APPLET (MOD_APPLET_CNT == 1)
Explorer0980172e42017-01-09 15:04:43 +080076#define is_modprobe (ENABLE_MODPROBE && (ONLY_APPLET || applet_name[0] == 'm'))
77#define is_depmod (ENABLE_DEPMOD && (ONLY_APPLET || applet_name[0] == 'd'))
78#define is_insmod (ENABLE_INSMOD && (ONLY_APPLET || applet_name[0] == 'i'))
Explorer0980172e42017-01-09 15:04:43 +080079#define is_rmmod (ENABLE_RMMOD && (ONLY_APPLET || applet_name[0] == 'r'))
80
Denis Vlasenko671691c2008-07-04 10:25:44 +000081enum {
82 OPT_q = (1 << 0), /* be quiet */
83 OPT_r = (1 << 1), /* module removal instead of loading */
84};
85
86typedef struct module_info {
87 char *pathname;
Denis Vlasenko78436992008-07-10 14:14:20 +000088 char *aliases;
89 char *deps;
Denys Vlasenko5c3e0602016-06-20 10:59:06 +020090 smallint open_read_failed;
Denis Vlasenko671691c2008-07-04 10:25:44 +000091} module_info;
92
93/*
94 * GLOBALS
95 */
96struct globals {
97 module_info *modinfo;
98 char *module_load_options;
Denis Vlasenko7f950a92008-07-10 14:14:45 +000099 smallint dep_bb_seen;
Denis Vlasenko0e2c93f2008-07-10 14:16:11 +0000100 smallint wrote_dep_bb_ok;
Denys Vlasenko0c6914e2009-09-07 02:38:26 +0200101 unsigned module_count;
Denis Vlasenko671691c2008-07-04 10:25:44 +0000102 int module_found_idx;
Denys Vlasenko0c6914e2009-09-07 02:38:26 +0200103 unsigned stringbuf_idx;
104 unsigned stringbuf_size;
105 char *stringbuf; /* some modules have lots of stuff */
Denis Vlasenko671691c2008-07-04 10:25:44 +0000106 /* for example, drivers/media/video/saa7134/saa7134.ko */
Denys Vlasenko0c6914e2009-09-07 02:38:26 +0200107 /* therefore having a fixed biggish buffer is not wise */
Denis Vlasenko671691c2008-07-04 10:25:44 +0000108};
109#define G (*ptr_to_globals)
110#define modinfo (G.modinfo )
Denis Vlasenko7f950a92008-07-10 14:14:45 +0000111#define dep_bb_seen (G.dep_bb_seen )
Denis Vlasenko0e2c93f2008-07-10 14:16:11 +0000112#define wrote_dep_bb_ok (G.wrote_dep_bb_ok )
Denis Vlasenko671691c2008-07-04 10:25:44 +0000113#define module_count (G.module_count )
114#define module_found_idx (G.module_found_idx )
115#define module_load_options (G.module_load_options)
116#define stringbuf_idx (G.stringbuf_idx )
Denys Vlasenko0c6914e2009-09-07 02:38:26 +0200117#define stringbuf_size (G.stringbuf_size )
Denis Vlasenko671691c2008-07-04 10:25:44 +0000118#define stringbuf (G.stringbuf )
119#define INIT_G() do { \
120 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
121} while (0)
122
Denys Vlasenko0c6914e2009-09-07 02:38:26 +0200123static void append(const char *s)
124{
125 unsigned len = strlen(s);
126 if (stringbuf_idx + len + 15 > stringbuf_size) {
127 stringbuf_size = stringbuf_idx + len + 127;
128 dbg2_error_msg("grow stringbuf to %u", stringbuf_size);
129 stringbuf = xrealloc(stringbuf, stringbuf_size);
130 }
131 memcpy(stringbuf + stringbuf_idx, s, len);
132 stringbuf_idx += len;
133}
Denis Vlasenko671691c2008-07-04 10:25:44 +0000134
135static void appendc(char c)
136{
Denys Vlasenko0c6914e2009-09-07 02:38:26 +0200137 /* We appendc() only after append(), + 15 trick in append()
138 * makes it unnecessary to check for overflow here */
139 stringbuf[stringbuf_idx++] = c;
Denis Vlasenko671691c2008-07-04 10:25:44 +0000140}
141
Denis Vlasenko24a131e2008-07-09 15:30:57 +0000142static void bksp(void)
143{
144 if (stringbuf_idx)
145 stringbuf_idx--;
146}
147
Denis Vlasenko671691c2008-07-04 10:25:44 +0000148static void reset_stringbuf(void)
149{
150 stringbuf_idx = 0;
151}
152
153static char* copy_stringbuf(void)
154{
Denys Vlasenko0c6914e2009-09-07 02:38:26 +0200155 char *copy = xzalloc(stringbuf_idx + 1); /* terminating NUL */
Denis Vlasenko671691c2008-07-04 10:25:44 +0000156 return memcpy(copy, stringbuf, stringbuf_idx);
157}
158
159static char* find_keyword(char *ptr, size_t len, const char *word)
160{
Denis Vlasenkoe9ad84d2008-08-05 13:10:34 +0000161 if (!ptr) /* happens if xmalloc_open_zipped_read_close cannot read it */
Denis Vlasenko671691c2008-07-04 10:25:44 +0000162 return NULL;
163
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100164 len -= strlen(word) - 1;
Denis Vlasenko671691c2008-07-04 10:25:44 +0000165 while ((ssize_t)len > 0) {
166 char *old = ptr;
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100167 char *after_word;
168
Denis Vlasenko671691c2008-07-04 10:25:44 +0000169 /* search for the first char in word */
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100170 ptr = memchr(ptr, word[0], len);
Denis Vlasenko671691c2008-07-04 10:25:44 +0000171 if (ptr == NULL) /* no occurance left, done */
172 break;
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100173 after_word = is_prefixed_with(ptr, word);
174 if (after_word)
175 return after_word; /* found, return ptr past it */
Denis Vlasenko671691c2008-07-04 10:25:44 +0000176 ++ptr;
177 len -= (ptr - old);
178 }
179 return NULL;
180}
181
182static void replace(char *s, char what, char with)
183{
184 while (*s) {
185 if (what == *s)
186 *s = with;
187 ++s;
188 }
189}
190
Denys Vlasenko07e55552014-04-21 16:59:36 +0200191static char *filename2modname(const char *filename, char *modname)
192{
193 int i;
Denys Vlasenko78854522015-01-01 19:02:40 +0100194 const char *from;
Denys Vlasenko07e55552014-04-21 16:59:36 +0200195
Denys Vlasenko78854522015-01-01 19:02:40 +0100196 // Disabled since otherwise "modprobe dir/name" would work
197 // as if it is "modprobe name". It is unclear why
198 // 'basenamization' was here in the first place.
199 //from = bb_get_last_path_component_nostrip(filename);
200 from = filename;
Denys Vlasenko07e55552014-04-21 16:59:36 +0200201 for (i = 0; i < (MODULE_NAME_LEN-1) && from[i] != '\0' && from[i] != '.'; i++)
202 modname[i] = (from[i] == '-') ? '_' : from[i];
203 modname[i] = '\0';
204
205 return modname;
206}
207
Denys Vlasenko1b671532015-01-11 17:46:56 +0100208static int pathname_matches_modname(const char *pathname, const char *modname)
209{
210 int r;
211 char name[MODULE_NAME_LEN];
212 filename2modname(bb_get_last_path_component_nostrip(pathname), name);
213 r = (strcmp(name, modname) == 0);
214 return r;
215}
216
Denis Vlasenko24a131e2008-07-09 15:30:57 +0000217/* Take "word word", return malloced "word",NUL,"word",NUL,NUL */
218static char* str_2_list(const char *str)
219{
220 int len = strlen(str) + 1;
221 char *dst = xmalloc(len + 1);
222
223 dst[len] = '\0';
224 memcpy(dst, str, len);
225//TODO: protect against 2+ spaces: "word word"
226 replace(dst, ' ', '\0');
227 return dst;
228}
229
Denis Vlasenko671691c2008-07-04 10:25:44 +0000230/* We use error numbers in a loose translation... */
231static const char *moderror(int err)
232{
233 switch (err) {
234 case ENOEXEC:
235 return "invalid module format";
236 case ENOENT:
237 return "unknown symbol in module or invalid parameter";
238 case ESRCH:
239 return "module has wrong symbol version";
240 case EINVAL: /* "invalid parameter" */
241 return "unknown symbol in module or invalid parameter"
242 + sizeof("unknown symbol in module or");
243 default:
244 return strerror(err);
245 }
246}
247
248static int load_module(const char *fname, const char *options)
249{
250#if 1
251 int r;
252 size_t len = MAXINT(ssize_t);
253 char *module_image;
Mike Frysinger3a45b872016-09-15 12:16:33 +0200254
255 if (!options)
256 options = "";
257
Denis Vlasenko671691c2008-07-04 10:25:44 +0000258 dbg1_error_msg("load_module('%s','%s')", fname, options);
259
Mike Frysinger3a45b872016-09-15 12:16:33 +0200260 /*
261 * First we try finit_module if available. Some kernels are configured
262 * to only allow loading of modules off of secure storage (like a read-
263 * only rootfs) which needs the finit_module call. If it fails, we fall
264 * back to normal module loading to support compressed modules.
265 */
266 r = 1;
267# ifdef __NR_finit_module
268 {
269 int fd = open(fname, O_RDONLY | O_CLOEXEC);
270 if (fd >= 0) {
271 r = finit_module(fd, options, 0) != 0;
272 close(fd);
273 }
274 }
275# endif
276 if (r != 0) {
277 module_image = xmalloc_open_zipped_read_close(fname, &len);
278 r = (!module_image || init_module(module_image, len, options) != 0);
279 free(module_image);
280 }
281
Denis Vlasenko671691c2008-07-04 10:25:44 +0000282 dbg1_error_msg("load_module:%d", r);
283 return r; /* 0 = success */
284#else
285 /* For testing */
286 dbg1_error_msg("load_module('%s','%s')", fname, options);
287 return 1;
288#endif
289}
290
Denys Vlasenko5c3e0602016-06-20 10:59:06 +0200291/* Returns !0 if open/read was unsuccessful */
292static int parse_module(module_info *info, const char *pathname)
Denis Vlasenko671691c2008-07-04 10:25:44 +0000293{
294 char *module_image;
295 char *ptr;
296 size_t len;
297 size_t pos;
Denis Vlasenko24a131e2008-07-09 15:30:57 +0000298 dbg1_error_msg("parse_module('%s')", pathname);
Denis Vlasenko671691c2008-07-04 10:25:44 +0000299
300 /* Read (possibly compressed) module */
Denys Vlasenko5c3e0602016-06-20 10:59:06 +0200301 errno = 0;
Denis Vlasenko671691c2008-07-04 10:25:44 +0000302 len = 64 * 1024 * 1024; /* 64 Mb at most */
Denis Vlasenkoe9ad84d2008-08-05 13:10:34 +0000303 module_image = xmalloc_open_zipped_read_close(pathname, &len);
Denys Vlasenko094cc512011-01-17 14:58:27 +0100304 /* module_image == NULL is ok here, find_keyword handles it */
Denis Vlasenko78436992008-07-10 14:14:20 +0000305//TODO: optimize redundant module body reads
Denis Vlasenko671691c2008-07-04 10:25:44 +0000306
Denis Vlasenko78436992008-07-10 14:14:20 +0000307 /* "alias1 symbol:sym1 alias2 symbol:sym2" */
Denis Vlasenko671691c2008-07-04 10:25:44 +0000308 reset_stringbuf();
Denis Vlasenko671691c2008-07-04 10:25:44 +0000309 pos = 0;
310 while (1) {
Denys Vlasenko6116cb22014-04-19 16:17:27 +0200311 unsigned start = stringbuf_idx;
Denis Vlasenko671691c2008-07-04 10:25:44 +0000312 ptr = find_keyword(module_image + pos, len - pos, "alias=");
313 if (!ptr) {
314 ptr = find_keyword(module_image + pos, len - pos, "__ksymtab_");
315 if (!ptr)
316 break;
317 /* DOCME: __ksymtab_gpl and __ksymtab_strings occur
318 * in many modules. What do they mean? */
Denis Vlasenko0e2c93f2008-07-10 14:16:11 +0000319 if (strcmp(ptr, "gpl") == 0 || strcmp(ptr, "strings") == 0)
320 goto skip;
321 dbg2_error_msg("alias:'symbol:%s'", ptr);
322 append("symbol:");
Denis Vlasenko671691c2008-07-04 10:25:44 +0000323 } else {
Denis Vlasenko24a131e2008-07-09 15:30:57 +0000324 dbg2_error_msg("alias:'%s'", ptr);
Denis Vlasenko671691c2008-07-04 10:25:44 +0000325 }
326 append(ptr);
327 appendc(' ');
Denys Vlasenko6116cb22014-04-19 16:17:27 +0200328 /*
329 * Don't add redundant aliases, such as:
330 * libcrc32c.ko symbol:crc32c symbol:crc32c
331 */
332 if (start) { /* "if we aren't the first alias" */
333 char *found, *last;
334 stringbuf[stringbuf_idx] = '\0';
335 last = stringbuf + start;
336 /*
337 * String at last-1 is " symbol:crc32c "
338 * (with both leading and trailing spaces).
339 */
340 if (strncmp(stringbuf, last, stringbuf_idx - start) == 0)
341 /* First alias matches us */
342 found = stringbuf;
343 else
344 /* Does any other alias match? */
345 found = strstr(stringbuf, last-1);
346 if (found < last-1) {
347 /* There is absolutely the same string before us */
348 dbg2_error_msg("redundant:'%s'", last);
349 stringbuf_idx = start;
350 goto skip;
351 }
352 }
Denis Vlasenko0e2c93f2008-07-10 14:16:11 +0000353 skip:
Denis Vlasenko671691c2008-07-04 10:25:44 +0000354 pos = (ptr - module_image);
355 }
Denis Vlasenko24a131e2008-07-09 15:30:57 +0000356 bksp(); /* remove last ' ' */
Denis Vlasenko78436992008-07-10 14:14:20 +0000357 info->aliases = copy_stringbuf();
Denys Vlasenkof9c814b2009-09-07 02:37:19 +0200358 replace(info->aliases, '-', '_');
Denis Vlasenko671691c2008-07-04 10:25:44 +0000359
Denis Vlasenko78436992008-07-10 14:14:20 +0000360 /* "dependency1 depandency2" */
361 reset_stringbuf();
Denis Vlasenko671691c2008-07-04 10:25:44 +0000362 ptr = find_keyword(module_image, len, "depends=");
363 if (ptr && *ptr) {
364 replace(ptr, ',', ' ');
365 replace(ptr, '-', '_');
366 dbg2_error_msg("dep:'%s'", ptr);
367 append(ptr);
368 }
Denys Vlasenko5c3e0602016-06-20 10:59:06 +0200369 free(module_image);
Denis Vlasenko78436992008-07-10 14:14:20 +0000370 info->deps = copy_stringbuf();
Denis Vlasenko671691c2008-07-04 10:25:44 +0000371
Denys Vlasenko5c3e0602016-06-20 10:59:06 +0200372 info->open_read_failed = (module_image == NULL);
373 return info->open_read_failed;
Denis Vlasenko671691c2008-07-04 10:25:44 +0000374}
375
Denis Vlasenko671691c2008-07-04 10:25:44 +0000376static FAST_FUNC int fileAction(const char *pathname,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000377 struct stat *sb UNUSED_PARAM,
Denis Vlasenko24a131e2008-07-09 15:30:57 +0000378 void *modname_to_match,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000379 int depth UNUSED_PARAM)
Denis Vlasenko671691c2008-07-04 10:25:44 +0000380{
381 int cur;
Denis Vlasenko671691c2008-07-04 10:25:44 +0000382 const char *fname;
Explorer0980172e42017-01-09 15:04:43 +0800383 bool is_remove = (ENABLE_RMMOD && ONLY_APPLET)
384 || ((ENABLE_RMMOD || ENABLE_MODPROBE) && (option_mask32 & OPT_r));
Denis Vlasenko671691c2008-07-04 10:25:44 +0000385
386 pathname += 2; /* skip "./" */
387 fname = bb_get_last_path_component_nostrip(pathname);
388 if (!strrstr(fname, ".ko")) {
389 dbg1_error_msg("'%s' is not a module", pathname);
390 return TRUE; /* not a module, continue search */
391 }
392
393 cur = module_count++;
Denis Vlasenkodeeed592008-07-08 05:14:36 +0000394 modinfo = xrealloc_vector(modinfo, 12, cur);
Denis Vlasenko671691c2008-07-04 10:25:44 +0000395 modinfo[cur].pathname = xstrdup(pathname);
Denis Vlasenko27842282008-08-04 13:20:36 +0000396 /*modinfo[cur].aliases = NULL; - xrealloc_vector did it */
397 /*modinfo[cur+1].pathname = NULL;*/
Denis Vlasenko671691c2008-07-04 10:25:44 +0000398
Denis Vlasenko24a131e2008-07-09 15:30:57 +0000399 if (!pathname_matches_modname(fname, modname_to_match)) {
Denis Vlasenko671691c2008-07-04 10:25:44 +0000400 dbg1_error_msg("'%s' module name doesn't match", pathname);
401 return TRUE; /* module name doesn't match, continue search */
402 }
403
404 dbg1_error_msg("'%s' module name matches", pathname);
405 module_found_idx = cur;
Denys Vlasenko5c3e0602016-06-20 10:59:06 +0200406 if (parse_module(&modinfo[cur], pathname) != 0)
407 return TRUE; /* failed to open/read it, no point in trying loading */
Denis Vlasenko671691c2008-07-04 10:25:44 +0000408
Explorer0980172e42017-01-09 15:04:43 +0800409 if (!is_remove) {
Denis Vlasenko671691c2008-07-04 10:25:44 +0000410 if (load_module(pathname, module_load_options) == 0) {
411 /* Load was successful, there is nothing else to do.
412 * This can happen ONLY for "top-level" module load,
413 * not a dep, because deps dont do dirscan. */
414 exit(EXIT_SUCCESS);
Denis Vlasenko671691c2008-07-04 10:25:44 +0000415 }
416 }
417
Denis Vlasenko671691c2008-07-04 10:25:44 +0000418 return TRUE;
419}
420
Denis Vlasenko7f950a92008-07-10 14:14:45 +0000421static int load_dep_bb(void)
Denis Vlasenko78436992008-07-10 14:14:20 +0000422{
423 char *line;
Denis Vlasenko5415c852008-07-21 23:05:26 +0000424 FILE *fp = fopen_for_read(DEPFILE_BB);
Denis Vlasenko78436992008-07-10 14:14:20 +0000425
426 if (!fp)
Denis Vlasenko7f950a92008-07-10 14:14:45 +0000427 return 0;
428
429 dep_bb_seen = 1;
430 dbg1_error_msg("loading "DEPFILE_BB);
431
432 /* Why? There is a rare scenario: we did not find modprobe.dep.bb,
433 * we scanned the dir and found no module by name, then we search
434 * for alias (full scan), and we decided to generate modprobe.dep.bb.
435 * But we see modprobe.dep.bb.new! Other modprobe is at work!
436 * We wait and other modprobe renames it to modprobe.dep.bb.
437 * Now we can use it.
438 * But we already have modinfo[] filled, and "module_count = 0"
439 * makes us start anew. Yes, we leak modinfo[].xxx pointers -
440 * there is not much of data there anyway. */
441 module_count = 0;
442 memset(&modinfo[0], 0, sizeof(modinfo[0]));
Denis Vlasenko78436992008-07-10 14:14:20 +0000443
444 while ((line = xmalloc_fgetline(fp)) != NULL) {
445 char* space;
Denys Vlasenko90a99042009-09-06 02:36:23 +0200446 char* linebuf;
Denis Vlasenko78436992008-07-10 14:14:20 +0000447 int cur;
448
449 if (!line[0]) {
450 free(line);
451 continue;
452 }
453 space = strchrnul(line, ' ');
454 cur = module_count++;
455 modinfo = xrealloc_vector(modinfo, 12, cur);
Denis Vlasenko27842282008-08-04 13:20:36 +0000456 /*modinfo[cur+1].pathname = NULL; - xrealloc_vector did it */
Denis Vlasenko78436992008-07-10 14:14:20 +0000457 modinfo[cur].pathname = line; /* we take ownership of malloced block here */
458 if (*space)
459 *space++ = '\0';
460 modinfo[cur].aliases = space;
Denys Vlasenko90a99042009-09-06 02:36:23 +0200461 linebuf = xmalloc_fgetline(fp);
462 modinfo[cur].deps = linebuf ? linebuf : xzalloc(1);
Denis Vlasenko78436992008-07-10 14:14:20 +0000463 if (modinfo[cur].deps[0]) {
464 /* deps are not "", so next line must be empty */
465 line = xmalloc_fgetline(fp);
466 /* Refuse to work with damaged config file */
467 if (line && line[0])
468 bb_error_msg_and_die("error in %s at '%s'", DEPFILE_BB, line);
469 free(line);
470 }
471 }
Denis Vlasenko7f950a92008-07-10 14:14:45 +0000472 return 1;
473}
474
475static int start_dep_bb_writeout(void)
476{
477 int fd;
478
Denis Vlasenko0e2c93f2008-07-10 14:16:11 +0000479 /* depmod -n: write result to stdout */
480 if (applet_name[0] == 'd' && (option_mask32 & 1))
481 return STDOUT_FILENO;
482
Denis Vlasenko7f950a92008-07-10 14:14:45 +0000483 fd = open(DEPFILE_BB".new", O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0644);
484 if (fd < 0) {
485 if (errno == EEXIST) {
486 int count = 5 * 20;
487 dbg1_error_msg(DEPFILE_BB".new exists, waiting for "DEPFILE_BB);
488 while (1) {
489 usleep(1000*1000 / 20);
490 if (load_dep_bb()) {
491 dbg1_error_msg(DEPFILE_BB" appeared");
492 return -2; /* magic number */
493 }
494 if (!--count)
495 break;
496 }
497 bb_error_msg("deleting stale %s", DEPFILE_BB".new");
498 fd = open_or_warn(DEPFILE_BB".new", O_WRONLY | O_CREAT | O_TRUNC);
499 }
500 }
501 dbg1_error_msg("opened "DEPFILE_BB".new:%d", fd);
502 return fd;
503}
504
505static void write_out_dep_bb(int fd)
506{
507 int i;
508 FILE *fp;
509
510 /* We want good error reporting. fdprintf is not good enough. */
Denys Vlasenkoa7ccdee2009-11-15 23:28:11 +0100511 fp = xfdopen_for_write(fd);
Denis Vlasenko7f950a92008-07-10 14:14:45 +0000512 i = 0;
513 while (modinfo[i].pathname) {
514 fprintf(fp, "%s%s%s\n" "%s%s\n",
515 modinfo[i].pathname, modinfo[i].aliases[0] ? " " : "", modinfo[i].aliases,
516 modinfo[i].deps, modinfo[i].deps[0] ? "\n" : "");
517 i++;
518 }
519 /* Badly formatted depfile is a no-no. Be paranoid. */
520 errno = 0;
Denis Vlasenko0e2c93f2008-07-10 14:16:11 +0000521 if (ferror(fp) | fclose(fp)) /* | instead of || is intended */
Denis Vlasenko7f950a92008-07-10 14:14:45 +0000522 goto err;
Denis Vlasenko0e2c93f2008-07-10 14:16:11 +0000523
524 if (fd == STDOUT_FILENO) /* it was depmod -n */
525 goto ok;
526
Denis Vlasenko7f950a92008-07-10 14:14:45 +0000527 if (rename(DEPFILE_BB".new", DEPFILE_BB) != 0) {
528 err:
Denys Vlasenko651a2692010-03-23 16:25:17 +0100529 bb_perror_msg("can't create '%s'", DEPFILE_BB);
Denis Vlasenko7f950a92008-07-10 14:14:45 +0000530 unlink(DEPFILE_BB".new");
531 } else {
Denis Vlasenko0e2c93f2008-07-10 14:16:11 +0000532 ok:
533 wrote_dep_bb_ok = 1;
Denis Vlasenko7f950a92008-07-10 14:14:45 +0000534 dbg1_error_msg("created "DEPFILE_BB);
535 }
Denis Vlasenko78436992008-07-10 14:14:20 +0000536}
537
Denys Vlasenko07e55552014-04-21 16:59:36 +0200538static module_info** find_alias(const char *alias)
Denis Vlasenko671691c2008-07-04 10:25:44 +0000539{
540 int i;
Denis Vlasenko7f950a92008-07-10 14:14:45 +0000541 int dep_bb_fd;
Denys Vlasenko07e55552014-04-21 16:59:36 +0200542 int infoidx;
543 module_info **infovec;
Denis Vlasenko671691c2008-07-04 10:25:44 +0000544 dbg1_error_msg("find_alias('%s')", alias);
545
Denis Vlasenko7f950a92008-07-10 14:14:45 +0000546 try_again:
Denis Vlasenko671691c2008-07-04 10:25:44 +0000547 /* First try to find by name (cheaper) */
548 i = 0;
549 while (modinfo[i].pathname) {
Denis Vlasenko24a131e2008-07-09 15:30:57 +0000550 if (pathname_matches_modname(modinfo[i].pathname, alias)) {
Denis Vlasenko671691c2008-07-04 10:25:44 +0000551 dbg1_error_msg("found '%s' in module '%s'",
552 alias, modinfo[i].pathname);
Denis Vlasenko78436992008-07-10 14:14:20 +0000553 if (!modinfo[i].aliases) {
554 parse_module(&modinfo[i], modinfo[i].pathname);
555 }
Denys Vlasenko07e55552014-04-21 16:59:36 +0200556 infovec = xzalloc(2 * sizeof(infovec[0]));
557 infovec[0] = &modinfo[i];
558 return infovec;
Denis Vlasenko671691c2008-07-04 10:25:44 +0000559 }
Denis Vlasenko671691c2008-07-04 10:25:44 +0000560 i++;
561 }
562
Denis Vlasenko7f950a92008-07-10 14:14:45 +0000563 /* Ok, we definitely have to scan module bodies. This is a good
564 * moment to generate modprobe.dep.bb, if it does not exist yet */
565 dep_bb_fd = dep_bb_seen ? -1 : start_dep_bb_writeout();
566 if (dep_bb_fd == -2) /* modprobe.dep.bb appeared? */
567 goto try_again;
568
Denis Vlasenko671691c2008-07-04 10:25:44 +0000569 /* Scan all module bodies, extract modinfo (it contains aliases) */
570 i = 0;
Denys Vlasenko07e55552014-04-21 16:59:36 +0200571 infoidx = 0;
572 infovec = NULL;
Denis Vlasenko671691c2008-07-04 10:25:44 +0000573 while (modinfo[i].pathname) {
574 char *desc, *s;
Denis Vlasenko78436992008-07-10 14:14:20 +0000575 if (!modinfo[i].aliases) {
576 parse_module(&modinfo[i], modinfo[i].pathname);
Denis Vlasenko671691c2008-07-04 10:25:44 +0000577 }
Denis Vlasenko24a131e2008-07-09 15:30:57 +0000578 /* "alias1 symbol:sym1 alias2 symbol:sym2" */
Denis Vlasenko78436992008-07-10 14:14:20 +0000579 desc = str_2_list(modinfo[i].aliases);
Denis Vlasenko671691c2008-07-04 10:25:44 +0000580 /* Does matching substring exist? */
Denis Vlasenko671691c2008-07-04 10:25:44 +0000581 for (s = desc; *s; s += strlen(s) + 1) {
Denis Vlasenko24a131e2008-07-09 15:30:57 +0000582 /* Aliases in module bodies can be defined with
Denis Vlasenko58f59a22008-07-06 11:52:23 +0000583 * shell patterns. Example:
584 * "pci:v000010DEd000000D9sv*sd*bc*sc*i*".
585 * Plain strcmp() won't catch that */
586 if (fnmatch(s, alias, 0) == 0) {
Denis Vlasenko671691c2008-07-04 10:25:44 +0000587 dbg1_error_msg("found alias '%s' in module '%s'",
588 alias, modinfo[i].pathname);
Denys Vlasenko07e55552014-04-21 16:59:36 +0200589 infovec = xrealloc_vector(infovec, 1, infoidx);
590 infovec[infoidx++] = &modinfo[i];
Denis Vlasenko7f950a92008-07-10 14:14:45 +0000591 break;
Denis Vlasenko671691c2008-07-04 10:25:44 +0000592 }
593 }
594 free(desc);
595 i++;
596 }
Denis Vlasenko7f950a92008-07-10 14:14:45 +0000597
598 /* Create module.dep.bb if needed */
599 if (dep_bb_fd >= 0) {
600 write_out_dep_bb(dep_bb_fd);
601 }
602
Denys Vlasenko07e55552014-04-21 16:59:36 +0200603 dbg1_error_msg("find_alias '%s' returns %d results", alias, infoidx);
604 return infovec;
Denis Vlasenko671691c2008-07-04 10:25:44 +0000605}
606
607#if ENABLE_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED
Denis Vlasenko0f99d492008-07-24 23:38:04 +0000608// TODO: open only once, invent config_rewind()
Denis Vlasenko671691c2008-07-04 10:25:44 +0000609static int already_loaded(const char *name)
610{
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100611 int ret;
Denys Vlasenko1fd84422015-02-12 16:18:39 +0100612 char *line;
613 FILE *fp;
614
615 ret = 5 * 2;
616 again:
617 fp = fopen_for_read("/proc/modules");
618 if (!fp)
619 return 0;
Denys Vlasenko1fd84422015-02-12 16:18:39 +0100620 while ((line = xmalloc_fgetline(fp)) != NULL) {
621 char *live;
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100622 char *after_name;
Denys Vlasenko1fd84422015-02-12 16:18:39 +0100623
624 // Examples from kernel 3.14.6:
625 //pcspkr 12718 0 - Live 0xffffffffa017e000
626 //snd_timer 28690 2 snd_seq,snd_pcm, Live 0xffffffffa025e000
627 //i915 801405 2 - Live 0xffffffffa0096000
Denys Vlasenko8dff01d2015-03-12 17:48:34 +0100628 after_name = is_prefixed_with(line, name);
629 if (!after_name || *after_name != ' ') {
Denys Vlasenko1fd84422015-02-12 16:18:39 +0100630 free(line);
631 continue;
Denis Vlasenko671691c2008-07-04 10:25:44 +0000632 }
Denys Vlasenko1fd84422015-02-12 16:18:39 +0100633 live = strstr(line, " Live");
634 free(line);
635 if (!live) {
636 /* State can be Unloading, Loading, or Live.
637 * modprobe must not return prematurely if we see "Loading":
638 * it can cause further programs to assume load completed,
639 * but it did not (yet)!
640 * Wait up to 5*20 ms for it to resolve.
641 */
642 ret -= 2;
643 if (ret == 0)
644 break; /* huh? report as "not loaded" */
645 fclose(fp);
646 usleep(20*1000);
647 goto again;
648 }
649 ret = 1;
650 break;
Denis Vlasenko671691c2008-07-04 10:25:44 +0000651 }
Denys Vlasenko1fd84422015-02-12 16:18:39 +0100652 fclose(fp);
653
Denys Vlasenko402afe12015-02-13 11:53:33 +0100654 return ret & 1;
Denis Vlasenko671691c2008-07-04 10:25:44 +0000655}
656#else
Denys Vlasenko68c048f2015-02-07 20:44:46 +0100657#define already_loaded(name) 0
Denis Vlasenko671691c2008-07-04 10:25:44 +0000658#endif
659
Denys Vlasenko68c048f2015-02-07 20:44:46 +0100660static int rmmod(const char *filename)
661{
662 int r;
663 char modname[MODULE_NAME_LEN];
664
665 filename2modname(filename, modname);
666 r = delete_module(modname, O_NONBLOCK | O_EXCL);
667 dbg1_error_msg("delete_module('%s', O_NONBLOCK | O_EXCL):%d", modname, r);
668 if (r != 0 && !(option_mask32 & OPT_q)) {
669 bb_perror_msg("remove '%s'", modname);
670 }
671 return r;
672}
673
Denis Vlasenko671691c2008-07-04 10:25:44 +0000674/*
Denis Vlasenko0e2c93f2008-07-10 14:16:11 +0000675 * Given modules definition and module name (or alias, or symbol)
676 * load/remove the module respecting dependencies.
677 * NB: also called by depmod with bogus name "/",
678 * just in order to force modprobe.dep.bb creation.
Denis Vlasenko671691c2008-07-04 10:25:44 +0000679*/
Kang-Che Sungb1d6a2c2017-01-31 21:09:17 +0800680#if !ENABLE_FEATURE_CMDLINE_MODULE_OPTIONS
Denis Vlasenko671691c2008-07-04 10:25:44 +0000681#define process_module(a,b) process_module(a)
682#define cmdline_options ""
683#endif
Denys Vlasenko5c3e0602016-06-20 10:59:06 +0200684static int process_module(char *name, const char *cmdline_options)
Denis Vlasenko671691c2008-07-04 10:25:44 +0000685{
686 char *s, *deps, *options;
Denys Vlasenko07e55552014-04-21 16:59:36 +0200687 module_info **infovec;
Denis Vlasenko671691c2008-07-04 10:25:44 +0000688 module_info *info;
Denys Vlasenko07e55552014-04-21 16:59:36 +0200689 int infoidx;
Explorer0980172e42017-01-09 15:04:43 +0800690 bool is_remove = (ENABLE_RMMOD && ONLY_APPLET)
691 || ((ENABLE_RMMOD || ENABLE_MODPROBE) && (option_mask32 & OPT_r));
Denys Vlasenko5c3e0602016-06-20 10:59:06 +0200692 int exitcode = EXIT_SUCCESS;
Denys Vlasenko07e55552014-04-21 16:59:36 +0200693
Denis Vlasenko671691c2008-07-04 10:25:44 +0000694 dbg1_error_msg("process_module('%s','%s')", name, cmdline_options);
695
696 replace(name, '-', '_');
697
Denys Vlasenko68c048f2015-02-07 20:44:46 +0100698 dbg1_error_msg("already_loaded:%d is_remove:%d", already_loaded(name), is_remove);
699
Explorer0980172e42017-01-09 15:04:43 +0800700 if (is_rmmod) {
701 /* Does not remove dependencies, no need to scan, just remove.
Denys Vlasenko68c048f2015-02-07 20:44:46 +0100702 * (compat note: this allows and strips .ko suffix)
703 */
704 rmmod(name);
Denys Vlasenko5c3e0602016-06-20 10:59:06 +0200705 return EXIT_SUCCESS;
Denys Vlasenko68c048f2015-02-07 20:44:46 +0100706 }
707
Denys Vlasenko07e55552014-04-21 16:59:36 +0200708 /*
Denys Vlasenko68c048f2015-02-07 20:44:46 +0100709 * We used to have "is_remove != already_loaded(name)" check here, but
Denys Vlasenko07e55552014-04-21 16:59:36 +0200710 * modprobe -r pci:v00008086d00007010sv00000000sd00000000bc01sc01i80
711 * won't unload modules (there are more than one)
712 * which have this alias.
713 */
Denys Vlasenko68c048f2015-02-07 20:44:46 +0100714 if (!is_remove && already_loaded(name)) {
Denis Vlasenko671691c2008-07-04 10:25:44 +0000715 dbg1_error_msg("nothing to do for '%s'", name);
Denys Vlasenko5c3e0602016-06-20 10:59:06 +0200716 return EXIT_SUCCESS;
Denis Vlasenko671691c2008-07-04 10:25:44 +0000717 }
718
719 options = NULL;
Denys Vlasenko68c048f2015-02-07 20:44:46 +0100720 if (!is_remove) {
Denis Vlasenko671691c2008-07-04 10:25:44 +0000721 char *opt_filename = xasprintf("/etc/modules/%s", name);
722 options = xmalloc_open_read_close(opt_filename, NULL);
723 if (options)
724 replace(options, '\n', ' ');
Kang-Che Sungb1d6a2c2017-01-31 21:09:17 +0800725#if ENABLE_FEATURE_CMDLINE_MODULE_OPTIONS
Denis Vlasenko671691c2008-07-04 10:25:44 +0000726 if (cmdline_options) {
727 /* NB: cmdline_options always have one leading ' '
728 * (see main()), we remove it here */
729 char *op = xasprintf(options ? "%s %s" : "%s %s" + 3,
730 cmdline_options + 1, options);
731 free(options);
732 options = op;
733 }
734#endif
735 free(opt_filename);
736 module_load_options = options;
737 dbg1_error_msg("process_module('%s'): options:'%s'", name, options);
738 }
739
740 if (!module_count) {
741 /* Scan module directory. This is done only once.
742 * It will attempt module load, and will exit(EXIT_SUCCESS)
Denys Vlasenko07e55552014-04-21 16:59:36 +0200743 * on success.
744 */
Denis Vlasenko671691c2008-07-04 10:25:44 +0000745 module_found_idx = -1;
746 recursive_action(".",
747 ACTION_RECURSE, /* flags */
748 fileAction, /* file action */
749 NULL, /* dir action */
750 name, /* user data */
Denys Vlasenko07e55552014-04-21 16:59:36 +0200751 0 /* depth */
752 );
Denis Vlasenko671691c2008-07-04 10:25:44 +0000753 dbg1_error_msg("dirscan complete");
Denys Vlasenko68c048f2015-02-07 20:44:46 +0100754 /* Module was not found, or load failed, or is_remove */
Denis Vlasenko671691c2008-07-04 10:25:44 +0000755 if (module_found_idx >= 0) { /* module was found */
Denys Vlasenko07e55552014-04-21 16:59:36 +0200756 infovec = xzalloc(2 * sizeof(infovec[0]));
757 infovec[0] = &modinfo[module_found_idx];
Denis Vlasenko671691c2008-07-04 10:25:44 +0000758 } else { /* search for alias, not a plain module name */
Denys Vlasenko07e55552014-04-21 16:59:36 +0200759 infovec = find_alias(name);
Denis Vlasenko671691c2008-07-04 10:25:44 +0000760 }
761 } else {
Denys Vlasenko07e55552014-04-21 16:59:36 +0200762 infovec = find_alias(name);
Denis Vlasenko671691c2008-07-04 10:25:44 +0000763 }
764
Denys Vlasenko3c75b1c2015-01-11 17:40:30 +0100765 if (!infovec) {
766 /* both dirscan and find_alias found nothing */
Explorer0980172e42017-01-09 15:04:43 +0800767 if (!is_remove && !is_depmod) /* it wasn't rmmod or depmod */
Denys Vlasenko3c75b1c2015-01-11 17:40:30 +0100768 bb_error_msg("module '%s' not found", name);
769//TODO: _and_die()? or should we continue (un)loading modules listed on cmdline?
770 goto ret;
771 }
772
Denys Vlasenko07e55552014-04-21 16:59:36 +0200773 /* There can be more than one module for the given alias. For example,
774 * "pci:v00008086d00007010sv00000000sd00000000bc01sc01i80" matches
775 * ata_piix because it has alias "pci:v00008086d00007010sv*sd*bc*sc*i*"
776 * and ata_generic, it has alias "pci:v*d*sv*sd*bc01sc01i*"
777 * Standard modprobe loads them both. We achieve it by returning
778 * a *list* of modinfo pointers from find_alias().
779 */
Denys Vlasenko63321512009-10-08 22:54:41 +0200780
Denys Vlasenko68c048f2015-02-07 20:44:46 +0100781 /* modprobe -r? unload module(s) */
782 if (is_remove) {
Denys Vlasenko07e55552014-04-21 16:59:36 +0200783 infoidx = 0;
784 while ((info = infovec[infoidx++]) != NULL) {
Denys Vlasenko68c048f2015-02-07 20:44:46 +0100785 int r = rmmod(bb_get_last_path_component_nostrip(info->pathname));
Denys Vlasenko07e55552014-04-21 16:59:36 +0200786 if (r != 0) {
Denys Vlasenko68c048f2015-02-07 20:44:46 +0100787 goto ret; /* error */
Denys Vlasenko07e55552014-04-21 16:59:36 +0200788 }
Denis Vlasenko671691c2008-07-04 10:25:44 +0000789 }
Denys Vlasenko06a98e32012-09-25 20:37:38 +0200790 /* modprobe -r: we do not stop here -
Denis Vlasenko671691c2008-07-04 10:25:44 +0000791 * continue to unload modules on which the module depends:
792 * "-r --remove: option causes modprobe to remove a module.
793 * If the modules it depends on are also unused, modprobe
Denys Vlasenko06a98e32012-09-25 20:37:38 +0200794 * will try to remove them, too."
795 */
Denis Vlasenko671691c2008-07-04 10:25:44 +0000796 }
797
Denys Vlasenko07e55552014-04-21 16:59:36 +0200798 infoidx = 0;
799 while ((info = infovec[infoidx++]) != NULL) {
800 /* Iterate thru dependencies, trying to (un)load them */
801 deps = str_2_list(info->deps);
802 for (s = deps; *s; s += strlen(s) + 1) {
803 //if (strcmp(name, s) != 0) // N.B. do loops exist?
804 dbg1_error_msg("recurse on dep '%s'", s);
805 process_module(s, NULL);
806 dbg1_error_msg("recurse on dep '%s' done", s);
807 }
808 free(deps);
Denis Vlasenko671691c2008-07-04 10:25:44 +0000809
Denys Vlasenko68c048f2015-02-07 20:44:46 +0100810 if (is_remove)
Denys Vlasenko07e55552014-04-21 16:59:36 +0200811 continue;
812
813 /* We are modprobe: load it */
814 if (options && strstr(options, "blacklist")) {
Denis Vlasenko1ad4db12008-11-12 00:09:58 +0000815 dbg1_error_msg("'%s': blacklisted", info->pathname);
Denys Vlasenko07e55552014-04-21 16:59:36 +0200816 continue;
817 }
Denys Vlasenko5c3e0602016-06-20 10:59:06 +0200818 if (info->open_read_failed) {
819 /* We already tried it, didn't work. Don't try load again */
820 exitcode = EXIT_FAILURE;
821 continue;
822 }
Denys Vlasenko07e55552014-04-21 16:59:36 +0200823 errno = 0;
824 if (load_module(info->pathname, options) != 0) {
825 if (EEXIST != errno) {
826 bb_error_msg("'%s': %s",
827 info->pathname,
828 moderror(errno));
829 } else {
830 dbg1_error_msg("'%s': %s",
831 info->pathname,
832 moderror(errno));
833 }
Denys Vlasenko5c3e0602016-06-20 10:59:06 +0200834 exitcode = EXIT_FAILURE;
Denis Vlasenko671691c2008-07-04 10:25:44 +0000835 }
836 }
837 ret:
Denys Vlasenko07e55552014-04-21 16:59:36 +0200838 free(infovec);
Denis Vlasenko671691c2008-07-04 10:25:44 +0000839 free(options);
Denys Vlasenko5c3e0602016-06-20 10:59:06 +0200840
841 return exitcode;
Denis Vlasenko671691c2008-07-04 10:25:44 +0000842}
843#undef cmdline_options
844
845
Denis Vlasenko0e2c93f2008-07-10 14:16:11 +0000846/* For reference, module-init-tools v3.4 options:
Denis Vlasenko671691c2008-07-04 10:25:44 +0000847
848# insmod
849Usage: insmod filename [args]
850
851# rmmod --help
852Usage: rmmod [-fhswvV] modulename ...
Denis Vlasenko0e2c93f2008-07-10 14:16:11 +0000853 -f (or --force) forces a module unload, and may crash your
854 machine. This requires the Forced Module Removal option
855 when the kernel was compiled.
856 -h (or --help) prints this help text
Denis Vlasenko671691c2008-07-04 10:25:44 +0000857 -s (or --syslog) says use syslog, not stderr
858 -v (or --verbose) enables more messages
Denis Vlasenko0e2c93f2008-07-10 14:16:11 +0000859 -V (or --version) prints the version code
Denis Vlasenko35d8c472008-08-05 07:59:25 +0000860 -w (or --wait) begins module removal even if it is used
Denis Vlasenko671691c2008-07-04 10:25:44 +0000861 and will stop new users from accessing the module (so it
862 should eventually fall to zero).
863
864# modprobe
Denis Vlasenko0e2c93f2008-07-10 14:16:11 +0000865Usage: modprobe [-v] [-V] [-C config-file] [-n] [-i] [-q] [-b]
866 [-o <modname>] [ --dump-modversions ] <modname> [parameters...]
867modprobe -r [-n] [-i] [-v] <modulename> ...
868modprobe -l -t <dirname> [ -a <modulename> ...]
Denis Vlasenko671691c2008-07-04 10:25:44 +0000869
870# depmod --help
Denis Vlasenko0e2c93f2008-07-10 14:16:11 +0000871depmod 3.4 -- part of module-init-tools
872depmod -[aA] [-n -e -v -q -V -r -u]
873 [-b basedirectory] [forced_version]
874depmod [-n -e -v -q -r -u] [-F kernelsyms] module1.ko module2.ko ...
875If no arguments (except options) are given, "depmod -a" is assumed.
Denys Vlasenkobf2af9a2009-05-25 04:15:37 +0200876depmod will output a dependency list suitable for the modprobe utility.
Denis Vlasenko671691c2008-07-04 10:25:44 +0000877Options:
Denis Vlasenko35d8c472008-08-05 07:59:25 +0000878 -a, --all Probe all modules
879 -A, --quick Only does the work if there's a new module
880 -n, --show Write the dependency file on stdout only
881 -e, --errsyms Report not supplied symbols
882 -V, --version Print the release version
883 -v, --verbose Enable verbose mode
884 -h, --help Print this usage message
Denis Vlasenko0e2c93f2008-07-10 14:16:11 +0000885The following options are useful for people managing distributions:
886 -b basedirectory
Denis Vlasenko35d8c472008-08-05 07:59:25 +0000887 --basedir basedirectory
888 Use an image of a module tree
Denis Vlasenko0e2c93f2008-07-10 14:16:11 +0000889 -F kernelsyms
Denis Vlasenko35d8c472008-08-05 07:59:25 +0000890 --filesyms kernelsyms
891 Use the file instead of the current kernel symbols
Denis Vlasenko671691c2008-07-04 10:25:44 +0000892*/
893
Pascal Bellardb82b34e2010-06-07 01:16:45 +0200894//usage:#if ENABLE_MODPROBE_SMALL
Denys Vlasenko1a5e11c2010-10-16 01:56:41 +0200895
896//usage:#define depmod_trivial_usage NOUSAGE_STR
897//usage:#define depmod_full_usage ""
898
Denys Vlasenko1a5e11c2010-10-16 01:56:41 +0200899//usage:#define insmod_trivial_usage
Kang-Che Sungb1d6a2c2017-01-31 21:09:17 +0800900//usage: "FILE" IF_FEATURE_CMDLINE_MODULE_OPTIONS(" [SYMBOL=VALUE]...")
Denys Vlasenko1a5e11c2010-10-16 01:56:41 +0200901//usage:#define insmod_full_usage "\n\n"
Denys Vlasenko5fd3ddf2014-04-19 15:04:39 +0200902//usage: "Load kernel module"
Denys Vlasenko1a5e11c2010-10-16 01:56:41 +0200903
904//usage:#define rmmod_trivial_usage
Denys Vlasenkoca659f82017-01-30 19:21:12 +0100905//usage: "MODULE..."
Denys Vlasenko1a5e11c2010-10-16 01:56:41 +0200906//usage:#define rmmod_full_usage "\n\n"
Denys Vlasenkoca659f82017-01-30 19:21:12 +0100907//usage: "Unload kernel modules"
Denys Vlasenko1a5e11c2010-10-16 01:56:41 +0200908
Pascal Bellardb82b34e2010-06-07 01:16:45 +0200909//usage:#define modprobe_trivial_usage
Kang-Che Sungb1d6a2c2017-01-31 21:09:17 +0800910//usage: "[-rq] MODULE" IF_FEATURE_CMDLINE_MODULE_OPTIONS(" [SYMBOL=VALUE]...")
Pascal Bellardb82b34e2010-06-07 01:16:45 +0200911//usage:#define modprobe_full_usage "\n\n"
Denys Vlasenkoca659f82017-01-30 19:21:12 +0100912//usage: " -r Remove MODULE"
Pascal Bellardb82b34e2010-06-07 01:16:45 +0200913//usage: "\n -q Quiet"
Denys Vlasenko1a5e11c2010-10-16 01:56:41 +0200914
915//usage:#endif
Pascal Bellardb82b34e2010-06-07 01:16:45 +0200916
Denis Vlasenko671691c2008-07-04 10:25:44 +0000917int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000918int modprobe_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko671691c2008-07-04 10:25:44 +0000919{
Denys Vlasenko6bf52b62017-01-09 09:48:58 +0100920#if ENABLE_MODPROBE || ENABLE_INSMOD || ENABLE_RMMOD
Denys Vlasenko5c3e0602016-06-20 10:59:06 +0200921 int exitcode;
Denys Vlasenko6bf52b62017-01-09 09:48:58 +0100922#endif
Denis Vlasenko671691c2008-07-04 10:25:44 +0000923 struct utsname uts;
Kang-Che Sungb1d6a2c2017-01-31 21:09:17 +0800924 IF_FEATURE_CMDLINE_MODULE_OPTIONS(char *options = NULL;)
Denis Vlasenko671691c2008-07-04 10:25:44 +0000925
Denis Vlasenko671691c2008-07-04 10:25:44 +0000926 INIT_G();
927
Denis Vlasenko0e2c93f2008-07-10 14:16:11 +0000928 /* Prevent ugly corner cases with no modules at all */
929 modinfo = xzalloc(sizeof(modinfo[0]));
930
Denys Vlasenkoc2b18582017-02-07 16:41:25 +0100931 if ((MOD_APPLET_CNT == 2 && ENABLE_DEPMOD && ENABLE_MODPROBE)
932 || is_depmod || is_modprobe
933 ) {
Denis Vlasenko1c781cc2008-09-06 14:14:01 +0000934 /* Goto modules directory */
935 xchdir(CONFIG_DEFAULT_MODULES_DIR);
Kang-Che Sung4ae658f2017-02-05 19:02:34 +0100936 uname(&uts); /* never fails */
Denis Vlasenko1c781cc2008-09-06 14:14:01 +0000937 }
Denis Vlasenko0e2c93f2008-07-10 14:16:11 +0000938
Denys Vlasenko6bf52b62017-01-09 09:48:58 +0100939 /* depmod? */
Kang-Che Sungfdfd7162017-01-31 17:06:43 +0800940 if (is_depmod) {
Denis Vlasenko0e2c93f2008-07-10 14:16:11 +0000941 /* Supported:
942 * -n: print result to stdout
943 * -a: process all modules (default)
944 * optional VERSION parameter
945 * Ignored:
946 * -A: do work only if a module is newer than depfile
947 * -e: report any symbols which a module needs
948 * which are not supplied by other modules or the kernel
949 * -F FILE: System.map (symbols for -e)
950 * -q, -r, -u: noop?
951 * Not supported:
952 * -b BASEDIR: (TODO!) modules are in
953 * $BASEDIR/lib/modules/$VERSION
954 * -v: human readable deps to stdout
955 * -V: version (don't want to support it - people may depend
956 * on it as an indicator of "standard" depmod)
957 * -h: help (well duh)
958 * module1.o module2.o parameters (just ignored for now)
959 */
960 getopt32(argv, "na" "AeF:qru" /* "b:vV", NULL */, NULL);
961 argv += optind;
962 /* if (argv[0] && argv[1]) bb_show_usage(); */
963 /* Goto $VERSION directory */
964 xchdir(argv[0] ? argv[0] : uts.release);
965 /* Force full module scan by asking to find a bogus module.
966 * This will generate modules.dep.bb as a side effect. */
967 process_module((char*)"/", NULL);
968 return !wrote_dep_bb_ok;
969 }
970
Explorer0980172e42017-01-09 15:04:43 +0800971#if ENABLE_MODPROBE || ENABLE_INSMOD || ENABLE_RMMOD
972 /* modprobe, insmod, rmmod require at least one argument */
Denis Vlasenko671691c2008-07-04 10:25:44 +0000973 opt_complementary = "-1";
974 /* only -q (quiet) and -r (rmmod),
975 * the rest are accepted and ignored (compat) */
Felipe Contreras428bd2d2012-01-31 14:55:15 +0100976 getopt32(argv, "qrfsvwb");
Denis Vlasenko671691c2008-07-04 10:25:44 +0000977 argv += optind;
978
Kang-Che Sung4ae658f2017-02-05 19:02:34 +0100979 if (is_modprobe) {
Denis Vlasenko1c781cc2008-09-06 14:14:01 +0000980 /* Goto $VERSION directory */
981 xchdir(uts.release);
982 }
Denis Vlasenko671691c2008-07-04 10:25:44 +0000983
Explorer0980172e42017-01-09 15:04:43 +0800984 /* are we rmmod? -> simulate modprobe -r, but don't bother the flag if
985 * there're no other applets here */
986 if (is_rmmod) {
987 if (!ONLY_APPLET)
988 option_mask32 |= OPT_r;
989 } else if (!ENABLE_MODPROBE || !(option_mask32 & OPT_r)) {
Kang-Che Sungb1d6a2c2017-01-31 21:09:17 +0800990# if ENABLE_FEATURE_CMDLINE_MODULE_OPTIONS
Denys Vlasenko68c048f2015-02-07 20:44:46 +0100991 /* If not rmmod/-r, parse possible module options given on command line.
Denis Vlasenko671691c2008-07-04 10:25:44 +0000992 * insmod/modprobe takes one module name, the rest are parameters. */
Denis Vlasenko671691c2008-07-04 10:25:44 +0000993 char **arg = argv;
994 while (*++arg) {
995 /* Enclose options in quotes */
996 char *s = options;
997 options = xasprintf("%s \"%s\"", s ? s : "", *arg);
998 free(s);
999 *arg = NULL;
1000 }
Explorer0980172e42017-01-09 15:04:43 +08001001# else
Denis Vlasenko671691c2008-07-04 10:25:44 +00001002 argv[1] = NULL;
Explorer0980172e42017-01-09 15:04:43 +08001003# endif
1004 }
Denis Vlasenko671691c2008-07-04 10:25:44 +00001005
Explorer0980172e42017-01-09 15:04:43 +08001006 if (is_insmod) {
Denis Vlasenko1c781cc2008-09-06 14:14:01 +00001007 size_t len;
1008 void *map;
1009
1010 len = MAXINT(ssize_t);
Denys Vlasenkoe9d12b52011-01-09 20:57:52 +01001011 map = xmalloc_open_zipped_read_close(*argv, &len);
Denys Vlasenko094cc512011-01-17 14:58:27 +01001012 if (!map)
1013 bb_perror_msg_and_die("can't read '%s'", *argv);
Denis Vlasenko1c781cc2008-09-06 14:14:01 +00001014 if (init_module(map, len,
Kang-Che Sungb1d6a2c2017-01-31 21:09:17 +08001015 (IF_FEATURE_CMDLINE_MODULE_OPTIONS(options ? options : ) "")
Denys Vlasenkoe9d12b52011-01-09 20:57:52 +01001016 ) != 0
1017 ) {
Denis Vlasenko1f632292009-04-13 02:25:40 +00001018 bb_error_msg_and_die("can't insert '%s': %s",
Denis Vlasenko1c781cc2008-09-06 14:14:01 +00001019 *argv, moderror(errno));
Denys Vlasenkoe9d12b52011-01-09 20:57:52 +01001020 }
Denys Vlasenko5c3e0602016-06-20 10:59:06 +02001021 return EXIT_SUCCESS;
Denis Vlasenko1c781cc2008-09-06 14:14:01 +00001022 }
1023
Denis Vlasenko7f950a92008-07-10 14:14:45 +00001024 /* Try to load modprobe.dep.bb */
Explorer0980172e42017-01-09 15:04:43 +08001025 if (!is_rmmod) {
Denys Vlasenko68c048f2015-02-07 20:44:46 +01001026 load_dep_bb();
Denys Vlasenko5c3e0602016-06-20 10:59:06 +02001027 }
Denis Vlasenko78436992008-07-10 14:14:20 +00001028
Denis Vlasenko671691c2008-07-04 10:25:44 +00001029 /* Load/remove modules.
Denys Vlasenko68c048f2015-02-07 20:44:46 +01001030 * Only rmmod/modprobe -r loops here, insmod/modprobe has only argv[0] */
Denys Vlasenko5c3e0602016-06-20 10:59:06 +02001031 exitcode = EXIT_SUCCESS;
Denis Vlasenko671691c2008-07-04 10:25:44 +00001032 do {
Denys Vlasenko5c3e0602016-06-20 10:59:06 +02001033 exitcode |= process_module(*argv, options);
Denys Vlasenko5b3151c2010-09-25 14:37:06 +02001034 } while (*++argv);
Denis Vlasenko671691c2008-07-04 10:25:44 +00001035
1036 if (ENABLE_FEATURE_CLEAN_UP) {
Kang-Che Sungb1d6a2c2017-01-31 21:09:17 +08001037 IF_FEATURE_CMDLINE_MODULE_OPTIONS(free(options);)
Denis Vlasenko671691c2008-07-04 10:25:44 +00001038 }
Denys Vlasenko5c3e0602016-06-20 10:59:06 +02001039 return exitcode;
Explorer0980172e42017-01-09 15:04:43 +08001040#endif /* MODPROBE || INSMOD || RMMOD */
Denis Vlasenko671691c2008-07-04 10:25:44 +00001041}
Denys Vlasenkoe7b54d02017-01-09 16:31:21 +01001042
1043#endif /* MOD_APPLET_CNT > 0 */