diff options
author | Haibo Huang <hhb@google.com> | 2020-10-28 22:24:00 -0700 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2020-10-29 12:53:41 -0700 |
commit | f9d235a152c633260a465729ab87e13529597200 (patch) | |
tree | fcb23160ed5b5444f85dedbb4e940df1ab74fa1a | |
parent | 3045ec0d51500aaecac4511d52571cb2a96f171d (diff) | |
parent | 819a125ca756003dce2d11624035b7fb605a8e99 (diff) | |
download | kmod-f9d235a152c633260a465729ab87e13529597200.tar.gz |
Upgrade kmod to v27
(Manually added the new source file to Android.bp.)
Test: make
Change-Id: I7621be93dce03f17a4989a949fd72ff8d6d29011
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | .travis.yml | 29 | ||||
-rw-r--r-- | Android.bp | 1 | ||||
-rw-r--r-- | METADATA | 8 | ||||
-rw-r--r-- | Makefile.am | 16 | ||||
-rw-r--r-- | NEWS | 49 | ||||
-rw-r--r-- | configure.ac | 7 | ||||
-rw-r--r-- | libkmod/libkmod-builtin.c | 329 | ||||
-rw-r--r-- | libkmod/libkmod-config.c | 1 | ||||
-rw-r--r-- | libkmod/libkmod-internal.h | 10 | ||||
-rw-r--r-- | libkmod/libkmod-module.c | 90 | ||||
-rw-r--r-- | libkmod/libkmod-signature.c | 37 | ||||
-rw-r--r-- | libkmod/libkmod.c | 25 | ||||
-rw-r--r-- | libkmod/libkmod.h | 1 | ||||
-rw-r--r-- | m4/dolt.m4 | 181 | ||||
-rw-r--r-- | testsuite/module-playground/.gitignore | 5 | ||||
-rw-r--r-- | tools/depmod.c | 63 | ||||
-rw-r--r-- | tools/modinfo.c | 39 | ||||
-rw-r--r-- | tools/modprobe.c | 20 | ||||
-rw-r--r-- | tools/remove.c | 9 | ||||
-rw-r--r-- | tools/rmmod.c | 9 |
21 files changed, 657 insertions, 274 deletions
@@ -18,8 +18,6 @@ /configure /coverage /cov-int -/doltcompile -/doltlibtool /libtool /stamp-h1 /test-suite.log diff --git a/.travis.yml b/.travis.yml index 4b36e1f..02c753e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,16 @@ language: c + +matrix: + include: + - compiler: gcc + env: MYCC=gcc + - compiler: gcc + env: MYCC=gcc-4.8 + - compiler: gcc + env: MYCC=gcc-4.9 + - compiler: clang + env: MYCC=clang + before_install: - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y - sudo apt-get update -qq @@ -9,20 +21,15 @@ before_install: - sudo apt-get install -qq linux-headers-generic - if [ "$MYCC" = "gcc-4.8" ]; then sudo apt-get install -qq gcc-4.8; sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 90; gcc --version; fi - if [ "$MYCC" = "gcc-4.9" ]; then sudo apt-get install -qq gcc-4.9; sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 90; gcc --version; fi + before_script: - unset PYTHON_CFLAGS # hack to broken travis setup - export KDIR="$(find /lib/modules/* -maxdepth 1 -name build | sort -n --reverse | head -1)" -matrix: - include: - - compiler: gcc - env: MYCC=gcc - - compiler: gcc - env: MYCC=gcc-4.8 - - compiler: gcc - env: MYCC=gcc-4.9 - - compiler: clang - env: MYCC=clang -script: ./autogen.sh c --without-openssl && make -j && make -j check + +script: + - ./autogen.sh c --without-openssl && make -j + - if [ "$MYCC" != "gcc-4.8" ]; then make -j check; fi + notifications: irc: channels: @@ -30,6 +30,7 @@ cc_library_static { name: "libkmod", srcs: [ "libkmod/libkmod.c", + "libkmod/libkmod-builtin.c", "libkmod/libkmod-file.c", "libkmod/libkmod-module.c", "libkmod/libkmod-config.c", @@ -5,11 +5,11 @@ third_party { type: GIT value: "https://git.kernel.org/pub/scm/utils/kernel/kmod/kmod.git" } - version: "v26" + version: "v27" license_type: RESTRICTED last_upgrade_date { - year: 2019 - month: 2 - day: 7 + year: 2020 + month: 10 + day: 28 } } diff --git a/Makefile.am b/Makefile.am index ddb25f0..8eadb99 100644 --- a/Makefile.am +++ b/Makefile.am @@ -35,15 +35,15 @@ SED_PROCESS = \ -e 's,@liblzma_LIBS\@,${liblzma_LIBS},g' \ -e 's,@zlib_CFLAGS\@,${zlib_CFLAGS},g' \ -e 's,@zlib_LIBS\@,${zlib_LIBS},g' \ - -e 's,@openssl_CFLAGS\@,${openssl_CFLAGS},g' \ - -e 's,@openssl_LIBS\@,${openssl_LIBS},g' \ + -e 's,@libcrypto_CFLAGS\@,${libcrypto_CFLAGS},g' \ + -e 's,@libcrypto_LIBS\@,${libcrypto_LIBS},g' \ < $< > $@ || rm $@ %.pc: %.pc.in Makefile $(SED_PROCESS) LIBKMOD_CURRENT=5 -LIBKMOD_REVISION=4 +LIBKMOD_REVISION=5 LIBKMOD_AGE=3 noinst_LTLIBRARIES = shared/libshared.la @@ -68,6 +68,7 @@ libkmod_libkmod_la_SOURCES = \ libkmod/libkmod.h \ libkmod/libkmod-internal.h \ libkmod/libkmod.c \ + libkmod/libkmod-builtin.c \ libkmod/libkmod-list.c \ libkmod/libkmod-config.c \ libkmod/libkmod-index.c \ @@ -89,7 +90,7 @@ libkmod_libkmod_la_DEPENDENCIES = \ ${top_srcdir}/libkmod/libkmod.sym libkmod_libkmod_la_LIBADD = \ shared/libshared.la \ - ${liblzma_LIBS} ${zlib_LIBS} ${openssl_LIBS} + ${liblzma_LIBS} ${zlib_LIBS} ${libcrypto_LIBS} noinst_LTLIBRARIES += libkmod/libkmod-internal.la libkmod_libkmod_internal_la_SOURCES = $(libkmod_libkmod_la_SOURCES) @@ -173,7 +174,10 @@ CPYTHON_MODULE_CFLAGS = \ $(AM_CFLAGS) -DCPYTHON_COMPILING_IN_PYPY=0 \ $(PYTHON_NOWARN) $(PYTHON_CFLAGS) \ -fvisibility=default -CPYTHON_MODULE_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version -shared +# Filter -Wl,--no-undefined to fix build with python 3.8 +comma = , +CPYTHON_MODULE_LDFLAGS = $(subst -Wl$(comma)--no-undefined,,$(AM_LDFLAGS)) +CPYTHON_MODULE_LDFLAGS += -module -avoid-version -shared if BUILD_PYTHON pkgpyexec_LTLIBRARIES = \ @@ -415,8 +419,6 @@ distclean-local: $(DISTCLEAN_LOCAL_HOOKS) buildtest-TESTS: $(MAKE) $(AM_MAKEFLAGS) $(check_LTLIBRARIES) $(check_PROGRAMS) -DISTCLEANFILES += $(DOLT_CLEANFILES) - # ------------------------------------------------------------------------------ # coverage # ------------------------------------------------------------------------------ @@ -1,3 +1,52 @@ +kmod 27 +======= + +- Improvements + - Link to libcrypto rather than requiring openssl + + - Print a better error message when kernel doesn't support module unload + + - Use PKCS#7 instead of CMS for parsing module signature to be + compatible with LibreSSL and OpenSSL < 1.1.0 + + - Teach modinfo to parse modules.builtin.modinfo. When using Linux kernel + >= v5.2-rc1 it's possible to get module information from this new file. Now + modinfo is able to show it instead of an error message that the module is + built-in: + + Before: + $ modinfo ext4 + modinfo: ERROR: Module ext4 not found. + + After: + $ modinfo ext4 + name: ext4 + filename: (builtin) + softdep: pre: crc32c + license: GPL + description: Fourth Extended Filesystem + author: Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others + alias: fs-ext4 + alias: ext3 + alias: fs-ext3 + alias: ext2 + alias: fs-ext2 + +- Bug fixes + - Do not link python bindings with libpython to be compatible with + python3.8 + + - Fix module removal with `modprobe -r` when a dependency is built-in. + Now it properly ignores them and proceed with removal of other + dependencies + + - Fix propagation of return code from install/remove commands to the + the probe function. The return values of kmod_module_probe_insert_module() + have very specific meanings, do not confuse the caller by return codes + from system() + + - Fix softdep config parsing leading to buffer overflow + kmod 26 ======= diff --git a/configure.ac b/configure.ac index ee72283..4a65d6b 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ AC_PREREQ(2.64) AC_INIT([kmod], - [26], + [27], [linux-modules@vger.kernel.org], [kmod], [http://git.kernel.org/?p=utils/kernel/kmod/kmod.git]) @@ -17,7 +17,6 @@ AM_MAINTAINER_MODE([enable]) AM_INIT_AUTOMAKE([check-news foreign 1.11 silent-rules tar-pax no-dist-gzip dist-xz subdir-objects color-tests parallel-tests]) AM_SILENT_RULES([yes]) LT_INIT([disable-static pic-only]) -DOLT AS_IF([test "x$enable_static" = "xyes"], [AC_MSG_ERROR([--enable-static is not supported by kmod])]) AS_IF([test "x$enable_largefile" = "xno"], [AC_MSG_ERROR([--disable-largefile is not supported by kmod])]) @@ -110,12 +109,12 @@ AC_ARG_WITH([openssl], AS_HELP_STRING([--with-openssl], [handle PKCS7 signatures @<:@default=disabled@:>@]), [], [with_openssl=no]) AS_IF([test "x$with_openssl" != "xno"], [ - PKG_CHECK_MODULES([openssl], [openssl >= 1.1.0]) + PKG_CHECK_MODULES([libcrypto], [libcrypto >= 1.1.0]) AC_DEFINE([ENABLE_OPENSSL], [1], [Enable openssl for modinfo.]) ], [ AC_MSG_NOTICE([openssl support not requested]) ]) -CC_FEATURE_APPEND([with_features], [with_openssl], [OPENSSL]) +CC_FEATURE_APPEND([with_features], [with_openssl], [LIBCRYPTO]) AC_ARG_WITH([bashcompletiondir], AS_HELP_STRING([--with-bashcompletiondir=DIR], [Bash completions directory]), diff --git a/libkmod/libkmod-builtin.c b/libkmod/libkmod-builtin.c new file mode 100644 index 0000000..aaec5dd --- /dev/null +++ b/libkmod/libkmod-builtin.c @@ -0,0 +1,329 @@ +/* + * libkmod - interface to kernel built-in modules + * + * Copyright (C) 2019 Alexey Gladkov <gladkov.alexey@gmail.com> + * + * This library 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <sys/types.h> +#include <sys/stat.h> + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include "libkmod.h" +#include "libkmod-internal.h" + +#define MODULES_BUILTIN_MODINFO "modules.builtin.modinfo" + +struct kmod_builtin_iter { + struct kmod_ctx *ctx; + + // The file descriptor. + int file; + + // The total size in bytes. + ssize_t size; + + // The offset of current module. + off_t pos; + + // The offset at which the next module is located. + off_t next; + + // Number of strings in the current block. + ssize_t nstrings; + + // Internal buffer and its size. + size_t bufsz; + char *buf; +}; + +struct kmod_builtin_iter *kmod_builtin_iter_new(struct kmod_ctx *ctx) +{ + char path[PATH_MAX]; + int file, sv_errno; + struct stat sb; + struct kmod_builtin_iter *iter = NULL; + const char *dirname = kmod_get_dirname(ctx); + size_t len = strlen(dirname); + + file = -1; + + if ((len + 1 + strlen(MODULES_BUILTIN_MODINFO) + 1) >= PATH_MAX) { + sv_errno = ENAMETOOLONG; + goto fail; + } + + snprintf(path, PATH_MAX, "%s/%s", dirname, MODULES_BUILTIN_MODINFO); + + file = open(path, O_RDONLY|O_CLOEXEC); + if (file < 0) { + sv_errno = errno; + goto fail; + } + + if (fstat(file, &sb) < 0) { + sv_errno = errno; + goto fail; + } + + iter = malloc(sizeof(*iter)); + if (!iter) { + sv_errno = ENOMEM; + goto fail; + } + + iter->ctx = ctx; + iter->file = file; + iter->size = sb.st_size; + iter->nstrings = 0; + iter->pos = 0; + iter->next = 0; + iter->bufsz = 0; + iter->buf = NULL; + + return iter; +fail: + if (file >= 0) + close(file); + + errno = sv_errno; + + return iter; +} + +void kmod_builtin_iter_free(struct kmod_builtin_iter *iter) +{ + close(iter->file); + free(iter->buf); + free(iter); +} + +static off_t get_string(struct kmod_builtin_iter *iter, off_t offset, + char **line, size_t *size) +{ + int sv_errno; + char *nullp = NULL; + size_t linesz = 0; + + while (!nullp) { + char buf[BUFSIZ]; + ssize_t sz; + size_t partsz; + + sz = pread(iter->file, buf, BUFSIZ, offset); + if (sz < 0) { + sv_errno = errno; + goto fail; + } else if (sz == 0) { + offset = 0; + break; + } + + nullp = memchr(buf, '\0', (size_t) sz); + partsz = (size_t)((nullp) ? (nullp - buf) + 1 : sz); + offset += (off_t) partsz; + + if (iter->bufsz < linesz + partsz) { + iter->bufsz = linesz + partsz; + iter->buf = realloc(iter->buf, iter->bufsz); + + if (!iter->buf) { + sv_errno = errno; + goto fail; + } + } + + strncpy(iter->buf + linesz, buf, partsz); + linesz += partsz; + } + + if (linesz) { + *line = iter->buf; + *size = linesz; + } + + return offset; +fail: + errno = sv_errno; + return -1; +} + +bool kmod_builtin_iter_next(struct kmod_builtin_iter *iter) +{ + char *line, *modname; + size_t linesz; + off_t pos, offset, modlen; + + modname = NULL; + + iter->nstrings = 0; + offset = pos = iter->next; + + while (offset < iter->size) { + char *dot; + off_t len; + + offset = get_string(iter, pos, &line, &linesz); + if (offset <= 0) { + if (offset) + ERR(iter->ctx, "get_string: %s\n", strerror(errno)); + pos = iter->size; + break; + } + + dot = strchr(line, '.'); + if (!dot) { + ERR(iter->ctx, "kmod_builtin_iter_next: unexpected string without modname prefix\n"); + pos = iter->size; + break; + } + + len = dot - line; + + if (!modname) { + modname = strdup(line); + modlen = len; + } else if (modlen != len || strncmp(modname, line, len)) { + break; + } + + iter->nstrings++; + pos = offset; + } + + iter->pos = iter->next; + iter->next = pos; + + free(modname); + + return (iter->pos < iter->size); +} + +bool kmod_builtin_iter_get_modname(struct kmod_builtin_iter *iter, + char modname[static PATH_MAX]) +{ + int sv_errno; + char *line, *dot; + size_t linesz, len; + off_t offset; + + if (iter->pos == iter->size) + return false; + + line = NULL; + + offset = get_string(iter, iter->pos, &line, &linesz); + if (offset <= 0) { + sv_errno = errno; + if (offset) + ERR(iter->ctx, "get_string: %s\n", strerror(errno)); + goto fail; + } + + dot = strchr(line, '.'); + if (!dot) { + sv_errno = errno; + ERR(iter->ctx, "kmod_builtin_iter_get_modname: unexpected string without modname prefix\n"); + goto fail; + } + + len = dot - line; + + if (len > PATH_MAX) { + sv_errno = ENAMETOOLONG; + goto fail; + } + + strncpy(modname, line, len); + modname[len] = '\0'; + + return true; +fail: + errno = sv_errno; + return false; +} + +/* array will be allocated with strings in a single malloc, just free *array */ +ssize_t kmod_builtin_get_modinfo(struct kmod_ctx *ctx, const char *modname, + char ***modinfo) +{ + ssize_t count = 0; + char *s, *line = NULL; + size_t i, n, linesz, modlen, size; + off_t pos, offset; + + char *name = NULL; + char buf[PATH_MAX]; + + struct kmod_builtin_iter *iter = kmod_builtin_iter_new(ctx); + + if (!iter) + return -errno; + + while (!name && kmod_builtin_iter_next(iter)) { + if (!kmod_builtin_iter_get_modname(iter, buf)) { + count = -errno; + goto fail; + } + + if (strcmp(modname, buf)) + continue; + + name = buf; + } + + if (!name) { + count = -ENOSYS; + goto fail; + } + + modlen = strlen(modname) + 1; + count = iter->nstrings; + size = iter->next - iter->pos - (modlen * count); + + *modinfo = malloc(size + sizeof(char *) * (count + 1)); + if (!*modinfo) { + count = -errno; + goto fail; + } + + s = (char *)(*modinfo + count + 1); + i = 0; + + n = 0; + offset = pos = iter->pos; + + while (offset < iter->next) { + offset = get_string(iter, pos, &line, &linesz); + if (offset <= 0) { + count = (offset) ? -errno : -EOF; + goto fail; + } + + strcpy(s + i, line + modlen); + (*modinfo)[n++] = s + i; + i += linesz - modlen; + + pos = offset; + } +fail: + kmod_builtin_iter_free(iter); + return count; +} diff --git a/libkmod/libkmod-config.c b/libkmod/libkmod-config.c index aaac0a1..7b62367 100644 --- a/libkmod/libkmod-config.c +++ b/libkmod/libkmod-config.c @@ -335,6 +335,7 @@ static int kmod_config_add_softdep(struct kmod_config *config, n_pre = 0; n_post = 0; mode = S_NONE; + was_space = false; for (p = s = line; ; s++) { size_t plen; diff --git a/libkmod/libkmod-internal.h b/libkmod/libkmod-internal.h index a65ddd1..b22ac2a 100644 --- a/libkmod/libkmod-internal.h +++ b/libkmod/libkmod-internal.h @@ -89,6 +89,7 @@ int kmod_lookup_alias_from_config(struct kmod_ctx *ctx, const char *name, struct int kmod_lookup_alias_from_symbols_file(struct kmod_ctx *ctx, const char *name, struct kmod_list **list) __attribute__((nonnull(1, 2, 3))); int kmod_lookup_alias_from_aliases_file(struct kmod_ctx *ctx, const char *name, struct kmod_list **list) __attribute__((nonnull(1, 2, 3))); int kmod_lookup_alias_from_moddep_file(struct kmod_ctx *ctx, const char *name, struct kmod_list **list) __attribute__((nonnull(1, 2, 3))); +int kmod_lookup_alias_from_kernel_builtin_file(struct kmod_ctx *ctx, const char *name, struct kmod_list **list) __attribute__((nonnull(1, 2, 3))); int kmod_lookup_alias_from_builtin_file(struct kmod_ctx *ctx, const char *name, struct kmod_list **list) __attribute__((nonnull(1, 2, 3))); bool kmod_lookup_alias_is_builtin(struct kmod_ctx *ctx, const char *name) __attribute__((nonnull(1, 2))); int kmod_lookup_alias_from_commands(struct kmod_ctx *ctx, const char *name, struct kmod_list **list) __attribute__((nonnull(1, 2, 3))); @@ -145,6 +146,7 @@ void kmod_module_set_visited(struct kmod_module *mod, bool visited) __attribute_ void kmod_module_set_builtin(struct kmod_module *mod, bool builtin) __attribute__((nonnull((1)))); void kmod_module_set_required(struct kmod_module *mod, bool required) __attribute__((nonnull(1))); bool kmod_module_is_builtin(struct kmod_module *mod) __attribute__((nonnull(1))); +int kmod_module_get_builtin(struct kmod_ctx *ctx, struct kmod_list **list) __attribute__((nonnull(1, 2))); /* libkmod-file.c */ struct kmod_file *kmod_file_open(const struct kmod_ctx *ctx, const char *filename) _must_check_ __attribute__((nonnull(1,2))); @@ -193,3 +195,11 @@ struct kmod_signature_info { }; bool kmod_module_signature_info(const struct kmod_file *file, struct kmod_signature_info *sig_info) _must_check_ __attribute__((nonnull(1, 2))); void kmod_module_signature_info_free(struct kmod_signature_info *sig_info) __attribute__((nonnull)); + +/* libkmod-builtin.c */ +struct kmod_builtin_iter; +struct kmod_builtin_iter *kmod_builtin_iter_new(struct kmod_ctx *ctx) __attribute__((nonnull(1))); +void kmod_builtin_iter_free(struct kmod_builtin_iter *iter) __attribute__((nonnull(1))); +bool kmod_builtin_iter_next(struct kmod_builtin_iter *iter) __attribute__((nonnull(1))); +bool kmod_builtin_iter_get_modname(struct kmod_builtin_iter *iter, char modname[static PATH_MAX]) __attribute__((nonnull(1, 2))); +ssize_t kmod_builtin_get_modinfo(struct kmod_ctx *ctx, const char *modname, char ***modinfo) __attribute__((nonnull(1, 2, 3))); diff --git a/libkmod/libkmod-module.c b/libkmod/libkmod-module.c index bffe715..714ee21 100644 --- a/libkmod/libkmod-module.c +++ b/libkmod/libkmod-module.c @@ -575,10 +575,16 @@ KMOD_EXPORT int kmod_module_new_from_lookup(struct kmod_ctx *ctx, err = kmod_lookup_alias_from_aliases_file(ctx, alias, list); CHECK_ERR_AND_FINISH(err, fail, list, finish); - DBG(ctx, "lookup modules.builtin %s\n", alias); - err = kmod_lookup_alias_from_builtin_file(ctx, alias, list); + DBG(ctx, "lookup modules.builtin.modinfo %s\n", alias); + err = kmod_lookup_alias_from_kernel_builtin_file(ctx, alias, list); CHECK_ERR_AND_FINISH(err, fail, list, finish); + if (err == 0) { + DBG(ctx, "lookup modules.builtin %s\n", alias); + err = kmod_lookup_alias_from_builtin_file(ctx, alias, list); + CHECK_ERR_AND_FINISH(err, fail, list, finish); + } + finish: DBG(ctx, "lookup %s=%d, list=%p\n", alias, err, *list); return err; @@ -974,14 +980,19 @@ static int command_do(struct kmod_module *mod, const char *type, err = system(cmd); unsetenv("MODPROBE_MODULE"); - if (err == -1 || WEXITSTATUS(err)) { - ERR(mod->ctx, "Error running %s command for %s\n", - type, modname); - if (err != -1) - err = -WEXITSTATUS(err); + if (err == -1) { + ERR(mod->ctx, "Could not run %s command '%s' for module %s: %m\n", + type, cmd, modname); + return -EINVAL; } - return err; + if (WEXITSTATUS(err)) { + ERR(mod->ctx, "Error running %s command '%s' for module %s: retcode %d\n", + type, cmd, modname, WEXITSTATUS(err)); + return -EINVAL; + } + + return 0; } struct probe_insert_cb { @@ -2280,13 +2291,22 @@ KMOD_EXPORT int kmod_module_get_info(const struct kmod_module *mod, struct kmod_ assert(*list == NULL); - elf = kmod_module_get_elf(mod); - if (elf == NULL) - return -errno; + /* remove const: this can only change internal state */ + if (kmod_module_is_builtin((struct kmod_module *)mod)) { + count = kmod_builtin_get_modinfo(mod->ctx, + kmod_module_get_name(mod), + &strings); + if (count < 0) + return count; + } else { + elf = kmod_module_get_elf(mod); + if (elf == NULL) + return -errno; - count = kmod_elf_get_strings(elf, ".modinfo", &strings); - if (count < 0) - return count; + count = kmod_elf_get_strings(elf, ".modinfo", &strings); + if (count < 0) + return count; + } for (i = 0; i < count; i++) { struct kmod_list *n; @@ -2310,7 +2330,7 @@ KMOD_EXPORT int kmod_module_get_info(const struct kmod_module *mod, struct kmod_ goto list_error; } - if (kmod_module_signature_info(mod->file, &sig_info)) { + if (mod->file && kmod_module_signature_info(mod->file, &sig_info)) { struct kmod_list *n; n = kmod_module_info_append(list, "sig_id", strlen("sig_id"), @@ -2866,3 +2886,43 @@ KMOD_EXPORT void kmod_module_dependency_symbols_free_list(struct kmod_list *list list = kmod_list_remove(list); } } + +/** + * kmod_module_get_builtin: + * @ctx: kmod library context + * @list: where to save the builtin module list + * + * Returns: 0 on success or < 0 otherwise. + */ +int kmod_module_get_builtin(struct kmod_ctx *ctx, struct kmod_list **list) +{ + struct kmod_builtin_iter *iter; + int err = 0; + + iter = kmod_builtin_iter_new(ctx); + if (!iter) + return -errno; + + while (kmod_builtin_iter_next(iter)) { + struct kmod_module *mod = NULL; + char modname[PATH_MAX]; + + if (!kmod_builtin_iter_get_modname(iter, modname)) { + err = -errno; + goto fail; + } + + kmod_module_new_from_name(ctx, modname, &mod); + kmod_module_set_builtin(mod, true); + + *list = kmod_list_append(*list, mod); + } + + kmod_builtin_iter_free(iter); + return err; +fail: + kmod_builtin_iter_free(iter); + kmod_module_unref_list(*list); + *list = NULL; + return err; +} diff --git a/libkmod/libkmod-signature.c b/libkmod/libkmod-signature.c index 27d0a8f..9877cf3 100644 --- a/libkmod/libkmod-signature.c +++ b/libkmod/libkmod-signature.c @@ -19,7 +19,7 @@ #include <inttypes.h> #ifdef ENABLE_OPENSSL -#include <openssl/cms.h> +#include <openssl/pkcs7.h> #include <openssl/ssl.h> #endif #include <stdio.h> @@ -121,7 +121,7 @@ static bool fill_default(const char *mem, off_t size, #ifdef ENABLE_OPENSSL struct pkcs7_private { - CMS_ContentInfo *cms; + PKCS7 *pkcs7; unsigned char *key_id; BIGNUM *sno; }; @@ -131,7 +131,7 @@ static void pkcs7_free(void *s) struct kmod_signature_info *si = s; struct pkcs7_private *pvt = si->private; - CMS_ContentInfo_free(pvt->cms); + PKCS7_free(pvt->pkcs7); BN_free(pvt->sno); free(pvt->key_id); free(pvt); @@ -196,11 +196,10 @@ static bool fill_pkcs7(const char *mem, off_t size, struct kmod_signature_info *sig_info) { const char *pkcs7_raw; - CMS_ContentInfo *cms; - STACK_OF(CMS_SignerInfo) *sis; - CMS_SignerInfo *si; - int rc; - ASN1_OCTET_STRING *key_id; + PKCS7 *pkcs7; + STACK_OF(PKCS7_SIGNER_INFO) *sis; + PKCS7_SIGNER_INFO *si; + PKCS7_ISSUER_AND_SERIAL *is; X509_NAME *issuer; ASN1_INTEGER *sno; ASN1_OCTET_STRING *sig; @@ -219,31 +218,33 @@ static bool fill_pkcs7(const char *mem, off_t size, in = BIO_new_mem_buf(pkcs7_raw, sig_len); - cms = d2i_CMS_bio(in, NULL); - if (cms == NULL) { + pkcs7 = d2i_PKCS7_bio(in, NULL); + if (pkcs7 == NULL) { BIO_free(in); return false; } BIO_free(in); - sis = CMS_get0_SignerInfos(cms); + sis = PKCS7_get_signer_info(pkcs7); if (sis == NULL) goto err; - si = sk_CMS_SignerInfo_value(sis, 0); + si = sk_PKCS7_SIGNER_INFO_value(sis, 0); if (si == NULL) goto err; - rc = CMS_SignerInfo_get0_signer_id(si, &key_id, &issuer, &sno); - if (rc == 0) + is = si->issuer_and_serial; + if (is == NULL) goto err; + issuer = is->issuer; + sno = is->serial; - sig = CMS_SignerInfo_get0_signature(si); + sig = si->enc_digest; if (sig == NULL) goto err; - CMS_SignerInfo_get0_algs(si, NULL, NULL, &dig_alg, &sig_alg); + PKCS7_SIGNER_INFO_get0_algs(si, NULL, &dig_alg, &sig_alg); sig_info->sig = (const char *)ASN1_STRING_get0_data(sig); sig_info->sig_len = ASN1_STRING_length(sig); @@ -276,7 +277,7 @@ static bool fill_pkcs7(const char *mem, off_t size, if (pvt == NULL) goto err3; - pvt->cms = cms; + pvt->pkcs7 = pkcs7; pvt->key_id = key_id_str; pvt->sno = sno_bn; sig_info->private = pvt; @@ -289,7 +290,7 @@ err3: err2: BN_free(sno_bn); err: - CMS_ContentInfo_free(cms); + PKCS7_free(pkcs7); return false; } diff --git a/libkmod/libkmod.c b/libkmod/libkmod.c index 69fe431..c9d9e2a 100644 --- a/libkmod/libkmod.c +++ b/libkmod/libkmod.c @@ -57,6 +57,7 @@ static struct _index_files { [KMOD_INDEX_MODULES_DEP] = { .fn = "modules.dep", .prefix = "" }, [KMOD_INDEX_MODULES_ALIAS] = { .fn = "modules.alias", .prefix = "alias " }, [KMOD_INDEX_MODULES_SYMBOL] = { .fn = "modules.symbols", .prefix = "alias "}, + [KMOD_INDEX_MODULES_BUILTIN_ALIAS] = { .fn = "modules.builtin.alias", .prefix = "" }, [KMOD_INDEX_MODULES_BUILTIN] = { .fn = "modules.builtin", .prefix = ""}, }; @@ -522,6 +523,30 @@ static char *lookup_builtin_file(struct kmod_ctx *ctx, const char *name) return line; } +int kmod_lookup_alias_from_kernel_builtin_file(struct kmod_ctx *ctx, + const char *name, + struct kmod_list **list) +{ + struct kmod_list *l; + int ret = kmod_lookup_alias_from_alias_bin(ctx, + KMOD_INDEX_MODULES_BUILTIN_ALIAS, + name, list); + if (ret > 0) { + kmod_list_foreach(l, *list) { + struct kmod_module *mod = l->data; + kmod_module_set_builtin(mod, true); + } + } else if (ret == -ENOSYS) { + /* + * If the system does not support this yet, then + * there is no need to return an error. + */ + ret = 0; + } + + return ret; +} + int kmod_lookup_alias_from_builtin_file(struct kmod_ctx *ctx, const char *name, struct kmod_list **list) { diff --git a/libkmod/libkmod.h b/libkmod/libkmod.h index 352627e..3cab2e5 100644 --- a/libkmod/libkmod.h +++ b/libkmod/libkmod.h @@ -70,6 +70,7 @@ enum kmod_index { KMOD_INDEX_MODULES_DEP = 0, KMOD_INDEX_MODULES_ALIAS, KMOD_INDEX_MODULES_SYMBOL, + KMOD_INDEX_MODULES_BUILTIN_ALIAS, KMOD_INDEX_MODULES_BUILTIN, /* Padding to make sure enum is not mapped to char */ _KMOD_INDEX_PAD = 1U << 31, diff --git a/m4/dolt.m4 b/m4/dolt.m4 deleted file mode 100644 index 775a572..0000000 --- a/m4/dolt.m4 +++ /dev/null @@ -1,181 +0,0 @@ -dnl dolt, a replacement for libtool -dnl Copyright © 2007-2010 Josh Triplett <josh@joshtriplett.org> -dnl Copying and distribution of this file, with or without modification, -dnl are permitted in any medium without royalty provided the copyright -dnl notice and this notice are preserved. -dnl -dnl To use dolt, invoke the DOLT macro immediately after the libtool macros. -dnl Optionally, copy this file into acinclude.m4, to avoid the need to have it -dnl installed when running autoconf on your project. - -AC_DEFUN([DOLT], [ -AC_REQUIRE([AC_CANONICAL_HOST]) -# dolt, a replacement for libtool -# Josh Triplett <josh@freedesktop.org> -AC_PATH_PROG([DOLT_BASH], [bash]) -AC_MSG_CHECKING([if dolt supports this host]) -dolt_supported=yes -AS_IF([test x$DOLT_BASH = x], [dolt_supported=no]) -AS_IF([test x$GCC != xyes], [dolt_supported=no]) - -AS_CASE([$host], - [*-*-linux*|*-*-freebsd*], [pic_options='-fPIC'], - [*-apple-darwin*], [pic_options='-fno-common'], - [*mingw*|*nacl*], [pic_options=''] - [*], [dolt_supported=no] -) -AS_IF([test x$dolt_supported = xno], [ - AC_MSG_RESULT([no, falling back to libtool]) - LTCOMPILE='$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(COMPILE)' - LTCXXCOMPILE='$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXXCOMPILE)' - m4_pattern_allow([AM_V_lt]) -], [ - AC_MSG_RESULT([yes, replacing libtool]) - -dnl Start writing out doltcompile. - cat <<__DOLTCOMPILE__EOF__ >doltcompile -#!$DOLT_BASH -__DOLTCOMPILE__EOF__ - cat <<'__DOLTCOMPILE__EOF__' >>doltcompile -args=("$[]@") -for ((arg=0; arg<${#args@<:@@@:>@}; arg++)) ; do - if test x"${args@<:@$arg@:>@}" = x-o ; then - objarg=$((arg+1)) - break - fi -done -if test x$objarg = x ; then - echo 'Error: no -o on compiler command line' 1>&2 - exit 1 -fi -lo="${args@<:@$objarg@:>@}" -obj="${lo%.lo}" -if test x"$lo" = x"$obj" ; then - echo "Error: libtool object file name \"$lo\" does not end in .lo" 1>&2 - exit 1 -fi -objbase="${obj##*/}" -__DOLTCOMPILE__EOF__ - -dnl Write out shared compilation code. - if test x$enable_shared = xyes; then - cat <<'__DOLTCOMPILE__EOF__' >>doltcompile -libobjdir="${obj%$objbase}.libs" -if test ! -d "$libobjdir" ; then - mkdir_out="$(mkdir "$libobjdir" 2>&1)" - mkdir_ret=$? - if test "$mkdir_ret" -ne 0 && test ! -d "$libobjdir" ; then - echo "$mkdir_out" 1>&2 - exit $mkdir_ret - fi -fi -pic_object="$libobjdir/$objbase.o" -args@<:@$objarg@:>@="$pic_object" -__DOLTCOMPILE__EOF__ - cat <<__DOLTCOMPILE__EOF__ >>doltcompile - pic_options="$pic_options" - if test x\$passthrough = xtrue; then - pic_options="" - fi -__DOLTCOMPILE__EOF__ - cat <<'__DOLTCOMPILE__EOF__' >>doltcompile -"${args@<:@@@:>@}" $pic_options -DPIC || exit $? -__DOLTCOMPILE__EOF__ - fi - -dnl Write out static compilation code. -dnl Avoid duplicate compiler output if also building shared objects. - if test x$enable_static = xyes; then - cat <<'__DOLTCOMPILE__EOF__' >>doltcompile -non_pic_object="$obj.o" -args@<:@$objarg@:>@="$non_pic_object" -__DOLTCOMPILE__EOF__ - if test x$enable_shared = xyes; then - cat <<'__DOLTCOMPILE__EOF__' >>doltcompile -"${args@<:@@@:>@}" >/dev/null 2>&1 || exit $? -__DOLTCOMPILE__EOF__ - else - cat <<'__DOLTCOMPILE__EOF__' >>doltcompile -"${args@<:@@@:>@}" || exit $? -__DOLTCOMPILE__EOF__ - fi - fi - -dnl Write out the code to write the .lo file. -dnl The second line of the .lo file must match "^# Generated by .*libtool" - cat <<'__DOLTCOMPILE__EOF__' >>doltcompile -{ -echo "# $lo - a libtool object file" -echo "# Generated by doltcompile, not libtool" -__DOLTCOMPILE__EOF__ - - if test x$enable_shared = xyes; then - cat <<'__DOLTCOMPILE__EOF__' >>doltcompile -echo "pic_object='.libs/${objbase}.o'" -__DOLTCOMPILE__EOF__ - else - cat <<'__DOLTCOMPILE__EOF__' >>doltcompile -echo pic_object=none -__DOLTCOMPILE__EOF__ - fi - - if test x$enable_static = xyes; then - cat <<'__DOLTCOMPILE__EOF__' >>doltcompile -echo "non_pic_object='${objbase}.o'" -__DOLTCOMPILE__EOF__ - else - cat <<'__DOLTCOMPILE__EOF__' >>doltcompile -echo non_pic_object=none -__DOLTCOMPILE__EOF__ - fi - - cat <<'__DOLTCOMPILE__EOF__' >>doltcompile -} > "$lo" -__DOLTCOMPILE__EOF__ - -dnl Done writing out doltcompile; substitute it for libtool compilation. - chmod +x doltcompile - LTCOMPILE='$(top_builddir)/doltcompile $(COMPILE)' - LTCXXCOMPILE='$(top_builddir)/doltcompile $(CXXCOMPILE)' - -dnl automake ignores LTCOMPILE and LTCXXCOMPILE when it has separate CFLAGS for -dnl a target, so write out a libtool wrapper to handle that case. -dnl Note that doltlibtool does not handle inferred tags or option arguments -dnl without '=', because automake does not use them. - cat <<__DOLTLIBTOOL__EOF__ > doltlibtool -#!$DOLT_BASH -__DOLTLIBTOOL__EOF__ - cat <<'__DOLTLIBTOOL__EOF__' >>doltlibtool -top_builddir_slash="${0%%doltlibtool}" -: ${top_builddir_slash:=./} -args=() -modeok=false -tagok=false -for arg in "$[]@"; do - case "$arg" in - --mode=compile) modeok=true ;; - --tag=CC|--tag=CXX) tagok=true ;; - --tag=disable-static) tagok=true ;; - --tag=ASM|--tag=YASM) tagok=true; passthrough=true;; - --silent|--quiet) ;; - *) args@<:@${#args[@]}@:>@="$arg" ;; - esac -done -if $modeok && $tagok ; then - . ${top_builddir_slash}doltcompile "${args@<:@@@:>@}" -else - exec ${top_builddir_slash}libtool "$[]@" -fi -__DOLTLIBTOOL__EOF__ - -dnl Done writing out doltlibtool; substitute it for libtool. - chmod +x doltlibtool - LIBTOOL='$(top_builddir)/doltlibtool' - -DOLT_CLEANFILES="doltlibtool doltcompile" -AC_SUBST(DOLT_CLEANFILES) -]) -AC_SUBST(LTCOMPILE) -AC_SUBST(LTCXXCOMPILE) -# end dolt -]) diff --git a/testsuite/module-playground/.gitignore b/testsuite/module-playground/.gitignore index 6767e0e..db63fe4 100644 --- a/testsuite/module-playground/.gitignore +++ b/testsuite/module-playground/.gitignore @@ -4,9 +4,12 @@ !cache/*.ko *.mod.c .tmp_versions +*.mod +*.a +*.cmd + modules.order Module.symvers - mod-simple-x86_64.c mod-simple-i386.c mod-simple-sparc64.c diff --git a/tools/depmod.c b/tools/depmod.c index 391afe9..fbbce10 100644 --- a/tools/depmod.c +++ b/tools/depmod.c @@ -2402,6 +2402,68 @@ static int output_devname(struct depmod *depmod, FILE *out) return 0; } +static int output_builtin_alias_bin(struct depmod *depmod, FILE *out) +{ + int ret = 0, count = 0; + struct index_node *idx; + struct kmod_list *l, *builtin = NULL; + + idx = index_create(); + + if (idx == NULL) { + ret = -ENOMEM; + goto fail; + } + + ret = kmod_module_get_builtin(depmod->ctx, &builtin); + if (ret < 0) { + if (ret == -ENOENT) + ret = 0; + goto fail; + } + + kmod_list_foreach(l, builtin) { + struct kmod_list *ll, *info_list = NULL; + struct kmod_module *mod = l->data; + const char *modname = kmod_module_get_name(mod); + + ret = kmod_module_get_info(mod, &info_list); + if (ret < 0) + goto fail; + + kmod_list_foreach(ll, info_list) { + char alias[PATH_MAX]; + const char *key = kmod_module_info_get_key(ll); + const char *value = kmod_module_info_get_value(ll); + + if (!streq(key, "alias")) + continue; + + alias[0] = '\0'; + if (alias_normalize(value, alias, NULL) < 0) { + WRN("Unmatched bracket in %s\n", value); + continue; + } + + index_insert(idx, alias, modname, 0); + } + + kmod_module_info_free_list(info_list); + + index_insert(idx, modname, modname, 0); + count++; + } + + if (count) + index_write(idx, out); + index_destroy(idx); +fail: + if (builtin) + kmod_module_unref_list(builtin); + + return ret; +} + static int depmod_output(struct depmod *depmod, FILE *out) { static const struct depfile { @@ -2416,6 +2478,7 @@ static int depmod_output(struct depmod *depmod, FILE *out) { "modules.symbols", output_symbols }, { "modules.symbols.bin", output_symbols_bin }, { "modules.builtin.bin", output_builtin_bin }, + { "modules.builtin.alias.bin", output_builtin_alias_bin }, { "modules.devname", output_devname }, { } }; diff --git a/tools/modinfo.c b/tools/modinfo.c index 86ac04b..0231bb0 100644 --- a/tools/modinfo.c +++ b/tools/modinfo.c @@ -172,18 +172,33 @@ static int modinfo_do(struct kmod_module *mod) { struct kmod_list *l, *list = NULL; struct param *params = NULL; - int err; + int err, is_builtin; + const char *filename = kmod_module_get_path(mod); + + is_builtin = (filename == NULL); + + if (is_builtin) { + printf("%-16s%s%c", "name:", kmod_module_get_name(mod), separator); + filename = "(builtin)"; + } if (field != NULL && streq(field, "filename")) { - printf("%s%c", kmod_module_get_path(mod), separator); + printf("%s%c", filename, separator); return 0; } else if (field == NULL) { printf("%-16s%s%c", "filename:", - kmod_module_get_path(mod), separator); + filename, separator); } err = kmod_module_get_info(mod, &list); if (err < 0) { + if (is_builtin && err == -ENOENT) { + /* + * This is an old kernel that does not have a file + * with information about built-in modules. + */ + return 0; + } ERR("could not get modinfo from '%s': %s\n", kmod_module_get_name(mod), strerror(-err)); return err; @@ -276,7 +291,7 @@ static int modinfo_path_do(struct kmod_ctx *ctx, const char *path) static int modinfo_alias_do(struct kmod_ctx *ctx, const char *alias) { - struct kmod_list *l, *filtered, *list = NULL; + struct kmod_list *l, *list = NULL; int err = kmod_module_new_from_lookup(ctx, alias, &list); if (err < 0) { ERR("Module alias %s not found.\n", alias); @@ -288,26 +303,14 @@ static int modinfo_alias_do(struct kmod_ctx *ctx, const char *alias) return -ENOENT; } - err = kmod_module_apply_filter(ctx, KMOD_FILTER_BUILTIN, list, &filtered); - kmod_module_unref_list(list); - if (err < 0) { - ERR("Failed to filter list: %m\n"); - return err; - } - - if (filtered == NULL) { - ERR("Module %s not found.\n", alias); - return -ENOENT; - } - - kmod_list_foreach(l, filtered) { + kmod_list_foreach(l, list) { struct kmod_module *mod = kmod_module_get_module(l); int r = modinfo_do(mod); kmod_module_unref(mod); if (r < 0) err = r; } - kmod_module_unref_list(filtered); + kmod_module_unref_list(list); return err; } diff --git a/tools/modprobe.c b/tools/modprobe.c index a9e2331..9387537 100644 --- a/tools/modprobe.c +++ b/tools/modprobe.c @@ -353,7 +353,9 @@ static int rmmod_do_remove_module(struct kmod_module *mod) return err; } -static int rmmod_do_module(struct kmod_module *mod, bool do_dependencies); +#define RMMOD_FLAG_DO_DEPENDENCIES 0x1 +#define RMMOD_FLAG_IGNORE_BUILTIN 0x2 +static int rmmod_do_module(struct kmod_module *mod, int flags); static int rmmod_do_deps_list(struct kmod_list *list, bool stop_on_errors) { @@ -361,7 +363,7 @@ static int rmmod_do_deps_list(struct kmod_list *list, bool stop_on_errors) kmod_list_foreach_reverse(l, list) { struct kmod_module *m = kmod_module_get_module(l); - int r = rmmod_do_module(m, false); + int r = rmmod_do_module(m, RMMOD_FLAG_IGNORE_BUILTIN); kmod_module_unref(m); if (r < 0 && stop_on_errors) @@ -371,7 +373,7 @@ static int rmmod_do_deps_list(struct kmod_list *list, bool stop_on_errors) return 0; } -static int rmmod_do_module(struct kmod_module *mod, bool do_dependencies) +static int rmmod_do_module(struct kmod_module *mod, int flags) { const char *modname = kmod_module_get_name(mod); struct kmod_list *pre = NULL, *post = NULL; @@ -401,15 +403,19 @@ static int rmmod_do_module(struct kmod_module *mod, bool do_dependencies) } goto error; } else if (state == KMOD_MODULE_BUILTIN) { - LOG("Module %s is builtin.\n", modname); - err = -ENOENT; + if (flags & RMMOD_FLAG_IGNORE_BUILTIN) { + err = 0; + } else { + LOG("Module %s is builtin.\n", modname); + err = -ENOENT; + } goto error; } } rmmod_do_deps_list(post, false); - if (do_dependencies && remove_dependencies) { + if ((flags & RMMOD_FLAG_DO_DEPENDENCIES) && remove_dependencies) { struct kmod_list *deps = kmod_module_get_dependencies(mod); err = rmmod_do_deps_list(deps, true); @@ -462,7 +468,7 @@ static int rmmod(struct kmod_ctx *ctx, const char *alias) kmod_list_foreach(l, list) { struct kmod_module *mod = kmod_module_get_module(l); - err = rmmod_do_module(mod, true); + err = rmmod_do_module(mod, RMMOD_FLAG_DO_DEPENDENCIES); kmod_module_unref(mod); if (err < 0) break; diff --git a/tools/remove.c b/tools/remove.c index 07e2cc0..387ef0e 100644 --- a/tools/remove.c +++ b/tools/remove.c @@ -44,7 +44,7 @@ static void help(void) static int check_module_inuse(struct kmod_module *mod) { struct kmod_list *holders; - int state; + int state, ret; state = kmod_module_get_initstate(mod); @@ -74,12 +74,15 @@ static int check_module_inuse(struct kmod_module *mod) { return -EBUSY; } - if (kmod_module_get_refcnt(mod) != 0) { + ret = kmod_module_get_refcnt(mod); + if (ret > 0) { ERR("Module %s is in use\n", kmod_module_get_name(mod)); return -EBUSY; + } else if (ret == -ENOENT) { + ERR("Module unloading is not supported\n"); } - return 0; + return ret; } static int do_remove(int argc, char *argv[]) diff --git a/tools/rmmod.c b/tools/rmmod.c index bcdea4c..3942e7b 100644 --- a/tools/rmmod.c +++ b/tools/rmmod.c @@ -63,7 +63,7 @@ static void help(void) static int check_module_inuse(struct kmod_module *mod) { struct kmod_list *holders; - int state; + int state, ret; state = kmod_module_get_initstate(mod); @@ -93,12 +93,15 @@ static int check_module_inuse(struct kmod_module *mod) { return -EBUSY; } - if (kmod_module_get_refcnt(mod) != 0) { + ret = kmod_module_get_refcnt(mod); + if (ret > 0) { ERR("Module %s is in use\n", kmod_module_get_name(mod)); return -EBUSY; + } else if (ret == -ENOENT) { + ERR("Module unloading is not supported\n"); } - return 0; + return ret; } static int do_rmmod(int argc, char *argv[]) |