diff --git a/docs/busybox.sgml b/docs/busybox.sgml
index aa3c37692..dacc13249 100644
--- a/docs/busybox.sgml
+++ b/docs/busybox.sgml
@@ -2788,7 +2788,7 @@
- -a Try to remove all unused kernel modules
+ -a Remove all unused modules (recursively)
diff --git a/include/libbb.h b/include/libbb.h
index 5f437a95f..3523cc410 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -357,6 +357,8 @@ typedef struct {
extern procps_status_t * procps_scan(int save_user_arg0);
extern unsigned short compare_string_array(const char *string_array[], const char *key);
+extern int my_query_module(const char *name, int which, void **buf, size_t *bufsize, size_t *ret);
+
typedef struct llist_s {
char *data;
struct llist_s *link;
diff --git a/include/usage.h b/include/usage.h
index 3b519e65d..16dd6fd78 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -1722,7 +1722,7 @@
#define rmmod_full_usage \
"Unloads the specified kernel modules from the kernel.\n\n" \
"Options:\n" \
- "\t-a\tTry to remove all unused kernel modules."
+ "\t-a\tRemove all unused modules (recursively)"
#define rmmod_example_usage \
"$ rmmod tulip\n"
diff --git a/libbb/Makefile.in b/libbb/Makefile.in
index 3f4e77314..c97f7d2b3 100644
--- a/libbb/Makefile.in
+++ b/libbb/Makefile.in
@@ -38,7 +38,7 @@ LIBBB_SRC:= \
my_getpwnam.c my_getpwnamegid.c my_getpwuid.c obscure.c parse_mode.c \
parse_number.c perror_msg.c perror_msg_and_die.c print_file.c \
process_escape_sequence.c procps.c pwd2spwd.c pw_encrypt.c \
- read_package_field.c recursive_action.c remove_file.c \
+ qmodule.c read_package_field.c recursive_action.c remove_file.c \
restricted_shell.c run_parts.c run_shell.c safe_read.c safe_strncpy.c \
setup_environment.c simplify_path.c syscalls.c syslog_msg_with_name.c \
time_string.c trim.c u_signal_names.c vdprintf.c verror_msg.c \
diff --git a/libbb/qmodule.c b/libbb/qmodule.c
new file mode 100644
index 000000000..fd14d10fa
--- /dev/null
+++ b/libbb/qmodule.c
@@ -0,0 +1,29 @@
+/*
+ Copyright (C) 2002 Tim Riker
+ everyone seems to claim it someplace. ;-)
+*/
+
+#include
+
+#include "libbb.h"
+
+int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret);
+
+int my_query_module(const char *name, int which, void **buf,
+ size_t *bufsize, size_t *ret)
+{
+ int my_ret;
+
+ my_ret = query_module(name, which, *buf, *bufsize, ret);
+
+ if (my_ret == -1 && errno == ENOSPC) {
+ *buf = xrealloc(*buf, *ret);
+ *bufsize = *ret;
+
+ my_ret = query_module(name, which, *buf, *bufsize, ret);
+ }
+
+ return my_ret;
+}
+
+
diff --git a/modutils/lsmod.c b/modutils/lsmod.c
index d51da2d16..0d5ac756b 100644
--- a/modutils/lsmod.c
+++ b/modutils/lsmod.c
@@ -98,23 +98,6 @@ static const int NEW_MOD_VISITED = 8;
static const int NEW_MOD_USED_ONCE = 16;
static const int NEW_MOD_INITIALIZING = 64;
-static int my_query_module(const char *name, int which, void **buf,
- size_t *bufsize, size_t *ret)
-{
- int my_ret;
-
- my_ret = query_module(name, which, *buf, *bufsize, ret);
-
- if (my_ret == -1 && errno == ENOSPC) {
- *buf = xrealloc(*buf, *ret);
- *bufsize = *ret;
-
- my_ret = query_module(name, which, *buf, *bufsize, ret);
- }
-
- return my_ret;
-}
-
extern int lsmod_main(int argc, char **argv)
{
struct module_info info;
diff --git a/modutils/rmmod.c b/modutils/rmmod.c
index affe975fa..0103d9145 100644
--- a/modutils/rmmod.c
+++ b/modutils/rmmod.c
@@ -34,14 +34,30 @@ extern int delete_module(const char * name);
extern int rmmod_main(int argc, char **argv)
{
int n, ret = EXIT_SUCCESS;
+ size_t nmod = 0; /* number of modules */
+ size_t pnmod = -1; /* previous number of modules */
+ void *buf; /* hold the module names which we ignore but must get */
+ size_t bufsize = 0;
/* Parse command line. */
while ((n = getopt(argc, argv, "a")) != EOF) {
switch (n) {
case 'a':
/* Unload _all_ unused modules via NULL delete_module() call */
- if (delete_module(NULL))
- perror_msg_and_die("rmmod");
+ /* until the number of modules does not change */
+ buf = xmalloc(bufsize = 256);
+ while (nmod != pnmod) {
+ if (delete_module(NULL))
+ perror_msg_and_die("rmmod");
+ pnmod = nmod;
+ /* 1 == QM_MODULES */
+ if (my_query_module(NULL, 1, &buf, &bufsize, &nmod)) {
+ perror_msg_and_die("QM_MODULES");
+ }
+ }
+#ifdef CONFIG_FEATURE_CLEAN_UP
+ free(buf);
+#endif
return EXIT_SUCCESS;
default:
show_usage();