]> git.ipfire.org Git - thirdparty/kmod.git/commitdiff
add lsmod, insmod and rmmod tools.
authorGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Sun, 11 Dec 2011 00:19:41 +0000 (22:19 -0200)
committerGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Sun, 11 Dec 2011 22:58:22 +0000 (20:58 -0200)
these tools are compatible with module-init-tools (except insmod does
not take data from stdin).

Makefile.am
configure.ac
test/test-loaded.c
tools/.gitignore [new file with mode: 0644]
tools/kmod-insmod.c [new file with mode: 0644]
tools/kmod-lsmod.c [new file with mode: 0644]
tools/kmod-rmmod.c [new file with mode: 0644]

index b6ba9d8312dbfd3dc79fbfa0b1e630dae63b9b1d..f6520cc40ae3968cf1e7b7ede6738b4bb90cba65 100644 (file)
@@ -48,6 +48,14 @@ libkmod_libkmod_la_LDFLAGS = $(AM_LDFLAGS) \
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libkmod/libkmod.pc
 
+if BUILD_TOOLS
+bin_PROGRAMS = tools/kmod-insmod tools/kmod-rmmod tools/kmod-lsmod
+
+tools_kmod_insmod_LDADD = libkmod/libkmod.la
+tools_kmod_rmmod_LDADD = libkmod/libkmod.la
+tools_kmod_lsmod_LDADD = libkmod/libkmod.la
+endif
+
 TESTS = test/test-init test/test-loaded
 
 check_PROGRAMS = test/test-init test/test-loaded
index 812f4abb0f5b675715c4965769a6b7067c8008b7..f5b16e8ab0e84acd562d63af8d31a47d385f8145 100644 (file)
@@ -22,6 +22,11 @@ AC_C_TYPEOF
 AM_PROG_CC_C_O
 AC_PROG_GCC_TRADITIONAL
 
+AC_ARG_ENABLE([tools],
+        AS_HELP_STRING([--disable-tools], [disable building tools that provide same functionality as module-init-tools @<:@default=enabled@:>@]),
+       [], enable_tools=yes)
+AM_CONDITIONAL([BUILD_TOOLS], [test "x$enable_tools" = "xyes"])
+
 AC_ARG_ENABLE([logging],
        AS_HELP_STRING([--disable-logging], [disable system logging @<:@default=enabled@:>@]),
        [], enable_logging=yes)
@@ -97,11 +102,13 @@ AC_MSG_RESULT([
        sysconfdir:             ${sysconfdir}
        libdir:                 ${libdir}
        includedir:             ${includedir}
+        bindir:                 ${bindir}
 
        compiler:               ${CC}
        cflags:                 ${CFLAGS}
        ldflags:                ${LDFLAGS}
 
+        tools:                  ${enable_tools}
        logging:                ${enable_logging}
        debug:                  ${enable_debug}
 ])
index c862cd9798a0cd7dbf38c9b7ca8519d9bdf67cc6..dc456958ad7b46014b74d9c627d0d8d80a085079 100644 (file)
@@ -23,6 +23,7 @@ int main(int argc, char *argv[])
        err = kmod_loaded_get_list(ctx, &list);
        if (err < 0) {
                fprintf(stderr, "%s\n", strerror(-err));
+               kmod_unref(ctx);
                exit(EXIT_FAILURE);
        }
 
diff --git a/tools/.gitignore b/tools/.gitignore
new file mode 100644 (file)
index 0000000..efd73dc
--- /dev/null
@@ -0,0 +1,4 @@
+.dirstamp
+kmod-insmod
+kmod-rmmod
+kmod-lsmod
diff --git a/tools/kmod-insmod.c b/tools/kmod-insmod.c
new file mode 100644 (file)
index 0000000..10c269a
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * kmod-insmod - insert modules into linux kernel using libkmod.
+ *
+ * Copyright (C) 2011  ProFUSION embedded systems
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+#include <string.h>
+#include "libkmod.h"
+
+
+static const char cmdopts_s[] = "psfVh";
+static const struct option cmdopts[] = {
+       {"version", no_argument, 0, 'V'},
+       {"help", no_argument, 0, 'h'},
+       {NULL, 0, 0, 0}
+};
+
+static void help(const char *progname)
+{
+       fprintf(stderr,
+               "Usage:\n"
+               "\t%s [options] filename [args]\n"
+               "Options:\n"
+               "\t-V, --version     show version\n"
+               "\t-h, --help        show this help\n",
+               progname);
+}
+
+static const char *mod_strerror(int err)
+{
+       switch (err) {
+       case ENOEXEC:
+               return "Invalid module format";
+       case ENOENT:
+               return "Unknown symbol in module";
+       case ESRCH:
+               return "Module has wrong symbol version";
+       case EINVAL:
+               return "Invalid parameters";
+       default:
+               return strerror(err);
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       struct kmod_ctx *ctx;
+       struct kmod_module *mod;
+       const char *filename;
+       char *opts = NULL;
+       size_t optslen = 0;
+       int i, err;
+
+       for (;;) {
+               int c, idx = 0;
+               c = getopt_long(argc, argv, cmdopts_s, cmdopts, &idx);
+               if (c == -1)
+                       break;
+               switch (c) {
+               case 'p':
+               case 's':
+               case 'f':
+                       /* ignored, for compatibility only */
+                       break;
+               case 'h':
+                       help(argv[0]);
+                       return EXIT_SUCCESS;
+               case 'V':
+                       puts(PACKAGE " version " VERSION);
+                       return EXIT_SUCCESS;
+               case '?':
+                       return EXIT_FAILURE;
+               default:
+                       fprintf(stderr,
+                               "Error: unexpected getopt_long() value '%c'.\n",
+                               c);
+                       return EXIT_FAILURE;
+               }
+       }
+
+       if (optind >= argc) {
+               fprintf(stderr, "Error: missing filename.\n");
+               return EXIT_FAILURE;
+       }
+
+       filename = argv[optind];
+       if (strcmp(filename, "-") == 0) {
+               fputs("Error: this tool does not support loading from stdin!\n",
+                     stderr);
+               return EXIT_FAILURE;
+       }
+
+       for (i = optind + 1; i < argc; i++) {
+               size_t len = strlen(argv[i]);
+               void *tmp = realloc(opts, optslen + len + 2);
+               if (tmp == NULL) {
+                       fputs("Error: out of memory\n", stderr);
+                       free(opts);
+                       return EXIT_FAILURE;
+               }
+               opts = tmp;
+               if (optslen > 0) {
+                       opts[optslen] = ' ';
+                       optslen++;
+               }
+               memcpy(opts + optslen, argv[i], len);
+               optslen += len;
+               opts[optslen] = '\0';
+       }
+
+       ctx = kmod_new(NULL);
+       if (!ctx) {
+               fputs("Error: kmod_new() failed!\n", stderr);
+               free(opts);
+               return EXIT_FAILURE;
+       }
+
+       err = kmod_module_new_from_path(ctx, filename, &mod);
+       if (err < 0) {
+               fprintf(stderr, "Error: could not load module %s: %s\n",
+                       filename, strerror(-err));
+               goto end;
+       }
+
+       err = kmod_module_insert_module(mod, 0, opts);
+       if (err < 0) {
+               fprintf(stderr, "Error: could not insert module %s: %s\n",
+                       filename, mod_strerror(-err));
+       }
+       kmod_module_unref(mod);
+
+end:
+       kmod_unref(ctx);
+       free(opts);
+       return err >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/tools/kmod-lsmod.c b/tools/kmod-lsmod.c
new file mode 100644 (file)
index 0000000..20d0757
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * kmod-lsmod - list modules from linux kernel using libkmod.
+ *
+ * Copyright (C) 2011  ProFUSION embedded systems
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include "libkmod.h"
+
+
+int main(int argc, char *argv[])
+{
+       struct kmod_ctx *ctx;
+       struct kmod_list *list, *itr;
+       int err;
+
+       if (argc != 1) {
+               fprintf(stderr, "Usage: %s\n", argv[0]);
+               return EXIT_FAILURE;
+       }
+
+       ctx = kmod_new(NULL);
+       if (ctx == NULL) {
+               fputs("Error: kmod_new() failed!\n", stderr);
+               return EXIT_FAILURE;
+       }
+
+       err = kmod_loaded_get_list(ctx, &list);
+       if (err < 0) {
+               fprintf(stderr, "Error: could not get list of modules: %s\n",
+                       strerror(-err));
+               kmod_unref(ctx);
+               return EXIT_FAILURE;
+       }
+
+       puts("Module                  Size  Used by");
+
+       kmod_list_foreach(itr, list) {
+               struct kmod_module *mod = kmod_module_get_module(itr);
+               const char *name = kmod_module_get_name(mod);
+               int use_count = kmod_module_get_refcnt(mod);
+               long size = kmod_module_get_size(mod);
+               struct kmod_list *holders, *hitr;
+               int first = 1;
+
+               printf("%-19s %8ld  %d ", name, size, use_count);
+               holders = kmod_module_get_holders(mod);
+               kmod_list_foreach(hitr, holders) {
+                       struct kmod_module *hm = kmod_module_get_module(hitr);
+
+                       if (!first)
+                               putchar(',');
+                       else
+                               first = 0;
+
+                       fputs(kmod_module_get_name(hm), stdout);
+                       kmod_module_unref(hm);
+               }
+               putchar('\n');
+               kmod_module_unref_list(holders);
+               kmod_module_unref(mod);
+       }
+       kmod_module_unref_list(list);
+       kmod_unref(ctx);
+
+       return EXIT_SUCCESS;
+}
diff --git a/tools/kmod-rmmod.c b/tools/kmod-rmmod.c
new file mode 100644 (file)
index 0000000..8963448
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * kmod-rmmod - remove modules from linux kernel using libkmod.
+ *
+ * Copyright (C) 2011  ProFUSION embedded systems
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <syslog.h>
+#include "libkmod.h"
+
+
+static const char cmdopts_s[] = "fsvVwh";
+static const struct option cmdopts[] = {
+       {"force", no_argument, 0, 'f'},
+       {"syslog", no_argument, 0, 's'},
+       {"verbose", no_argument, 0, 'v'},
+       {"version", no_argument, 0, 'V'},
+       {"wait", no_argument, 0, 'w'},
+       {"help", no_argument, 0, 'h'},
+       {NULL, 0, 0, 0}
+};
+
+static void help(const char *progname)
+{
+       fprintf(stderr,
+               "Usage:\n"
+               "\t%s [options] modulename ...\n"
+               "Options:\n"
+               "\t-f, --force       forces a module unload and may crash your\n"
+               "\t                  machine. This requires Forced Module Removal\n"
+               "\t                  option in your kernel. DANGEROUS\n"
+               "\t-s, --syslog      print to syslog, not stderr\n"
+               "\t-v, --verbose     enables more messages\n"
+               "\t-V, --version     show version\n"
+               "\t-w, --wait        begins module removal even if it is used and\n"
+               "\t                  will stop new users from accessing it.\n"
+               "\t-h, --help        show this help\n",
+               progname);
+}
+
+static void log_syslog(void *data, int priority, const char *file, int line,
+                               const char *fn, const char *format,
+                               va_list args)
+{
+       char *str, buf[32];
+       const char *prioname;
+
+       switch (priority) {
+       case LOG_CRIT:
+               prioname = "FATAL";
+               break;
+       case LOG_ERR:
+               prioname = "ERROR";
+               break;
+       case LOG_WARNING:
+               prioname = "WARNING";
+               break;
+       case LOG_NOTICE:
+               prioname = "NOTICE";
+               break;
+       case LOG_INFO:
+               prioname = "INFO";
+               break;
+       case LOG_DEBUG:
+               prioname = "DEBUG";
+               break;
+       default:
+               snprintf(buf, sizeof(buf), "LOG-%03d", priority);
+               prioname = buf;
+       }
+
+       if (vasprintf(&str, format, args) < 0)
+               return;
+#ifdef ENABLE_DEBUG
+       syslog(LOG_NOTICE, "%s: %s:%d %s() %s", prioname, file, line, fn, str);
+#else
+       syslog(LOG_NOTICE, "%s: %s", prioname, str);
+#endif
+       free(str);
+       (void)data;
+}
+
+int main(int argc, char *argv[])
+{
+       struct kmod_ctx *ctx;
+       int flags = KMOD_REMOVE_NOWAIT;
+       int use_syslog = 0;
+       int verbose = 0;
+       int i, err;
+
+       for (;;) {
+               int c, idx = 0;
+               c = getopt_long(argc, argv, cmdopts_s, cmdopts, &idx);
+               if (c == -1)
+                       break;
+               switch (c) {
+               case 'f':
+                       flags |= KMOD_REMOVE_FORCE;
+                       break;
+               case 's':
+                       use_syslog = 1;
+                       break;
+               case 'v':
+                       verbose++;
+                       break;
+               case 'w':
+                       flags &= ~KMOD_REMOVE_NOWAIT;
+                       break;
+               case 'h':
+                       help(argv[0]);
+                       return EXIT_SUCCESS;
+               case 'V':
+                       puts(PACKAGE " version " VERSION);
+                       return EXIT_SUCCESS;
+               case '?':
+                       return EXIT_FAILURE;
+               default:
+                       fprintf(stderr,
+                               "Error: unexpected getopt_long() value '%c'.\n",
+                               c);
+                       return EXIT_FAILURE;
+               }
+       }
+
+       if (optind >= argc) {
+               fprintf(stderr, "Error: missing module name.\n");
+               return EXIT_FAILURE;
+       }
+
+       ctx = kmod_new(NULL);
+       if (!ctx) {
+               fputs("Error: kmod_new() failed!\n", stderr);
+               return EXIT_FAILURE;
+       }
+
+       kmod_set_log_priority(ctx, kmod_get_log_priority(ctx) + verbose);
+       if (use_syslog) {
+               openlog("rmmod", LOG_CONS, LOG_DAEMON);
+               kmod_set_log_fn(ctx, log_syslog, NULL);
+       }
+
+       for (i = optind; i < argc; i++) {
+               struct kmod_module *mod;
+               const char *arg = argv[i];
+               struct stat st;
+               if (stat(arg, &st) == 0)
+                       err = kmod_module_new_from_path(ctx, arg, &mod);
+               else
+                       err = kmod_module_new_from_name(ctx, arg, &mod);
+
+               if (err < 0) {
+                       fprintf(stderr, "Error: could not use module %s: %s\n",
+                               arg, strerror(-err));
+                       break;
+               }
+
+               err = kmod_module_remove_module(mod, flags);
+               if (err < 0) {
+                       fprintf(stderr,
+                               "Error: could not remove module %s: %s\n",
+                               arg, strerror(-err));
+               }
+               kmod_module_unref(mod);
+               if (err < 0)
+                       break;
+       }
+
+       kmod_unref(ctx);
+
+       if (use_syslog)
+               closelog();
+
+       return err >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}