Bump to version 1.22.1
[platform/upstream/busybox.git] / modutils / modprobe-small.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * simplified modprobe
4  *
5  * Copyright (c) 2008 Vladimir Dronnikov
6  * Copyright (c) 2008 Bernhard Reutner-Fischer (initial depmod code)
7  *
8  * Licensed under GPLv2, see file LICENSE in this source tree.
9  */
10
11 //applet:IF_MODPROBE_SMALL(APPLET(modprobe, BB_DIR_SBIN, BB_SUID_DROP))
12 //applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(depmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, modprobe))
13 //applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(insmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, modprobe))
14 //applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, modprobe))
15 //applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(rmmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, modprobe))
16
17 #include "libbb.h"
18 /* After libbb.h, since it needs sys/types.h on some systems */
19 #include <sys/utsname.h> /* uname() */
20 #include <fnmatch.h>
21
22 extern int init_module(void *module, unsigned long len, const char *options);
23 extern int delete_module(const char *module, unsigned flags);
24 extern int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret);
25
26
27 #if 1
28 # define dbg1_error_msg(...) ((void)0)
29 # define dbg2_error_msg(...) ((void)0)
30 #else
31 # define dbg1_error_msg(...) bb_error_msg(__VA_ARGS__)
32 # define dbg2_error_msg(...) bb_error_msg(__VA_ARGS__)
33 #endif
34
35 #define DEPFILE_BB CONFIG_DEFAULT_DEPMOD_FILE".bb"
36
37 enum {
38         OPT_q = (1 << 0), /* be quiet */
39         OPT_r = (1 << 1), /* module removal instead of loading */
40 };
41
42 typedef struct module_info {
43         char *pathname;
44         char *aliases;
45         char *deps;
46 } module_info;
47
48 /*
49  * GLOBALS
50  */
51 struct globals {
52         module_info *modinfo;
53         char *module_load_options;
54         smallint dep_bb_seen;
55         smallint wrote_dep_bb_ok;
56         unsigned module_count;
57         int module_found_idx;
58         unsigned stringbuf_idx;
59         unsigned stringbuf_size;
60         char *stringbuf; /* some modules have lots of stuff */
61         /* for example, drivers/media/video/saa7134/saa7134.ko */
62         /* therefore having a fixed biggish buffer is not wise */
63 };
64 #define G (*ptr_to_globals)
65 #define modinfo             (G.modinfo            )
66 #define dep_bb_seen         (G.dep_bb_seen        )
67 #define wrote_dep_bb_ok     (G.wrote_dep_bb_ok    )
68 #define module_count        (G.module_count       )
69 #define module_found_idx    (G.module_found_idx   )
70 #define module_load_options (G.module_load_options)
71 #define stringbuf_idx       (G.stringbuf_idx      )
72 #define stringbuf_size      (G.stringbuf_size     )
73 #define stringbuf           (G.stringbuf          )
74 #define INIT_G() do { \
75         SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
76 } while (0)
77
78 static void append(const char *s)
79 {
80         unsigned len = strlen(s);
81         if (stringbuf_idx + len + 15 > stringbuf_size) {
82                 stringbuf_size = stringbuf_idx + len + 127;
83                 dbg2_error_msg("grow stringbuf to %u", stringbuf_size);
84                 stringbuf = xrealloc(stringbuf, stringbuf_size);
85         }
86         memcpy(stringbuf + stringbuf_idx, s, len);
87         stringbuf_idx += len;
88 }
89
90 static void appendc(char c)
91 {
92         /* We appendc() only after append(), + 15 trick in append()
93          * makes it unnecessary to check for overflow here */
94         stringbuf[stringbuf_idx++] = c;
95 }
96
97 static void bksp(void)
98 {
99         if (stringbuf_idx)
100                 stringbuf_idx--;
101 }
102
103 static void reset_stringbuf(void)
104 {
105         stringbuf_idx = 0;
106 }
107
108 static char* copy_stringbuf(void)
109 {
110         char *copy = xzalloc(stringbuf_idx + 1); /* terminating NUL */
111         return memcpy(copy, stringbuf, stringbuf_idx);
112 }
113
114 static char* find_keyword(char *ptr, size_t len, const char *word)
115 {
116         int wlen;
117
118         if (!ptr) /* happens if xmalloc_open_zipped_read_close cannot read it */
119                 return NULL;
120
121         wlen = strlen(word);
122         len -= wlen - 1;
123         while ((ssize_t)len > 0) {
124                 char *old = ptr;
125                 /* search for the first char in word */
126                 ptr = memchr(ptr, *word, len);
127                 if (ptr == NULL) /* no occurance left, done */
128                         break;
129                 if (strncmp(ptr, word, wlen) == 0)
130                         return ptr + wlen; /* found, return ptr past it */
131                 ++ptr;
132                 len -= (ptr - old);
133         }
134         return NULL;
135 }
136
137 static void replace(char *s, char what, char with)
138 {
139         while (*s) {
140                 if (what == *s)
141                         *s = with;
142                 ++s;
143         }
144 }
145
146 /* Take "word word", return malloced "word",NUL,"word",NUL,NUL */
147 static char* str_2_list(const char *str)
148 {
149         int len = strlen(str) + 1;
150         char *dst = xmalloc(len + 1);
151
152         dst[len] = '\0';
153         memcpy(dst, str, len);
154 //TODO: protect against 2+ spaces: "word  word"
155         replace(dst, ' ', '\0');
156         return dst;
157 }
158
159 /* We use error numbers in a loose translation... */
160 static const char *moderror(int err)
161 {
162         switch (err) {
163         case ENOEXEC:
164                 return "invalid module format";
165         case ENOENT:
166                 return "unknown symbol in module or invalid parameter";
167         case ESRCH:
168                 return "module has wrong symbol version";
169         case EINVAL: /* "invalid parameter" */
170                 return "unknown symbol in module or invalid parameter"
171                 + sizeof("unknown symbol in module or");
172         default:
173                 return strerror(err);
174         }
175 }
176
177 static int load_module(const char *fname, const char *options)
178 {
179 #if 1
180         int r;
181         size_t len = MAXINT(ssize_t);
182         char *module_image;
183         dbg1_error_msg("load_module('%s','%s')", fname, options);
184
185         module_image = xmalloc_open_zipped_read_close(fname, &len);
186         r = (!module_image || init_module(module_image, len, options ? options : "") != 0);
187         free(module_image);
188         dbg1_error_msg("load_module:%d", r);
189         return r; /* 0 = success */
190 #else
191         /* For testing */
192         dbg1_error_msg("load_module('%s','%s')", fname, options);
193         return 1;
194 #endif
195 }
196
197 static void parse_module(module_info *info, const char *pathname)
198 {
199         char *module_image;
200         char *ptr;
201         size_t len;
202         size_t pos;
203         dbg1_error_msg("parse_module('%s')", pathname);
204
205         /* Read (possibly compressed) module */
206         len = 64 * 1024 * 1024; /* 64 Mb at most */
207         module_image = xmalloc_open_zipped_read_close(pathname, &len);
208         /* module_image == NULL is ok here, find_keyword handles it */
209 //TODO: optimize redundant module body reads
210
211         /* "alias1 symbol:sym1 alias2 symbol:sym2" */
212         reset_stringbuf();
213         pos = 0;
214         while (1) {
215                 ptr = find_keyword(module_image + pos, len - pos, "alias=");
216                 if (!ptr) {
217                         ptr = find_keyword(module_image + pos, len - pos, "__ksymtab_");
218                         if (!ptr)
219                                 break;
220                         /* DOCME: __ksymtab_gpl and __ksymtab_strings occur
221                          * in many modules. What do they mean? */
222                         if (strcmp(ptr, "gpl") == 0 || strcmp(ptr, "strings") == 0)
223                                 goto skip;
224                         dbg2_error_msg("alias:'symbol:%s'", ptr);
225                         append("symbol:");
226                 } else {
227                         dbg2_error_msg("alias:'%s'", ptr);
228                 }
229                 append(ptr);
230                 appendc(' ');
231  skip:
232                 pos = (ptr - module_image);
233         }
234         bksp(); /* remove last ' ' */
235         info->aliases = copy_stringbuf();
236         replace(info->aliases, '-', '_');
237
238         /* "dependency1 depandency2" */
239         reset_stringbuf();
240         ptr = find_keyword(module_image, len, "depends=");
241         if (ptr && *ptr) {
242                 replace(ptr, ',', ' ');
243                 replace(ptr, '-', '_');
244                 dbg2_error_msg("dep:'%s'", ptr);
245                 append(ptr);
246         }
247         info->deps = copy_stringbuf();
248
249         free(module_image);
250 }
251
252 static int pathname_matches_modname(const char *pathname, const char *modname)
253 {
254         const char *fname = bb_get_last_path_component_nostrip(pathname);
255         const char *suffix = strrstr(fname, ".ko");
256 //TODO: can do without malloc?
257         char *name = xstrndup(fname, suffix - fname);
258         int r;
259         replace(name, '-', '_');
260         r = (strcmp(name, modname) == 0);
261         free(name);
262         return r;
263 }
264
265 static FAST_FUNC int fileAction(const char *pathname,
266                 struct stat *sb UNUSED_PARAM,
267                 void *modname_to_match,
268                 int depth UNUSED_PARAM)
269 {
270         int cur;
271         const char *fname;
272
273         pathname += 2; /* skip "./" */
274         fname = bb_get_last_path_component_nostrip(pathname);
275         if (!strrstr(fname, ".ko")) {
276                 dbg1_error_msg("'%s' is not a module", pathname);
277                 return TRUE; /* not a module, continue search */
278         }
279
280         cur = module_count++;
281         modinfo = xrealloc_vector(modinfo, 12, cur);
282         modinfo[cur].pathname = xstrdup(pathname);
283         /*modinfo[cur].aliases = NULL; - xrealloc_vector did it */
284         /*modinfo[cur+1].pathname = NULL;*/
285
286         if (!pathname_matches_modname(fname, modname_to_match)) {
287                 dbg1_error_msg("'%s' module name doesn't match", pathname);
288                 return TRUE; /* module name doesn't match, continue search */
289         }
290
291         dbg1_error_msg("'%s' module name matches", pathname);
292         module_found_idx = cur;
293         parse_module(&modinfo[cur], pathname);
294
295         if (!(option_mask32 & OPT_r)) {
296                 if (load_module(pathname, module_load_options) == 0) {
297                         /* Load was successful, there is nothing else to do.
298                          * This can happen ONLY for "top-level" module load,
299                          * not a dep, because deps dont do dirscan. */
300                         exit(EXIT_SUCCESS);
301                 }
302         }
303
304         return TRUE;
305 }
306
307 static int load_dep_bb(void)
308 {
309         char *line;
310         FILE *fp = fopen_for_read(DEPFILE_BB);
311
312         if (!fp)
313                 return 0;
314
315         dep_bb_seen = 1;
316         dbg1_error_msg("loading "DEPFILE_BB);
317
318         /* Why? There is a rare scenario: we did not find modprobe.dep.bb,
319          * we scanned the dir and found no module by name, then we search
320          * for alias (full scan), and we decided to generate modprobe.dep.bb.
321          * But we see modprobe.dep.bb.new! Other modprobe is at work!
322          * We wait and other modprobe renames it to modprobe.dep.bb.
323          * Now we can use it.
324          * But we already have modinfo[] filled, and "module_count = 0"
325          * makes us start anew. Yes, we leak modinfo[].xxx pointers -
326          * there is not much of data there anyway. */
327         module_count = 0;
328         memset(&modinfo[0], 0, sizeof(modinfo[0]));
329
330         while ((line = xmalloc_fgetline(fp)) != NULL) {
331                 char* space;
332                 char* linebuf;
333                 int cur;
334
335                 if (!line[0]) {
336                         free(line);
337                         continue;
338                 }
339                 space = strchrnul(line, ' ');
340                 cur = module_count++;
341                 modinfo = xrealloc_vector(modinfo, 12, cur);
342                 /*modinfo[cur+1].pathname = NULL; - xrealloc_vector did it */
343                 modinfo[cur].pathname = line; /* we take ownership of malloced block here */
344                 if (*space)
345                         *space++ = '\0';
346                 modinfo[cur].aliases = space;
347                 linebuf = xmalloc_fgetline(fp);
348                 modinfo[cur].deps = linebuf ? linebuf : xzalloc(1);
349                 if (modinfo[cur].deps[0]) {
350                         /* deps are not "", so next line must be empty */
351                         line = xmalloc_fgetline(fp);
352                         /* Refuse to work with damaged config file */
353                         if (line && line[0])
354                                 bb_error_msg_and_die("error in %s at '%s'", DEPFILE_BB, line);
355                         free(line);
356                 }
357         }
358         return 1;
359 }
360
361 static int start_dep_bb_writeout(void)
362 {
363         int fd;
364
365         /* depmod -n: write result to stdout */
366         if (applet_name[0] == 'd' && (option_mask32 & 1))
367                 return STDOUT_FILENO;
368
369         fd = open(DEPFILE_BB".new", O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0644);
370         if (fd < 0) {
371                 if (errno == EEXIST) {
372                         int count = 5 * 20;
373                         dbg1_error_msg(DEPFILE_BB".new exists, waiting for "DEPFILE_BB);
374                         while (1) {
375                                 usleep(1000*1000 / 20);
376                                 if (load_dep_bb()) {
377                                         dbg1_error_msg(DEPFILE_BB" appeared");
378                                         return -2; /* magic number */
379                                 }
380                                 if (!--count)
381                                         break;
382                         }
383                         bb_error_msg("deleting stale %s", DEPFILE_BB".new");
384                         fd = open_or_warn(DEPFILE_BB".new", O_WRONLY | O_CREAT | O_TRUNC);
385                 }
386         }
387         dbg1_error_msg("opened "DEPFILE_BB".new:%d", fd);
388         return fd;
389 }
390
391 static void write_out_dep_bb(int fd)
392 {
393         int i;
394         FILE *fp;
395
396         /* We want good error reporting. fdprintf is not good enough. */
397         fp = xfdopen_for_write(fd);
398         i = 0;
399         while (modinfo[i].pathname) {
400                 fprintf(fp, "%s%s%s\n" "%s%s\n",
401                         modinfo[i].pathname, modinfo[i].aliases[0] ? " " : "", modinfo[i].aliases,
402                         modinfo[i].deps, modinfo[i].deps[0] ? "\n" : "");
403                 i++;
404         }
405         /* Badly formatted depfile is a no-no. Be paranoid. */
406         errno = 0;
407         if (ferror(fp) | fclose(fp)) /* | instead of || is intended */
408                 goto err;
409
410         if (fd == STDOUT_FILENO) /* it was depmod -n */
411                 goto ok;
412
413         if (rename(DEPFILE_BB".new", DEPFILE_BB) != 0) {
414  err:
415                 bb_perror_msg("can't create '%s'", DEPFILE_BB);
416                 unlink(DEPFILE_BB".new");
417         } else {
418  ok:
419                 wrote_dep_bb_ok = 1;
420                 dbg1_error_msg("created "DEPFILE_BB);
421         }
422 }
423
424 static module_info* find_alias(const char *alias)
425 {
426         int i;
427         int dep_bb_fd;
428         module_info *result;
429         dbg1_error_msg("find_alias('%s')", alias);
430
431  try_again:
432         /* First try to find by name (cheaper) */
433         i = 0;
434         while (modinfo[i].pathname) {
435                 if (pathname_matches_modname(modinfo[i].pathname, alias)) {
436                         dbg1_error_msg("found '%s' in module '%s'",
437                                         alias, modinfo[i].pathname);
438                         if (!modinfo[i].aliases) {
439                                 parse_module(&modinfo[i], modinfo[i].pathname);
440                         }
441                         return &modinfo[i];
442                 }
443                 i++;
444         }
445
446         /* Ok, we definitely have to scan module bodies. This is a good
447          * moment to generate modprobe.dep.bb, if it does not exist yet */
448         dep_bb_fd = dep_bb_seen ? -1 : start_dep_bb_writeout();
449         if (dep_bb_fd == -2) /* modprobe.dep.bb appeared? */
450                 goto try_again;
451
452         /* Scan all module bodies, extract modinfo (it contains aliases) */
453         i = 0;
454         result = NULL;
455         while (modinfo[i].pathname) {
456                 char *desc, *s;
457                 if (!modinfo[i].aliases) {
458                         parse_module(&modinfo[i], modinfo[i].pathname);
459                 }
460                 if (result) {
461                         i++;
462                         continue;
463                 }
464                 /* "alias1 symbol:sym1 alias2 symbol:sym2" */
465                 desc = str_2_list(modinfo[i].aliases);
466                 /* Does matching substring exist? */
467                 for (s = desc; *s; s += strlen(s) + 1) {
468                         /* Aliases in module bodies can be defined with
469                          * shell patterns. Example:
470                          * "pci:v000010DEd000000D9sv*sd*bc*sc*i*".
471                          * Plain strcmp() won't catch that */
472                         if (fnmatch(s, alias, 0) == 0) {
473                                 dbg1_error_msg("found alias '%s' in module '%s'",
474                                                 alias, modinfo[i].pathname);
475                                 result = &modinfo[i];
476                                 break;
477                         }
478                 }
479                 free(desc);
480                 if (result && dep_bb_fd < 0)
481                         return result;
482                 i++;
483         }
484
485         /* Create module.dep.bb if needed */
486         if (dep_bb_fd >= 0) {
487                 write_out_dep_bb(dep_bb_fd);
488         }
489
490         dbg1_error_msg("find_alias '%s' returns %p", alias, result);
491         return result;
492 }
493
494 #if ENABLE_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED
495 // TODO: open only once, invent config_rewind()
496 static int already_loaded(const char *name)
497 {
498         int ret = 0;
499         char *s;
500         parser_t *parser = config_open2("/proc/modules", xfopen_for_read);
501         while (config_read(parser, &s, 1, 1, "# \t", PARSE_NORMAL & ~PARSE_GREEDY)) {
502                 if (strcmp(s, name) == 0) {
503                         ret = 1;
504                         break;
505                 }
506         }
507         config_close(parser);
508         return ret;
509 }
510 #else
511 #define already_loaded(name) is_rmmod
512 #endif
513
514 /*
515  * Given modules definition and module name (or alias, or symbol)
516  * load/remove the module respecting dependencies.
517  * NB: also called by depmod with bogus name "/",
518  * just in order to force modprobe.dep.bb creation.
519 */
520 #if !ENABLE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE
521 #define process_module(a,b) process_module(a)
522 #define cmdline_options ""
523 #endif
524 static void process_module(char *name, const char *cmdline_options)
525 {
526         char *s, *deps, *options;
527         module_info *info;
528         int is_rmmod = (option_mask32 & OPT_r) != 0;
529         dbg1_error_msg("process_module('%s','%s')", name, cmdline_options);
530
531         replace(name, '-', '_');
532
533         dbg1_error_msg("already_loaded:%d is_rmmod:%d", already_loaded(name), is_rmmod);
534         if (already_loaded(name) != is_rmmod) {
535                 dbg1_error_msg("nothing to do for '%s'", name);
536                 return;
537         }
538
539         options = NULL;
540         if (!is_rmmod) {
541                 char *opt_filename = xasprintf("/etc/modules/%s", name);
542                 options = xmalloc_open_read_close(opt_filename, NULL);
543                 if (options)
544                         replace(options, '\n', ' ');
545 #if ENABLE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE
546                 if (cmdline_options) {
547                         /* NB: cmdline_options always have one leading ' '
548                          * (see main()), we remove it here */
549                         char *op = xasprintf(options ? "%s %s" : "%s %s" + 3,
550                                                 cmdline_options + 1, options);
551                         free(options);
552                         options = op;
553                 }
554 #endif
555                 free(opt_filename);
556                 module_load_options = options;
557                 dbg1_error_msg("process_module('%s'): options:'%s'", name, options);
558         }
559
560         if (!module_count) {
561                 /* Scan module directory. This is done only once.
562                  * It will attempt module load, and will exit(EXIT_SUCCESS)
563                  * on success. */
564                 module_found_idx = -1;
565                 recursive_action(".",
566                         ACTION_RECURSE, /* flags */
567                         fileAction, /* file action */
568                         NULL, /* dir action */
569                         name, /* user data */
570                         0); /* depth */
571                 dbg1_error_msg("dirscan complete");
572                 /* Module was not found, or load failed, or is_rmmod */
573                 if (module_found_idx >= 0) { /* module was found */
574                         info = &modinfo[module_found_idx];
575                 } else { /* search for alias, not a plain module name */
576                         info = find_alias(name);
577                 }
578         } else {
579                 info = find_alias(name);
580         }
581
582 // Problem here: there can be more than one module
583 // for the given alias. For example,
584 // "pci:v00008086d00007010sv00000000sd00000000bc01sc01i80" matches
585 // ata_piix because it has an alias "pci:v00008086d00007010sv*sd*bc*sc*i*"
586 // and ata_generic, it has an alias "alias=pci:v*d*sv*sd*bc01sc01i*"
587 // Standard modprobe would load them both.
588 // In this code, find_alias() returns only the first matching module.
589
590         /* rmmod? unload it by name */
591         if (is_rmmod) {
592                 if (delete_module(name, O_NONBLOCK | O_EXCL) != 0) {
593                         if (!(option_mask32 & OPT_q))
594                                 bb_perror_msg("remove '%s'", name);
595                         goto ret;
596                 }
597
598                 if (applet_name[0] == 'r') {
599                         /* rmmod: do not remove dependencies, exit */
600                         goto ret;
601                 }
602
603                 /* modprobe -r: we do not stop here -
604                  * continue to unload modules on which the module depends:
605                  * "-r --remove: option causes modprobe to remove a module.
606                  * If the modules it depends on are also unused, modprobe
607                  * will try to remove them, too."
608                  */
609         }
610
611         if (!info) {
612                 /* both dirscan and find_alias found nothing */
613                 if (!is_rmmod && applet_name[0] != 'd') /* it wasn't rmmod or depmod */
614                         bb_error_msg("module '%s' not found", name);
615 //TODO: _and_die()? or should we continue (un)loading modules listed on cmdline?
616                 goto ret;
617         }
618
619         /* Iterate thru dependencies, trying to (un)load them */
620         deps = str_2_list(info->deps);
621         for (s = deps; *s; s += strlen(s) + 1) {
622                 //if (strcmp(name, s) != 0) // N.B. do loops exist?
623                 dbg1_error_msg("recurse on dep '%s'", s);
624                 process_module(s, NULL);
625                 dbg1_error_msg("recurse on dep '%s' done", s);
626         }
627         free(deps);
628
629         /* modprobe -> load it */
630         if (!is_rmmod) {
631                 if (!options || strstr(options, "blacklist") == NULL) {
632                         errno = 0;
633                         if (load_module(info->pathname, options) != 0) {
634                                 if (EEXIST != errno) {
635                                         bb_error_msg("'%s': %s",
636                                                 info->pathname,
637                                                 moderror(errno));
638                                 } else {
639                                         dbg1_error_msg("'%s': %s",
640                                                 info->pathname,
641                                                 moderror(errno));
642                                 }
643                         }
644                 } else {
645                         dbg1_error_msg("'%s': blacklisted", info->pathname);
646                 }
647         }
648  ret:
649         free(options);
650 //TODO: return load attempt result from process_module.
651 //If dep didn't load ok, continuing makes little sense.
652 }
653 #undef cmdline_options
654
655
656 /* For reference, module-init-tools v3.4 options:
657
658 # insmod
659 Usage: insmod filename [args]
660
661 # rmmod --help
662 Usage: rmmod [-fhswvV] modulename ...
663  -f (or --force) forces a module unload, and may crash your
664     machine. This requires the Forced Module Removal option
665     when the kernel was compiled.
666  -h (or --help) prints this help text
667  -s (or --syslog) says use syslog, not stderr
668  -v (or --verbose) enables more messages
669  -V (or --version) prints the version code
670  -w (or --wait) begins module removal even if it is used
671     and will stop new users from accessing the module (so it
672     should eventually fall to zero).
673
674 # modprobe
675 Usage: modprobe [-v] [-V] [-C config-file] [-n] [-i] [-q] [-b]
676     [-o <modname>] [ --dump-modversions ] <modname> [parameters...]
677 modprobe -r [-n] [-i] [-v] <modulename> ...
678 modprobe -l -t <dirname> [ -a <modulename> ...]
679
680 # depmod --help
681 depmod 3.4 -- part of module-init-tools
682 depmod -[aA] [-n -e -v -q -V -r -u]
683       [-b basedirectory] [forced_version]
684 depmod [-n -e -v -q -r -u] [-F kernelsyms] module1.ko module2.ko ...
685 If no arguments (except options) are given, "depmod -a" is assumed.
686 depmod will output a dependency list suitable for the modprobe utility.
687 Options:
688     -a, --all           Probe all modules
689     -A, --quick         Only does the work if there's a new module
690     -n, --show          Write the dependency file on stdout only
691     -e, --errsyms       Report not supplied symbols
692     -V, --version       Print the release version
693     -v, --verbose       Enable verbose mode
694     -h, --help          Print this usage message
695 The following options are useful for people managing distributions:
696     -b basedirectory
697     --basedir basedirectory
698                         Use an image of a module tree
699     -F kernelsyms
700     --filesyms kernelsyms
701                         Use the file instead of the current kernel symbols
702 */
703
704 //usage:#if ENABLE_MODPROBE_SMALL
705
706 //// Note: currently, help system shows modprobe --help text for all aliased cmds
707 //// (see APPLET_ODDNAME macro definition).
708 //// All other help texts defined below are not used. FIXME?
709
710 //usage:#define depmod_trivial_usage NOUSAGE_STR
711 //usage:#define depmod_full_usage ""
712
713 //usage:#define lsmod_trivial_usage
714 //usage:       ""
715 //usage:#define lsmod_full_usage "\n\n"
716 //usage:       "List the currently loaded kernel modules"
717
718 //usage:#define insmod_trivial_usage
719 //usage:        IF_FEATURE_2_4_MODULES("[OPTIONS] MODULE ")
720 //usage:        IF_NOT_FEATURE_2_4_MODULES("FILE ")
721 //usage:        "[SYMBOL=VALUE]..."
722 //usage:#define insmod_full_usage "\n\n"
723 //usage:       "Load the specified kernel modules into the kernel"
724 //usage:        IF_FEATURE_2_4_MODULES( "\n"
725 //usage:     "\n        -f      Force module to load into the wrong kernel version"
726 //usage:     "\n        -k      Make module autoclean-able"
727 //usage:     "\n        -v      Verbose"
728 //usage:     "\n        -q      Quiet"
729 //usage:     "\n        -L      Lock: prevent simultaneous loads"
730 //usage:        IF_FEATURE_INSMOD_LOAD_MAP(
731 //usage:     "\n        -m      Output load map to stdout"
732 //usage:        )
733 //usage:     "\n        -x      Don't export externs"
734 //usage:        )
735
736 //usage:#define rmmod_trivial_usage
737 //usage:       "[-wfa] [MODULE]..."
738 //usage:#define rmmod_full_usage "\n\n"
739 //usage:       "Unload kernel modules\n"
740 //usage:     "\n        -w      Wait until the module is no longer used"
741 //usage:     "\n        -f      Force unload"
742 //usage:     "\n        -a      Remove all unused modules (recursively)"
743 //usage:
744 //usage:#define rmmod_example_usage
745 //usage:       "$ rmmod tulip\n"
746
747 //usage:#define modprobe_trivial_usage
748 //usage:        "[-qfwrsv] MODULE [symbol=value]..."
749 //usage:#define modprobe_full_usage "\n\n"
750 //usage:       "        -r      Remove MODULE (stacks) or do autoclean"
751 //usage:     "\n        -q      Quiet"
752 //usage:     "\n        -v      Verbose"
753 //usage:     "\n        -f      Force"
754 //usage:     "\n        -w      Wait for unload"
755 //usage:     "\n        -s      Report via syslog instead of stderr"
756
757 //usage:#endif
758
759 int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
760 int modprobe_main(int argc UNUSED_PARAM, char **argv)
761 {
762         struct utsname uts;
763         char applet0 = applet_name[0];
764         IF_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(char *options;)
765
766         /* are we lsmod? -> just dump /proc/modules */
767         if ('l' == applet0) {
768                 xprint_and_close_file(xfopen_for_read("/proc/modules"));
769                 return EXIT_SUCCESS;
770         }
771
772         INIT_G();
773
774         /* Prevent ugly corner cases with no modules at all */
775         modinfo = xzalloc(sizeof(modinfo[0]));
776
777         if ('i' != applet0) { /* not insmod */
778                 /* Goto modules directory */
779                 xchdir(CONFIG_DEFAULT_MODULES_DIR);
780         }
781         uname(&uts); /* never fails */
782
783         /* depmod? */
784         if ('d' == applet0) {
785                 /* Supported:
786                  * -n: print result to stdout
787                  * -a: process all modules (default)
788                  * optional VERSION parameter
789                  * Ignored:
790                  * -A: do work only if a module is newer than depfile
791                  * -e: report any symbols which a module needs
792                  *  which are not supplied by other modules or the kernel
793                  * -F FILE: System.map (symbols for -e)
794                  * -q, -r, -u: noop?
795                  * Not supported:
796                  * -b BASEDIR: (TODO!) modules are in
797                  *  $BASEDIR/lib/modules/$VERSION
798                  * -v: human readable deps to stdout
799                  * -V: version (don't want to support it - people may depend
800                  *  on it as an indicator of "standard" depmod)
801                  * -h: help (well duh)
802                  * module1.o module2.o parameters (just ignored for now)
803                  */
804                 getopt32(argv, "na" "AeF:qru" /* "b:vV", NULL */, NULL);
805                 argv += optind;
806                 /* if (argv[0] && argv[1]) bb_show_usage(); */
807                 /* Goto $VERSION directory */
808                 xchdir(argv[0] ? argv[0] : uts.release);
809                 /* Force full module scan by asking to find a bogus module.
810                  * This will generate modules.dep.bb as a side effect. */
811                 process_module((char*)"/", NULL);
812                 return !wrote_dep_bb_ok;
813         }
814
815         /* insmod, modprobe, rmmod require at least one argument */
816         opt_complementary = "-1";
817         /* only -q (quiet) and -r (rmmod),
818          * the rest are accepted and ignored (compat) */
819         getopt32(argv, "qrfsvwb");
820         argv += optind;
821
822         /* are we rmmod? -> simulate modprobe -r */
823         if ('r' == applet0) {
824                 option_mask32 |= OPT_r;
825         }
826
827         if ('i' != applet0) { /* not insmod */
828                 /* Goto $VERSION directory */
829                 xchdir(uts.release);
830         }
831
832 #if ENABLE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE
833         /* If not rmmod, parse possible module options given on command line.
834          * insmod/modprobe takes one module name, the rest are parameters. */
835         options = NULL;
836         if ('r' != applet0) {
837                 char **arg = argv;
838                 while (*++arg) {
839                         /* Enclose options in quotes */
840                         char *s = options;
841                         options = xasprintf("%s \"%s\"", s ? s : "", *arg);
842                         free(s);
843                         *arg = NULL;
844                 }
845         }
846 #else
847         if ('r' != applet0)
848                 argv[1] = NULL;
849 #endif
850
851         if ('i' == applet0) { /* insmod */
852                 size_t len;
853                 void *map;
854
855                 len = MAXINT(ssize_t);
856                 map = xmalloc_open_zipped_read_close(*argv, &len);
857                 if (!map)
858                         bb_perror_msg_and_die("can't read '%s'", *argv);
859                 if (init_module(map, len,
860                         IF_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(options ? options : "")
861                         IF_NOT_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE("")
862                         ) != 0
863                 ) {
864                         bb_error_msg_and_die("can't insert '%s': %s",
865                                         *argv, moderror(errno));
866                 }
867                 return 0;
868         }
869
870         /* Try to load modprobe.dep.bb */
871         load_dep_bb();
872
873         /* Load/remove modules.
874          * Only rmmod loops here, modprobe has only argv[0] */
875         do {
876                 process_module(*argv, options);
877         } while (*++argv);
878
879         if (ENABLE_FEATURE_CLEAN_UP) {
880                 IF_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(free(options);)
881         }
882         return EXIT_SUCCESS;
883 }