ash: rename redir5.tests (hush has redir5.tests which is different)
[oweals/busybox.git] / modutils / modprobe-small.c
index a47e52234bdfb4eedada66f578a0e625a161c28e..053a7df896611ae43f4a3beec7e7cdcd3bc26723 100644 (file)
@@ -8,11 +8,17 @@
  * Licensed under GPLv2, see file LICENSE in this source tree.
  */
 
-//applet:IF_MODPROBE_SMALL(APPLET(modprobe, BB_DIR_SBIN, BB_SUID_DROP))
-//applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(depmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, depmod))
-//applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(insmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, insmod))
-//applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, lsmod))
-//applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(rmmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, rmmod))
+/* modprobe-small configs are defined in Config.src to ensure better
+ * "make config" order */
+
+//applet:IF_LSMOD(   IF_MODPROBE_SMALL(APPLET(lsmod,    BB_DIR_SBIN, BB_SUID_DROP)))
+//applet:IF_MODPROBE(IF_MODPROBE_SMALL(APPLET(modprobe, BB_DIR_SBIN, BB_SUID_DROP)))
+//                                   APPLET_ODDNAME:name    main      location     suid_type     help
+//applet:IF_DEPMOD(IF_MODPROBE_SMALL(APPLET_ODDNAME(depmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, depmod)))
+//applet:IF_INSMOD(IF_MODPROBE_SMALL(APPLET_ODDNAME(insmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, insmod)))
+//applet:IF_RMMOD( IF_MODPROBE_SMALL(APPLET_ODDNAME(rmmod,  modprobe, BB_DIR_SBIN, BB_SUID_DROP, rmmod)))
+
+//kbuild:lib-$(CONFIG_MODPROBE_SMALL) += modprobe-small.o
 
 #include "libbb.h"
 /* After libbb.h, since it needs sys/types.h on some systems */
@@ -20,8 +26,8 @@
 #include <fnmatch.h>
 #include <sys/syscall.h>
 
-extern int init_module(void *module, unsigned long len, const char *options);
-extern int delete_module(const char *module, unsigned flags);
+#define init_module(mod, len, opts) syscall(__NR_init_module, mod, len, opts)
+#define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags)
 #ifdef __NR_finit_module
 # define finit_module(fd, uargs, flags) syscall(__NR_finit_module, fd, uargs, flags)
 #endif
@@ -40,7 +46,40 @@ extern int delete_module(const char *module, unsigned flags);
 
 #define DEPFILE_BB CONFIG_DEFAULT_DEPMOD_FILE".bb"
 
+//usage:#if ENABLE_MODPROBE_SMALL
+
+//usage:#define lsmod_trivial_usage
+//usage:       ""
+//usage:#define lsmod_full_usage "\n\n"
+//usage:       "List loaded kernel modules"
+
+//usage:#endif
+
+#if ENABLE_LSMOD
+int lsmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int lsmod_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
+{
+       xprint_and_close_file(xfopen_for_read("/proc/modules"));
+       return EXIT_SUCCESS;
+}
+#endif
+
+/* Num of applets that use modprobe_main() entry point. */
+/* lsmod is not here. */
+#define MOD_APPLET_CNT (ENABLE_MODPROBE + ENABLE_DEPMOD + ENABLE_INSMOD + ENABLE_RMMOD)
+
+/* Do not bother if MODPROBE_SMALL=y but no applets selected. */
+/* The rest of the file is in this if block. */
+#if MOD_APPLET_CNT > 0
+
+#define ONLY_APPLET (MOD_APPLET_CNT == 1)
+#define is_modprobe (ENABLE_MODPROBE && (ONLY_APPLET || applet_name[0] == 'm'))
+#define is_depmod   (ENABLE_DEPMOD   && (ONLY_APPLET || applet_name[0] == 'd'))
+#define is_insmod   (ENABLE_INSMOD   && (ONLY_APPLET || applet_name[0] == 'i'))
+#define is_rmmod    (ENABLE_RMMOD    && (ONLY_APPLET || applet_name[0] == 'r'))
+
 enum {
+       DEPMOD_OPT_n = (1 << 0), /* dry-run, print to stdout */
        OPT_q = (1 << 0), /* be quiet */
        OPT_r = (1 << 1), /* module removal instead of loading */
 };
@@ -130,7 +169,7 @@ static char* find_keyword(char *ptr, size_t len, const char *word)
 
                /* search for the first char in word */
                ptr = memchr(ptr, word[0], len);
-               if (ptr == NULL) /* no occurance left, done */
+               if (ptr == NULL) /* no occurrence left, done */
                        break;
                after_word = is_prefixed_with(ptr, word);
                if (after_word)
@@ -342,6 +381,8 @@ static FAST_FUNC int fileAction(const char *pathname,
 {
        int cur;
        const char *fname;
+       bool is_remove = (ENABLE_RMMOD && ONLY_APPLET)
+               || ((ENABLE_RMMOD || ENABLE_MODPROBE) && (option_mask32 & OPT_r));
 
        pathname += 2; /* skip "./" */
        fname = bb_get_last_path_component_nostrip(pathname);
@@ -366,11 +407,11 @@ static FAST_FUNC int fileAction(const char *pathname,
        if (parse_module(&modinfo[cur], pathname) != 0)
                return TRUE; /* failed to open/read it, no point in trying loading */
 
-       if (!(option_mask32 & OPT_r)) {
+       if (!is_remove) {
                if (load_module(pathname, module_load_options) == 0) {
                        /* Load was successful, there is nothing else to do.
                         * This can happen ONLY for "top-level" module load,
-                        * not a dep, because deps dont do dirscan. */
+                        * not a dep, because deps don't do dirscan. */
                        exit(EXIT_SUCCESS);
                }
        }
@@ -437,7 +478,7 @@ static int start_dep_bb_writeout(void)
        int fd;
 
        /* depmod -n: write result to stdout */
-       if (applet_name[0] == 'd' && (option_mask32 & 1))
+       if (is_depmod && (option_mask32 & DEPMOD_OPT_n))
                return STDOUT_FILENO;
 
        fd = open(DEPFILE_BB".new", O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0644);
@@ -637,7 +678,7 @@ static int rmmod(const char *filename)
  * NB: also called by depmod with bogus name "/",
  * just in order to force modprobe.dep.bb creation.
 */
-#if !ENABLE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE
+#if !ENABLE_FEATURE_CMDLINE_MODULE_OPTIONS
 #define process_module(a,b) process_module(a)
 #define cmdline_options ""
 #endif
@@ -647,7 +688,8 @@ static int process_module(char *name, const char *cmdline_options)
        module_info **infovec;
        module_info *info;
        int infoidx;
-       int is_remove = (option_mask32 & OPT_r) != 0;
+       bool is_remove = (ENABLE_RMMOD && ONLY_APPLET)
+               || ((ENABLE_RMMOD || ENABLE_MODPROBE) && (option_mask32 & OPT_r));
        int exitcode = EXIT_SUCCESS;
 
        dbg1_error_msg("process_module('%s','%s')", name, cmdline_options);
@@ -656,9 +698,8 @@ static int process_module(char *name, const char *cmdline_options)
 
        dbg1_error_msg("already_loaded:%d is_remove:%d", already_loaded(name), is_remove);
 
-       if (applet_name[0] == 'r') {
-               /* rmmod.
-                * Does not remove dependencies, no need to scan, just remove.
+       if (is_rmmod) {
+               /* Does not remove dependencies, no need to scan, just remove.
                 * (compat note: this allows and strips .ko suffix)
                 */
                rmmod(name);
@@ -682,7 +723,7 @@ static int process_module(char *name, const char *cmdline_options)
                options = xmalloc_open_read_close(opt_filename, NULL);
                if (options)
                        replace(options, '\n', ' ');
-#if ENABLE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE
+#if ENABLE_FEATURE_CMDLINE_MODULE_OPTIONS
                if (cmdline_options) {
                        /* NB: cmdline_options always have one leading ' '
                         * (see main()), we remove it here */
@@ -724,9 +765,12 @@ static int process_module(char *name, const char *cmdline_options)
 
        if (!infovec) {
                /* both dirscan and find_alias found nothing */
-               if (!is_remove && applet_name[0] != 'd') /* it wasn't rmmod or depmod */
+               if (!is_remove && !is_depmod) { /* it wasn't rmmod or depmod */
                        bb_error_msg("module '%s' not found", name);
 //TODO: _and_die()? or should we continue (un)loading modules listed on cmdline?
+                       /* "modprobe non-existing-module; echo $?" must print 1 */
+                       exitcode = EXIT_FAILURE;
+               }
                goto ret;
        }
 
@@ -822,25 +866,28 @@ Usage: rmmod [-fhswvV] modulename ...
     should eventually fall to zero).
 
 # modprobe
-Usage: modprobe [-v] [-V] [-C config-file] [-n] [-i] [-q] [-b]
-    [-o <modname>] [ --dump-modversions ] <modname> [parameters...]
+Usage: modprobe [-v] [-V] [-C config-file] [-d <dirname> ] [-n] [-i] [-q]
+    [-b] [-o <modname>] [ --dump-modversions ] <modname> [parameters...]
 modprobe -r [-n] [-i] [-v] <modulename> ...
 modprobe -l -t <dirname> [ -a <modulename> ...]
 
 # depmod --help
-depmod 3.4 -- part of module-init-tools
-depmod -[aA] [-n -e -v -q -V -r -u]
+depmod 3.13 -- part of module-init-tools
+depmod -[aA] [-n -e -v -q -V -r -u -w -m]
       [-b basedirectory] [forced_version]
-depmod [-n -e -v -q -r -u] [-F kernelsyms] module1.ko module2.ko ...
+depmod [-n -e -v -q -r -u -w] [-F kernelsyms] module1.ko module2.ko ...
 If no arguments (except options) are given, "depmod -a" is assumed.
 depmod will output a dependency list suitable for the modprobe utility.
 Options:
     -a, --all           Probe all modules
     -A, --quick         Only does the work if there's a new module
-    -n, --show          Write the dependency file on stdout only
     -e, --errsyms       Report not supplied symbols
+    -m, --map           Create the legacy map files
+    -n, --show          Write the dependency file on stdout only
+    -P, --symbol-prefix Architecture symbol prefix
     -V, --version       Print the release version
     -v, --verbose       Enable verbose mode
+    -w, --warn          Warn on duplicates
     -h, --help          Print this usage message
 The following options are useful for people managing distributions:
     -b basedirectory
@@ -849,86 +896,61 @@ The following options are useful for people managing distributions:
     -F kernelsyms
     --filesyms kernelsyms
                         Use the file instead of the current kernel symbols
+    -E Module.symvers
+    --symvers Module.symvers
+                        Use Module.symvers file to check symbol versions
 */
 
 //usage:#if ENABLE_MODPROBE_SMALL
 
-//usage:#define depmod_trivial_usage NOUSAGE_STR
-//usage:#define depmod_full_usage ""
-
-//usage:#define lsmod_trivial_usage
-//usage:       ""
-//usage:#define lsmod_full_usage "\n\n"
-//usage:       "List the currently loaded kernel modules"
+//usage:#define depmod_trivial_usage "[-n]"
+//usage:#define depmod_full_usage "\n\n"
+//usage:       "Generate modules.dep.bb"
+//usage:     "\n"
+//usage:     "\n       -n      Dry run: print file to stdout"
 
 //usage:#define insmod_trivial_usage
-//usage:       IF_FEATURE_2_4_MODULES("[OPTIONS] MODULE ")
-//usage:       IF_NOT_FEATURE_2_4_MODULES("FILE ")
-//usage:       "[SYMBOL=VALUE]..."
+//usage:       "FILE" IF_FEATURE_CMDLINE_MODULE_OPTIONS(" [SYMBOL=VALUE]...")
 //usage:#define insmod_full_usage "\n\n"
 //usage:       "Load kernel module"
-//usage:       IF_FEATURE_2_4_MODULES( "\n"
-//usage:     "\n       -f      Force module to load into the wrong kernel version"
-//usage:     "\n       -k      Make module autoclean-able"
-//usage:     "\n       -v      Verbose"
-//usage:     "\n       -q      Quiet"
-//usage:     "\n       -L      Lock: prevent simultaneous loads"
-//usage:       IF_FEATURE_INSMOD_LOAD_MAP(
-//usage:     "\n       -m      Output load map to stdout"
-//usage:       )
-//usage:     "\n       -x      Don't export externs"
-//usage:       )
 
 //usage:#define rmmod_trivial_usage
-//usage:       "[-wfa] [MODULE]..."
+//usage:       "MODULE..."
 //usage:#define rmmod_full_usage "\n\n"
-//usage:       "Unload kernel modules\n"
-//usage:     "\n       -w      Wait until the module is no longer used"
-//usage:     "\n       -f      Force unload"
-//usage:     "\n       -a      Remove all unused modules (recursively)"
-//usage:
-//usage:#define rmmod_example_usage
-//usage:       "$ rmmod tulip\n"
+//usage:       "Unload kernel modules"
 
 //usage:#define modprobe_trivial_usage
-//usage:       "[-qfwrsv] MODULE [SYMBOL=VALUE]..."
+//usage:       "[-rq] MODULE" IF_FEATURE_CMDLINE_MODULE_OPTIONS(" [SYMBOL=VALUE]...")
 //usage:#define modprobe_full_usage "\n\n"
-//usage:       "       -r      Remove MODULE (stacks) or do autoclean"
+//usage:       "       -r      Remove MODULE"
 //usage:     "\n       -q      Quiet"
-//usage:     "\n       -v      Verbose"
-//usage:     "\n       -f      Force"
-//usage:     "\n       -w      Wait for unload"
-//usage:     "\n       -s      Report via syslog instead of stderr"
 
 //usage:#endif
 
 int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int modprobe_main(int argc UNUSED_PARAM, char **argv)
 {
+#if ENABLE_MODPROBE || ENABLE_INSMOD || ENABLE_RMMOD
        int exitcode;
+#endif
        struct utsname uts;
-       char applet0 = applet_name[0];
-       IF_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(char *options;)
-
-       /* are we lsmod? -> just dump /proc/modules */
-       if ('l' == applet0) {
-               xprint_and_close_file(xfopen_for_read("/proc/modules"));
-               return EXIT_SUCCESS;
-       }
+       IF_FEATURE_CMDLINE_MODULE_OPTIONS(char *options = NULL;)
 
        INIT_G();
 
        /* Prevent ugly corner cases with no modules at all */
        modinfo = xzalloc(sizeof(modinfo[0]));
 
-       if ('i' != applet0) { /* not insmod */
+       if ((MOD_APPLET_CNT == 2 && ENABLE_DEPMOD && ENABLE_MODPROBE)
+        || is_depmod || is_modprobe
+       ) {
                /* Goto modules directory */
                xchdir(CONFIG_DEFAULT_MODULES_DIR);
+               uname(&uts); /* never fails */
        }
-       uname(&uts); /* never fails */
 
        /* depmod? */
-       if ('d' == applet0) {
+       if (is_depmod) {
                /* Supported:
                 * -n: print result to stdout
                 * -a: process all modules (default)
@@ -938,10 +960,12 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
                 * -e: report any symbols which a module needs
                 *  which are not supplied by other modules or the kernel
                 * -F FILE: System.map (symbols for -e)
-                * -q, -r, -u: noop?
+                * -q, -r, -u: noop
                 * Not supported:
                 * -b BASEDIR: (TODO!) modules are in
                 *  $BASEDIR/lib/modules/$VERSION
+                * -m: create legacy "modules.*map" files (deprecated; in
+                *  kmod's depmod, prints a warning message and continues)
                 * -v: human readable deps to stdout
                 * -V: version (don't want to support it - people may depend
                 *  on it as an indicator of "standard" depmod)
@@ -959,28 +983,28 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
                return !wrote_dep_bb_ok;
        }
 
-       /* insmod, modprobe, rmmod require at least one argument */
+#if ENABLE_MODPROBE || ENABLE_INSMOD || ENABLE_RMMOD
+       /* modprobe, insmod, rmmod require at least one argument */
        opt_complementary = "-1";
        /* only -q (quiet) and -r (rmmod),
         * the rest are accepted and ignored (compat) */
        getopt32(argv, "qrfsvwb");
        argv += optind;
 
-       /* are we rmmod? -> simulate modprobe -r */
-       if ('r' == applet0) {
-               option_mask32 |= OPT_r;
-       }
-
-       if ('i' != applet0) { /* not insmod */
+       if (is_modprobe) {
                /* Goto $VERSION directory */
                xchdir(uts.release);
        }
 
-#if ENABLE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE
+       /* are we rmmod? -> simulate modprobe -r, but don't bother the flag if
+        * there're no other applets here */
+       if (is_rmmod) {
+               if (!ONLY_APPLET)
+                       option_mask32 |= OPT_r;
+       } else if (!ENABLE_MODPROBE || !(option_mask32 & OPT_r)) {
+# if ENABLE_FEATURE_CMDLINE_MODULE_OPTIONS
        /* If not rmmod/-r, parse possible module options given on command line.
         * insmod/modprobe takes one module name, the rest are parameters. */
-       options = NULL;
-       if (!(option_mask32 & OPT_r)) {
                char **arg = argv;
                while (*++arg) {
                        /* Enclose options in quotes */
@@ -989,13 +1013,12 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
                        free(s);
                        *arg = NULL;
                }
-       }
-#else
-       if (!(option_mask32 & OPT_r))
+# else
                argv[1] = NULL;
-#endif
+# endif
+       }
 
-       if ('i' == applet0) { /* insmod */
+       if (is_insmod) {
                size_t len;
                void *map;
 
@@ -1004,8 +1027,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
                if (!map)
                        bb_perror_msg_and_die("can't read '%s'", *argv);
                if (init_module(map, len,
-                       IF_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(options ? options : "")
-                       IF_NOT_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE("")
+                       (IF_FEATURE_CMDLINE_MODULE_OPTIONS(options ? options : ) "")
                        ) != 0
                ) {
                        bb_error_msg_and_die("can't insert '%s': %s",
@@ -1015,7 +1037,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
        }
 
        /* Try to load modprobe.dep.bb */
-       if ('r' != applet0) { /* not rmmod */
+       if (!is_rmmod) {
                load_dep_bb();
        }
 
@@ -1027,7 +1049,10 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
        } while (*++argv);
 
        if (ENABLE_FEATURE_CLEAN_UP) {
-               IF_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(free(options);)
+               IF_FEATURE_CMDLINE_MODULE_OPTIONS(free(options);)
        }
        return exitcode;
+#endif /* MODPROBE || INSMOD || RMMOD */
 }
+
+#endif /* MOD_APPLET_CNT > 0 */