*.o
*.gcda
*.gcno
+*.pc
/*.tar.xz
/*.md5sum
+/*.mbx
+/*.cover
.deps/
.libs/
/Makefile
/configure
/cov-int
/coverage
+/gtk-doc.make
/kmod-*.tar.*
/libtool
/stamp-h1
+++ /dev/null
-version: v1.0
-name: Build and Check
-agent:
- machine:
- type: e1-standard-2
- os_image: ubuntu1804
-
-blocks:
- - name: "Build"
- task:
- jobs:
- - name: Build gcc-8
- commands:
- - sem-version c 8
- - name: Build gcc-7
- commands:
- - sem-version c 7
- - name: Build gcc-6
- commands:
- - sem-version c 6
-
- prologue:
- commands:
- - sudo apt update
- - sudo apt --yes install docbook-xsl liblzma-dev zlib1g-dev cython linux-headers-generic libssl-dev
- - checkout
-
- epilogue:
- commands:
- - ./autogen.sh c
- - make
-
- - name: "Unit tests"
- task:
- jobs:
- - name: check
- commands:
- - sem-version c 8
- - ./autogen.sh c
- - make check
-
- prologue:
- commands:
- - sudo apt update
- - sudo apt --yes install docbook-xsl liblzma-dev zlib1g-dev cython linux-headers-generic libssl-dev
- - checkout
+++ /dev/null
-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
- - sudo apt-get install -qq liblzma-dev
- - sudo apt-get install -qq zlib1g-dev
- - sudo apt-get install -qq xsltproc docbook-xsl
- - sudo apt-get install -qq cython
- - 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)"
-
-script:
- - ./autogen.sh c --without-openssl && make -j
- - if [ "$MYCC" != "gcc-4.8" ]; then make -j check; fi
-
-notifications:
- irc:
- channels:
- - "irc.freenode.org#kmod"
- template:
- - "%{commit}: %{author} - %{message}"
-include $(top_builddir)/config.h \
-I$(top_srcdir) \
-DSYSCONFDIR=\""$(sysconfdir)"\" \
+ -DDISTCONFDIR=\""$(distconfdir)"\" \
+ -DMODULE_DIRECTORY=\""$(module_directory)"\" \
${zlib_CFLAGS}
AM_CFLAGS = $(OUR_CFLAGS)
AM_LDFLAGS = $(OUR_LDFLAGS)
-SED_PROCESS = \
- $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(SED) \
- -e 's,@VERSION\@,$(VERSION),g' \
- -e 's,@prefix\@,$(prefix),g' \
- -e 's,@exec_prefix\@,$(exec_prefix),g' \
- -e 's,@libdir\@,$(libdir),g' \
- -e 's,@includedir\@,$(includedir),g' \
- -e 's,@liblzma_CFLAGS\@,${liblzma_CFLAGS},g' \
- -e 's,@liblzma_LIBS\@,${liblzma_LIBS},g' \
- -e 's,@zlib_CFLAGS\@,${zlib_CFLAGS},g' \
- -e 's,@zlib_LIBS\@,${zlib_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=5
-LIBKMOD_AGE=3
+# Rules for libtool versioning (from https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html)
+# 1. Start with version information of ‘0:0:0’ for each libtool library.
+# 2. Update the version information only immediately before a public release of
+# your software. More frequent updates are unnecessary, and only guarantee that
+# the current interface number gets larger faster.
+# 3. If the library source code has changed at all since the last update, then
+# increment revision (‘c:r:a’ becomes ‘c:r+1:a’).
+# 4. If any interfaces have been added, removed, or changed since the last
+# update, increment current, and set revision to 0.
+# 5. If any interfaces have been added since the last public release, then
+# increment age.
+# 6. If any interfaces have been removed or changed since the last public
+# release, then set age to 0.
+LIBKMOD_CURRENT=6
+LIBKMOD_REVISION=2
+LIBKMOD_AGE=4
noinst_LTLIBRARIES = shared/libshared.la
shared_libshared_la_SOURCES = \
${top_srcdir}/libkmod/libkmod.sym
libkmod_libkmod_la_LIBADD = \
shared/libshared.la \
- ${liblzma_LIBS} ${zlib_LIBS} ${libcrypto_LIBS}
+ ${libzstd_LIBS} ${liblzma_LIBS} ${zlib_LIBS} ${libcrypto_LIBS}
noinst_LTLIBRARIES += libkmod/libkmod-internal.la
libkmod_libkmod_internal_la_SOURCES = $(libkmod_libkmod_la_SOURCES)
libkmod_libkmod_internal_la_DEPENDENCIES = $(libkmod_libkmod_la_DEPENDENCIES)
libkmod_libkmod_internal_la_LIBADD = $(libkmod_libkmod_la_LIBADD)
-pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libkmod/libkmod.pc
-EXTRA_DIST += libkmod/libkmod.pc.in
-CLEANFILES += libkmod/libkmod.pc
+noarch_pkgconfig_DATA = tools/kmod.pc
bashcompletiondir=@bashcompletiondir@
dist_bashcompletion_DATA = \
ln -sf $$so_img_rel_target_prefix$(rootlibdir)/$$so_img_name $(DESTDIR)$(libdir)/libkmod.so && \
mv $(DESTDIR)$(libdir)/libkmod.so.* $(DESTDIR)$(rootlibdir); \
fi
+if BUILD_TOOLS
+ for tool in insmod lsmod rmmod depmod modprobe modinfo; do \
+ $(LN_S) -f kmod $(DESTDIR)$(bindir)/$$tool; \
+ done
+endif
uninstall-hook:
rm -f $(DESTDIR)$(rootlibdir)/libkmod.so*
+if BUILD_TOOLS
+ for tool in insmod lsmod rmmod depmod modprobe modinfo; do \
+ rm -f $(DESTDIR)$(bindir)/$$tool; \
+ done
+endif
if BUILD_TOOLS
bin_PROGRAMS = tools/kmod
tools/depmod.c tools/log.h tools/log.c \
tools/static-nodes.c
-if BUILD_EXPERIMENTAL
-tools_kmod_SOURCES += \
- tools/insert.c \
- tools/remove.c
-endif
-
tools_kmod_LDADD = \
shared/libshared.la \
libkmod/libkmod-internal.la
$(LN_S) $(notdir $<) $@)
endif
-# ------------------------------------------------------------------------------
-# PYTHON BINDINGS
-# ------------------------------------------------------------------------------
-
-CYTHON_FLAGS_VERBOSE_ =
-CYTHON_FLAGS_VERBOSE_0 =
-CYTHON_FLAGS_VERBOSE_1 = -v
-CYTHON_FLAGS = $(CYTHON_FLAGS_VERBOSE_$(V))
-AM_V_CYTHON = $(am__v_CYTHON_$(V))
-am__v_CYTHON_ = $(am__v_CYTHON_$(AM_DEFAULT_VERBOSITY))
-am__v_CYTHON_0 = @echo " CYTHON " $@;
-
-.pyx.c:
- $(AM_V_CYTHON)$(CYTHON) -o $@ $<
-
-%.py: %.py.in Makefile
- $(SED_PROCESS)
-
-# Remove some warnings for generated code
-PYTHON_NOWARN = -Wno-redundant-decls -Wno-shadow -Wno-strict-aliasing
-
-CPYTHON_MODULE_CFLAGS = \
- $(AM_CFLAGS) -DCPYTHON_COMPILING_IN_PYPY=0 \
- $(PYTHON_NOWARN) $(PYTHON_CFLAGS) \
- -fvisibility=default
-# 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 = \
- libkmod/python/kmod/kmod.la \
- libkmod/python/kmod/list.la \
- libkmod/python/kmod/module.la \
- libkmod/python/kmod/_util.la
-
-libkmod_python_kmod_kmod_la_SOURCES = libkmod/python/kmod/kmod.c
-libkmod_python_kmod_kmod_la_CFLAGS = $(CPYTHON_MODULE_CFLAGS)
-libkmod_python_kmod_kmod_la_LDFLAGS = $(CPYTHON_MODULE_LDFLAGS)
-libkmod_python_kmod_kmod_la_LIBADD = $(PYTHON_LIBS) libkmod/libkmod.la
-
-libkmod_python_kmod_list_la_SOURCES = libkmod/python/kmod/list.c
-libkmod_python_kmod_list_la_CFLAGS = $(CPYTHON_MODULE_CFLAGS)
-libkmod_python_kmod_list_la_LDFLAGS = $(CPYTHON_MODULE_LDFLAGS)
-libkmod_python_kmod_list_la_LIBADD = $(PYTHON_LIBS) libkmod/libkmod.la
-
-libkmod_python_kmod_module_la_SOURCES = libkmod/python/kmod/module.c
-libkmod_python_kmod_module_la_CFLAGS = $(CPYTHON_MODULE_CFLAGS)
-libkmod_python_kmod_module_la_LDFLAGS = $(CPYTHON_MODULE_LDFLAGS)
-libkmod_python_kmod_module_la_LIBADD = $(PYTHON_LIBS) libkmod/libkmod.la
-
-libkmod_python_kmod__util_la_SOURCES = libkmod/python/kmod/_util.c
-libkmod_python_kmod__util_la_CFLAGS = $(CPYTHON_MODULE_CFLAGS)
-libkmod_python_kmod__util_la_LDFLAGS = $(CPYTHON_MODULE_LDFLAGS)
-libkmod_python_kmod__util_la_LIBADD = $(PYTHON_LIBS) libkmod/libkmod.la
-
-BUILT_FILES += \
- $(libkmod_python_kmod_kmod_la_SOURCES) \
- $(libkmod_python_kmod_list_la_SOURCES) \
- $(libkmod_python_kmod_module_la_SOURCES) \
- $(libkmod_python_kmod__util_la_SOURCES)
-
-dist_pkgpyexec_PYTHON = \
- libkmod/python/kmod/error.py \
- libkmod/python/kmod/__init__.py \
- libkmod/python/kmod/version.py
-
-BUILT_FILES += libkmod/python/kmod/version.py
-
-endif
# ------------------------------------------------------------------------------
# TESTSUITE
# ------------------------------------------------------------------------------
-EXTRA_DIST += testsuite/populate-modules.sh
+EXTRA_DIST += testsuite/setup-rootfs.sh
MODULE_PLAYGROUND = testsuite/module-playground
ROOTFS = testsuite/rootfs
ROOTFS_PRISTINE = $(top_srcdir)/testsuite/rootfs-pristine
-CREATE_ROOTFS = $(AM_V_GEN) ( $(RM) -rf $(ROOTFS) && mkdir -p $(dir $(ROOTFS)) && \
- cp -r $(ROOTFS_PRISTINE) $(ROOTFS) && \
- find $(ROOTFS) -type d -exec chmod +w {} \; && \
- find $(ROOTFS) -type f -name .gitignore -exec rm -f {} \; && \
- $(top_srcdir)/testsuite/populate-modules.sh \
- $(MODULE_PLAYGROUND) $(ROOTFS) ) && \
- touch testsuite/stamp-rootfs
+CREATE_ROOTFS = $(AM_V_GEN) MODULE_DIRECTORY=$(module_directory) $(top_srcdir)/testsuite/setup-rootfs.sh $(ROOTFS_PRISTINE) $(ROOTFS) $(MODULE_PLAYGROUND) $(top_builddir)/config.h $(sysconfdir)
build-module-playground:
$(AM_V_GEN)if test "$(top_srcdir)" != "$(top_builddir)"; then \
$(RM) -rf testsuite/module-playground && \
+ mkdir -p testsuite/ && \
cp -r $(top_srcdir)/$(MODULE_PLAYGROUND) $(top_builddir)/$(MODULE_PLAYGROUND) && \
find $(top_builddir)/$(MODULE_PLAYGROUND) -type d -exec chmod +w {} \; ; \
fi
TESTSUITE_OVERRIDE_LIBS_LDFLAGS = \
avoid-version -module -shared -export-dynamic -rpath /nowhere -ldl
-check-sysconfdir:
- $(AM_V_at)if test "$(sysconfdir)" != "/etc" -a "$(sysconfdir)" != "/etc/"; then \
- echo "warning: Some tests will fail without --sysconfdir=/etc" >&2; \
- fi
-.PHONY: check-sysconfdir
-
-check-am: rootfs check-sysconfdir
+check-am: rootfs
EXTRA_DIST += \
testsuite/test-dependencies testsuite/test-depmod \
testsuite/test-list
-if BUILD_EXPERIMENTAL
-TESTSUITE += \
- testsuite/test-tools
-endif
-
check_PROGRAMS = $(TESTSUITE)
TESTS = $(TESTSUITE)
testsuite_test_list_LDADD = $(TESTSUITE_LDADD)
testsuite_test_list_CPPFLAGS = $(TESTSUITE_CPPFLAGS)
-if BUILD_EXPERIMENTAL
-testsuite_test_tools_LDADD = $(TESTSUITE_LDADD)
-testsuite_test_tools_CPPFLAGS = $(TESTSUITE_CPPFLAGS)
-endif
-
testsuite-distclean:
$(RM) -r $(ROOTFS)
$(RM) testsuite/stamp-rootfs
DISTCLEAN_LOCAL_HOOKS += testsuite-distclean
EXTRA_DIST += testsuite/rootfs-pristine
-DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc --enable-python --sysconfdir=/etc \
- --with-zlib --with-openssl \
+DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc --sysconfdir=/etc \
+ --with-zlib --with-zstd --with-openssl \
--with-bashcompletiondir=$$dc_install_base/$(bashcompletiondir)
distclean-local: $(DISTCLEAN_LOCAL_HOOKS)
kmod-coverity-%.tar.xz:
rm -rf $< cov-int
- ./autogen.sh c --disable-python --disable-manpages
+ ./autogen.sh c --disable-manpages
make clean
cov-build --dir cov-int make -j 4
tar caf $@ cov-int
tar-sync: kmod-$(VERSION).tar.xz kmod-$(VERSION).tar.sign
kup put kmod-$(VERSION).tar.xz kmod-$(VERSION).tar.sign /pub/linux/utils/kernel/kmod/
-
-# ------------------------------------------------------------------------------
-# mkosi
-# ------------------------------------------------------------------------------
-
-DISTRO ?= "arch"
-
-mkosi:
- -$(MKDIR_P) $(top_srcdir)/testsuite/mkosi/mkosi.cache
- $(MKOSI) -C $(top_srcdir)/testsuite/mkosi --build-sources ../../ --default mkosi.${DISTRO} -fi
+kmod 32
+=======
+
+- Improvements
+
+ - Use any hash algo known by kernel/openssl instead of keep needing
+ to update the mapping
+
+ - Teach kmod to load modprobe.d/depmod.d configuration from ${prefix}/lib
+ and allow it to be overriden during build with --with-distconfdir=DIR
+
+ - Make kernel modules directory configurable. This allows distro to
+ make kmod use only files from /usr regardless of having a compat
+ symlink in place.
+
+ - Install kmod.pc containing the features selected at build time.
+
+ - Install all tools and symlinks by default. Previously kmod relied on
+ distro packaging to set up the symlinks in place like modprobe,
+ depmod, lsmod, etc. Now those symlinks are created by kmod itself
+ and they are always placed in $bindir.
+
+- Bug Fixes
+
+ - Fix warnings due to -Walloc-size
+
+- Others
+
+ - Drop python bindings. Those were not update in ages and not compatible
+ with latest python releases.
+
+ - Cleanup test infra, dropping what was not used anymore
+
+ - Drop experimental tools `kmod insert` / `kmod remove`. Building those
+ was protected by a configure option never set by distros. They also
+ didn't gain enough traction to replace the older interfaces via
+ modprobe/insmod/rmmod.
+
+kmod 31
+=======
+
+- Improvements
+
+ - Allow passing a path to modprobe so the module is loaded from
+ anywhere from the filesystem, but still handling the module
+ dependencies recorded in the indexes. This is mostly intended for kernel
+ developers to speedup testing their kernel modules without having to load the
+ dependencies manually or override the module in /usr/lib/modules/.
+ Now it's possible to do:
+
+ # modprobe ./drivers/gpu/drm/i915/i915.ko
+
+ As long as the dependencies didn't change, this should do the right thing
+
+ - Use in-kernel decompression if available. This will check the runtime support
+ in the kernel for decompressing modules and use it through finit_module().
+ Previously kmod would fallback to the older init_module() when using
+ compressed modules since there wasn't a way to instruct the kernel to
+ uncompress it on load or check if the kernel supported it or not.
+ This requires a recent kernel (>= 6.4) to have that support and
+ in-kernel decompression properly working in the kernel.
+
+ - Make modprobe fallback to syslog when stderr is not available, as was
+ documented in the man page, but not implemented
+
+ - Better explaing `modprobe -r` and how it differentiates from rmmod
+
+ - depmod learned a `-o <dir>` option to allow using a separate output
+ directory. With this, it's possible to split the output files from
+ the ones used as input from the kernel build system
+
+ - Add compat with glibc >= 2.32.9000 that dropped __xstat
+
+ - Improve testsuite to stop skipping tests when sysconfdir is something
+ other than /etc
+
+ - Build system improvements and updates
+
+ - Change a few return codes from -ENOENT to -ENODATA to avoid confusing output
+ in depmod when the module itself lacks a particular ELF section due to e.g.
+ CONFIG_MODVERSIONS=n in the kernel.
+
+
+- Bug Fixes
+
+ - Fix testsuite using uninitialized memory when testing module removal
+ with --wait
+
+ - Fix testsuite not correctly overriding the stat syscall on 32-bit
+ platforms. For most architectures this was harmless, but for MIPS it
+ was causing some tests to fail.
+
+ - Fix handling unknown signature algorithm
+
+ - Fix linking with a static liblzma, libzstd or zlib
+
+ - Fix memory leak when removing module holders
+
+ - Fix out-of-bounds access when using very long paths as argument to rmmod
+
+ - Fix warnings reported by UBSan
+
+kmod 30
+=======
+
+- Improvements
+ - Stop adding duplicate information on modules.builtin.alias.bin, just use
+ the modules.builtin.bin index
+
+ - Speedup depmod, particularly under qemu with emulated arch, by
+ avoiding a lot of open/read/close of modules.alias.bin. On an
+ emulated ARM rootfs, depmod with only 2 modules was taking ~32s
+ vs ~0.07s now.
+
+ - Add kmod_module_new_from_name_lookup() which allows doing a lookup by
+ module name, without considering the aliases. Other than that search
+ order is similar to kmod_module_new_from_lookup().
+
+ - modinfo learned the --modname option to explicitely show information
+ about the module, even if there is an alias with the same name. This
+ allows showing information about e.g. kernel/lib/crc32.ko, even if
+ kernel also exports a crc32 alias in modules.alias:
+
+ alias crc32 crc32_pclmul
+ alias crc32 crc32_generic
+
+ Same behavior will be used to other modules and to aliases provided
+ by user/distro.
+
+ - depmod.conf learned a new "excludedir" directive so distro/user can
+ configure more directories to be excluded from its search, besides
+ the hardcoded values "build" and "source".
+
+ - Better group modprobe options on help output under "Management, Query and General".
+
+ - modprobe learned a --wait <MSEC> option to be used together with -r
+ when removing a module. This allows modprobe to keep trying the
+ removal if it fails because the module is still in use. An exponential backoff
+ time is used for further retries.
+
+ The wait behavior provided by the kernel when not passing O_NONBLOCK
+ to delete_module() was removed in v3.13 due to not be used and the
+ consequences of having to support it in the kernel. However there may
+ be some users, particularly on testsuites for individual susbsystems, that
+ would want that. So provide a userspace implementation inside modprobe for
+ such users. "rmmod" doesn't have a --wait as it remains a bare minimal over
+ the API provided by the kernel. In future the --wait behavior can be added
+ to libkmod for testsuites not exec'ing modprobe for module removal.
+
+ - kmod_module_remove_module() learned a new flag to silence output when
+ caller wants to handle them - this is particularly important for the
+ --wait flag to modprobe, as it's not desired to keep seeing error messages
+ while waiting for the module to be unused.
+
+ - Add SM3 hash algo support to modinfo output, as already available in the kernel.
+
+- Bug Fixes
+ - Fix modinfo output when showing information for a .ko module when running
+ on a kernel that has that module as builtin.
+
+ - Fix kmod_module_new_from_lookup() returning > 0 rather than 0
+ when it matches an alias.
+
+ - Fix modinfo segfault when module doesn't exist.
+
+ - Add missing function in the html documentation: kmod_get_dirname().
+
+ - Fix modprobe incorrectly handling number of arguments when prepending values from
+ MODPROBE_OPTIONS environment variable.
+
+ - Fix modprobe -r --remove-dependencies and since "dependencies" was a
+ misnomer, add the preferred argument option: "--remove-holders". This
+ is the same name used by the kernel. It allows users to also remove
+ other modules holding the one that is being removed.
+
+ - Fix off-by-one in max module name length in depmod.
+
+- Infra/internal
+ - Start some changes in the out-of-tree test modules in kmod so they are useful
+ for being really inserted in the kernel rather than relying on kmod's mock
+ interface. This helps manual testing and may be used to exercise to test
+ changes in the kernel.
+
+kmod 29
+=======
+
+- Improvements
+ - Add support to use /usr/local as a place for configuration files. This makes it easier
+ to install locally without overriding distro files.
+
+- Bug fixes
+ - Fix `modinfo -F` when module is builtin: when we asked by a specific field from modinfo,
+ it was not working correctly if the module was builtin
+
+ - Documentation fixes on precedence order of /etc and /run: the correct order is
+ /etc/modprobe.d, /run/modprobe.d, /lib/modprobe.d
+
+ - Fix the priority order that we use for searching configuration files. The
+ correct one is /etc, /run, /usr/local/lib, /lib, for both modprobe.d
+ and depmo.d
+
+ - Fix kernel command line parsing when there are quotes present. Grub
+ mangles the command line and changes it from 'module.option="val with
+ spaces"' to '"module.option=val with spaces"'. Although this is weird
+ behavior and grub could have been fixed, the kernel understands it
+ correctly for builtin modules. So change libkmod to also parse it
+ correctly. This also brings another hidden behavior from the kernel:
+ newline in the kernel command line is also allowed and can be used to
+ separate options.
+
+ - Fix a memory leak, overflow and double free on error path
+
+ - Fix documentation for return value from kmod_module_get_info(): we
+ return the number of entries we added to the list
+
+ - Fix output of modules.builtin.alias.bin index: we were writing an empty file due to
+ the misuse of kmod_module_get_info()
+
+- Infra/internal
+ - Retire integration with semaphoreci
+
+ - Declare the github mirror also as an official upstream source: now besides accepting
+ patches via mailing list, PRs on github are also acceptable
+
+ - Misc improvements to testsuite, so we can use it reliably regardless
+ of the configuration used: now tests will skip if we don't have the
+ build dependencies)
+
+kmod 28
+=======
+
+- Improvements
+ - Add Zstandard to the supported compression formats using libzstd
+ (pass --with-zstd to configure)
+
+- Bug fixes
+ - Ignore ill-formed kernel command line, e.g. with "ivrs_acpihid[00:14.5]=AMD0020:0"
+ option in it
+ - Fix some memory leaks
+ - Fix 0-length builtin.alias.bin: it needs at least the index header
+
kmod 27
=======
- New features:
- libkmod now keeps a file opened after the first call to
kmod_module_get_{info,versions,symbols,dependency_symbols}. This
- reduces signficantly the amount of time depmod tool takes to
+ reduces significantly the amount of time depmod tool takes to
execute. Particularly if compressed modules are used.
- Remove --with-rootprefix from build system. It was not a great idea
after all and should not be use since it causes more harm then
+++ /dev/null
-kmod - Linux kernel module handling
-
-Information
-===========
-
-Build Status:
- https://lucasdemarchi.semaphoreci.com/projects/kmod
-
-Mailing list:
- linux-modules@vger.kernel.org (no subscription needed)
- https://lore.kernel.org/linux-modules/
-
-Patchwork:
- https://patchwork.kernel.org/project/linux-modules/
-
-Signed packages:
- http://www.kernel.org/pub/linux/utils/kernel/kmod/
-
-Git:
- git://git.kernel.org/pub/scm/utils/kernel/kmod/kmod.git
- http://git.kernel.org/pub/scm/utils/kernel/kmod/kmod.git
- https://git.kernel.org/pub/scm/utils/kernel/kmod/kmod.git
-
-Gitweb:
- http://git.kernel.org/?p=utils/kernel/kmod/kmod.git
-
-Irc:
- #kmod on irc.freenode.org
-
-License:
- LGPLv2.1+ for libkmod, testsuite and helper libraries
- GPLv2+ for tools/*
-
-
-OVERVIEW
-========
-
-kmod is a set of tools to handle common tasks with Linux kernel modules like
-insert, remove, list, check properties, resolve dependencies and aliases.
-
-These tools are designed on top of libkmod, a library that is shipped with
-kmod. See libkmod/README for more details on this library and how to use it.
-The aim is to be compatible with tools, configurations and indexes from
-module-init-tools project.
-
-Compilation and installation
-============================
-
-In order to compiler the source code you need following software packages:
- - GCC compiler
- - GNU C library
-
-Optional dependencies:
- - ZLIB library
- - LZMA library
-
-Typical configuration:
- ./configure CFLAGS="-g -O2" --prefix=/usr \
- --sysconfdir=/etc --libdir=/usr/lib
-
-Configure automatically searches for all required components and packages.
-
-To compile and install run:
- make && make install
-
-Hacking
-=======
-
-Run 'autogen.sh' script before configure. If you want to accept the recommended
-flags, you just need to run 'autogen.sh c'. Note that the recommended
-flags require cython be installed to compile successfully.
-
-Make sure to read the CODING-STYLE file and the other READMEs: libkmod/README
-and testsuite/README.
-
-Compatibility with module-init-tools
-====================================
-
-kmod replaces module-init-tools, which is end-of-life. Most of its tools are
-rewritten on top of libkmod so it can be used as a drop in replacements.
-Somethings however were changed. Reasons vary from "the feature was already
-long deprecated on module-init-tools" to "it would be too much trouble to
-support it".
-
-There are several features that are being added in kmod, but we don't
-keep track of them here.
-
-modprobe
---------
-
-* 'modprobe -l' was marked as deprecated and does not exist anymore
-
-* 'modprobe -t' is gone, together with 'modprobe -l'
-
-* modprobe doesn't parse configuration files with names not ending in
- '.alias' or '.conf'. modprobe used to warn about these files.
-
-* modprobe doesn't parse 'config' and 'include' commands in configuration
- files.
-
-* modprobe from m-i-t does not honour softdeps for install commands. E.g.:
- config:
-
- install bli "echo bli"
- install bla "echo bla"
- softdep bla pre: bli
-
- With m-i-t, the output of 'modprobe --show-depends bla' will be:
- install "echo bla"
-
- While with kmod:
- install "echo bli"
- install "echo bla"
-
-* kmod doesn't dump the configuration as is in the config files. Instead it
- dumps the configuration as it was parsed. Therefore, comments and file names
- are not dumped, but on the good side we know what the exact configuration
- kmod is using. We did this because if we only want to know the entire content
- of configuration files, it's enough to use find(1) in modprobe.d directories
-
-depmod
-------
-
-* there's no 'depmod -m' option: legacy modules.*map files are gone
-
-lsmod
------
-
-* module-init-tools used /proc/modules to parse module info. kmod uses
- /sys/module/*, but there's a fallback to /proc/modules if the latter isn't
- available
[![Coverity Scan Status](https://scan.coverity.com/projects/2096/badge.svg)](https://scan.coverity.com/projects/2096)
-This is a ***mirror only***. Please see [README](../master/README) file for more information.
+
+Information
+===========
+
+Mailing list:
+ linux-modules@vger.kernel.org (no subscription needed)
+ https://lore.kernel.org/linux-modules/
+
+Signed packages:
+ http://www.kernel.org/pub/linux/utils/kernel/kmod/
+
+Git:
+ git://git.kernel.org/pub/scm/utils/kernel/kmod/kmod.git
+ http://git.kernel.org/pub/scm/utils/kernel/kmod/kmod.git
+ https://git.kernel.org/pub/scm/utils/kernel/kmod/kmod.git
+
+Gitweb:
+ http://git.kernel.org/?p=utils/kernel/kmod/kmod.git
+ https://github.com/kmod-project/kmod
+
+Irc:
+ #kmod on irc.freenode.org
+
+License:
+ LGPLv2.1+ for libkmod, testsuite and helper libraries
+ GPLv2+ for tools/*
+
+
+OVERVIEW
+========
+
+kmod is a set of tools to handle common tasks with Linux kernel modules like
+insert, remove, list, check properties, resolve dependencies and aliases.
+
+These tools are designed on top of libkmod, a library that is shipped with
+kmod. See libkmod/README for more details on this library and how to use it.
+The aim is to be compatible with tools, configurations and indexes from
+module-init-tools project.
+
+Compilation and installation
+============================
+
+In order to compiler the source code you need following software packages:
+ - GCC compiler
+ - GNU C library
+
+Optional dependencies:
+ - ZLIB library
+ - LZMA library
+ - ZSTD library
+ - OPENSSL library (signature handling in modinfo)
+
+Typical configuration:
+ ./configure CFLAGS="-g -O2" --prefix=/usr \
+ --sysconfdir=/etc --libdir=/usr/lib
+
+Configure automatically searches for all required components and packages.
+
+To compile and install run:
+ make && make install
+
+Hacking
+=======
+
+Run 'autogen.sh' script before configure. If you want to accept the recommended
+flags, you just need to run 'autogen.sh c'.
+
+Make sure to read the CODING-STYLE file and the other READMEs: libkmod/README
+and testsuite/README.
+
+Compatibility with module-init-tools
+====================================
+
+kmod replaces module-init-tools, which is end-of-life. Most of its tools are
+rewritten on top of libkmod so it can be used as a drop in replacements.
+Somethings however were changed. Reasons vary from "the feature was already
+long deprecated on module-init-tools" to "it would be too much trouble to
+support it".
+
+There are several features that are being added in kmod, but we don't
+keep track of them here.
+
+modprobe
+--------
+
+* 'modprobe -l' was marked as deprecated and does not exist anymore
+
+* 'modprobe -t' is gone, together with 'modprobe -l'
+
+* modprobe doesn't parse configuration files with names not ending in
+ '.alias' or '.conf'. modprobe used to warn about these files.
+
+* modprobe doesn't parse 'config' and 'include' commands in configuration
+ files.
+
+* modprobe from m-i-t does not honour softdeps for install commands. E.g.:
+ config:
+
+ install bli "echo bli"
+ install bla "echo bla"
+ softdep bla pre: bli
+
+ With m-i-t, the output of 'modprobe --show-depends bla' will be:
+ install "echo bla"
+
+ While with kmod:
+ install "echo bli"
+ install "echo bla"
+
+* kmod doesn't dump the configuration as is in the config files. Instead it
+ dumps the configuration as it was parsed. Therefore, comments and file names
+ are not dumped, but on the good side we know what the exact configuration
+ kmod is using. We did this because if we only want to know the entire content
+ of configuration files, it's enough to use find(1) in modprobe.d directories
+
+depmod
+------
+
+* there's no 'depmod -m' option: legacy modules.*map files are gone
+
+lsmod
+-----
+
+* module-init-tools used /proc/modules to parse module info. kmod uses
+ /sys/module/*, but there's a fallback to /proc/modules if the latter isn't
+ available
if [ ! -L /bin ]; then
args="$args \
- --with-rootprefix= \
--with-rootlibdir=$(libdir /lib) \
"
fi
cd $oldpwd
-hackargs="--enable-debug --enable-python --with-xz --with-zlib --with-openssl"
+hackargs="\
+--enable-debug \
+--with-zstd \
+--with-xz \
+--with-zlib \
+--with-openssl \
+"
if [ "x$1" = "xc" ]; then
shift
AC_PREREQ(2.64)
AC_INIT([kmod],
- [27],
+ [32],
[linux-modules@vger.kernel.org],
[kmod],
[http://git.kernel.org/?p=utils/kernel/kmod/kmod.git])
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])])
+module_compressions=""
+module_signatures="legacy"
+
#####################################################################
# Program checks and configurations
#####################################################################
AC_PROG_LN_S
PKG_PROG_PKG_CONFIG
AC_PATH_PROG([XSLTPROC], [xsltproc])
-AC_PATH_PROG([MKOSI], [mkosi])
AC_PROG_CC_C99
AC_MSG_CHECKING([whether _Noreturn is supported])
AC_COMPILE_IFELSE(
- [AC_LANG_SOURCE([[_Noreturn int foo(void) { exit(0); }]])],
+ [AC_LANG_SOURCE([[#include <stdlib.h>
+ _Noreturn int foo(void) { exit(0); }]])],
[AC_DEFINE([HAVE_NORETURN], [1], [Define if _Noreturn is available])
AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])])
# --with-
#####################################################################
+AC_ARG_WITH([distconfdir], AS_HELP_STRING([--with-distconfdir=DIR], [directory to search for distribution configuration files]),
+ [], [with_distconfdir='${prefix}/lib'])
+AC_SUBST([distconfdir], [$with_distconfdir])
+
AC_ARG_WITH([rootlibdir],
AS_HELP_STRING([--with-rootlibdir=DIR], [rootfs directory to install shared libraries]),
[], [with_rootlibdir=$libdir])
AC_SUBST([rootlibdir], [$with_rootlibdir])
+# Ideally this would be $prefix/lib/modules but default to /lib/modules for compatibility with earlier versions
+AC_ARG_WITH([module_directory],
+ AS_HELP_STRING([--with-module-directory=DIR], [directory in which to look for kernel modules @<:@default=/lib/modules@:>@]),
+ [], [with_module_directory=/lib/modules])
+AC_SUBST([module_directory], [$with_module_directory])
+
+# Check all directory arguments for consistency.
+for ac_var in distconfdir rootlibdir module_directory
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*@<:@^/@:>@\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ @<:@\\/$@:>@* | ?:@<:@\\/@:>@* ) continue;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+AC_ARG_WITH([zstd],
+ AS_HELP_STRING([--with-zstd], [handle Zstandard-compressed modules @<:@default=disabled@:>@]),
+ [], [with_zstd=no])
+AS_IF([test "x$with_zstd" != "xno"], [
+ PKG_CHECK_MODULES([libzstd], [libzstd >= 1.4.4], [LIBS="$LIBS $libzstd_LIBS"])
+ AC_DEFINE([ENABLE_ZSTD], [1], [Enable Zstandard for modules.])
+ module_compressions="zstd $module_compressions"
+], [
+ AC_MSG_NOTICE([Zstandard support not requested])
+])
+CC_FEATURE_APPEND([with_features], [with_zstd], [ZSTD])
+
AC_ARG_WITH([xz],
AS_HELP_STRING([--with-xz], [handle Xz-compressed modules @<:@default=disabled@:>@]),
[], [with_xz=no])
AS_IF([test "x$with_xz" != "xno"], [
- PKG_CHECK_MODULES([liblzma], [liblzma >= 4.99])
+ PKG_CHECK_MODULES([liblzma], [liblzma >= 4.99], [LIBS="$LIBS $liblzma_LIBS"])
AC_DEFINE([ENABLE_XZ], [1], [Enable Xz for modules.])
+ module_compressions="xz $module_compressions"
], [
AC_MSG_NOTICE([Xz support not requested])
])
AS_HELP_STRING([--with-zlib], [handle gzipped modules @<:@default=disabled@:>@]),
[], [with_zlib=no])
AS_IF([test "x$with_zlib" != "xno"], [
- PKG_CHECK_MODULES([zlib], [zlib])
+ PKG_CHECK_MODULES([zlib], [zlib], [LIBS="$LIBS $zlib_LIBS"])
AC_DEFINE([ENABLE_ZLIB], [1], [Enable zlib for modules.])
+ module_compressions="gzip $module_compressions"
], [
AC_MSG_NOTICE([zlib support not requested])
])
AS_HELP_STRING([--with-openssl], [handle PKCS7 signatures @<:@default=disabled@:>@]),
[], [with_openssl=no])
AS_IF([test "x$with_openssl" != "xno"], [
- PKG_CHECK_MODULES([libcrypto], [libcrypto >= 1.1.0])
+ PKG_CHECK_MODULES([libcrypto], [libcrypto >= 1.1.0], [LIBS="$LIBS $libcrypto_LIBS"])
AC_DEFINE([ENABLE_OPENSSL], [1], [Enable openssl for modinfo.])
+ module_signatures="PKCS7 $module_signatures"
], [
AC_MSG_NOTICE([openssl support not requested])
])
# --enable-
#####################################################################
-AC_ARG_ENABLE([experimental],
- AS_HELP_STRING([--enable-experimental], [enable experimental tools and features. Do not enable it unless you know what you are doing. @<:@default=disabled@:>@]),
- [], enable_experimental=no)
-AM_CONDITIONAL([BUILD_EXPERIMENTAL], [test "x$enable_experimental" = "xyes"])
-AS_IF([test "x$enable_experimental" = "xyes"], [
- AC_DEFINE(ENABLE_EXPERIMENTAL, [1], [Experimental features.])
-])
-CC_FEATURE_APPEND([with_features], [enable_experimental], [EXPERIMENTAL])
-
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)
AC_DEFINE(ENABLE_DEBUG, [1], [Debug messages.])
])
-AC_ARG_ENABLE([python],
- AS_HELP_STRING([--enable-python], [enable Python libkmod bindings @<:@default=disabled@:>@]),
- [], [enable_python=no])
-AS_IF([test "x$enable_python" = "xyes"], [
- AM_PATH_PYTHON(,,[:])
- AC_PATH_PROG([CYTHON], [cython], [:])
-
- PKG_CHECK_MODULES([PYTHON], [python-${PYTHON_VERSION}],
- [have_python=yes],
- [PKG_CHECK_MODULES([PYTHON], [python],
- [have_python=yes],
- [have_python=no])])
-
- AS_IF([test "x$have_python" = xno],
- [AC_MSG_ERROR([*** python support requested but libraries not found])])
-])
-AM_CONDITIONAL([BUILD_PYTHON], [test "x$enable_python" = "xyes"])
-
AC_ARG_ENABLE([coverage],
AS_HELP_STRING([--enable-coverage], [enable test coverage @<:@default=disabled@:>@]),
[], [enable_coverage=no])
], [
AM_CONDITIONAL([ENABLE_GTK_DOC], false)])
+PKG_INSTALLDIR
+PKG_NOARCH_INSTALLDIR
#####################################################################
# Default CFLAGS and LDFLAGS
# Generate files from *.in
#####################################################################
+AC_SUBST([module_compressions], $module_compressions)
+AC_SUBST([module_signatures], $module_signatures)
+
AC_CONFIG_FILES([
Makefile
man/Makefile
libkmod/docs/Makefile
libkmod/docs/version.xml
+ libkmod/libkmod.pc
+ tools/kmod.pc
])
$PACKAGE $VERSION
=======
+ module_directory: ${module_directory}
prefix: ${prefix}
sysconfdir: ${sysconfdir}
+ distconfdir: ${distconfdir}
libdir: ${libdir}
rootlibdir: ${rootlibdir}
includedir: ${includedir}
cflags: ${with_cflags} ${CFLAGS}
ldflags: ${with_ldflags} ${LDFLAGS}
- experimental features: ${enable_experimental}
tools: ${enable_tools}
- python bindings: ${enable_python}
logging: ${enable_logging}
- compression: xz=${with_xz} zlib=${with_zlib}
+ compression: zstd=${with_zstd} xz=${with_xz} zlib=${with_zlib}
debug: ${enable_debug}
coverage: ${enable_coverage}
doc: ${enable_gtk_doc}
kmod_set_log_fn
kmod_get_userdata
kmod_set_userdata
+kmod_get_dirname
</SECTION>
<SECTION>
<FILE>libkmod-module</FILE>
kmod_module
kmod_module_new_from_lookup
+kmod_module_new_from_name_lookup
kmod_module_new_from_name
kmod_module_new_from_path
char *buf;
};
-struct kmod_builtin_iter *kmod_builtin_iter_new(struct kmod_ctx *ctx)
+static struct kmod_builtin_iter *kmod_builtin_iter_new(struct kmod_ctx *ctx)
{
char path[PATH_MAX];
int file, sv_errno;
return iter;
}
-void kmod_builtin_iter_free(struct kmod_builtin_iter *iter)
+static void kmod_builtin_iter_free(struct kmod_builtin_iter *iter)
{
close(iter->file);
free(iter->buf);
return -1;
}
-bool kmod_builtin_iter_next(struct kmod_builtin_iter *iter)
+static bool kmod_builtin_iter_next(struct kmod_builtin_iter *iter)
{
char *line, *modname;
size_t linesz;
return (iter->pos < iter->size);
}
-bool kmod_builtin_iter_get_modname(struct kmod_builtin_iter *iter,
+static bool kmod_builtin_iter_get_modname(struct kmod_builtin_iter *iter,
char modname[static PATH_MAX])
{
int sv_errno;
len = dot - line;
- if (len > PATH_MAX) {
+ if (len >= PATH_MAX) {
sv_errno = ENAMETOOLONG;
goto fail;
}
while (offset < iter->next) {
offset = get_string(iter, pos, &line, &linesz);
if (offset <= 0) {
- count = (offset) ? -errno : -EOF;
+ count = (offset) ? -errno : -EINVAL;
+ free(*modinfo);
goto fail;
}
{
char buf[KCMD_LINE_SIZE];
int fd, err;
- char *p, *modname, *param = NULL, *value = NULL;
- bool is_quoted = false, is_module = true;
+ char *p, *p_quote_start, *modname, *param = NULL, *value = NULL;
+ bool is_quoted = false, iter = true;
+ enum state {
+ STATE_IGNORE,
+ STATE_MODNAME,
+ STATE_PARAM,
+ STATE_VALUE,
+ STATE_COMPLETE,
+ } state;
fd = open("/proc/cmdline", O_RDONLY|O_CLOEXEC);
if (fd < 0) {
return err;
}
- for (p = buf, modname = buf; *p != '\0' && *p != '\n'; p++) {
- if (*p == '"') {
+ state = STATE_MODNAME;
+ p_quote_start = NULL;
+ for (p = buf, modname = buf; iter; p++) {
+ switch (*p) {
+ case '"':
is_quoted = !is_quoted;
- if (is_quoted) {
- /* don't consider a module until closing quotes */
- is_module = false;
- } else if (param != NULL && value != NULL) {
- /*
- * If we are indeed expecting a value and
- * closing quotes, then this can be considered
- * a valid option for a module
- */
- is_module = true;
+ /*
+ * only allow starting quote as first char when looking
+ * for a modname: anything else is considered ill-formed
+ */
+ if (is_quoted && state == STATE_MODNAME && p == modname) {
+ p_quote_start = p;
+ modname = p + 1;
+ } else if (state != STATE_VALUE) {
+ state = STATE_IGNORE;
}
- continue;
- }
- if (is_quoted)
- continue;
-
- switch (*p) {
+ break;
+ case '\0':
+ iter = false;
+ /* fall-through */
case ' ':
- *p = '\0';
- if (is_module)
- kcmdline_parse_result(config, modname, param, value);
- param = value = NULL;
- modname = p + 1;
- is_module = true;
+ case '\n':
+ case '\t':
+ case '\v':
+ case '\f':
+ case '\r':
+ if (is_quoted && state == STATE_VALUE) {
+ /* no state change*/;
+ } else if (is_quoted) {
+ /* spaces are only allowed in the value part */
+ state = STATE_IGNORE;
+ } else if (state == STATE_VALUE || state == STATE_PARAM) {
+ *p = '\0';
+ state = STATE_COMPLETE;
+ } else {
+ /*
+ * go to next option, ignoring any possible
+ * partial match we have
+ */
+ modname = p + 1;
+ state = STATE_MODNAME;
+ p_quote_start = NULL;
+ }
break;
case '.':
- if (param == NULL) {
+ if (state == STATE_MODNAME) {
*p = '\0';
param = p + 1;
+ state = STATE_PARAM;
+ } else if (state == STATE_PARAM) {
+ state = STATE_IGNORE;
}
break;
case '=':
- if (param != NULL)
+ if (state == STATE_PARAM) {
+ /*
+ * Don't set *p to '\0': the value var shadows
+ * param
+ */
value = p + 1;
- else
- is_module = false;
+ state = STATE_VALUE;
+ } else if (state == STATE_MODNAME) {
+ state = STATE_IGNORE;
+ }
break;
}
- }
- *p = '\0';
- if (is_module)
- kcmdline_parse_result(config, modname, param, value);
+ if (state == STATE_COMPLETE) {
+ /*
+ * We may need to re-quote to unmangle what the
+ * bootloader passed. Example: grub passes the option as
+ * "parport.dyndbg=file drivers/parport/ieee1284_ops.c +mpf"
+ * instead of
+ * parport.dyndbg="file drivers/parport/ieee1284_ops.c +mpf"
+ */
+ if (p_quote_start && p_quote_start < modname) {
+ /*
+ * p_quote_start
+ * |
+ * |modname param value
+ * || | |
+ * vv v v
+ * "parport\0dyndbg=file drivers/parport/ieee1284_ops.c +mpf" */
+ memmove(p_quote_start, modname, value - modname);
+ value--; modname--; param--;
+ *value = '"';
+ }
+ kcmdline_parse_result(config, modname, param, value);
+ /* start over on next iteration */
+ modname = p + 1;
+ state = STATE_MODNAME;
+ p_quote_start = NULL;
+ }
+ }
return 0;
}
memcpy(cf->path, path, pathlen);
tmp = kmod_list_append(path_list, cf);
- if (tmp == NULL)
+ if (tmp == NULL) {
+ free(cf);
goto oom;
+ }
path_list = tmp;
}
assert_cc(sizeof(uint32_t) == sizeof(Elf32_Word));
assert_cc(sizeof(uint32_t) == sizeof(Elf64_Word));
+ if (!memory) {
+ errno = -EINVAL;
+ return NULL;
+ }
+
class = elf_identify(memory, size);
if (class < 0) {
errno = -class;
return i;
}
- return -ENOENT;
+ return -ENODATA;
}
int kmod_elf_get_section(const struct kmod_elf *elf, const char *section, const void **buf, uint64_t *buf_size)
return 0;
}
- return -ENOENT;
+ return -ENODATA;
}
/* array will be allocated with strings in a single malloc, just free *array */
}
ELFDBG(elf, "no vermagic found in .modinfo\n");
- return -ENOENT;
+ return -ENODATA;
}
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
+#ifdef ENABLE_ZSTD
+#include <zstd.h>
+#endif
#ifdef ENABLE_XZ
#include <lzma.h>
#endif
};
struct kmod_file {
+#ifdef ENABLE_ZSTD
+ bool zstd_used;
+#endif
#ifdef ENABLE_XZ
bool xz_used;
#endif
gzFile gzf;
#endif
int fd;
- bool direct;
+ enum kmod_file_compression_type compression;
off_t size;
void *memory;
const struct file_ops *ops;
struct kmod_elf *elf;
};
+#ifdef ENABLE_ZSTD
+static int zstd_read_block(struct kmod_file *file, size_t block_size,
+ ZSTD_inBuffer *input, size_t *input_capacity)
+{
+ ssize_t rdret;
+ int ret;
+
+ if (*input_capacity < block_size) {
+ free((void *)input->src);
+ input->src = malloc(block_size);
+ if (input->src == NULL) {
+ ret = -errno;
+ ERR(file->ctx, "zstd: %m\n");
+ return ret;
+ }
+ *input_capacity = block_size;
+ }
+
+ rdret = read(file->fd, (void *)input->src, block_size);
+ if (rdret < 0) {
+ ret = -errno;
+ ERR(file->ctx, "zstd: %m\n");
+ return ret;
+ }
+
+ input->pos = 0;
+ input->size = rdret;
+ return 0;
+}
+
+static int zstd_ensure_outbuffer_space(ZSTD_outBuffer *buffer, size_t min_free)
+{
+ uint8_t *old_buffer = buffer->dst;
+ int ret = 0;
+
+ if (buffer->size - buffer->pos >= min_free)
+ return 0;
+
+ buffer->size += min_free;
+ buffer->dst = realloc(buffer->dst, buffer->size);
+ if (buffer->dst == NULL) {
+ ret = -errno;
+ free(old_buffer);
+ }
+
+ return ret;
+}
+
+static int zstd_decompress_block(struct kmod_file *file, ZSTD_DStream *dstr,
+ ZSTD_inBuffer *input, ZSTD_outBuffer *output,
+ size_t *next_block_size)
+{
+ size_t out_buf_min_size = ZSTD_DStreamOutSize();
+ int ret = 0;
+
+ do {
+ ssize_t dsret;
+
+ ret = zstd_ensure_outbuffer_space(output, out_buf_min_size);
+ if (ret) {
+ ERR(file->ctx, "zstd: %s\n", strerror(-ret));
+ break;
+ }
+
+ dsret = ZSTD_decompressStream(dstr, output, input);
+ if (ZSTD_isError(dsret)) {
+ ret = -EINVAL;
+ ERR(file->ctx, "zstd: %s\n", ZSTD_getErrorName(dsret));
+ break;
+ }
+ if (dsret > 0)
+ *next_block_size = (size_t)dsret;
+ } while (input->pos < input->size
+ || output->pos > output->size
+ || output->size - output->pos < out_buf_min_size);
+
+ return ret;
+}
+
+static int load_zstd(struct kmod_file *file)
+{
+ ZSTD_DStream *dstr;
+ size_t next_block_size;
+ size_t zst_inb_capacity = 0;
+ ZSTD_inBuffer zst_inb = { 0 };
+ ZSTD_outBuffer zst_outb = { 0 };
+ int ret;
+
+ dstr = ZSTD_createDStream();
+ if (dstr == NULL) {
+ ret = -EINVAL;
+ ERR(file->ctx, "zstd: Failed to create decompression stream\n");
+ goto out;
+ }
+
+ next_block_size = ZSTD_initDStream(dstr);
+
+ while (true) {
+ ret = zstd_read_block(file, next_block_size, &zst_inb,
+ &zst_inb_capacity);
+ if (ret != 0)
+ goto out;
+ if (zst_inb.size == 0) /* EOF */
+ break;
+
+ ret = zstd_decompress_block(file, dstr, &zst_inb, &zst_outb,
+ &next_block_size);
+ if (ret != 0)
+ goto out;
+ }
+
+ ZSTD_freeDStream(dstr);
+ free((void *)zst_inb.src);
+ file->zstd_used = true;
+ file->memory = zst_outb.dst;
+ file->size = zst_outb.pos;
+ return 0;
+out:
+ if (dstr != NULL)
+ ZSTD_freeDStream(dstr);
+ free((void *)zst_inb.src);
+ free((void *)zst_outb.dst);
+ return ret;
+}
+
+static void unload_zstd(struct kmod_file *file)
+{
+ if (!file->zstd_used)
+ return;
+ free(file->memory);
+}
+
+static const char magic_zstd[] = {0x28, 0xB5, 0x2F, 0xFD};
+#endif
+
#ifdef ENABLE_XZ
static void xz_uncompress_belch(struct kmod_file *file, lzma_ret ret)
{
static const struct comp_type {
size_t magic_size;
+ enum kmod_file_compression_type compression;
const char *magic_bytes;
const struct file_ops ops;
} comp_types[] = {
+#ifdef ENABLE_ZSTD
+ {sizeof(magic_zstd), KMOD_FILE_COMPRESSION_ZSTD, magic_zstd, {load_zstd, unload_zstd}},
+#endif
#ifdef ENABLE_XZ
- {sizeof(magic_xz), magic_xz, {load_xz, unload_xz}},
+ {sizeof(magic_xz), KMOD_FILE_COMPRESSION_XZ, magic_xz, {load_xz, unload_xz}},
#endif
#ifdef ENABLE_ZLIB
- {sizeof(magic_zlib), magic_zlib, {load_zlib, unload_zlib}},
+ {sizeof(magic_zlib), KMOD_FILE_COMPRESSION_ZLIB, magic_zlib, {load_zlib, unload_zlib}},
#endif
- {0, NULL, {NULL, NULL}}
+ {0, KMOD_FILE_COMPRESSION_NONE, NULL, {NULL, NULL}}
};
static int load_reg(struct kmod_file *file)
file->fd, 0);
if (file->memory == MAP_FAILED)
return -errno;
- file->direct = true;
+
return 0;
}
if (file->elf)
return file->elf;
+ kmod_file_load_contents(file);
file->elf = kmod_elf_new(file->memory, file->size);
return file->elf;
}
struct kmod_file *file = calloc(1, sizeof(struct kmod_file));
const struct comp_type *itr;
size_t magic_size_max = 0;
- int err;
+ int err = 0;
if (file == NULL)
return NULL;
magic_size_max = itr->magic_size;
}
- file->direct = false;
if (magic_size_max > 0) {
char *buf = alloca(magic_size_max + 1);
ssize_t sz;
}
for (itr = comp_types; itr->ops.load != NULL; itr++) {
- if (memcmp(buf, itr->magic_bytes, itr->magic_size) == 0)
+ if (memcmp(buf, itr->magic_bytes, itr->magic_size) == 0) {
+ file->ops = &itr->ops;
+ file->compression = itr->compression;
break;
+ }
}
- if (itr->ops.load != NULL)
- file->ops = &itr->ops;
}
- if (file->ops == NULL)
+ if (file->ops == NULL) {
file->ops = ®_ops;
+ file->compression = KMOD_FILE_COMPRESSION_NONE;
+ }
- err = file->ops->load(file);
file->ctx = ctx;
+
error:
if (err < 0) {
if (file->fd >= 0)
return file;
}
+/*
+ * Callers should just check file->memory got updated
+ */
+void kmod_file_load_contents(struct kmod_file *file)
+{
+ if (file->memory)
+ return;
+
+ /* The load functions already log possible errors. */
+ file->ops->load(file);
+}
+
void *kmod_file_get_contents(const struct kmod_file *file)
{
return file->memory;
return file->size;
}
-bool kmod_file_get_direct(const struct kmod_file *file)
+enum kmod_file_compression_type kmod_file_get_compression(const struct kmod_file *file)
{
- return file->direct;
+ return file->compression;
}
int kmod_file_get_fd(const struct kmod_file *file)
if (file->elf)
kmod_elf_unref(file->elf);
- file->ops->unload(file);
+ if (file->memory)
+ file->ops->unload(file);
+
if (file->fd >= 0)
close(file->fd);
free(file);
#include "libkmod.h"
static _always_inline_ _printf_format_(2, 3) void
- kmod_log_null(struct kmod_ctx *ctx, const char *format, ...) {}
+ kmod_log_null(const struct kmod_ctx *ctx, const char *format, ...) {}
#define kmod_log_cond(ctx, prio, arg...) \
do { \
# else
# define DBG(ctx, arg...) kmod_log_null(ctx, ## arg)
# endif
+# define NOTICE(ctx, arg...) kmod_log_cond(ctx, LOG_NOTICE, ## arg)
# define INFO(ctx, arg...) kmod_log_cond(ctx, LOG_INFO, ## arg)
# define ERR(ctx, arg...) kmod_log_cond(ctx, LOG_ERR, ## arg)
#else
# define DBG(ctx, arg...) kmod_log_null(ctx, ## arg)
+# define NOTICE(ctx, arg...) kmod_log_null(ctx, ## arg)
# define INFO(ctx, arg...) kmod_log_null(ctx, ## arg)
# define ERR(ctx, arg...) kmod_log_null(ctx, ## arg)
#endif
void *data;
};
+enum kmod_file_compression_type {
+ KMOD_FILE_COMPRESSION_NONE = 0,
+ KMOD_FILE_COMPRESSION_ZSTD,
+ KMOD_FILE_COMPRESSION_XZ,
+ KMOD_FILE_COMPRESSION_ZLIB,
+};
+
struct kmod_list *kmod_list_append(struct kmod_list *list, const void *data) _must_check_ __attribute__((nonnull(2)));
struct kmod_list *kmod_list_prepend(struct kmod_list *list, const void *data) _must_check_ __attribute__((nonnull(2)));
struct kmod_list *kmod_list_remove(struct kmod_list *list) _must_check_;
void kmod_pool_del_module(struct kmod_ctx *ctx, struct kmod_module *mod, const char *key) __attribute__((nonnull(1, 2, 3)));
const struct kmod_config *kmod_get_config(const struct kmod_ctx *ctx) __attribute__((nonnull(1)));
+enum kmod_file_compression_type kmod_get_kernel_compression(const struct kmod_ctx *ctx) __attribute__((nonnull(1)));
/* libkmod-config.c */
struct kmod_config_path {
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)));
struct kmod_elf *kmod_file_get_elf(struct kmod_file *file) __attribute__((nonnull(1)));
+void kmod_file_load_contents(struct kmod_file *file) __attribute__((nonnull(1)));
void *kmod_file_get_contents(const struct kmod_file *file) _must_check_ __attribute__((nonnull(1)));
off_t kmod_file_get_size(const struct kmod_file *file) _must_check_ __attribute__((nonnull(1)));
-bool kmod_file_get_direct(const struct kmod_file *file) _must_check_ __attribute__((nonnull(1)));
+enum kmod_file_compression_type kmod_file_get_compression(const struct kmod_file *file) _must_check_ __attribute__((nonnull(1)));
int kmod_file_get_fd(const struct kmod_file *file) _must_check_ __attribute__((nonnull(1)));
void kmod_file_unref(struct kmod_file *file) __attribute__((nonnull(1)));
char *symbol;
};
-struct kmod_elf *kmod_elf_new(const void *memory, off_t size) _must_check_ __attribute__((nonnull(1)));
+struct kmod_elf *kmod_elf_new(const void *memory, off_t size) _must_check_;
void kmod_elf_unref(struct kmod_elf *elf) __attribute__((nonnull(1)));
const void *kmod_elf_get_memory(const struct kmod_elf *elf) _must_check_ __attribute__((nonnull(1)));
int kmod_elf_get_strings(const struct kmod_elf *elf, const char *section, char ***array) _must_check_ __attribute__((nonnull(1,2,3)));
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)));
return -EEXIST;
}
- *mod = kmod_module_ref(m);
- return 0;
- }
+ kmod_module_ref(m);
+ } else {
+ err = kmod_module_new(ctx, name, name, namelen, NULL, 0, &m);
+ if (err < 0) {
+ free(abspath);
+ return err;
+ }
- err = kmod_module_new(ctx, name, name, namelen, NULL, 0, &m);
- if (err < 0) {
- free(abspath);
- return err;
+ m->path = abspath;
}
- m->path = abspath;
+ m->builtin = KMOD_MODULE_BUILTIN_NO;
*mod = m;
return 0;
return mod;
}
-#define CHECK_ERR_AND_FINISH(_err, _label_err, _list, label_finish) \
- do { \
- if ((_err) < 0) \
- goto _label_err; \
- if (*(_list) != NULL) \
- goto finish; \
- } while (0)
+typedef int (*lookup_func)(struct kmod_ctx *ctx, const char *name, struct kmod_list **list) __attribute__((nonnull(1, 2, 3)));
+
+static int __kmod_module_new_from_lookup(struct kmod_ctx *ctx, const lookup_func lookup[],
+ size_t lookup_count, const char *s,
+ struct kmod_list **list)
+{
+ unsigned int i;
+
+ for (i = 0; i < lookup_count; i++) {
+ int err;
+
+ err = lookup[i](ctx, s, list);
+ if (err < 0 && err != -ENOSYS)
+ return err;
+ else if (*list != NULL)
+ return 0;
+ }
+
+ return 0;
+}
/**
* kmod_module_new_from_lookup:
*
* The search order is: 1. aliases in configuration file; 2. module names in
* modules.dep index; 3. symbol aliases in modules.symbols index; 4. aliases
- * in modules.alias index.
+ * from install commands; 5. builtin indexes from kernel.
*
* The initial refcount is 1, and needs to be decremented to release the
* resources of the kmod_module. The returned @list must be released by
const char *given_alias,
struct kmod_list **list)
{
- int err;
+ static const lookup_func lookup[] = {
+ kmod_lookup_alias_from_config,
+ kmod_lookup_alias_from_moddep_file,
+ kmod_lookup_alias_from_symbols_file,
+ kmod_lookup_alias_from_commands,
+ kmod_lookup_alias_from_aliases_file,
+ kmod_lookup_alias_from_builtin_file,
+ kmod_lookup_alias_from_kernel_builtin_file,
+ };
char alias[PATH_MAX];
+ int err;
if (ctx == NULL || given_alias == NULL)
return -ENOENT;
DBG(ctx, "input alias=%s, normalized=%s\n", given_alias, alias);
- /* Aliases from config file override all the others */
- err = kmod_lookup_alias_from_config(ctx, alias, list);
- CHECK_ERR_AND_FINISH(err, fail, list, finish);
+ err = __kmod_module_new_from_lookup(ctx, lookup, ARRAY_SIZE(lookup),
+ alias, list);
- DBG(ctx, "lookup modules.dep %s\n", alias);
- err = kmod_lookup_alias_from_moddep_file(ctx, alias, list);
- CHECK_ERR_AND_FINISH(err, fail, list, finish);
+ DBG(ctx, "lookup=%s found=%d\n", alias, err >= 0 && *list);
- DBG(ctx, "lookup modules.symbols %s\n", alias);
- err = kmod_lookup_alias_from_symbols_file(ctx, alias, list);
- CHECK_ERR_AND_FINISH(err, fail, list, finish);
+ if (err < 0) {
+ kmod_module_unref_list(*list);
+ *list = NULL;
+ }
- DBG(ctx, "lookup install and remove commands %s\n", alias);
- err = kmod_lookup_alias_from_commands(ctx, alias, list);
- CHECK_ERR_AND_FINISH(err, fail, list, finish);
+ return err;
+}
- DBG(ctx, "lookup modules.aliases %s\n", alias);
- err = kmod_lookup_alias_from_aliases_file(ctx, alias, list);
- CHECK_ERR_AND_FINISH(err, fail, list, finish);
+/**
+ * kmod_module_new_from_name_lookup:
+ * @ctx: kmod library context
+ * @modname: module name to look for
+ * @mod: returned module on success
+ *
+ * Lookup by module name, without considering possible aliases. This is similar
+ * to kmod_module_new_from_lookup(), but don't consider as source indexes and
+ * configurations that work with aliases. When succesful, this always resolves
+ * to one and only one module.
+ *
+ * The search order is: 1. module names in modules.dep index;
+ * 2. builtin indexes from kernel.
+ *
+ * The initial refcount is 1, and needs to be decremented to release the
+ * resources of the kmod_module. Since libkmod keeps track of all
+ * kmod_modules created, they are all released upon @ctx destruction too. Do
+ * not unref @ctx before all the desired operations with the returned list are
+ * completed.
+ *
+ * Returns: 0 on success or < 0 otherwise. It fails if any of the lookup
+ * methods failed, which is basically due to memory allocation failure. If
+ * module is not found, it still returns 0, but @mod is left untouched.
+ */
+KMOD_EXPORT int kmod_module_new_from_name_lookup(struct kmod_ctx *ctx,
+ const char *modname,
+ struct kmod_module **mod)
+{
+ static const lookup_func lookup[] = {
+ kmod_lookup_alias_from_moddep_file,
+ kmod_lookup_alias_from_builtin_file,
+ kmod_lookup_alias_from_kernel_builtin_file,
+ };
+ char name_norm[PATH_MAX];
+ struct kmod_list *list = NULL;
+ int err;
- DBG(ctx, "lookup modules.builtin.modinfo %s\n", alias);
- err = kmod_lookup_alias_from_kernel_builtin_file(ctx, alias, list);
- if (err == -ENOSYS) {
- /* Optional index missing, try the old one */
- 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);
+ if (ctx == NULL || modname == NULL || mod == NULL)
+ return -ENOENT;
+ modname_normalize(modname, name_norm, NULL);
+
+ DBG(ctx, "input modname=%s, normalized=%s\n", modname, name_norm);
+
+ err = __kmod_module_new_from_lookup(ctx, lookup, ARRAY_SIZE(lookup),
+ name_norm, &list);
+
+ DBG(ctx, "lookup=%s found=%d\n", name_norm, err >= 0 && list);
+
+ if (err >= 0 && list != NULL)
+ *mod = kmod_module_get_module(list);
+
+ kmod_module_unref_list(list);
-finish:
- DBG(ctx, "lookup %s=%d, list=%p\n", alias, err, *list);
- return err;
-fail:
- DBG(ctx, "Failed to lookup %s\n", alias);
- kmod_module_unref_list(*list);
- *list = NULL;
return err;
}
-#undef CHECK_ERR_AND_FINISH
/**
* kmod_module_unref_list:
/**
* kmod_module_remove_module:
* @mod: kmod module
- * @flags: flags to pass to Linux kernel when removing the module. The only valid flag is
+ * @flags: flags used when removing the module.
* KMOD_REMOVE_FORCE: force remove module regardless if it's still in
- * use by a kernel subsystem or other process;
- * KMOD_REMOVE_NOWAIT is always enforced, causing us to pass O_NONBLOCK to
+ * use by a kernel subsystem or other process; passed directly to Linux kernel
+ * KMOD_REMOVE_NOWAIT: is always enforced, causing us to pass O_NONBLOCK to
* delete_module(2).
+ * KMOD_REMOVE_NOLOG: when module removal fails, do not log anything as the
+ * caller may want to handle retries and log when appropriate.
*
* Remove a module from Linux kernel.
*
KMOD_EXPORT int kmod_module_remove_module(struct kmod_module *mod,
unsigned int flags)
{
+ unsigned int libkmod_flags = flags & 0xff;
+
int err;
if (mod == NULL)
err = delete_module(mod->name, flags);
if (err != 0) {
err = -errno;
- ERR(mod->ctx, "could not remove '%s': %m\n", mod->name);
+ if (!(libkmod_flags & KMOD_REMOVE_NOLOG))
+ ERR(mod->ctx, "could not remove '%s': %m\n", mod->name);
}
return err;
extern long init_module(const void *mem, unsigned long len, const char *args);
+static int do_finit_module(struct kmod_module *mod, unsigned int flags,
+ const char *args)
+{
+ enum kmod_file_compression_type compression, kernel_compression;
+ unsigned int kernel_flags = 0;
+ int err;
+
+ /*
+ * When module is not compressed or its compression type matches the
+ * one in use by the kernel, there is no need to read the file
+ * in userspace. Otherwise, re-use ENOSYS to trigger the same fallback
+ * as when finit_module() is not supported.
+ */
+ compression = kmod_file_get_compression(mod->file);
+ kernel_compression = kmod_get_kernel_compression(mod->ctx);
+ if (!(compression == KMOD_FILE_COMPRESSION_NONE ||
+ compression == kernel_compression))
+ return -ENOSYS;
+
+ if (compression != KMOD_FILE_COMPRESSION_NONE)
+ kernel_flags |= MODULE_INIT_COMPRESSED_FILE;
+
+ if (flags & KMOD_INSERT_FORCE_VERMAGIC)
+ kernel_flags |= MODULE_INIT_IGNORE_VERMAGIC;
+ if (flags & KMOD_INSERT_FORCE_MODVERSION)
+ kernel_flags |= MODULE_INIT_IGNORE_MODVERSIONS;
+
+ err = finit_module(kmod_file_get_fd(mod->file), args, kernel_flags);
+ if (err < 0)
+ err = -errno;
+
+ return err;
+}
+
+static int do_init_module(struct kmod_module *mod, unsigned int flags,
+ const char *args)
+{
+ struct kmod_elf *elf;
+ const void *mem;
+ off_t size;
+ int err;
+
+ kmod_file_load_contents(mod->file);
+
+ if (flags & (KMOD_INSERT_FORCE_VERMAGIC | KMOD_INSERT_FORCE_MODVERSION)) {
+ elf = kmod_file_get_elf(mod->file);
+ if (elf == NULL) {
+ err = -errno;
+ return err;
+ }
+
+ if (flags & KMOD_INSERT_FORCE_MODVERSION) {
+ err = kmod_elf_strip_section(elf, "__versions");
+ if (err < 0)
+ INFO(mod->ctx, "Failed to strip modversion: %s\n", strerror(-err));
+ }
+
+ if (flags & KMOD_INSERT_FORCE_VERMAGIC) {
+ err = kmod_elf_strip_vermagic(elf);
+ if (err < 0)
+ INFO(mod->ctx, "Failed to strip vermagic: %s\n", strerror(-err));
+ }
+
+ mem = kmod_elf_get_memory(elf);
+ } else {
+ mem = kmod_file_get_contents(mod->file);
+ }
+ size = kmod_file_get_size(mod->file);
+
+ err = init_module(mem, size, args);
+ if (err < 0)
+ err = -errno;
+
+ return err;
+}
+
/**
* kmod_module_insert_module:
* @mod: kmod module
const char *options)
{
int err;
- const void *mem;
- off_t size;
- struct kmod_elf *elf;
const char *path;
const char *args = options ? options : "";
}
}
- if (kmod_file_get_direct(mod->file)) {
- unsigned int kernel_flags = 0;
-
- if (flags & KMOD_INSERT_FORCE_VERMAGIC)
- kernel_flags |= MODULE_INIT_IGNORE_VERMAGIC;
- if (flags & KMOD_INSERT_FORCE_MODVERSION)
- kernel_flags |= MODULE_INIT_IGNORE_MODVERSIONS;
-
- err = finit_module(kmod_file_get_fd(mod->file), args, kernel_flags);
- if (err == 0 || errno != ENOSYS)
- goto init_finished;
- }
-
- if (flags & (KMOD_INSERT_FORCE_VERMAGIC | KMOD_INSERT_FORCE_MODVERSION)) {
- elf = kmod_file_get_elf(mod->file);
- if (elf == NULL) {
- err = -errno;
- return err;
- }
-
- if (flags & KMOD_INSERT_FORCE_MODVERSION) {
- err = kmod_elf_strip_section(elf, "__versions");
- if (err < 0)
- INFO(mod->ctx, "Failed to strip modversion: %s\n", strerror(-err));
- }
-
- if (flags & KMOD_INSERT_FORCE_VERMAGIC) {
- err = kmod_elf_strip_vermagic(elf);
- if (err < 0)
- INFO(mod->ctx, "Failed to strip vermagic: %s\n", strerror(-err));
- }
+ err = do_finit_module(mod, flags, args);
+ if (err == -ENOSYS)
+ err = do_init_module(mod, flags, args);
- mem = kmod_elf_get_memory(elf);
- } else {
- mem = kmod_file_get_contents(mod->file);
- }
- size = kmod_file_get_size(mod->file);
+ if (err < 0)
+ INFO(mod->ctx, "Failed to insert module '%s': %s\n",
+ path, strerror(-err));
- err = init_module(mem, size, args);
-init_finished:
- if (err < 0) {
- err = -errno;
- INFO(mod->ctx, "Failed to insert module '%s': %m\n", path);
- }
return err;
}
pathlen = snprintf(path, sizeof(path),
"/sys/module/%s/initstate", mod->name);
+ if (pathlen >= (int)sizeof(path)) {
+ /* Too long path was truncated */
+ return -ENAMETOOLONG;
+ }
fd = open(path, O_RDONLY|O_CLOEXEC);
if (fd < 0) {
err = -errno;
*
* After use, free the @list by calling kmod_module_info_free_list().
*
- * Returns: 0 on success or < 0 otherwise.
+ * Returns: number of entries in @list on success or < 0 otherwise.
*/
KMOD_EXPORT int kmod_module_get_info(const struct kmod_module *mod, 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;
-}
PKEY_HASH_SHA384,
PKEY_HASH_SHA512,
PKEY_HASH_SHA224,
+ PKEY_HASH_SM3,
PKEY_HASH__LAST
};
[PKEY_HASH_SHA384] = "sha384",
[PKEY_HASH_SHA512] = "sha512",
[PKEY_HASH_SHA224] = "sha224",
+ [PKEY_HASH_SM3] = "sm3",
};
enum pkey_id_type {
PKCS7 *pkcs7;
unsigned char *key_id;
BIGNUM *sno;
+ char *hash_algo;
};
static void pkcs7_free(void *s)
PKCS7_free(pvt->pkcs7);
BN_free(pvt->sno);
free(pvt->key_id);
+ free(pvt->hash_algo);
free(pvt);
si->private = NULL;
}
-static int obj_to_hash_algo(const ASN1_OBJECT *o)
-{
- int nid;
-
- nid = OBJ_obj2nid(o);
- switch (nid) {
- case NID_md4:
- return PKEY_HASH_MD4;
- case NID_md5:
- return PKEY_HASH_MD5;
- case NID_sha1:
- return PKEY_HASH_SHA1;
- case NID_ripemd160:
- return PKEY_HASH_RIPE_MD_160;
- case NID_sha256:
- return PKEY_HASH_SHA256;
- case NID_sha384:
- return PKEY_HASH_SHA384;
- case NID_sha512:
- return PKEY_HASH_SHA512;
- case NID_sha224:
- return PKEY_HASH_SHA224;
- default:
- return -1;
- }
- return -1;
-}
-
static const char *x509_name_to_str(X509_NAME *name)
{
int i;
unsigned char *key_id_str;
struct pkcs7_private *pvt;
const char *issuer_str;
+ char *hash_algo;
+ int hash_algo_len;
size -= sig_len;
pkcs7_raw = mem + size;
X509_ALGOR_get0(&o, NULL, NULL, dig_alg);
- sig_info->hash_algo = pkey_hash_algo[obj_to_hash_algo(o)];
+ // Use OBJ_obj2txt to calculate string length
+ hash_algo_len = OBJ_obj2txt(NULL, 0, o, 0);
+ if (hash_algo_len < 0)
+ goto err3;
+ hash_algo = malloc(hash_algo_len + 1);
+ if (hash_algo == NULL)
+ goto err3;
+ hash_algo_len = OBJ_obj2txt(hash_algo, hash_algo_len + 1, o, 0);
+ if (hash_algo_len < 0)
+ goto err4;
+
+ // Assign libcrypto hash algo string or number
+ sig_info->hash_algo = hash_algo;
+
sig_info->id_type = pkey_id_type[modsig->id_type];
pvt = malloc(sizeof(*pvt));
if (pvt == NULL)
- goto err3;
+ goto err4;
pvt->pkcs7 = pkcs7;
pvt->key_id = key_id_str;
pvt->sno = sno_bn;
+ pvt->hash_algo = hash_algo;
sig_info->private = pvt;
sig_info->free = pkcs7_free;
return true;
+err4:
+ free(hash_algo);
err3:
free(key_id_str);
err2:
* and is passed to all library operations.
*/
-static struct _index_files {
+static const struct {
const char *fn;
const char *prefix;
} index_files[] = {
[KMOD_INDEX_MODULES_BUILTIN] = { .fn = "modules.builtin", .prefix = ""},
};
-static const char *default_config_paths[] = {
+static const char *const default_config_paths[] = {
SYSCONFDIR "/modprobe.d",
"/run/modprobe.d",
+ "/usr/local/lib/modprobe.d",
+ DISTCONFDIR "/modprobe.d",
"/lib/modprobe.d",
NULL
};
void *log_data;
const void *userdata;
char *dirname;
+ enum kmod_file_compression_type kernel_compression;
struct kmod_config *config;
struct hash *modules_by_name;
struct index_mm *indexes[_KMOD_INDEX_MODULES_SIZE];
return 0;
}
-static const char *dirname_default_prefix = "/lib/modules";
+static const char *dirname_default_prefix = MODULE_DIRECTORY;
static char *get_kernel_release(const char *dirname)
{
return p;
}
+static enum kmod_file_compression_type get_kernel_compression(struct kmod_ctx *ctx)
+{
+ const char *path = "/sys/module/compression";
+ char buf[16];
+ int fd;
+ int err;
+
+ fd = open(path, O_RDONLY|O_CLOEXEC);
+ if (fd < 0) {
+ /* Not having the file is not an error: kernel may be too old */
+ DBG(ctx, "could not open '%s' for reading: %m\n", path);
+ return KMOD_FILE_COMPRESSION_NONE;
+ }
+
+ err = read_str_safe(fd, buf, sizeof(buf));
+ close(fd);
+ if (err < 0) {
+ ERR(ctx, "could not read from '%s': %s\n",
+ path, strerror(-err));
+ return KMOD_FILE_COMPRESSION_NONE;
+ }
+
+ if (streq(buf, "zstd\n"))
+ return KMOD_FILE_COMPRESSION_ZSTD;
+ else if (streq(buf, "xz\n"))
+ return KMOD_FILE_COMPRESSION_XZ;
+ else if (streq(buf, "gzip\n"))
+ return KMOD_FILE_COMPRESSION_ZLIB;
+
+ ERR(ctx, "unknown kernel compression %s", buf);
+
+ return KMOD_FILE_COMPRESSION_NONE;
+}
+
/**
* kmod_new:
* @dirname: what to consider as linux module's directory, if NULL
- * defaults to /lib/modules/`uname -r`. If it's relative,
+ * defaults to $MODULE_DIRECTORY/`uname -r`. If it's relative,
* it's treated as relative to the current working directory.
* Otherwise, give an absolute dirname.
* @config_paths: ordered array of paths (directories or files) where
* to load from user-defined configuration parameters such as
- * alias, blacklists, commands (install, remove). If
- * NULL defaults to /run/modprobe.d, /etc/modprobe.d and
+ * alias, blacklists, commands (install, remove). If NULL
+ * defaults to /etc/modprobe.d, /run/modprobe.d,
+ * /usr/local/lib/modprobe.d, DISTCONFDIR/modprobe.d, and
* /lib/modprobe.d. Give an empty vector if configuration should
* not be read. This array must be null terminated.
*
if (env != NULL)
kmod_set_log_priority(ctx, log_priority(env));
+ ctx->kernel_compression = get_kernel_compression(ctx);
+
if (config_paths == NULL)
config_paths = default_config_paths;
err = kmod_config_new(ctx, &ctx->config, config_paths);
{
return ctx->config;
}
+
+enum kmod_file_compression_type kmod_get_kernel_compression(const struct kmod_ctx *ctx)
+{
+ return ctx->kernel_compression;
+}
struct kmod_module **mod);
int kmod_module_new_from_lookup(struct kmod_ctx *ctx, const char *given_alias,
struct kmod_list **list);
+int kmod_module_new_from_name_lookup(struct kmod_ctx *ctx,
+ const char *modname,
+ struct kmod_module **mod);
int kmod_module_new_from_loaded(struct kmod_ctx *ctx,
struct kmod_list **list);
enum kmod_remove {
KMOD_REMOVE_FORCE = O_TRUNC,
KMOD_REMOVE_NOWAIT = O_NONBLOCK, /* always set */
+ /* libkmod-only defines, not passed to kernel */
+ KMOD_REMOVE_NOLOG = 1,
};
/* Insertion flags */
Description: Library to deal with kernel modules
Version: @VERSION@
Libs: -L${libdir} -lkmod
-Libs.private: @liblzma_LIBS@ @zlib_LIBS@
+Libs.private: @libzstd_LIBS@ @liblzma_LIBS@ @zlib_LIBS@
Cflags: -I${includedir}
kmod_module_new_from_name;
kmod_module_new_from_path;
kmod_module_new_from_lookup;
+ kmod_module_new_from_name_lookup;
kmod_module_new_from_loaded;
kmod_module_ref;
kmod_module_unref;
+++ /dev/null
-__pycache__
-dist
-*.c
-*.pyc
-*.so
-kmod/version.py
+++ /dev/null
-python-kmod
-===========
-
-Python bindings for kmod/libkmod
-
-python-kmod is a Python wrapper module for libkmod, exposing common
-module operations: listing installed modules, modprobe, and rmmod.
-It is at:
-
-Example (python invoked as root)
---------------------------------
-
-::
-
- >>> import kmod
- >>> km = kmod.Kmod()
- >>> [(m.name, m.size) for m in km.loaded()]
- [(u'nfs', 407706),
- (u'nfs_acl', 12741)
- ...
- (u'virtio_blk', 17549)]
- >>> km.modprobe("btrfs")
- >>> km.rmmod("btrfs")
+++ /dev/null
-# Copyright (C) 2012 W. Trevor King <wking@tremily.us>
-#
-# This file is part of python-kmod.
-#
-# python-kmod is free software: you can redistribute it and/or modify it under
-# the terms of the GNU Lesser General Public License version 2.1 as published
-# by the Free Software Foundation.
-#
-# python-kmod 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 python-kmod. If not, see <http://www.gnu.org/licenses/>.
-
-"Libkmod -- Python interface to kmod API."
-
-from .version import __version__
-try:
- from .kmod import Kmod
-except ImportError:
- # this is a non-Linux platform
- pass
+++ /dev/null
-# Copyright (C) 2012 W. Trevor King <wking@tremily.us>
-#
-# This file is part of python-kmod.
-#
-# python-kmod is free software: you can redistribute it and/or modify it under
-# the terms of the GNU Lesser General Public License version 2.1 as published
-# by the Free Software Foundation.
-#
-# python-kmod 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 python-kmod. If not, see <http://www.gnu.org/licenses/>.
-
-cimport libc.stdint as _stdint
-
-
-cdef extern from *:
- ctypedef char* const_char_ptr 'const char *'
- ctypedef char* const_char_const_ptr 'const char const *'
- ctypedef void* const_void_ptr 'const void *'
-
-
-cdef extern from 'stdbool.h':
- ctypedef struct bool:
- pass
-
-
-cdef extern from 'libkmod/libkmod.h':
- # library user context - reads the config and system
- # environment, user variables, allows custom logging
- cdef struct kmod_ctx:
- pass
-
- kmod_ctx *kmod_new(
- const_char_ptr dirname, const_char_const_ptr config_paths)
- kmod_ctx *kmod_ref(kmod_ctx *ctx)
- kmod_ctx *kmod_unref(kmod_ctx *ctx)
-
- # Management of libkmod's resources
- int kmod_load_resources(kmod_ctx *ctx)
- void kmod_unload_resources(kmod_ctx *ctx)
-
- # access to kmod generated lists
- cdef struct kmod_list:
- pass
- ctypedef kmod_list* const_kmod_list_ptr 'const struct kmod_list *'
- kmod_list *kmod_list_next(
- const_kmod_list_ptr list, const_kmod_list_ptr curr)
- kmod_list *kmod_list_prev(
- const_kmod_list_ptr list, const_kmod_list_ptr curr)
- kmod_list *kmod_list_last(const_kmod_list_ptr list)
-
- # Operate on kernel modules
- cdef struct kmod_module:
- pass
- ctypedef kmod_module* const_kmod_module_ptr 'const struct kmod_module *'
- int kmod_module_new_from_name(
- kmod_ctx *ctx, const_char_ptr name, kmod_module **mod)
- int kmod_module_new_from_lookup(
- kmod_ctx *ctx, const_char_ptr given_alias, kmod_list **list)
- int kmod_module_new_from_loaded(kmod_ctx *ctx, kmod_list **list)
-
- kmod_module *kmod_module_ref(kmod_module *mod)
- kmod_module *kmod_module_unref(kmod_module *mod)
- int kmod_module_unref_list(kmod_list *list)
- kmod_module *kmod_module_get_module(kmod_list *entry)
-
- # Flags to kmod_module_probe_insert_module
- # codes below can be used in return value, too
- enum: KMOD_PROBE_APPLY_BLACKLIST
-
- #ctypedef int (*install_callback_t)(
- # kmod_module *m, const_char_ptr cmdline, const_void_ptr data)
- #ctypedef void (*print_action_callback_t)(
- # kmod_module *m, bool install, const_char_ptr options)
-
- int kmod_module_remove_module(
- kmod_module *mod, unsigned int flags)
- int kmod_module_insert_module(
- kmod_module *mod, unsigned int flags, const_char_ptr options)
- int kmod_module_probe_insert_module(
- kmod_module *mod, unsigned int flags, const_char_ptr extra_options,
- int (*run_install)(
- kmod_module *m, const_char_ptr cmdline, void *data),
- const_void_ptr data,
- void (*print_action)(
- kmod_module *m, bool install, const_char_ptr options),
- )
-
- const_char_ptr kmod_module_get_name(const_kmod_module_ptr mod)
- const_char_ptr kmod_module_get_path(const_kmod_module_ptr mod)
- const_char_ptr kmod_module_get_options(const_kmod_module_ptr mod)
- const_char_ptr kmod_module_get_install_commands(const_kmod_module_ptr mod)
- const_char_ptr kmod_module_get_remove_commands(const_kmod_module_ptr mod)
-
- # Information regarding "live information" from module's state, as
- # returned by kernel
- int kmod_module_get_refcnt(const_kmod_module_ptr mod)
- long kmod_module_get_size(const_kmod_module_ptr mod)
-
- # Information retrieved from ELF headers and section
- int kmod_module_get_info(const_kmod_module_ptr mod, kmod_list **list)
- const_char_ptr kmod_module_info_get_key(const_kmod_list_ptr entry)
- const_char_ptr kmod_module_info_get_value(const_kmod_list_ptr entry)
- void kmod_module_info_free_list(kmod_list *list)
-
- int kmod_module_get_versions(const_kmod_module_ptr mod, kmod_list **list)
- const_char_ptr kmod_module_version_get_symbol(const_kmod_list_ptr entry)
- _stdint.uint64_t kmod_module_version_get_crc(const_kmod_list_ptr entry)
- void kmod_module_versions_free_list(kmod_list *list)
+++ /dev/null
-# Copyright (C) 2012 W. Trevor King <wking@tremily.us>
-#
-# This file is part of python-kmod.
-#
-# python-kmod is free software: you can redistribute it and/or modify it under
-# the terms of the GNU Lesser General Public License version 2.1 as published
-# by the Free Software Foundation.
-#
-# python-kmod 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 python-kmod. If not, see <http://www.gnu.org/licenses/>.
-
-cimport _libkmod_h
-
-
-cdef object char_ptr_to_str(_libkmod_h.const_char_ptr bytes)
+++ /dev/null
-# Copyright (C) 2012 W. Trevor King <wking@tremily.us>
-#
-# This file is part of python-kmod.
-#
-# python-kmod is free software: you can redistribute it and/or modify it under
-# the terms of the GNU Lesser General Public License version 2.1 as published
-# by the Free Software Foundation.
-#
-# python-kmod 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 python-kmod. If not, see <http://www.gnu.org/licenses/>.
-
-import sys as _sys
-
-cimport _libkmod_h
-
-
-cdef object char_ptr_to_str(_libkmod_h.const_char_ptr char_ptr):
- if char_ptr is NULL:
- return None
- if _sys.version_info >= (3,): # Python 3
- return str(char_ptr, 'ascii')
- # Python 2
- return unicode(char_ptr, 'ascii')
+++ /dev/null
-# Copyright (C) 2012 W. Trevor King <wking@tremily.us>
-#
-# This file is part of python-kmod.
-#
-# python-kmod is free software: you can redistribute it and/or modify it under
-# the terms of the GNU Lesser General Public License version 2.1 as published
-# by the Free Software Foundation.
-#
-# python-kmod 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 python-kmod. If not, see <http://www.gnu.org/licenses/>.
-
-class KmodError (Exception):
- pass
+++ /dev/null
-# Copyright (C) 2012 W. Trevor King <wking@tremily.us>
-#
-# This file is part of python-kmod.
-#
-# python-kmod is free software: you can redistribute it and/or modify it under
-# the terms of the GNU Lesser General Public License version 2.1 as published
-# by the Free Software Foundation.
-#
-# python-kmod 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 python-kmod. If not, see <http://www.gnu.org/licenses/>.
-
-cimport _libkmod_h
-
-
-cdef class Kmod (object):
- cdef _libkmod_h.kmod_ctx *_kmod_ctx
- cdef object mod_dir
+++ /dev/null
-# Copyright (C) 2012 Red Hat, Inc.
-# W. Trevor King <wking@tremily.us>
-#
-# This file is part of python-kmod.
-#
-# python-kmod is free software: you can redistribute it and/or modify it under
-# the terms of the GNU Lesser General Public License version 2.1 as published
-# by the Free Software Foundation.
-#
-# python-kmod 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 python-kmod. If not, see <http://www.gnu.org/licenses/>.
-
-"Define the Kmod class"
-
-cimport cython as _cython
-cimport _libkmod_h
-from error import KmodError as _KmodError
-cimport module as _module
-import module as _module
-cimport list as _list
-import list as _list
-
-
-cdef class Kmod (object):
- "Wrap a struct kmod_ctx* item"
- def __cinit__(self):
- self._kmod_ctx = NULL
- self.mod_dir = None
-
- def __dealloc__(self):
- self._cleanup()
-
- def __init__(self, mod_dir=None):
- self.set_mod_dir(mod_dir=mod_dir)
-
- def set_mod_dir(self, mod_dir=None):
- self.mod_dir = mod_dir
- self._setup()
-
- def _setup(self):
- cdef char *mod_dir = NULL
- self._cleanup()
- if self.mod_dir:
- mod_dir = self.mod_dir
- self._kmod_ctx = _libkmod_h.kmod_new(mod_dir, NULL);
- if self._kmod_ctx is NULL:
- raise _KmodError('Could not initialize')
- _libkmod_h.kmod_load_resources(self._kmod_ctx)
-
- def _cleanup(self):
- if self._kmod_ctx is not NULL:
- _libkmod_h.kmod_unload_resources(self._kmod_ctx);
- self._kmod_ctx = NULL
-
- def loaded(self):
- "iterate through currently loaded modules"
- cdef _list.ModList ml = _list.ModList()
- cdef _list.ModListItem mli
- err = _libkmod_h.kmod_module_new_from_loaded(self._kmod_ctx, &ml.list)
- if err < 0:
- raise _KmodError('Could not get loaded modules')
- for item in ml:
- mli = <_list.ModListItem> item
- mod = _module.Module()
- mod.from_mod_list_item(item)
- yield mod
-
- def lookup(self, alias_name, flags=_libkmod_h.KMOD_PROBE_APPLY_BLACKLIST):
- "iterate through modules matching `alias_name`"
- cdef _list.ModList ml = _list.ModList()
- cdef _list.ModListItem mli
- if hasattr(alias_name, 'encode'):
- alias_name = alias_name.encode('ascii')
- err = _libkmod_h.kmod_module_new_from_lookup(
- self._kmod_ctx, alias_name, &ml.list)
- if err < 0:
- raise _KmodError('Could not modprobe')
- for item in ml:
- mli = <_list.ModListItem> item
- mod = _module.Module()
- mod.from_mod_list_item(item)
- yield mod
-
- @_cython.always_allow_keywords(True)
- def module_from_name(self, name):
- cdef _module.Module mod = _module.Module()
- if hasattr(name, 'encode'):
- name = name.encode('ascii')
- err = _libkmod_h.kmod_module_new_from_name(
- self._kmod_ctx, name, &mod.module)
- if err < 0:
- raise _KmodError('Could not get module')
- return mod
-
- def list(self):
- "iterate through currently loaded modules and sizes"
- for mod in self.loaded():
- yield (mod.name, mod.size)
-
- def modprobe(self, name, quiet=False, *args, **kwargs):
- """
- Load a module (or alias) and all modules on which it depends.
- The 'quiet' option defaults to False; set to True to mimic the behavior
- of the '--quiet' commandline option.
- """
- mods = list(self.lookup(alias_name=name))
-
- if not mods and not quiet:
- raise _KmodError('Could not modprobe %s' % name)
-
- for mod in mods:
- mod.insert(*args, **kwargs)
-
- def rmmod(self, module_name, *args, **kwargs):
- """
- remove module from current tree
- e.g. km.rmmod("thinkpad_acpi")
- """
- mod = self.module_from_name(name=module_name)
- mod.remove(*args, **kwargs)
+++ /dev/null
-# Copyright (C) 2012 W. Trevor King <wking@tremily.us>
-#
-# This file is part of python-kmod.
-#
-# python-kmod is free software: you can redistribute it and/or modify it under
-# the terms of the GNU Lesser General Public License version 2.1 as published
-# by the Free Software Foundation.
-#
-# python-kmod 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 python-kmod. If not, see <http://www.gnu.org/licenses/>.
-
-cimport _libkmod_h
-
-
-cdef class ModListItem (object):
- cdef _libkmod_h.kmod_list *list
-
-
-cdef class ModList (ModListItem):
- cdef _libkmod_h.kmod_list *_next
+++ /dev/null
-# Copyright (C) 2012 W. Trevor King <wking@tremily.us>
-#
-# This file is part of python-kmod.
-#
-# python-kmod is free software: you can redistribute it and/or modify it under
-# the terms of the GNU Lesser General Public License version 2.1 as published
-# by the Free Software Foundation.
-#
-# python-kmod 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 python-kmod. If not, see <http://www.gnu.org/licenses/>.
-
-cimport _libkmod_h
-
-
-cdef class ModListItem (object):
- "Wrap a struct kmod_list* list item"
- def __cinit__(self):
- self.list = NULL
-
-
-cdef class ModList (ModListItem):
- "Wrap a struct kmod_list* list with iteration"
- def __cinit__(self):
- self._next = NULL
-
- def __dealloc__(self):
- if self.list is not NULL:
- _libkmod_h.kmod_module_unref_list(self.list)
-
- def __iter__(self):
- self._next = self.list
- return self
-
- def __next__(self):
- if self._next is NULL:
- raise StopIteration()
- mli = ModListItem()
- mli.list = self._next
- self._next = _libkmod_h.kmod_list_next(self.list, self._next)
- return mli
+++ /dev/null
-# Copyright (C) 2012 W. Trevor King <wking@tremily.us>
-#
-# This file is part of python-kmod.
-#
-# python-kmod is free software: you can redistribute it and/or modify it under
-# the terms of the GNU Lesser General Public License version 2.1 as published
-# by the Free Software Foundation.
-#
-# python-kmod 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 python-kmod. If not, see <http://www.gnu.org/licenses/>.
-
-cimport _libkmod_h
-cimport list as _list
-
-
-cdef class Module (object):
- cdef _libkmod_h.kmod_module *module
-
- cpdef from_mod_list_item(self, _list.ModListItem item)
+++ /dev/null
-# Copyright (C) 2012 W. Trevor King <wking@tremily.us>
-#
-# This file is part of python-kmod.
-#
-# python-kmod is free software: you can redistribute it and/or modify it under
-# the terms of the GNU Lesser General Public License version 2.1 as published
-# by the Free Software Foundation.
-#
-# python-kmod 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 python-kmod. If not, see <http://www.gnu.org/licenses/>.
-
-import collections as _collections
-
-cimport libc.errno as _errno
-
-cimport _libkmod_h
-from error import KmodError as _KmodError
-cimport list as _list
-import list as _list
-cimport _util
-import _util
-
-
-cdef class Module (object):
- "Wrap a struct kmod_module* item"
- def __cinit__(self):
- self.module = NULL
-
- def __dealloc__(self):
- self._cleanup()
-
- def _cleanup(self):
- if self.module is not NULL:
- _libkmod_h.kmod_module_unref(self.module)
- self.module = NULL
-
- cpdef from_mod_list_item(self, _list.ModListItem item):
- self._cleanup()
- self.module = _libkmod_h.kmod_module_get_module(item.list)
-
- def _name_get(self):
- return _util.char_ptr_to_str(
- _libkmod_h.kmod_module_get_name(self.module))
- name = property(fget=_name_get)
-
- def _path_get(self):
- return _util.char_ptr_to_str(
- _libkmod_h.kmod_module_get_path(self.module))
- path = property(fget=_path_get)
-
- def _options_get(self):
- return _util.char_ptr_to_str(
- _libkmod_h.kmod_module_get_options(self.module))
- options = property(fget=_options_get)
-
- def _install_commands_get(self):
- return _util.char_ptr_to_str(
- _libkmod_h.kmod_module_get_install_commands(self.module))
- install_commands = property(fget=_install_commands_get)
-
- def _remove_commands_get(self):
- return _util.char_ptr_to_str(
- _libkmod_h.kmod_module_get_remove_commands(self.module))
- remove_commands = property(fget=_remove_commands_get)
-
- def _refcnt_get(self):
- return _libkmod_h.kmod_module_get_refcnt(self.module)
- refcnt = property(fget=_refcnt_get)
-
- def _size_get(self):
- return _libkmod_h.kmod_module_get_size(self.module)
- size = property(fget=_size_get)
-
- def _info_get(self):
- cdef _list.ModList ml = _list.ModList()
- cdef _list.ModListItem mli
- err = _libkmod_h.kmod_module_get_info(self.module, &ml.list)
- if err < 0:
- raise _KmodError('Could not get info')
- info = _collections.OrderedDict()
- try:
- for item in ml:
- mli = <_list.ModListItem> item
- key = _util.char_ptr_to_str(
- _libkmod_h.kmod_module_info_get_key(mli.list))
- value = _util.char_ptr_to_str(
- _libkmod_h.kmod_module_info_get_value(mli.list))
- info[key] = value
- finally:
- _libkmod_h.kmod_module_info_free_list(ml.list)
- ml.list = NULL
- return info
- info = property(fget=_info_get)
-
- def _versions_get(self):
- cdef _list.ModList ml = _list.ModList()
- cdef _list.ModListItem mli
- err = _libkmod_h.kmod_module_get_versions(self.module, &ml.list)
- if err < 0:
- raise _KmodError('Could not get versions')
- try:
- for item in ml:
- mli = <_list.ModListItem> item
- symbol = _util.char_ptr_to_str(
- _libkmod_h.kmod_module_version_get_symbol(mli.list))
- crc = _libkmod_h.kmod_module_version_get_crc(mli.list)
- yield {'symbol': symbol, 'crc': crc}
- finally:
- _libkmod_h.kmod_module_versions_free_list(ml.list)
- ml.list = NULL
- versions = property(fget=_versions_get)
-
- def insert(self, flags=0, extra_options=None, install_callback=None,
- data=None, print_action_callback=None):
- """
- insert module to current tree.
- e.g.
- km = kmod.Kmod()
- tp = km.module_from_name("thinkpad_acpi")
- tp.insert(extra_options='fan_control=1')
- """
- cdef char *opt = NULL
- #cdef _libkmod_h.install_callback_t install = NULL
- cdef int (*install)(
- _libkmod_h.kmod_module *, _libkmod_h.const_char_ptr, void *)
- install = NULL
- cdef void *d = NULL
- #cdef _libkmod_h.print_action_callback_t print_action = NULL
- cdef void (*print_action)(
- _libkmod_h.kmod_module *, _libkmod_h.bool,
- _libkmod_h.const_char_ptr)
- print_action = NULL
- if extra_options:
- opt = extra_options
- # TODO: convert callbacks and data from Python object to C types
- err = _libkmod_h.kmod_module_probe_insert_module(
- self.module, flags, opt, install, d, print_action)
- if err == -_errno.EEXIST:
- raise _KmodError('Module already loaded')
- elif err < 0:
- raise _KmodError('Could not load module')
-
- def remove(self, flags=0):
- """
- remove module from current tree
- e.g.
- km = kmod.Kmod()
- tp = km.module_from_name("thinkpad_acpi")
- tp.remove()
- """
- err = _libkmod_h.kmod_module_remove_module(self.module, flags)
- if err < 0:
- raise _KmodError('Could not remove module')
+++ /dev/null
-# Copyright (C) 2012 W. Trevor King <wking@tremily.us>
-#
-# This file is part of python-kmod.
-#
-# python-kmod is free software: you can redistribute it and/or modify it under
-# the terms of the GNU Lesser General Public License version 2.1 as published
-# by the Free Software Foundation.
-#
-# python-kmod 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 python-kmod. If not, see <http://www.gnu.org/licenses/>.
-
-__version__ = '@VERSION@'
modules.dep.bin.5: modules.dep.5
endif
-EXTRA_DIST = $(MAN5:%.5=%.xml) $(MAN8:%.8=%.xml)
+EXTRA_DIST = $(MAN5:%.5=%.5.xml) $(MAN8:%.8=%.8.xml)
CLEANFILES = $(dist_man_MANS)
-%.5 %.8: %.xml
- $(AM_V_XSLT)$(XSLT) \
+define generate_manpage
+ $(AM_V_XSLT)if [ '$(distconfdir)' != '/lib' ] ; then \
+ sed -e 's|@DISTCONFDIR@|$(distconfdir)|g' $< ; \
+ else \
+ sed -e '/@DISTCONFDIR@/d' $< ; \
+ fi | \
+ sed -e 's|@MODULE_DIRECTORY@|$(module_directory)|g' | \
+ $(XSLT) \
-o $@ \
--nonet \
--stringparam man.output.quietly 1 \
--param funcsynopsis.style "'ansi'" \
- http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
+ http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl -
+endef
+
+%.5: %.5.xml
+ $(generate_manpage)
+
+%.8: %.8.xml
+ $(generate_manpage)
<cmdsynopsis>
<command>depmod</command>
<arg><option>-b <replaceable>basedir</replaceable></option></arg>
+ <arg><option>-o <replaceable>outdir</replaceable></option></arg>
<arg><option>-e</option></arg>
<arg><option>-E <replaceable>Module.symvers</replaceable></option></arg>
<arg><option>-F <replaceable>System.map</replaceable></option></arg>
</para>
<para> <command>depmod</command> creates a list of module dependencies by
reading each module under
- <filename>/lib/modules/</filename><replaceable>version</replaceable> and
+ <filename>@MODULE_DIRECTORY@/</filename><replaceable>version</replaceable> and
determining what symbols it exports and what symbols it needs. By
default, this list is written to <filename>modules.dep</filename>, and a
binary hashed version named <filename>modules.dep.bin</filename>, in the
<listitem>
<para>
If your modules are not currently in the (normal) directory
- <filename>/lib/modules/</filename><replaceable>version</replaceable>,
+ <filename>@MODULE_DIRECTORY@/</filename><replaceable>version</replaceable>,
but in a staging area, you can specify a
<replaceable>basedir</replaceable> which is prepended to the
directory name. This <replaceable>basedir</replaceable> is
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>
+ <option>-o <replaceable>outdir</replaceable></option>
+ </term>
+ <term>
+ <option>--outdir <replaceable>outdir</replaceable></option>
+ </term>
+ <listitem>
+ <para>
+ Set the output directory where depmod will store any generated file.
+ <replaceable>outdir</replaceable> serves as a root to that location,
+ similar to how <replaceable>basedir</replaceable> is used. Also this
+ setting takes precedence and if used together with
+ <replaceable>basedir</replaceable> it will result in the input being
+ that directory, but the output being the one set by
+ <replaceable>outdir</replaceable>.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term>
<option>-C</option>
</refnamediv>
<refsynopsisdiv>
- <para><filename>/usr/lib/depmod.d/*.conf</filename></para>
- <para><filename>/etc/depmod.d/*.conf</filename></para>
+ <para><filename>/lib/depmod.d/*.conf</filename></para>
+ <para><filename>@DISTCONFDIR@/depmod.d/*.conf</filename></para>
+ <para><filename>/usr/local/lib/depmod.d/*.conf</filename></para>
<para><filename>/run/depmod.d/*.conf</filename></para>
+ <para><filename>/etc/depmod.d/*.conf</filename></para>
</refsynopsisdiv>
<refsect1><title>DESCRIPTION</title>
</term>
<listitem>
<para>
- This allows you to specify the order in which /lib/modules
+ This allows you to specify the order in which @MODULE_DIRECTORY@
(or other configured module location) subdirectories will
be processed by <command>depmod</command>. Directories are
listed in order, with the highest priority given to the
<command>depmod</command> command. It is possible to
specify one kernel or all kernels using the * wildcard.
<replaceable>modulesubdirectory</replaceable> is the
- name of the subdirectory under /lib/modules (or other
+ name of the subdirectory under @MODULE_DIRECTORY@ (or other
module location) where the target module is installed.
</para>
<para>
specifying the following command: "override kmod * extra".
This will ensure that any matching module name installed
under the <command>extra</command> subdirectory within
- /lib/modules (or other module location) will take priority
+ @MODULE_DIRECTORY@ (or other module location) will take priority
over any likenamed module already provided by the kernel.
</para>
</listitem>
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>exclude <replaceable>excludedir</replaceable>
+ </term>
+ <listitem>
+ <para>
+ This specifies the trailing directories that will be excluded
+ during the search for kernel modules.
+ </para>
+ <para>
+ The <replaceable>excludedir</replaceable> is the trailing directory
+ to exclude
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
<command>modinfo</command> extracts information from the Linux Kernel
modules given on the command line. If the module name is not a filename,
then the
- <filename>/lib/modules/</filename><replaceable>version</replaceable>
+ <filename>@MODULE_DIRECTORY@/</filename><replaceable>version</replaceable>
directory is searched, as is also done by
<citerefentry><refentrytitle>modprobe</refentrytitle><manvolnum>8</manvolnum></citerefentry>
when loading kernel modules.
is no difference between _ and - in module names (automatic
underscore conversion is performed).
<command>modprobe</command> looks in the module directory
- <filename>/lib/modules/`uname -r`</filename> for all
+ <filename>@MODULE_DIRECTORY@/`uname -r`</filename> for all
the modules and other files, except for the optional
configuration files in the
<filename>/etc/modprobe.d</filename> directory
kernel (in addition to any options listed in the configuration
file).
</para>
+ <para>
+ When loading modules, <replaceable>modulename</replaceable> can also
+ be a path to the module. If the path is relative, it must
+ explicitly start with "./". Note that this may fail when using a
+ path to a module with dependencies not matching the installed depmod
+ database.
+ </para>
</refsect1>
<refsect1><title>OPTIONS</title>
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>
+ <option>-w</option>
+ </term>
+ <term>
+ <option>--wait=</option>TIMEOUT_MSEC
+ </term>
+ <listitem>
+ <para>
+ This option causes <command>modprobe -r</command> to continue trying to
+ remove a module if it fails due to the module being busy, i.e. its refcount
+ is not 0 at the time the call is made. Modprobe tries to remove the module
+ with an incremental sleep time between each tentative up until the maximum
+ wait time in milliseconds passed in this option.
+ </para>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term>
<option>-S</option>
<refsynopsisdiv>
<para><filename>/lib/modprobe.d/*.conf</filename></para>
- <para><filename>/etc/modprobe.d/*.conf</filename></para>
+ <para><filename>@DISTCONFDIR@/modprobe.d/*.conf</filename></para>
+ <para><filename>/usr/local/lib/modprobe.d/*.conf</filename></para>
<para><filename>/run/modprobe.d/*.conf</filename></para>
+ <para><filename>/etc/modprobe.d/*.conf</filename></para>
</refsynopsisdiv>
<refsect1><title>DESCRIPTION</title>
</refnamediv>
<refsynopsisdiv>
- <para><filename>/lib/modules/modules.dep</filename></para>
- <para><filename>/lib/modules/modules.dep.bin</filename></para>
+ <para><filename>@MODULE_DIRECTORY@/modules.dep</filename></para>
+ <para><filename>@MODULE_DIRECTORY@/modules.dep.bin</filename></para>
</refsynopsisdiv>
<refsect1><title>DESCRIPTION</title>
<filename>modules.dep.bin</filename> is a binary file generated by
<command>depmod</command> listing the dependencies for
every module in the directories under
- <filename>/lib/modules/</filename><replaceable>version</replaceable>.
+ <filename>@MODULE_DIRECTORY@/</filename><replaceable>version</replaceable>.
It is used by kmod tools such as <command>modprobe</command> and
libkmod.
</para>
<para>
- Its text counterpar is located in the same directory with the name
+ Its text counterpart is located in the same directory with the name
<filename>modules.dep</filename>. The text version is maintained only
for easy of reading by humans and is in no way used by any kmod tool.
</para>
want to use
<citerefentry>
<refentrytitle>modprobe</refentrytitle><manvolnum>8</manvolnum>
- </citerefentry> with the <option>-r</option> option instead.
+ </citerefentry> with the <option>-r</option> option instead
+ since it removes unused dependent modules as well.
</para>
</refsect1>
.key = key,
.value = NULL
};
- const struct hash_entry *entry = bsearch(
- &se, bucket->entries, bucket->used,
- sizeof(struct hash_entry), hash_entry_cmp);
- if (entry == NULL)
+ const struct hash_entry *entry;
+
+ if (!bucket->entries)
return NULL;
- return (void *)entry->value;
+
+ entry = bsearch(&se, bucket->entries, bucket->used,
+ sizeof(struct hash_entry), hash_entry_cmp);
+
+ return entry ? (void *)entry->value : NULL;
}
int hash_del(struct hash *hash, const char *key)
})
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + _array_size_chk(arr))
+
#define XSTRINGIFY(x) #x
#define STRINGIFY(x) XSTRINGIFY(x)
+#define XCONCATENATE(x, y) x ## y
+#define CONCATENATE(x, y) XCONCATENATE(x, y)
+#define UNIQ(x) CONCATENATE(x, __COUNTER__)
+
/* Temporaries for importing index handling */
#define NOFAIL(x) (x)
#define fatal(x...) do { } while (0)
#define noreturn __attribute__((noreturn))
#endif
#endif
-
-#define UNIQ __COUNTER__
# define MODULE_INIT_IGNORE_VERMAGIC 2
#endif
+#ifndef MODULE_INIT_COMPRESSED_FILE
+# define MODULE_INIT_COMPRESSED_FILE 4
+#endif
+
#ifndef __NR_finit_module
# define __NR_finit_module -1
#endif
#endif
#ifdef ENABLE_XZ
{".ko.xz", sizeof(".ko.xz") - 1},
+#endif
+#ifdef ENABLE_ZSTD
+ {".ko.zst", sizeof(".ko.zst") - 1},
#endif
{ }
};
/* path handling functions */
/* ************************************************************************ */
-bool path_is_absolute(const char *p)
+static bool path_is_absolute(const char *p)
{
assert(p != NULL);
return mkdir_p(path, end - path, mode);
}
-unsigned long long ts_usec(const struct timespec *ts)
+static unsigned long long ts_usec(const struct timespec *ts)
{
return (unsigned long long) ts->tv_sec * USEC_PER_SEC +
(unsigned long long) ts->tv_nsec / NSEC_PER_USEC;
}
+static unsigned long long ts_msec(const struct timespec *ts)
+{
+ return (unsigned long long) ts->tv_sec * MSEC_PER_SEC +
+ (unsigned long long) ts->tv_nsec / NSEC_PER_MSEC;
+}
+
+static struct timespec msec_ts(unsigned long long msec)
+{
+ struct timespec ts = {
+ .tv_sec = msec / MSEC_PER_SEC,
+ .tv_nsec = (msec % MSEC_PER_SEC) * NSEC_PER_MSEC,
+ };
+
+ return ts;
+}
+
+int sleep_until_msec(unsigned long long msec)
+{
+ struct timespec ts = msec_ts(msec);
+
+ if (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL) < 0 &&
+ errno != EINTR)
+ return -errno;
+
+ return 0;
+}
+
+/*
+ * Exponential retry backoff with tail
+ */
+unsigned long long get_backoff_delta_msec(unsigned long long t0,
+ unsigned long long tend,
+ unsigned long long *delta)
+{
+ unsigned long long t;
+
+ t = now_msec();
+
+ if (!*delta)
+ *delta = 1;
+ else
+ *delta <<= 1;
+
+ while (t + *delta > tend)
+ *delta >>= 1;
+
+ if (!*delta && tend > t)
+ *delta = tend - t;
+
+ return t + *delta;
+}
+
+unsigned long long now_usec(void)
+{
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
+ return 0;
+
+ return ts_usec(&ts);
+}
+
+unsigned long long now_msec(void)
+{
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
+ return 0;
+
+ return ts_msec(&ts);
+}
+
unsigned long long stat_mstamp(const struct stat *st)
{
#ifdef HAVE_STRUCT_STAT_ST_MTIM
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <time.h>
#include <shared/macro.h>
/* path handling functions */
/* ************************************************************************ */
-bool path_is_absolute(const char *p) _must_check_ __attribute__((nonnull(1)));
char *path_make_absolute_cwd(const char *p) _must_check_ __attribute__((nonnull(1)));
int mkdir_p(const char *path, int len, mode_t mode);
int mkdir_parents(const char *path, mode_t mode);
unsigned long long stat_mstamp(const struct stat *st);
-unsigned long long ts_usec(const struct timespec *ts);
+
+/* time-related functions
+ * ************************************************************************ */
+#define USEC_PER_SEC 1000000ULL
+#define USEC_PER_MSEC 1000ULL
+#define MSEC_PER_SEC 1000ULL
+#define NSEC_PER_MSEC 1000000ULL
+
+unsigned long long now_usec(void);
+unsigned long long now_msec(void);
+int sleep_until_msec(unsigned long long msec);
+unsigned long long get_backoff_delta_msec(unsigned long long t0,
+ unsigned long long tend,
+ unsigned long long *delta);
+
/* endianess and alignments */
/* ************************************************************************ */
/test-modprobe
/test-hash
/test-list
-/test-tools
/rootfs
/stamp-rootfs
/test-scratchbuf.log
/test-testsuite.trs
/test-list.log
/test-list.trs
-/test-tools.log
-/test-tools.trs
+++ /dev/null
-/*-image.raw*
-/.mkosi-*
-/mkosi.cache
+++ /dev/null
-[Distribution]
-Distribution=arch
-Release=(rolling)
-
-[Output]
-Output = arch-image.raw
-
-[Packages]
-Packages = valgrind
-BuildPackages =
- automake
- gcc
- git
- make
- pkg-config
- python2
- python2-future
- autoconf
- gtk-doc
- docbook-xml
- docbook-xsl
- linux-headers
- openssl
-
-[Partitions]
-RootSize = 3G
+++ /dev/null
-#!/bin/bash -ex
-
-function find_kdir() {
- local kdirs=(/usr/lib/modules/*/build/Makefile /usr/src/kernels/*/Makefile)
- local kdir=""
-
- for f in "${kdirs[@]}"; do
- if [ -f "$f" ]; then
- kdir=$f
- break
- fi
- done
-
- if [ -z "$kdir" ]; then
- printf '==> Unable to find kernel headers to build modules for tests\n' >&2
- exit 1
- fi
-
- kdir=${kdir%/Makefile}
-
- echo $kdir
-}
-
-if [ -f configure ]; then
- make distclean
-fi
-
-rm -rf build
-mkdir build
-cd build
-
-kdir=$(find_kdir)
-IFS=/ read _ _ _ kver _ <<<"$kdir"
-
-../autogen.sh c --disable-python
-make -j
-make check KDIR="$kdir" KVER="$kver"
-make install
+++ /dev/null
-[Distribution]
-Distribution=clear
-Release=latest
-
-[Output]
-Output = clear-image.raw
-
-[Packages]
-Packages=
- os-core-update
-BuildPackages=
- os-core-dev
- linux-dev
-
-[Partitions]
-RootSize = 5G
-
-[Host]
-# This is where swupd-extract is usually installed.
-ExtraSearchPaths=$SUDO_HOME/go/bin
\ No newline at end of file
+++ /dev/null
-[Distribution]
-Distribution=fedora
-Release=29
-
-[Output]
-Output = fedora-image.raw
-
-[Packages]
-Packages = valgrind
-BuildPackages =
- autoconf
- automake
- gcc
- git
- gtk-doc
- kernel-devel
- libtool
- libxslt
- make
- pkgconf-pkg-config
- xml-common
- xz-devel
- zlib-devel
- openssl-devel
-
-[Partitions]
-RootSize = 2G
-*o.cmd
*.ko
!mod-simple-*.ko
!cache/*.ko
*.mod
*.a
*.cmd
+*.o.d
modules.order
Module.symvers
else
# normal makefile
-KDIR ?= /lib/modules/`uname -r`/build
+KDIR ?= $(module_prefix)/lib/modules/`uname -r`/build
KVER ?= `uname -r`
ifeq ($(FAKE_BUILD),)
FAKE_BUILD=0
+#include <linux/debugfs.h>
#include <linux/init.h>
#include <linux/module.h>
+static struct dentry *debugfs_dir;
+
+static int test_show(struct seq_file *s, void *data)
+{
+ seq_puts(s, "test");
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(test);
+
static int __init test_module_init(void)
{
+ debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+ debugfs_create_file("test", 0444, debugfs_dir, NULL, &test_fops);
+
return 0;
}
static void test_module_exit(void)
{
+ debugfs_remove_recursive(debugfs_dir);
}
+
module_init(test_module_init);
module_exit(test_module_exit);
MODULE_AUTHOR("Lucas De Marchi <lucas.demarchi@intel.com>");
-MODULE_LICENSE("LGPL");
+MODULE_LICENSE("GPL");
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
+/* We unset _FILE_OFFSET_BITS here so we can override both stat and stat64 on
+ * 32-bit architectures and forward each to the right libc function */
+#undef _FILE_OFFSET_BITS
+
#include <assert.h>
#include <dirent.h>
#include <dlfcn.h>
return _fn(p, flags); \
}
-/* wrapper template for __xstat family */
+/*
+ * wrapper template for __xstat family
+ * This family got deprecated/dropped in glibc 2.32.9000, but we still need
+ * to keep it for a while for programs that were built against previous versions
+ */
#define WRAP_VERSTAT(prefix, suffix) \
+TS_EXPORT int prefix ## stat ## suffix (int ver, \
+ const char *path, \
+ struct stat ## suffix *st); \
TS_EXPORT int prefix ## stat ## suffix (int ver, \
const char *path, \
struct stat ## suffix *st) \
}
WRAP_1ARG(DIR*, NULL, opendir);
+WRAP_1ARG(int, -1, chdir);
WRAP_2ARGS(FILE*, NULL, fopen, const char*);
+WRAP_2ARGS(FILE*, NULL, fopen64, const char*);
WRAP_2ARGS(int, -1, mkdir, mode_t);
WRAP_2ARGS(int, -1, access, int);
WRAP_2ARGS(int, -1, stat, struct stat*);
WRAP_2ARGS(int, -1, lstat, struct stat*);
-#ifndef _FILE_OFFSET_BITS
WRAP_2ARGS(int, -1, stat64, struct stat64*);
WRAP_2ARGS(int, -1, lstat64, struct stat64*);
WRAP_OPEN(64);
-#endif
WRAP_OPEN();
#ifdef HAVE___XSTAT
WRAP_VERSTAT(__x,);
WRAP_VERSTAT(__lx,);
-#ifndef _FILE_OFFSET_BITS
WRAP_VERSTAT(__x,64);
WRAP_VERSTAT(__lx,64);
#endif
-#endif
+++ /dev/null
-#!/bin/bash
-
-set -e
-
-MODULE_PLAYGROUND=$1
-ROOTFS=$2
-
-declare -A map
-map=(
- ["test-depmod/search-order-simple/lib/modules/4.4.4/kernel/crypto/"]="mod-simple.ko"
- ["test-depmod/search-order-simple/lib/modules/4.4.4/updates/"]="mod-simple.ko"
- ["test-depmod/search-order-same-prefix/lib/modules/4.4.4/foo/"]="mod-simple.ko"
- ["test-depmod/search-order-same-prefix/lib/modules/4.4.4/foobar/"]="mod-simple.ko"
- ["test-depmod/detect-loop/lib/modules/4.4.4/kernel/mod-loop-a.ko"]="mod-loop-a.ko"
- ["test-depmod/detect-loop/lib/modules/4.4.4/kernel/mod-loop-b.ko"]="mod-loop-b.ko"
- ["test-depmod/detect-loop/lib/modules/4.4.4/kernel/mod-loop-c.ko"]="mod-loop-c.ko"
- ["test-depmod/detect-loop/lib/modules/4.4.4/kernel/mod-loop-d.ko"]="mod-loop-d.ko"
- ["test-depmod/detect-loop/lib/modules/4.4.4/kernel/mod-loop-e.ko"]="mod-loop-e.ko"
- ["test-depmod/detect-loop/lib/modules/4.4.4/kernel/mod-loop-f.ko"]="mod-loop-f.ko"
- ["test-depmod/detect-loop/lib/modules/4.4.4/kernel/mod-loop-g.ko"]="mod-loop-g.ko"
- ["test-depmod/detect-loop/lib/modules/4.4.4/kernel/mod-loop-h.ko"]="mod-loop-h.ko"
- ["test-depmod/detect-loop/lib/modules/4.4.4/kernel/mod-loop-i.ko"]="mod-loop-i.ko"
- ["test-depmod/detect-loop/lib/modules/4.4.4/kernel/mod-loop-j.ko"]="mod-loop-j.ko"
- ["test-depmod/detect-loop/lib/modules/4.4.4/kernel/mod-loop-k.ko"]="mod-loop-k.ko"
- ["test-depmod/search-order-external-first/lib/modules/4.4.4/foo/"]="mod-simple.ko"
- ["test-depmod/search-order-external-first/lib/modules/4.4.4/foobar/"]="mod-simple.ko"
- ["test-depmod/search-order-external-first/lib/modules/external/"]="mod-simple.ko"
- ["test-depmod/search-order-external-last/lib/modules/4.4.4/foo/"]="mod-simple.ko"
- ["test-depmod/search-order-external-last/lib/modules/4.4.4/foobar/"]="mod-simple.ko"
- ["test-depmod/search-order-external-last/lib/modules/external/"]="mod-simple.ko"
- ["test-depmod/search-order-override/lib/modules/4.4.4/foo/"]="mod-simple.ko"
- ["test-depmod/search-order-override/lib/modules/4.4.4/override/"]="mod-simple.ko"
- ["test-dependencies/lib/modules/4.0.20-kmod/kernel/fs/foo/"]="mod-foo-b.ko"
- ["test-dependencies/lib/modules/4.0.20-kmod/kernel/"]="mod-foo-c.ko"
- ["test-dependencies/lib/modules/4.0.20-kmod/kernel/lib/"]="mod-foo-a.ko"
- ["test-dependencies/lib/modules/4.0.20-kmod/kernel/fs/"]="mod-foo.ko"
- ["test-init/"]="mod-simple.ko"
- ["test-remove/"]="mod-simple.ko"
- ["test-modprobe/show-depends/lib/modules/4.4.4/kernel/mod-loop-a.ko"]="mod-loop-a.ko"
- ["test-modprobe/show-depends/lib/modules/4.4.4/kernel/mod-loop-b.ko"]="mod-loop-b.ko"
- ["test-modprobe/show-depends/lib/modules/4.4.4/kernel/mod-simple.ko"]="mod-simple.ko"
- ["test-modprobe/show-exports/mod-loop-a.ko"]="mod-loop-a.ko"
- ["test-modprobe/softdep-loop/lib/modules/4.4.4/kernel/mod-loop-a.ko"]="mod-loop-a.ko"
- ["test-modprobe/softdep-loop/lib/modules/4.4.4/kernel/mod-loop-b.ko"]="mod-loop-b.ko"
- ["test-modprobe/install-cmd-loop/lib/modules/4.4.4/kernel/mod-loop-a.ko"]="mod-loop-a.ko"
- ["test-modprobe/install-cmd-loop/lib/modules/4.4.4/kernel/mod-loop-b.ko"]="mod-loop-b.ko"
- ["test-modprobe/force/lib/modules/4.4.4/kernel/"]="mod-simple.ko"
- ["test-modprobe/oldkernel/lib/modules/3.3.3/kernel/"]="mod-simple.ko"
- ["test-modprobe/oldkernel-force/lib/modules/3.3.3/kernel/"]="mod-simple.ko"
- ["test-modprobe/alias-to-none/lib/modules/4.4.4/kernel/"]="mod-simple.ko"
- ["test-modprobe/module-param-kcmdline/lib/modules/4.4.4/kernel/"]="mod-simple.ko"
- ["test-modprobe/external/lib/modules/external/"]="mod-simple.ko"
- ["test-depmod/modules-order-compressed/lib/modules/4.4.4/kernel/drivers/block/cciss.ko"]="mod-fake-cciss.ko"
- ["test-depmod/modules-order-compressed/lib/modules/4.4.4/kernel/drivers/scsi/hpsa.ko"]="mod-fake-hpsa.ko"
- ["test-depmod/modules-order-compressed/lib/modules/4.4.4/kernel/drivers/scsi/scsi_mod.ko"]="mod-fake-scsi-mod.ko"
- ["test-modinfo/mod-simple-i386.ko"]="mod-simple-i386.ko"
- ["test-modinfo/mod-simple-x86_64.ko"]="mod-simple-x86_64.ko"
- ["test-modinfo/mod-simple-sparc64.ko"]="mod-simple-sparc64.ko"
- ["test-modinfo/mod-simple-sha1.ko"]="mod-simple.ko"
- ["test-modinfo/mod-simple-sha256.ko"]="mod-simple.ko"
- ["test-modinfo/mod-simple-pkcs7.ko"]="mod-simple.ko"
- ["test-modinfo/external/lib/modules/external/mod-simple.ko"]="mod-simple.ko"
- ["test-tools/insert/lib/modules/4.4.4/kernel/"]="mod-simple.ko"
- ["test-tools/remove/lib/modules/4.4.4/kernel/"]="mod-simple.ko"
-)
-
-gzip_array=(
- "test-depmod/modules-order-compressed/lib/modules/4.4.4/kernel/drivers/block/cciss.ko"
- "test-depmod/modules-order-compressed/lib/modules/4.4.4/kernel/drivers/scsi/hpsa.ko"
- "test-depmod/modules-order-compressed/lib/modules/4.4.4/kernel/drivers/scsi/scsi_mod.ko"
- )
-
-attach_sha256_array=(
- "test-modinfo/mod-simple-sha256.ko"
- )
-
-attach_sha1_array=(
- "test-modinfo/mod-simple-sha1.ko"
- )
-
-attach_pkcs7_array=(
- "test-modinfo/mod-simple-pkcs7.ko"
- )
-
-for k in ${!map[@]}; do
- dst=${ROOTFS}/$k
- src=${MODULE_PLAYGROUND}/${map[$k]}
-
- if test "${dst: -1}" = "/"; then
- install -d $dst
- install -t $dst $src
- else
- install -D $src $dst
- fi
-done
-
-# start poking the final rootfs...
-
-# gzip these modules
-for m in "${gzip_array[@]}"; do
- gzip $ROOTFS/$m
-done
-
-for m in "${attach_sha1_array[@]}"; do
- cat ${MODULE_PLAYGROUND}/dummy.sha1 >> ${ROOTFS}/$m
-done
-
-for m in "${attach_sha256_array[@]}"; do
- cat ${MODULE_PLAYGROUND}/dummy.sha256 >> ${ROOTFS}/$m
-done
-
-for m in "${attach_pkcs7_array[@]}"; do
- cat ${MODULE_PLAYGROUND}/dummy.pkcs7 >> ${ROOTFS}/$m
-done
--- /dev/null
+# Aliases extracted from modules themselves.
+alias pci:v0000103Cd00003230sv0000103Csd0000323Dbc*sc*i* cciss
+alias pci:v0000103Cd00003230sv0000103Csd00003237bc*sc*i* cciss
+alias pci:v0000103Cd00003238sv0000103Csd00003215bc*sc*i* cciss
+alias pci:v0000103Cd00003238sv0000103Csd00003214bc*sc*i* cciss
+alias pci:v0000103Cd00003238sv0000103Csd00003213bc*sc*i* cciss
+alias pci:v0000103Cd00003238sv0000103Csd00003212bc*sc*i* cciss
+alias pci:v0000103Cd00003238sv0000103Csd00003211bc*sc*i* cciss
+alias pci:v0000103Cd00003230sv0000103Csd00003235bc*sc*i* cciss
+alias pci:v0000103Cd00003230sv0000103Csd00003234bc*sc*i* cciss
+alias pci:v0000103Cd00003230sv0000103Csd00003223bc*sc*i* cciss
+alias pci:v0000103Cd00003220sv0000103Csd00003225bc*sc*i* cciss
+alias pci:v00000E11d00000046sv00000E11sd0000409Dbc*sc*i* cciss
+alias pci:v00000E11d00000046sv00000E11sd0000409Cbc*sc*i* cciss
+alias pci:v00000E11d00000046sv00000E11sd0000409Bbc*sc*i* cciss
+alias pci:v00000E11d00000046sv00000E11sd0000409Abc*sc*i* cciss
+alias pci:v00000E11d00000046sv00000E11sd00004091bc*sc*i* cciss
+alias pci:v00000E11d0000B178sv00000E11sd00004083bc*sc*i* cciss
+alias pci:v00000E11d0000B178sv00000E11sd00004082bc*sc*i* cciss
+alias pci:v00000E11d0000B178sv00000E11sd00004080bc*sc*i* cciss
+alias pci:v00000E11d0000B060sv00000E11sd00004070bc*sc*i* cciss
+alias pci:v0000103Cd*sv*sd*bc01sc04i* hpsa
+alias pci:v0000103Cd0000323Bsv0000103Csd00003356bc*sc*i* hpsa
+alias pci:v0000103Cd0000323Bsv0000103Csd00003355bc*sc*i* hpsa
+alias pci:v0000103Cd0000323Bsv0000103Csd00003354bc*sc*i* hpsa
+alias pci:v0000103Cd0000323Bsv0000103Csd00003353bc*sc*i* hpsa
+alias pci:v0000103Cd0000323Bsv0000103Csd00003352bc*sc*i* hpsa
+alias pci:v0000103Cd0000323Bsv0000103Csd00003351bc*sc*i* hpsa
+alias pci:v0000103Cd0000323Bsv0000103Csd00003350bc*sc*i* hpsa
+alias pci:v0000103Cd0000323Asv0000103Csd00003233bc*sc*i* hpsa
+alias pci:v0000103Cd0000323Asv0000103Csd0000324Bbc*sc*i* hpsa
+alias pci:v0000103Cd0000323Asv0000103Csd0000324Abc*sc*i* hpsa
+alias pci:v0000103Cd0000323Asv0000103Csd00003249bc*sc*i* hpsa
+alias pci:v0000103Cd0000323Asv0000103Csd00003247bc*sc*i* hpsa
+alias pci:v0000103Cd0000323Asv0000103Csd00003245bc*sc*i* hpsa
+alias pci:v0000103Cd0000323Asv0000103Csd00003243bc*sc*i* hpsa
+alias pci:v0000103Cd0000323Asv0000103Csd00003241bc*sc*i* hpsa
--- /dev/null
+kernel/drivers/block/cciss.ko:
+kernel/drivers/scsi/scsi_mod.ko:
+kernel/drivers/scsi/hpsa.ko: kernel/drivers/scsi/scsi_mod.ko
--- /dev/null
+#336
+kernel/drivers/block/cciss.ko
+#2094
+kernel/drivers/scsi/scsi_mod.ko
+#2137
+kernel/drivers/scsi/hpsa.ko
+
--- /dev/null
+kernel/fake_builtin.ko
--- /dev/null
+kernel/fake_builtin.ko
--- /dev/null
+# Aliases extracted from modules themselves.
--- /dev/null
+/lib/modules/external/mod-simple.ko:
--- /dev/null
+# Soft dependencies extracted from modules themselves.
--- /dev/null
+# Aliases for symbols, used by symbol_request().
--- /dev/null
+# Aliases extracted from modules themselves.
--- /dev/null
+/lib/modules/external/mod-simple.ko:
--- /dev/null
+# Soft dependencies extracted from modules themselves.
--- /dev/null
+# Aliases for symbols, used by symbol_request().
--- /dev/null
+options psmouse foo
+options parport dyndbg="file drivers/parport/ieee1284_ops.c +mpf"
+
+# End of configuration files. Dumping indexes now:
+
--- /dev/null
+options psmouse foo
+options parport dyndbg="file drivers/parport/ieee1284_ops.c +mpf"
+
+# End of configuration files. Dumping indexes now:
+
--- /dev/null
+psmouse.foo parport.dyndbg="file drivers/parport/ieee1284_ops.c +mpf" quiet rw
--- /dev/null
+psmouse.foo parport.dyndbg="file drivers/parport/ieee1284_ops.c +mpf" quiet rw
--- /dev/null
+options psmouse foo
+options parport dyndbg="file drivers/parport/ieee1284_ops.c +mpf"
+
+# End of configuration files. Dumping indexes now:
+
--- /dev/null
+options psmouse foo
+options parport dyndbg="file drivers/parport/ieee1284_ops.c +mpf"
+
+# End of configuration files. Dumping indexes now:
+
--- /dev/null
+psmouse.foo parport.dyndbg="file drivers/parport/ieee1284_ops.c +mpf" quiet rw
--- /dev/null
+psmouse.foo "parport.dyndbg=file drivers/parport/ieee1284_ops.c +mpf" quiet rw
+++ /dev/null
-kernel/mod-simple.ko:
+++ /dev/null
-kernel/mod-simple.ko:
--- /dev/null
+#!/bin/bash
+
+set -e
+
+ROOTFS_PRISTINE=$1
+ROOTFS=$2
+MODULE_PLAYGROUND=$3
+CONFIG_H=$4
+SYSCONFDIR=$5
+
+# create rootfs from rootfs-pristine
+
+create_rootfs() {
+ rm -rf "$ROOTFS"
+ mkdir -p $(dirname "$ROOTFS")
+ cp -r "$ROOTFS_PRISTINE" "$ROOTFS"
+ find "$ROOTFS" -type d -exec chmod +w {} \;
+ find "$ROOTFS" -type f -name .gitignore -exec rm -f {} \;
+ if [ "$MODULE_DIRECTORY" != "/lib/modules" ] ; then
+ sed -i -e "s|/lib/modules|$MODULE_DIRECTORY|g" $(find "$ROOTFS" -name \*.txt -o -name \*.conf -o -name \*.dep)
+ sed -i -e "s|$MODULE_DIRECTORY/external|/lib/modules/external|g" $(find "$ROOTFS" -name \*.txt -o -name \*.conf -o -name \*.dep)
+ for i in "$ROOTFS"/*/lib/modules/* "$ROOTFS"/*/*/lib/modules/* ; do
+ version="$(basename $i)"
+ [ $version != 'external' ] || continue
+ mod="$(dirname $i)"
+ lib="$(dirname $mod)"
+ up="$(dirname $lib)$MODULE_DIRECTORY"
+ mkdir -p "$up"
+ mv "$i" "$up"
+ done
+ fi
+
+ if [ "$SYSCONFDIR" != "/etc" ]; then
+ find "$ROOTFS" -type d -name etc -printf "%h\n" | while read -r e; do
+ mkdir -p "$(dirname $e/$SYSCONFDIR)"
+ mv $e/{etc,$SYSCONFDIR}
+ done
+ fi
+}
+
+feature_enabled() {
+ local feature=$1
+ grep KMOD_FEATURES $CONFIG_H | head -n 1 | grep -q \+$feature
+}
+
+declare -A map
+map=(
+ ["test-depmod/search-order-simple$MODULE_DIRECTORY/4.4.4/kernel/crypto/"]="mod-simple.ko"
+ ["test-depmod/search-order-simple$MODULE_DIRECTORY/4.4.4/updates/"]="mod-simple.ko"
+ ["test-depmod/search-order-same-prefix$MODULE_DIRECTORY/4.4.4/foo/"]="mod-simple.ko"
+ ["test-depmod/search-order-same-prefix$MODULE_DIRECTORY/4.4.4/foobar/"]="mod-simple.ko"
+ ["test-depmod/detect-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-a.ko"]="mod-loop-a.ko"
+ ["test-depmod/detect-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-b.ko"]="mod-loop-b.ko"
+ ["test-depmod/detect-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-c.ko"]="mod-loop-c.ko"
+ ["test-depmod/detect-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-d.ko"]="mod-loop-d.ko"
+ ["test-depmod/detect-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-e.ko"]="mod-loop-e.ko"
+ ["test-depmod/detect-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-f.ko"]="mod-loop-f.ko"
+ ["test-depmod/detect-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-g.ko"]="mod-loop-g.ko"
+ ["test-depmod/detect-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-h.ko"]="mod-loop-h.ko"
+ ["test-depmod/detect-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-i.ko"]="mod-loop-i.ko"
+ ["test-depmod/detect-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-j.ko"]="mod-loop-j.ko"
+ ["test-depmod/detect-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-k.ko"]="mod-loop-k.ko"
+ ["test-depmod/search-order-external-first$MODULE_DIRECTORY/4.4.4/foo/"]="mod-simple.ko"
+ ["test-depmod/search-order-external-first$MODULE_DIRECTORY/4.4.4/foobar/"]="mod-simple.ko"
+ ["test-depmod/search-order-external-first/lib/modules/external/"]="mod-simple.ko"
+ ["test-depmod/search-order-external-last$MODULE_DIRECTORY/4.4.4/foo/"]="mod-simple.ko"
+ ["test-depmod/search-order-external-last$MODULE_DIRECTORY/4.4.4/foobar/"]="mod-simple.ko"
+ ["test-depmod/search-order-external-last/lib/modules/external/"]="mod-simple.ko"
+ ["test-depmod/search-order-override$MODULE_DIRECTORY/4.4.4/foo/"]="mod-simple.ko"
+ ["test-depmod/search-order-override$MODULE_DIRECTORY/4.4.4/override/"]="mod-simple.ko"
+ ["test-dependencies$MODULE_DIRECTORY/4.0.20-kmod/kernel/fs/foo/"]="mod-foo-b.ko"
+ ["test-dependencies$MODULE_DIRECTORY/4.0.20-kmod/kernel/"]="mod-foo-c.ko"
+ ["test-dependencies$MODULE_DIRECTORY/4.0.20-kmod/kernel/lib/"]="mod-foo-a.ko"
+ ["test-dependencies$MODULE_DIRECTORY/4.0.20-kmod/kernel/fs/"]="mod-foo.ko"
+ ["test-init/"]="mod-simple.ko"
+ ["test-remove/"]="mod-simple.ko"
+ ["test-modprobe/show-depends$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-a.ko"]="mod-loop-a.ko"
+ ["test-modprobe/show-depends$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-b.ko"]="mod-loop-b.ko"
+ ["test-modprobe/show-depends$MODULE_DIRECTORY/4.4.4/kernel/mod-simple.ko"]="mod-simple.ko"
+ ["test-modprobe/show-exports/mod-loop-a.ko"]="mod-loop-a.ko"
+ ["test-modprobe/softdep-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-a.ko"]="mod-loop-a.ko"
+ ["test-modprobe/softdep-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-b.ko"]="mod-loop-b.ko"
+ ["test-modprobe/install-cmd-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-a.ko"]="mod-loop-a.ko"
+ ["test-modprobe/install-cmd-loop$MODULE_DIRECTORY/4.4.4/kernel/mod-loop-b.ko"]="mod-loop-b.ko"
+ ["test-modprobe/force$MODULE_DIRECTORY/4.4.4/kernel/"]="mod-simple.ko"
+ ["test-modprobe/oldkernel$MODULE_DIRECTORY/3.3.3/kernel/"]="mod-simple.ko"
+ ["test-modprobe/oldkernel-force$MODULE_DIRECTORY/3.3.3/kernel/"]="mod-simple.ko"
+ ["test-modprobe/alias-to-none$MODULE_DIRECTORY/4.4.4/kernel/"]="mod-simple.ko"
+ ["test-modprobe/module-param-kcmdline$MODULE_DIRECTORY/4.4.4/kernel/"]="mod-simple.ko"
+ ["test-modprobe/external/lib/modules/external/"]="mod-simple.ko"
+ ["test-modprobe/module-from-abspath/home/foo/"]="mod-simple.ko"
+ ["test-modprobe/module-from-relpath/home/foo/"]="mod-simple.ko"
+ ["test-depmod/modules-order-compressed$MODULE_DIRECTORY/4.4.4/kernel/drivers/block/cciss.ko"]="mod-fake-cciss.ko"
+ ["test-depmod/modules-order-compressed$MODULE_DIRECTORY/4.4.4/kernel/drivers/scsi/hpsa.ko"]="mod-fake-hpsa.ko"
+ ["test-depmod/modules-order-compressed$MODULE_DIRECTORY/4.4.4/kernel/drivers/scsi/scsi_mod.ko"]="mod-fake-scsi-mod.ko"
+ ["test-depmod/modules-outdir$MODULE_DIRECTORY/4.4.4/kernel/drivers/block/cciss.ko"]="mod-fake-cciss.ko"
+ ["test-depmod/modules-outdir$MODULE_DIRECTORY/4.4.4/kernel/drivers/scsi/hpsa.ko"]="mod-fake-hpsa.ko"
+ ["test-depmod/modules-outdir$MODULE_DIRECTORY/4.4.4/kernel/drivers/scsi/scsi_mod.ko"]="mod-fake-scsi-mod.ko"
+ ["test-modinfo/mod-simple-i386.ko"]="mod-simple-i386.ko"
+ ["test-modinfo/mod-simple-x86_64.ko"]="mod-simple-x86_64.ko"
+ ["test-modinfo/mod-simple-sparc64.ko"]="mod-simple-sparc64.ko"
+ ["test-modinfo/mod-simple-sha1.ko"]="mod-simple.ko"
+ ["test-modinfo/mod-simple-sha256.ko"]="mod-simple.ko"
+ ["test-modinfo/mod-simple-pkcs7.ko"]="mod-simple.ko"
+ ["test-modinfo/external/lib/modules/external/mod-simple.ko"]="mod-simple.ko"
+)
+
+gzip_array=(
+ "test-depmod/modules-order-compressed$MODULE_DIRECTORY/4.4.4/kernel/drivers/block/cciss.ko"
+ )
+
+xz_array=(
+ "test-depmod/modules-order-compressed$MODULE_DIRECTORY/4.4.4/kernel/drivers/scsi/scsi_mod.ko"
+ )
+
+zstd_array=(
+ "test-depmod/modules-order-compressed$MODULE_DIRECTORY/4.4.4/kernel/drivers/scsi/hpsa.ko"
+ )
+
+attach_sha256_array=(
+ "test-modinfo/mod-simple-sha256.ko"
+ )
+
+attach_sha1_array=(
+ "test-modinfo/mod-simple-sha1.ko"
+ )
+
+attach_pkcs7_array=(
+ "test-modinfo/mod-simple-pkcs7.ko"
+ )
+
+create_rootfs
+
+for k in "${!map[@]}"; do
+ dst=${ROOTFS}/$k
+ src=${MODULE_PLAYGROUND}/${map[$k]}
+
+ if [[ $dst = */ ]]; then
+ install -d "$dst"
+ install -t "$dst" "$src"
+ else
+ install -D "$src" "$dst"
+ fi
+done
+
+# start poking the final rootfs...
+
+# compress modules with each format if feature is enabled
+if feature_enabled ZLIB; then
+ for m in "${gzip_array[@]}"; do
+ gzip "$ROOTFS/$m"
+ done
+fi
+
+if feature_enabled XZ; then
+ for m in "${xz_array[@]}"; do
+ xz "$ROOTFS/$m"
+ done
+fi
+
+if feature_enabled ZSTD; then
+ for m in "${zstd_array[@]}"; do
+ zstd --rm $ROOTFS/$m
+ done
+fi
+
+for m in "${attach_sha1_array[@]}"; do
+ cat "${MODULE_PLAYGROUND}/dummy.sha1" >>"${ROOTFS}/$m"
+done
+
+for m in "${attach_sha256_array[@]}"; do
+ cat "${MODULE_PLAYGROUND}/dummy.sha256" >>"${ROOTFS}/$m"
+done
+
+for m in "${attach_pkcs7_array[@]}"; do
+ cat "${MODULE_PLAYGROUND}/dummy.pkcs7" >>"${ROOTFS}/$m"
+done
+
+touch testsuite/stamp-rootfs
#include "testsuite.h"
-#ifdef ENABLE_ZLIB
-#define MODULES_ORDER_UNAME "4.4.4"
+#define MODULES_UNAME "4.4.4"
#define MODULES_ORDER_ROOTFS TESTSUITE_ROOTFS "test-depmod/modules-order-compressed"
-#define MODULES_ORDER_LIB_MODULES MODULES_ORDER_ROOTFS "/lib/modules/" MODULES_ORDER_UNAME
+#define MODULES_ORDER_LIB_MODULES MODULES_ORDER_ROOTFS MODULE_DIRECTORY "/" MODULES_UNAME
static noreturn int depmod_modules_order_for_compressed(const struct test *t)
{
const char *progname = ABS_TOP_BUILDDIR "/tools/depmod";
DEFINE_TEST(depmod_modules_order_for_compressed,
.description = "check if depmod let aliases in right order when using compressed modules",
.config = {
- [TC_UNAME_R] = MODULES_ORDER_UNAME,
+ [TC_UNAME_R] = MODULES_UNAME,
[TC_ROOTFS] = MODULES_ORDER_ROOTFS,
},
.output = {
{ }
},
});
-#endif
+
+#define MODULES_OUTDIR_ROOTFS TESTSUITE_ROOTFS "test-depmod/modules-outdir"
+#define MODULES_OUTDIR_LIB_MODULES_OUTPUT MODULES_OUTDIR_ROOTFS "/outdir" MODULE_DIRECTORY "/" MODULES_UNAME
+#define MODULES_OUTDIR_LIB_MODULES_INPUT MODULES_OUTDIR_ROOTFS MODULE_DIRECTORY "/" MODULES_UNAME
+static noreturn int depmod_modules_outdir(const struct test *t)
+{
+ const char *progname = ABS_TOP_BUILDDIR "/tools/depmod";
+ const char *const args[] = {
+ progname,
+ "--outdir", MODULES_OUTDIR_ROOTFS "/outdir/",
+ NULL,
+ };
+
+ test_spawn_prog(progname, args);
+ exit(EXIT_FAILURE);
+}
+
+DEFINE_TEST(depmod_modules_outdir,
+ .description = "check if depmod honours the outdir option",
+ .config = {
+ [TC_UNAME_R] = MODULES_UNAME,
+ [TC_ROOTFS] = MODULES_OUTDIR_ROOTFS,
+ },
+ .output = {
+ .files = (const struct keyval[]) {
+ { MODULES_OUTDIR_LIB_MODULES_OUTPUT "/modules.dep",
+ MODULES_OUTDIR_ROOTFS "/correct-modules.dep" },
+ { MODULES_OUTDIR_LIB_MODULES_OUTPUT "/modules.alias",
+ MODULES_OUTDIR_ROOTFS "/correct-modules.alias" },
+ { }
+ },
+ });
#define SEARCH_ORDER_SIMPLE_ROOTFS TESTSUITE_ROOTFS "test-depmod/search-order-simple"
+#define SEARCH_ORDER_SIMPLE_LIB_MODULES SEARCH_ORDER_SIMPLE_ROOTFS MODULE_DIRECTORY "/" MODULES_UNAME
static noreturn int depmod_search_order_simple(const struct test *t)
{
const char *progname = ABS_TOP_BUILDDIR "/tools/depmod";
DEFINE_TEST(depmod_search_order_simple,
.description = "check if depmod honor search order in config",
.config = {
- [TC_UNAME_R] = "4.4.4",
+ [TC_UNAME_R] = MODULES_UNAME,
[TC_ROOTFS] = SEARCH_ORDER_SIMPLE_ROOTFS,
},
.output = {
.files = (const struct keyval[]) {
- { SEARCH_ORDER_SIMPLE_ROOTFS "/lib/modules/4.4.4/correct-modules.dep",
- SEARCH_ORDER_SIMPLE_ROOTFS "/lib/modules/4.4.4/modules.dep" },
+ { SEARCH_ORDER_SIMPLE_LIB_MODULES "/correct-modules.dep",
+ SEARCH_ORDER_SIMPLE_LIB_MODULES "/modules.dep" },
{ }
},
});
#define SEARCH_ORDER_SAME_PREFIX_ROOTFS TESTSUITE_ROOTFS "test-depmod/search-order-same-prefix"
+#define SEARCH_ORDER_SAME_PREFIX_LIB_MODULES SEARCH_ORDER_SAME_PREFIX_ROOTFS MODULE_DIRECTORY "/" MODULES_UNAME
static noreturn int depmod_search_order_same_prefix(const struct test *t)
{
const char *progname = ABS_TOP_BUILDDIR "/tools/depmod";
DEFINE_TEST(depmod_search_order_same_prefix,
.description = "check if depmod honor search order in config with same prefix",
.config = {
- [TC_UNAME_R] = "4.4.4",
+ [TC_UNAME_R] = MODULES_UNAME,
[TC_ROOTFS] = SEARCH_ORDER_SAME_PREFIX_ROOTFS,
},
.output = {
.files = (const struct keyval[]) {
- { SEARCH_ORDER_SAME_PREFIX_ROOTFS "/lib/modules/4.4.4/correct-modules.dep",
- SEARCH_ORDER_SAME_PREFIX_ROOTFS "/lib/modules/4.4.4/modules.dep" },
+ { SEARCH_ORDER_SAME_PREFIX_LIB_MODULES "/correct-modules.dep",
+ SEARCH_ORDER_SAME_PREFIX_LIB_MODULES "/modules.dep" },
{ }
},
});
DEFINE_TEST(depmod_detect_loop,
.description = "check if depmod detects module loops correctly",
.config = {
- [TC_UNAME_R] = "4.4.4",
+ [TC_UNAME_R] = MODULES_UNAME,
[TC_ROOTFS] = DETECT_LOOP_ROOTFS,
},
.expected_fail = true,
});
#define SEARCH_ORDER_EXTERNAL_FIRST_ROOTFS TESTSUITE_ROOTFS "test-depmod/search-order-external-first"
+#define SEARCH_ORDER_EXTERNAL_FIRST_LIB_MODULES SEARCH_ORDER_EXTERNAL_FIRST_ROOTFS MODULE_DIRECTORY "/" MODULES_UNAME
static noreturn int depmod_search_order_external_first(const struct test *t)
{
const char *progname = ABS_TOP_BUILDDIR "/tools/depmod";
DEFINE_TEST(depmod_search_order_external_first,
.description = "check if depmod honor external keyword with higher priority",
.config = {
- [TC_UNAME_R] = "4.4.4",
+ [TC_UNAME_R] = MODULES_UNAME,
[TC_ROOTFS] = SEARCH_ORDER_EXTERNAL_FIRST_ROOTFS,
},
.output = {
.files = (const struct keyval[]) {
- { SEARCH_ORDER_EXTERNAL_FIRST_ROOTFS "/lib/modules/4.4.4/correct-modules.dep",
- SEARCH_ORDER_EXTERNAL_FIRST_ROOTFS "/lib/modules/4.4.4/modules.dep" },
+ { SEARCH_ORDER_EXTERNAL_FIRST_LIB_MODULES "/correct-modules.dep",
+ SEARCH_ORDER_EXTERNAL_FIRST_LIB_MODULES "/modules.dep" },
{ }
},
});
#define SEARCH_ORDER_EXTERNAL_LAST_ROOTFS TESTSUITE_ROOTFS "test-depmod/search-order-external-last"
+#define SEARCH_ORDER_EXTERNAL_LAST_LIB_MODULES SEARCH_ORDER_EXTERNAL_LAST_ROOTFS MODULE_DIRECTORY "/" MODULES_UNAME
static noreturn int depmod_search_order_external_last(const struct test *t)
{
const char *progname = ABS_TOP_BUILDDIR "/tools/depmod";
DEFINE_TEST(depmod_search_order_external_last,
.description = "check if depmod honor external keyword with lower priority",
.config = {
- [TC_UNAME_R] = "4.4.4",
+ [TC_UNAME_R] = MODULES_UNAME,
[TC_ROOTFS] = SEARCH_ORDER_EXTERNAL_LAST_ROOTFS,
},
.output = {
.files = (const struct keyval[]) {
- { SEARCH_ORDER_EXTERNAL_LAST_ROOTFS "/lib/modules/4.4.4/correct-modules.dep",
- SEARCH_ORDER_EXTERNAL_LAST_ROOTFS "/lib/modules/4.4.4/modules.dep" },
+ { SEARCH_ORDER_EXTERNAL_LAST_LIB_MODULES "/correct-modules.dep",
+ SEARCH_ORDER_EXTERNAL_LAST_LIB_MODULES "/modules.dep" },
{ }
},
});
#define SEARCH_ORDER_OVERRIDE_ROOTFS TESTSUITE_ROOTFS "test-depmod/search-order-override"
+#define SEARCH_ORDER_OVERRIDE_LIB_MODULES SEARCH_ORDER_OVERRIDE_ROOTFS MODULE_DIRECTORY "/" MODULES_UNAME
static noreturn int depmod_search_order_override(const struct test *t)
{
const char *progname = ABS_TOP_BUILDDIR "/tools/depmod";
DEFINE_TEST(depmod_search_order_override,
.description = "check if depmod honor override keyword",
.config = {
- [TC_UNAME_R] = "4.4.4",
+ [TC_UNAME_R] = MODULES_UNAME,
[TC_ROOTFS] = SEARCH_ORDER_OVERRIDE_ROOTFS,
},
.output = {
.files = (const struct keyval[]) {
- { SEARCH_ORDER_OVERRIDE_ROOTFS "/lib/modules/4.4.4/correct-modules.dep",
- SEARCH_ORDER_OVERRIDE_ROOTFS "/lib/modules/4.4.4/modules.dep" },
+ { SEARCH_ORDER_OVERRIDE_LIB_MODULES "/correct-modules.dep",
+ SEARCH_ORDER_OVERRIDE_LIB_MODULES "/modules.dep" },
{ }
},
});
#include "testsuite.h"
+static noreturn int test_load_resources(const struct test *t)
+{
+ struct kmod_ctx *ctx;
+ const char *null_config = NULL;
+ int err;
+
+ ctx = kmod_new(NULL, &null_config);
+ if (ctx == NULL)
+ exit(EXIT_FAILURE);
+
+ kmod_set_log_priority(ctx, 7);
+
+ err = kmod_load_resources(ctx);
+ if (err != 0) {
+ ERR("could not load libkmod resources: %s\n", strerror(-err));
+ exit(EXIT_FAILURE);
+ }
+
+ kmod_unref(ctx);
+
+ exit(EXIT_SUCCESS);
+}
+DEFINE_TEST(test_load_resources,
+ .description = "test if kmod_load_resources works (recent modprobe on kernel without modules.builtin.modinfo)",
+ .config = {
+ [TC_ROOTFS] = TESTSUITE_ROOTFS "test-init-load-resources/",
+ [TC_UNAME_R] = "5.6.0",
+ },
+ .need_spawn = true);
+
+DEFINE_TEST(test_load_resources,
+ .description = "test if kmod_load_resources works with empty modules.builtin.aliases.bin (recent depmod on kernel without modules.builtin.modinfo)",
+ .config = {
+ [TC_ROOTFS] = TESTSUITE_ROOTFS "test-init-load-resources-empty-builtin-aliases-bin/",
+ [TC_UNAME_R] = "5.6.0",
+ },
+ .need_spawn = true);
+
static noreturn int test_initlib(const struct test *t)
{
struct kmod_ctx *ctx;
exit(EXIT_FAILURE);
err = kmod_module_new_from_lookup(ctx, "fake-builtin", &list);
- if (err != 0) {
+ if (err < 0) {
ERR("could not create module from lookup: %s\n", strerror(-err));
exit(EXIT_FAILURE);
}
.modules_loaded = "mod-loop-b,mod-loop-a",
);
-static noreturn int modprobe_param_kcmdline(const struct test *t)
+static noreturn int modprobe_param_kcmdline_show_deps(const struct test *t)
{
const char *progname = ABS_TOP_BUILDDIR "/tools/modprobe";
const char *const args[] = {
test_spawn_prog(progname, args);
exit(EXIT_FAILURE);
}
-DEFINE_TEST(modprobe_param_kcmdline,
+DEFINE_TEST(modprobe_param_kcmdline_show_deps,
.description = "check if params from kcmdline are passed to (f)init_module call",
.config = {
[TC_UNAME_R] = "4.4.4",
.modules_loaded = "",
);
-static noreturn int modprobe_param_kcmdline2(const struct test *t)
+static noreturn int modprobe_param_kcmdline(const struct test *t)
{
const char *progname = ABS_TOP_BUILDDIR "/tools/modprobe";
const char *const args[] = {
test_spawn_prog(progname, args);
exit(EXIT_FAILURE);
}
-DEFINE_TEST(modprobe_param_kcmdline2,
+DEFINE_TEST_WITH_FUNC(modprobe_param_kcmdline2, modprobe_param_kcmdline,
.description = "check if params with no value are parsed correctly from kcmdline",
.config = {
[TC_UNAME_R] = "4.4.4",
.modules_loaded = "",
);
-static noreturn int modprobe_param_kcmdline3(const struct test *t)
-{
- const char *progname = ABS_TOP_BUILDDIR "/tools/modprobe";
- const char *const args[] = {
- progname,
- "-c",
- NULL,
- };
-
- test_spawn_prog(progname, args);
- exit(EXIT_FAILURE);
-}
-DEFINE_TEST(modprobe_param_kcmdline3,
+DEFINE_TEST_WITH_FUNC(modprobe_param_kcmdline3, modprobe_param_kcmdline,
.description = "check if unrelated strings in kcmdline are correctly ignored",
.config = {
[TC_UNAME_R] = "4.4.4",
.modules_loaded = "",
);
-static noreturn int modprobe_param_kcmdline4(const struct test *t)
-{
- const char *progname = ABS_TOP_BUILDDIR "/tools/modprobe";
- const char *const args[] = {
- progname,
- "-c",
- NULL,
- };
-
- test_spawn_prog(progname, args);
- exit(EXIT_FAILURE);
-}
-DEFINE_TEST(modprobe_param_kcmdline4,
+DEFINE_TEST_WITH_FUNC(modprobe_param_kcmdline4, modprobe_param_kcmdline,
.description = "check if unrelated strings in kcmdline are correctly ignored",
.config = {
[TC_UNAME_R] = "4.4.4",
.modules_loaded = "",
);
-static noreturn int modprobe_param_kcmdline5(const struct test *t)
-{
- const char *progname = ABS_TOP_BUILDDIR "/tools/modprobe";
- const char *const args[] = {
- progname,
- "-c",
- NULL,
- };
-
- test_spawn_prog(progname, args);
- exit(EXIT_FAILURE);
-}
-DEFINE_TEST(modprobe_param_kcmdline5,
+DEFINE_TEST_WITH_FUNC(modprobe_param_kcmdline5, modprobe_param_kcmdline,
.description = "check if params with spaces are parsed correctly from kcmdline",
.config = {
[TC_UNAME_R] = "4.4.4",
.modules_loaded = "",
);
-
-static noreturn int modprobe_param_kcmdline6(const struct test *t)
-{
- const char *progname = ABS_TOP_BUILDDIR "/tools/modprobe";
- const char *const args[] = {
- progname,
- "-c",
- NULL,
- };
-
- test_spawn_prog(progname, args);
- exit(EXIT_FAILURE);
-}
-DEFINE_TEST(modprobe_param_kcmdline6,
+DEFINE_TEST_WITH_FUNC(modprobe_param_kcmdline6, modprobe_param_kcmdline,
.description = "check if dots on other parts of kcmdline don't confuse our parser",
.config = {
[TC_UNAME_R] = "4.4.4",
.modules_loaded = "",
);
+DEFINE_TEST_WITH_FUNC(modprobe_param_kcmdline7, modprobe_param_kcmdline,
+ .description = "check if dots on other parts of kcmdline don't confuse our parser",
+ .config = {
+ [TC_UNAME_R] = "4.4.4",
+ [TC_ROOTFS] = TESTSUITE_ROOTFS "test-modprobe/module-param-kcmdline7",
+ },
+ .output = {
+ .out = TESTSUITE_ROOTFS "test-modprobe/module-param-kcmdline7/correct.txt",
+ },
+ .modules_loaded = "",
+ );
+
+DEFINE_TEST_WITH_FUNC(modprobe_param_kcmdline8, modprobe_param_kcmdline,
+ .description = "check if dots on other parts of kcmdline don't confuse our parser",
+ .config = {
+ [TC_UNAME_R] = "4.4.4",
+ [TC_ROOTFS] = TESTSUITE_ROOTFS "test-modprobe/module-param-kcmdline8",
+ },
+ .output = {
+ .out = TESTSUITE_ROOTFS "test-modprobe/module-param-kcmdline8/correct.txt",
+ },
+ .modules_loaded = "",
+ );
+
static noreturn int modprobe_force(const struct test *t)
{
.modules_loaded = "mod-simple",
);
+static noreturn int modprobe_module_from_abspath(const struct test *t)
+{
+ const char *progname = ABS_TOP_BUILDDIR "/tools/modprobe";
+ const char *const args[] = {
+ progname,
+ "/home/foo/mod-simple.ko",
+ NULL,
+ };
+
+ test_spawn_prog(progname, args);
+ exit(EXIT_FAILURE);
+}
+DEFINE_TEST(modprobe_module_from_abspath,
+ .description = "check modprobe able to load module given as an absolute path",
+ .config = {
+ [TC_UNAME_R] = "4.4.4",
+ [TC_ROOTFS] = TESTSUITE_ROOTFS "test-modprobe/module-from-abspath",
+ [TC_INIT_MODULE_RETCODES] = "",
+ },
+ .modules_loaded = "mod-simple",
+ );
+
+static noreturn int modprobe_module_from_relpath(const struct test *t)
+{
+ const char *progname = ABS_TOP_BUILDDIR "/tools/modprobe";
+ const char *const args[] = {
+ progname,
+ "./mod-simple.ko",
+ NULL,
+ };
+
+ if (chdir("/home/foo") != 0) {
+ perror("failed to change into /home/foo");
+ exit(EXIT_FAILURE);
+ }
+
+ test_spawn_prog(progname, args);
+ exit(EXIT_FAILURE);
+}
+DEFINE_TEST(modprobe_module_from_relpath,
+ .description = "check modprobe able to load module given as a relative path",
+ .config = {
+ [TC_UNAME_R] = "4.4.4",
+ [TC_ROOTFS] = TESTSUITE_ROOTFS "test-modprobe/module-from-relpath",
+ [TC_INIT_MODULE_RETCODES] = "",
+ },
+ .need_spawn = true,
+ .modules_loaded = "mod-simple",
+ );
+
TESTSUITE_MAIN();
static int from_name(const struct test *t)
{
- static const char *modnames[] = {
+ static const char *const modnames[] = {
"ext4",
"balbalbalbbalbalbalbalbalbalbal",
"snd-hda-intel",
"iTCO_wdt",
NULL,
};
- const char **p;
+ const char *const *p;
struct kmod_ctx *ctx;
struct kmod_module *mod;
const char *null_config = NULL;
static int from_alias(const struct test *t)
{
- static const char *modnames[] = {
+ static const char *const modnames[] = {
"ext4.*",
NULL,
};
- const char **p;
+ const char *const *p;
struct kmod_ctx *ctx;
int err;
char s[100];
int n;
- fp = fopen("/lib/modules/a", "r");
+ fp = fopen(MODULE_DIRECTORY "/a", "r");
if (fp == NULL)
return EXIT_FAILURE;;
char buf[100];
int fd, done;
- fd = open("/lib/modules/a", O_RDONLY);
+ fd = open(MODULE_DIRECTORY "/a", O_RDONLY);
if (fd < 0)
return EXIT_FAILURE;
{
struct stat st;
- if (access("/lib/modules/a", F_OK) < 0) {
+ if (access(MODULE_DIRECTORY "/a", F_OK) < 0) {
ERR("access failed: %m\n");
return EXIT_FAILURE;
}
- if (stat("/lib/modules/a", &st) < 0) {
+ if (stat(MODULE_DIRECTORY "/a", &st) < 0) {
ERR("stat failed: %m\n");
return EXIT_FAILURE;
}
+++ /dev/null
-/*
- * Copyright (C) 2015 Intel Corporation. All rights reserved.
- *
- * 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; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * 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 library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <errno.h>
-#include <inttypes.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "testsuite.h"
-
-static noreturn int kmod_tool_insert(const struct test *t)
-{
- const char *progname = ABS_TOP_BUILDDIR "/tools/kmod";
- const char *const args[] = {
- progname,
- "insert", "mod-simple",
- NULL,
- };
-
- test_spawn_prog(progname, args);
- exit(EXIT_FAILURE);
-}
-DEFINE_TEST(kmod_tool_insert,
- .description = "check kmod insert",
- .config = {
- [TC_UNAME_R] = "4.4.4",
- [TC_ROOTFS] = TESTSUITE_ROOTFS "test-tools/insert",
- [TC_INIT_MODULE_RETCODES] = "",
- },
- .modules_loaded = "mod-simple",
- );
-
-static noreturn int kmod_tool_remove(const struct test *t)
-{
- const char *progname = ABS_TOP_BUILDDIR "/tools/kmod";
- const char *const args[] = {
- progname,
- "remove", "mod-simple",
- NULL,
- };
-
- test_spawn_prog(progname, args);
- exit(EXIT_FAILURE);
-}
-DEFINE_TEST(kmod_tool_remove,
- .description = "check kmod remove",
- .config = {
- [TC_UNAME_R] = "4.4.4",
- [TC_ROOTFS] = TESTSUITE_ROOTFS "test-tools/remove",
- [TC_DELETE_MODULE_RETCODES] = "",
- },
- );
-
-TESTSUITE_MAIN();
static int alias_1(const struct test *t)
{
- static const char *input[] = {
+ static const char *const input[] = {
"test1234",
"test[abcfoobar]2211",
"bar[aaa][bbbb]sss",
char buf[PATH_MAX];
size_t len;
- const char **alias;
+ const char *const *alias;
for (alias = input; *alias != NULL; alias++) {
int ret;
#endif
#ifdef ENABLE_XZ
{ "/bla.ko.xz", true },
+#endif
+#ifdef ENABLE_ZSTD
+ { "/bla.ko.zst", true },
#endif
{ "/bla.ko.x", false },
{ "/bla.ko.", false },
);
+static int test_backoff_time(const struct test *t)
+{
+ unsigned long long delta = 0;
+
+ /* Check exponential increments */
+ get_backoff_delta_msec(now_msec(), now_msec() + 10, &delta);
+ assert_return(delta == 1, EXIT_FAILURE);
+ get_backoff_delta_msec(now_msec(), now_msec() + 10, &delta);
+ assert_return(delta == 2, EXIT_FAILURE);
+ get_backoff_delta_msec(now_msec(), now_msec() + 10, &delta);
+ assert_return(delta == 4, EXIT_FAILURE);
+ get_backoff_delta_msec(now_msec(), now_msec() + 10, &delta);
+ assert_return(delta == 8, EXIT_FAILURE);
+
+ {
+ unsigned long long t0, tend;
+
+ /* Check tail */
+ delta = 4;
+ tend = now_msec() + 3;
+ t0 = tend - 10;
+ get_backoff_delta_msec(t0, tend, &delta);
+ assert_return(delta == 2, EXIT_FAILURE);
+ tend = now_msec() + 1;
+ t0 = tend - 9;
+ get_backoff_delta_msec(t0, tend, &delta);
+ assert_return(delta == 1, EXIT_FAILURE);
+ tend = now_msec();
+ t0 = tend - 10;
+ get_backoff_delta_msec(t0, tend, &delta);
+ assert_return(delta == 0, EXIT_FAILURE);
+ }
+
+ return EXIT_SUCCESS;
+}
+DEFINE_TEST(test_backoff_time,
+ .description = "check implementation of get_backoff_delta_msec()",
+ .need_spawn = false,
+ );
+
+
TESTSUITE_MAIN();
#include "testsuite.h"
static const char *ANSI_HIGHLIGHT_GREEN_ON = "\x1B[1;32m";
+static const char *ANSI_HIGHLIGHT_YELLOW_ON = "\x1B[1;33m";
static const char *ANSI_HIGHLIGHT_RED_ON = "\x1B[1;31m";
static const char *ANSI_HIGHLIGHT_OFF = "\x1B[0m";
};
#define OVERRIDE_LIBDIR ABS_TOP_BUILDDIR "/testsuite/.libs/"
+#define TEST_TIMEOUT_USEC 2 * USEC_PER_SEC
-struct _env_config {
+static const struct {
const char *key;
const char *ldpreload;
} env_config[_TC_LAST] = {
[TC_DELETE_MODULE_RETCODES] = { S_TC_DELETE_MODULE_RETCODES, OVERRIDE_LIBDIR "delete_module.so" },
};
-#define USEC_PER_SEC 1000000ULL
-#define USEC_PER_MSEC 1000ULL
-#define TEST_TIMEOUT_USEC 2 * USEC_PER_SEC
-static unsigned long long now_usec(void)
-{
- struct timespec ts;
-
- if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
- return 0;
-
- return ts_usec(&ts);
-}
-
static void help(void)
{
const struct option *itr;
int err;
bool matchout, match_modules;
+ if (t->skip) {
+ LOG("%sSKIPPED%s: %s\n",
+ ANSI_HIGHLIGHT_YELLOW_ON, ANSI_HIGHLIGHT_OFF,
+ t->name);
+ err = EXIT_SUCCESS;
+ goto exit;
+ }
+
/* Close write-fds */
if (t->output.out != NULL)
close(fdout[1]);
const struct keyval *env_vars;
bool need_spawn;
bool expected_fail;
+ /* allow to skip tests that don't meet compile-time dependencies */
+ bool skip;
bool print_outputs;
} __attribute__((aligned(8)));
/* Test definitions */
-#define DEFINE_TEST(_name, ...) \
- static const struct test s##_name##UNIQ \
+#define DEFINE_TEST_WITH_FUNC(_name, _func, ...) \
+ static const struct test UNIQ(s##_name) \
__attribute__((used, section("kmod_tests"), aligned(8))) = { \
.name = #_name, \
- .func = _name, \
+ .func = _func, \
## __VA_ARGS__ \
};
+#define DEFINE_TEST(_name, ...) DEFINE_TEST_WITH_FUNC(_name, _name, __VA_ARGS__)
+
#define TESTSUITE_MAIN() \
extern struct test __start_kmod_tests[] __attribute__((weak, visibility("hidden"))); \
extern struct test __stop_kmod_tests[] __attribute__((weak, visibility("hidden"))); \
static const char CFG_BUILTIN_KEY[] = "built-in";
static const char CFG_EXTERNAL_KEY[] = "external";
-static const char *default_cfg_paths[] = {
- "/run/depmod.d",
+static const char *const default_cfg_paths[] = {
SYSCONFDIR "/depmod.d",
+ "/run/depmod.d",
+ "/usr/local/lib/depmod.d",
+ DISTCONFDIR "/depmod.d",
"/lib/depmod.d",
NULL
};
-static const char cmdopts_s[] = "aAb:C:E:F:euqrvnP:wmVh";
+static const char cmdopts_s[] = "aAb:o:C:E:F:euqrvnP:wmVh";
static const struct option cmdopts[] = {
{ "all", no_argument, 0, 'a' },
{ "quick", no_argument, 0, 'A' },
{ "basedir", required_argument, 0, 'b' },
+ { "outdir", required_argument, 0, 'o' },
{ "config", required_argument, 0, 'C' },
{ "symvers", required_argument, 0, 'E' },
{ "filesyms", required_argument, 0, 'F' },
"\n"
"The following options are useful for people managing distributions:\n"
"\t-b, --basedir=DIR Use an image of a module tree.\n"
+ "\t-o, --outdir=DIR Output directory for generated files.\n"
"\t-F, --filesyms=FILE Use the file instead of the\n"
"\t current kernel symbols.\n"
"\t-E, --symvers=FILE Use Module.symvers file to check\n"
{
struct index_node *node;
- node = NOFAIL(calloc(sizeof(struct index_node), 1));
+ node = NOFAIL(calloc(1, sizeof(struct index_node)));
node->prefix = NOFAIL(strdup(""));
node->first = INDEX_CHILDMAX;
values = &(*values)->next;
len = strlen(value);
- v = NOFAIL(calloc(sizeof(struct index_value) + len + 1, 1));
+ v = NOFAIL(calloc(1, sizeof(struct index_value) + len + 1));
v->next = *values;
v->priority = priority;
memcpy(v->value, value, len + 1);
struct index_node *n;
/* New child is copy of node with prefix[j+1..N] */
- n = NOFAIL(calloc(sizeof(struct index_node), 1));
+ n = NOFAIL(calloc(1, sizeof(struct index_node)));
memcpy(n, node, sizeof(struct index_node));
n->prefix = NOFAIL(strdup(&prefix[j+1]));
node->first = ch;
if (ch > node->last)
node->last = ch;
- node->children[ch] = NOFAIL(calloc(sizeof(struct index_node), 1));
+ node->children[ch] = NOFAIL(calloc(1, sizeof(struct index_node)));
child = node->children[ch];
child->prefix = NOFAIL(strdup(&key[i+1]));
char path[];
};
+struct cfg_exclude {
+ struct cfg_exclude *next;
+ char exclude_dir[];
+};
+
struct cfg {
const char *kversion;
char dirname[PATH_MAX];
size_t dirnamelen;
+ char outdirname[PATH_MAX];
+ size_t outdirnamelen;
char sym_prefix;
uint8_t check_symvers;
uint8_t print_unknown;
struct cfg_override *overrides;
struct cfg_search *searches;
struct cfg_external *externals;
+ struct cfg_exclude *excludes;
};
static enum search_type cfg_define_search_type(const char *path)
free(ext);
}
+static int cfg_exclude_add(struct cfg *cfg, const char *path)
+{
+ struct cfg_exclude *exc;
+ size_t len = strlen(path);
+
+ exc = malloc(sizeof(struct cfg_exclude) + len + 1);
+ if (exc == NULL) {
+ ERR("exclude add: out of memory\n");
+ return -ENOMEM;
+ }
+ memcpy(exc->exclude_dir, path, len + 1);
+
+ DBG("exclude add: %s\n", path);
+
+ exc->next = cfg->excludes;
+ cfg->excludes = exc;
+ return 0;
+}
+
+static void cfg_exclude_free(struct cfg_exclude *exc)
+{
+ free(exc);
+}
+
static int cfg_kernel_matches(const struct cfg *cfg, const char *pattern)
{
regex_t re;
}
cfg_external_add(cfg, dir);
+ } else if (streq(cmd, "exclude")) {
+ const char *sp;
+ while ((sp = strtok_r(NULL, "\t ", &saveptr)) != NULL) {
+ cfg_exclude_add(cfg, sp);
+ }
} else if (streq(cmd, "include")
|| streq(cmd, "make_map_files")) {
INF("%s:%u: command %s not implemented yet\n",
cfg->externals = cfg->externals->next;
cfg_external_free(tmp);
}
+
+ while (cfg->excludes) {
+ struct cfg_exclude *tmp = cfg->excludes;
+ cfg->excludes = cfg->excludes->next;
+ cfg_exclude_free(tmp);
+ }
}
struct mod {
struct kmod_module *kmod;
char *path;
- const char *relpath; /* path relative to '$ROOT/lib/modules/$VER/' */
+ const char *relpath; /* path relative to '$ROOT$MODULE_DIRECTORY/$VER/' */
char *uncrelpath; /* same as relpath but ending in .ko */
struct kmod_list *info_list;
struct kmod_list *dep_sym_list;
return 0;
}
+static bool should_exclude_dir(const struct cfg *cfg, const char *name)
+{
+ struct cfg_exclude *exc;
+
+ if (name[0] == '.' && (name[1] == '\0' ||
+ (name[1] == '.' && name[2] == '\0')))
+ return true;
+
+ if (streq(name, "build") || streq(name, "source"))
+ return true;
+
+ for (exc = cfg->excludes; exc != NULL; exc = exc->next) {
+ if (streq(name, exc->exclude_dir))
+ return true;
+ }
+
+ return false;
+}
+
static int depmod_modules_search_dir(struct depmod *depmod, DIR *d, size_t baselen, struct scratchbuf *s_path)
{
struct dirent *de;
size_t namelen;
uint8_t is_dir;
- if (name[0] == '.' && (name[1] == '\0' ||
- (name[1] == '.' && name[2] == '\0')))
- continue;
- if (streq(name, "build") || streq(name, "source"))
+ if (should_exclude_dir(depmod->cfg, name))
continue;
+
namelen = strlen(name);
if (scratchbuf_alloc(s_path, baselen + namelen + 2) < 0) {
err = -ENOMEM;
struct kmod_list *l, *list = NULL;
int err = kmod_module_get_symbols(mod->kmod, &list);
if (err < 0) {
- if (err == -ENOENT)
+ if (err == -ENODATA)
DBG("ignoring %s: no symbols\n", mod->path);
else
ERR("failed to load symbols from %s: %s\n",
return 0;
}
+static int flush_stream(FILE *in, int endchar)
+{
+ size_t i = 0;
+ int c;
+
+ for (c = fgetc(in);
+ c != EOF && c != endchar && c != '\0';
+ c = fgetc(in))
+ ;
+
+ return c == endchar ? i : 0;
+}
+
+static int flush_stream_to(FILE *in, int endchar, char *dst, size_t dst_sz)
+{
+ size_t i = 0;
+ int c;
+
+ for (c = fgetc(in);
+ c != EOF && c != endchar && c != '\0' && i < dst_sz;
+ c = fgetc(in))
+ dst[i++] = c;
+
+ if (i == dst_sz) {
+ WRN("Could not flush stream: %d. Partial content: %.*s\n",
+ ENOSPC, (int) dst_sz, dst);
+ i--;
+ }
+
+ return c == endchar ? i : 0;
+}
+
+static int output_builtin_alias_bin(struct depmod *depmod, FILE *out)
+{
+ FILE *in;
+ struct index_node *idx;
+ int ret;
+
+ if (out == stdout)
+ return 0;
+
+ in = dfdopen(depmod->cfg->dirname, "modules.builtin.modinfo", O_RDONLY, "r");
+ if (in == NULL)
+ return 0;
+
+ idx = index_create();
+ if (idx == NULL) {
+ fclose(in);
+ return -ENOMEM;
+ }
+
+ /* format: modname.key=value\0 */
+ while (!feof(in) && !ferror(in)) {
+ char alias[PATH_MAX];
+ char modname[PATH_MAX];
+ char value[PATH_MAX];
+ size_t len;
+
+ len = flush_stream_to(in, '.', modname, sizeof(modname));
+ modname[len] = '\0';
+ if (!len)
+ continue;
+
+ len = flush_stream_to(in, '=', value, sizeof(value));
+ value[len] = '\0';
+ if (!streq(value, "alias")) {
+ flush_stream(in, '\0');
+ continue;
+ }
+
+ len = flush_stream_to(in, '\0', value, sizeof(value));
+ value[len] = '\0';
+ if (!len)
+ 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);
+ }
+
+ if (ferror(in)) {
+ ret = -EINVAL;
+ } else {
+ index_write(idx, out);
+ ret = 0;
+ }
+
+ index_destroy(idx);
+ fclose(in);
+
+ return ret;
+}
+
static int output_devname(struct depmod *depmod, FILE *out)
{
size_t i;
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;
-
- if (out == stdout)
- return 0;
-
- 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 {
{ "modules.devname", output_devname },
{ }
};
- const char *dname = depmod->cfg->dirname;
+ const char *dname = depmod->cfg->outdirname;
int dfd, err = 0;
struct timeval tv;
if (out != NULL)
dfd = -1;
else {
+ err = mkdir_p(dname, strlen(dname), 0755);
+ if (err < 0) {
+ CRIT("could not create directory %s: %m\n", dname);
+ return err;
+ }
dfd = open(dname, O_RDONLY);
if (dfd < 0) {
err = -errno;
FILE *out = NULL;
int err = 0, all = 0, maybe_all = 0, n_config_paths = 0;
_cleanup_free_ char *root = NULL;
+ _cleanup_free_ char *out_root = NULL;
_cleanup_free_ const char **config_paths = NULL;
const char *system_map = NULL;
const char *module_symvers = NULL;
free(root);
root = path_make_absolute_cwd(optarg);
break;
+ case 'o':
+ if (out_root)
+ free(out_root);
+ out_root = path_make_absolute_cwd(optarg);
+ break;
case 'C': {
size_t bytes = sizeof(char *) * (n_config_paths + 2);
void *tmp = realloc(config_paths, bytes);
}
cfg.dirnamelen = snprintf(cfg.dirname, PATH_MAX,
- "%s/lib/modules/%s",
- root == NULL ? "" : root, cfg.kversion);
+ "%s" MODULE_DIRECTORY "/%s",
+ root ?: "", cfg.kversion);
+
+ cfg.outdirnamelen = snprintf(cfg.outdirname, PATH_MAX,
+ "%s" MODULE_DIRECTORY "/%s",
+ out_root ?: (root ?: ""), cfg.kversion);
if (optind == argc)
all = 1;
+++ /dev/null
-/*
- * kmod-insert - insert a module into the kernel.
- *
- * Copyright (C) 2015 Intel Corporation. All rights reserved.
- * Copyright (C) 2011-2013 ProFUSION embedded systems
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <errno.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <libkmod/libkmod.h>
-
-#include "kmod.h"
-
-static const char cmdopts_s[] = "h";
-static const struct option cmdopts[] = {
- {"help", no_argument, 0, 'h'},
- { }
-};
-
-static void help(void)
-{
- printf("Usage:\n"
- "\t%s insert [options] module\n"
- "Options:\n"
- "\t-h, --help show this help\n",
- program_invocation_short_name);
-}
-
-static const char *mod_strerror(int err)
-{
- switch (err) {
- case KMOD_PROBE_APPLY_BLACKLIST:
- return "Module is blacklisted";
- case -EEXIST:
- return "Module already in kernel";
- case -ENOENT:
- return "Unknown symbol in module or unknown parameter (see dmesg)";
- default:
- return strerror(-err);
- }
-}
-
-static int do_insert(int argc, char *argv[])
-{
- struct kmod_ctx *ctx;
- struct kmod_list *list = NULL, *l;
- const char *name;
- int err, r = EXIT_SUCCESS;
-
- for (;;) {
- int c, idx = 0;
- c = getopt_long(argc, argv, cmdopts_s, cmdopts, &idx);
- if (c == -1)
- break;
- switch (c) {
- case 'h':
- help();
- return EXIT_SUCCESS;
- default:
- ERR("Unexpected getopt_long() value '%c'.\n", c);
- return EXIT_FAILURE;
- }
- }
-
- if (optind >= argc) {
- ERR("Missing module name\n");
- return EXIT_FAILURE;
- }
-
- ctx = kmod_new(NULL, NULL);
- if (!ctx) {
- ERR("kmod_new() failed!\n");
- return EXIT_FAILURE;
- }
-
- name = argv[optind];
- err = kmod_module_new_from_lookup(ctx, name, &list);
- if (err < 0) {
- ERR("Could not lookup module matching '%s': %s\n", name, strerror(-err));
- r = EXIT_FAILURE;
- goto end;
- }
-
- if (list == NULL) {
- ERR("No module matches '%s'\n", name);
- r = EXIT_FAILURE;
- goto end;
- }
-
- kmod_list_foreach(l, list) {
- struct kmod_module *mod = kmod_module_get_module(l);
-
- err = kmod_module_probe_insert_module(mod, KMOD_PROBE_APPLY_BLACKLIST, NULL, NULL, NULL, NULL);
- if (err != 0) {
- r = EXIT_FAILURE;
- ERR("Could not insert '%s': %s\n", kmod_module_get_name(mod), mod_strerror(err));
- }
-
- kmod_module_unref(mod);
- }
-
- kmod_module_unref_list(list);
-end:
- kmod_unref(ctx);
- return r;
-}
-
-const struct kmod_cmd kmod_cmd_insert = {
- .name = "insert",
- .cmd = do_insert,
- .help = "insert a module into the kernel",
-};
&kmod_cmd_help,
&kmod_cmd_list,
&kmod_cmd_static_nodes,
-
-#ifdef ENABLE_EXPERIMENTAL
- &kmod_cmd_insert,
- &kmod_cmd_remove,
-#endif
};
static const struct kmod_cmd *kmod_compat_cmds[] = {
--- /dev/null
+prefix=@prefix@
+sysconfdir=@sysconfdir@
+distconfdir=@distconfdir@
+module_directory=@module_directory@
+module_compressions=@module_compressions@
+module_signatures=@module_signatures@
+
+Name: kmod
+Description: Tools to deal with kernel modules
+Version: @VERSION@
is_builtin = (filename == NULL);
if (is_builtin) {
- printf("%-16s%s%c", "name:", kmod_module_get_name(mod), separator);
+ if (field == NULL)
+ printf("%-16s%s%c", "name:",
+ kmod_module_get_name(mod), separator);
+ else if (field != NULL && streq(field, "name"))
+ printf("%s%c", kmod_module_get_name(mod), separator);
filename = "(builtin)";
}
return err;
}
+static int modinfo_name_do(struct kmod_ctx *ctx, const char *name)
+{
+ struct kmod_module *mod = NULL;
+ int err;
+
+ err = kmod_module_new_from_name_lookup(ctx, name, &mod);
+ if (err < 0 || mod == NULL) {
+ ERR("Module name %s not found.\n", name);
+ return err < 0 ? err : -ENOENT;
+ }
+
+ err = modinfo_do(mod);
+ kmod_module_unref(mod);
+
+ return err;
+}
+
+
static int modinfo_alias_do(struct kmod_ctx *ctx, const char *alias)
{
struct kmod_list *l, *list = NULL;
return err;
}
-static const char cmdopts_s[] = "adlpn0F:k:b:Vh";
+static const char cmdopts_s[] = "adlpn0mF:k:b:Vh";
static const struct option cmdopts[] = {
{"author", no_argument, 0, 'a'},
{"description", no_argument, 0, 'd'},
{"parameters", no_argument, 0, 'p'},
{"filename", no_argument, 0, 'n'},
{"null", no_argument, 0, '0'},
+ {"modname", no_argument, 0, 'm'},
{"field", required_argument, 0, 'F'},
{"set-version", required_argument, 0, 'k'},
{"basedir", required_argument, 0, 'b'},
static void help(void)
{
printf("Usage:\n"
- "\t%s [options] filename [args]\n"
+ "\t%s [options] <modulename|filename> [args]\n"
"Options:\n"
"\t-a, --author Print only 'author'\n"
"\t-d, --description Print only 'description'\n"
"\t-p, --parameters Print only 'parm'\n"
"\t-n, --filename Print only 'filename'\n"
"\t-0, --null Use \\0 instead of \\n\n"
+ "\t-m, --modname Handle argument as module name instead of alias or filename\n"
"\t-F, --field=FIELD Print only provided FIELD\n"
"\t-k, --set-version=VERSION Use VERSION instead of `uname -r`\n"
- "\t-b, --basedir=DIR Use DIR as filesystem root for /lib/modules\n"
+ "\t-b, --basedir=DIR Use DIR as filesystem root for " MODULE_DIRECTORY "\n"
"\t-V, --version Show version\n"
"\t-h, --help Show this help\n",
program_invocation_short_name);
const char *kversion = NULL;
const char *root = NULL;
const char *null_config = NULL;
+ bool arg_is_modname = false;
int i, err;
for (;;) {
case '0':
separator = '\0';
break;
+ case 'm':
+ arg_is_modname = true;
+ break;
case 'F':
field = optarg;
break;
}
kversion = u.release;
}
- snprintf(dirname_buf, sizeof(dirname_buf), "%s/lib/modules/%s",
+ snprintf(dirname_buf, sizeof(dirname_buf), "%s" MODULE_DIRECTORY "/%s",
root, kversion);
dirname = dirname_buf;
}
const char *name = argv[i];
int r;
- if (is_module_filename(name))
+ if (arg_is_modname)
+ r = modinfo_name_do(ctx, name);
+ else if (is_module_filename(name))
r = modinfo_path_do(ctx, name);
else
r = modinfo_alias_do(ctx, name);
#include <sys/wait.h>
#include <shared/array.h>
+#include <shared/util.h>
#include <shared/macro.h>
#include <libkmod/libkmod.h>
static int force = 0;
static int strip_modversion = 0;
static int strip_vermagic = 0;
-static int remove_dependencies = 0;
+static int remove_holders = 0;
+static unsigned long long wait_msec = 0;
static int quiet_inuse = 0;
-static const char cmdopts_s[] = "arRibfDcnC:d:S:sqvVh";
+static const char cmdopts_s[] = "arw:RibfDcnC:d:S:sqvVh";
static const struct option cmdopts[] = {
{"all", no_argument, 0, 'a'},
+
{"remove", no_argument, 0, 'r'},
{"remove-dependencies", no_argument, 0, 5},
+ {"remove-holders", no_argument, 0, 5},
+ {"wait", required_argument, 0, 'w'},
+
{"resolve-alias", no_argument, 0, 'R'},
{"first-time", no_argument, 0, 3},
{"ignore-install", no_argument, 0, 'i'},
"\t be a module name to be inserted\n"
"\t or removed (-r)\n"
"\t-r, --remove Remove modules instead of inserting\n"
- "\t --remove-dependencies Also remove modules depending on it\n"
- "\t-R, --resolve-alias Only lookup and print alias and exit\n"
+ "\t --remove-dependencies Deprecated: use --remove-holders\n"
+ "\t --remove-holders Also remove module holders (use together with -r)\n"
+ "\t-w, --wait <MSEC> When removing a module, wait up to MSEC for\n"
+ "\t module's refcount to become 0 so it can be\n"
+ "\t removed (use together with -r)\n"
"\t --first-time Fail if module already inserted or removed\n"
"\t-i, --ignore-install Ignore install commands\n"
"\t-i, --ignore-remove Ignore remove commands\n"
"\t --force-vermagic Ignore module's version magic\n"
"\n"
"Query Options:\n"
+ "\t-R, --resolve-alias Only lookup and print alias and exit\n"
"\t-D, --show-depends Only print module dependencies and exit\n"
"\t-c, --showconfig Print out known configuration and exit\n"
"\t-c, --show-config Same as --showconfig\n"
"\t-n, --show Same as --dry-run\n"
"\t-C, --config=FILE Use FILE instead of default search paths\n"
- "\t-d, --dirname=DIR Use DIR as filesystem root for /lib/modules\n"
+ "\t-d, --dirname=DIR Use DIR as filesystem root for " MODULE_DIRECTORY "\n"
"\t-S, --set-version=VERSION Use VERSION instead of `uname -r`\n"
"\t-s, --syslog print to syslog, not stderr\n"
static int rmmod_do_remove_module(struct kmod_module *mod)
{
const char *modname = kmod_module_get_name(mod);
- struct kmod_list *deps, *itr;
+ unsigned long long interval_msec = 0, t0_msec = 0,
+ tend_msec = 0;
int flags = 0, err;
- SHOW("rmmod %s\n", kmod_module_get_name(mod));
+ SHOW("rmmod %s\n", modname);
if (dry_run)
return 0;
if (force)
flags |= KMOD_REMOVE_FORCE;
- err = kmod_module_remove_module(mod, flags);
- if (err == -EEXIST) {
- if (!first_time)
- err = 0;
- else
- LOG("Module %s is not in kernel.\n", modname);
- }
+ if (wait_msec)
+ flags |= KMOD_REMOVE_NOLOG;
- deps = kmod_module_get_dependencies(mod);
- if (deps != NULL) {
- kmod_list_foreach(itr, deps) {
- struct kmod_module *dep = kmod_module_get_module(itr);
- if (kmod_module_get_refcnt(dep) == 0)
- rmmod_do_remove_module(dep);
- kmod_module_unref(dep);
+ do {
+ err = kmod_module_remove_module(mod, flags);
+ if (err == -EEXIST) {
+ if (!first_time)
+ err = 0;
+ else
+ LOG("Module %s is not in kernel.\n", modname);
+ break;
+ } else if (err == -EAGAIN && wait_msec) {
+ unsigned long long until_msec;
+
+ if (!t0_msec) {
+ t0_msec = now_msec();
+ tend_msec = t0_msec + wait_msec;
+ interval_msec = 1;
+ }
+
+ until_msec = get_backoff_delta_msec(t0_msec, tend_msec,
+ &interval_msec);
+ err = sleep_until_msec(until_msec);
+
+ if (!t0_msec)
+ err = -ENOTSUP;
+
+ if (err < 0) {
+ ERR("Failed to sleep: %s\n", strerror(-err));
+ err = -EAGAIN;
+ break;
+ }
+ } else {
+ break;
}
- kmod_module_unref_list(deps);
- }
+ } while (interval_msec);
+
+ if (err < 0 && wait_msec)
+ ERR("could not remove '%s': %s\n", modname, strerror(-err));
return err;
}
-#define RMMOD_FLAG_DO_DEPENDENCIES 0x1
+#define RMMOD_FLAG_REMOVE_HOLDERS 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)
+/* Remove modules in reverse order */
+static int rmmod_do_modlist(struct kmod_list *list, bool stop_on_errors)
{
struct kmod_list *l;
cmd = kmod_module_get_remove_commands(mod);
}
- if (cmd == NULL && !ignore_loaded) {
+ /* Quick check if module is loaded, otherwise there's nothing to do */
+ if (!cmd && !ignore_loaded) {
int state = kmod_module_get_initstate(mod);
if (state < 0) {
}
}
- rmmod_do_deps_list(post, false);
+ /* 1. @mod's post-softdeps in reverse order */
+ rmmod_do_modlist(post, false);
- if ((flags & RMMOD_FLAG_DO_DEPENDENCIES) && remove_dependencies) {
- struct kmod_list *deps = kmod_module_get_dependencies(mod);
+ /* 2. Other modules holding @mod */
+ if (flags & RMMOD_FLAG_REMOVE_HOLDERS) {
+ struct kmod_list *holders = kmod_module_get_holders(mod);
- err = rmmod_do_deps_list(deps, true);
+ err = rmmod_do_modlist(holders, true);
+ kmod_module_unref_list(holders);
if (err < 0)
goto error;
}
- if (!ignore_loaded && !cmd) {
+ /* 3. @mod itself, but check for refcnt first */
+ if (!cmd && !ignore_loaded && !wait_msec) {
int usage = kmod_module_get_refcnt(mod);
if (usage > 0) {
}
}
- if (cmd == NULL)
+ if (!cmd)
err = rmmod_do_remove_module(mod);
else
err = command_do(mod, "remove", cmd, NULL);
if (err < 0)
goto error;
- rmmod_do_deps_list(pre, false);
+ /* 4. Other modules that became unused: errors are non-fatal */
+ if (!cmd) {
+ struct kmod_list *deps, *itr;
+
+ deps = kmod_module_get_dependencies(mod);
+ kmod_list_foreach(itr, deps) {
+ struct kmod_module *dep = kmod_module_get_module(itr);
+ if (kmod_module_get_refcnt(dep) == 0)
+ rmmod_do_remove_module(dep);
+ kmod_module_unref(dep);
+ }
+ kmod_module_unref_list(deps);
+ }
+
+ /* 5. @mod's pre-softdeps in reverse order: errors are non-fatal */
+ rmmod_do_modlist(pre, false);
error:
kmod_module_unref_list(pre);
kmod_list_foreach(l, list) {
struct kmod_module *mod = kmod_module_get_module(l);
- err = rmmod_do_module(mod, RMMOD_FLAG_DO_DEPENDENCIES);
+ int flags = remove_holders ? RMMOD_FLAG_REMOVE_HOLDERS : 0;
+
+ err = rmmod_do_module(mod, flags);
kmod_module_unref(mod);
if (err < 0)
break;
printf("insmod %s %s\n", kmod_module_get_path(m), options);
}
+static int insmod_insert(struct kmod_module *mod, int flags,
+ const char *extra_options)
+{
+ int err = 0;
+ void (*show)(struct kmod_module *m, bool install,
+ const char *options) = NULL;
+
+ if (do_show || verbose > DEFAULT_VERBOSE)
+ show = &print_action;
+
+ if (lookup_only)
+ printf("%s\n", kmod_module_get_name(mod));
+ else
+ err = kmod_module_probe_insert_module(mod, flags,
+ extra_options, NULL, NULL, show);
+
+ if (err >= 0)
+ /* ignore flag return values such as a mod being blacklisted */
+ err = 0;
+ else {
+ switch (err) {
+ case -EEXIST:
+ ERR("could not insert '%s': Module already in kernel\n",
+ kmod_module_get_name(mod));
+ break;
+ case -ENOENT:
+ ERR("could not insert '%s': Unknown symbol in module, "
+ "or unknown parameter (see dmesg)\n",
+ kmod_module_get_name(mod));
+ break;
+ default:
+ ERR("could not insert '%s': %s\n",
+ kmod_module_get_name(mod),
+ strerror(-err));
+ break;
+ }
+ }
+
+ return err;
+}
+
static int insmod(struct kmod_ctx *ctx, const char *alias,
const char *extra_options)
{
struct kmod_list *l, *list = NULL;
+ struct kmod_module *mod = NULL;
int err, flags = 0;
- void (*show)(struct kmod_module *m, bool install,
- const char *options) = NULL;
-
- err = kmod_module_new_from_lookup(ctx, alias, &list);
-
- if (list == NULL || err < 0) {
- LOG("Module %s not found in directory %s\n", alias,
- ctx ? kmod_get_dirname(ctx) : "(missing)");
- return -ENOENT;
+ if (strncmp(alias, "/", 1) == 0 || strncmp(alias, "./", 2) == 0) {
+ err = kmod_module_new_from_path(ctx, alias, &mod);
+ if (err < 0) {
+ LOG("Failed to get module from path %s: %s\n", alias,
+ strerror(-err));
+ return -ENOENT;
+ }
+ } else {
+ err = kmod_module_new_from_lookup(ctx, alias, &list);
+ if (list == NULL || err < 0) {
+ LOG("Module %s not found in directory %s\n", alias,
+ ctx ? kmod_get_dirname(ctx) : "(missing)");
+ return -ENOENT;
+ }
}
if (strip_modversion || force)
flags |= KMOD_PROBE_IGNORE_LOADED;
if (dry_run)
flags |= KMOD_PROBE_DRY_RUN;
- if (do_show || verbose > DEFAULT_VERBOSE)
- show = &print_action;
flags |= KMOD_PROBE_APPLY_BLACKLIST_ALIAS_ONLY;
if (first_time)
flags |= KMOD_PROBE_FAIL_ON_LOADED;
- kmod_list_foreach(l, list) {
- struct kmod_module *mod = kmod_module_get_module(l);
-
- if (lookup_only)
- printf("%s\n", kmod_module_get_name(mod));
- else {
- err = kmod_module_probe_insert_module(mod, flags,
- extra_options, NULL, NULL, show);
- }
-
- if (err >= 0)
- /* ignore flag return values such as a mod being blacklisted */
- err = 0;
- else {
- switch (err) {
- case -EEXIST:
- ERR("could not insert '%s': Module already in kernel\n",
- kmod_module_get_name(mod));
- break;
- case -ENOENT:
- ERR("could not insert '%s': Unknown symbol in module, "
- "or unknown parameter (see dmesg)\n",
- kmod_module_get_name(mod));
- break;
- default:
- ERR("could not insert '%s': %s\n",
- kmod_module_get_name(mod),
- strerror(-err));
- break;
- }
- }
-
+ /* If module is loaded from path */
+ if (mod != NULL) {
+ err = insmod_insert(mod, flags, extra_options);
kmod_module_unref(mod);
+ } else {
+ kmod_list_foreach(l, list) {
+ mod = kmod_module_get_module(l);
+ err = insmod_insert(mod, flags, extra_options);
+ kmod_module_unref(mod);
+ }
+ kmod_module_unref_list(list);
}
-
- kmod_module_unref_list(list);
return err;
}
static char **prepend_options_from_env(int *p_argc, char **orig_argv)
{
const char *p, *env = getenv("MODPROBE_OPTIONS");
- char **new_argv, *str_start, *str_end, *str, *s, *quote;
+ char **new_argv, *str_end, *str, *s, *quote;
int i, argc = *p_argc;
size_t envlen, space_count = 0;
return NULL;
new_argv[0] = orig_argv[0];
- str_start = str = (char *) (new_argv + argc + space_count + 3);
+ str = (char *) (new_argv + argc + space_count + 3);
memcpy(str, env, envlen + 1);
- str_end = str_start + envlen;
+ str_end = str + envlen;
quote = NULL;
for (i = 1, s = str; *s != '\0'; s++) {
}
memcpy(new_argv + i, orig_argv + 1, sizeof(char *) * (argc - 1));
- new_argv[i + argc] = NULL;
+ new_argv[i + argc - 1] = NULL;
*p_argc = i + argc - 1;
return new_argv;
int do_show_modversions = 0;
int do_show_exports = 0;
int err;
+ struct stat stat_buf;
argv = prepend_options_from_env(&argc, orig_argv);
if (argv == NULL) {
do_remove = 1;
break;
case 5:
- remove_dependencies = 1;
+ remove_holders = 1;
break;
- case 'R':
- lookup_only = 1;
+ case 'w': {
+ char *endptr = NULL;
+ wait_msec = strtoul(optarg, &endptr, 0);
+ if (!*optarg || *endptr) {
+ ERR("unexpected wait value '%s'.\n", optarg);
+ err = -1;
+ goto done;
+ }
break;
+ }
case 3:
first_time = 1;
break;
dry_run = 1;
do_show = 1;
break;
+ case 'R':
+ lookup_only = 1;
+ break;
case 'c':
do_show_config = 1;
break;
args = argv + optind;
nargs = argc - optind;
+ if (!use_syslog &&
+ (!stderr ||
+ fileno(stderr) == -1 ||
+ fstat(fileno(stderr), &stat_buf)))
+ use_syslog = 1;
+
log_open(use_syslog);
if (!do_show_config) {
kversion = u.release;
}
snprintf(dirname_buf, sizeof(dirname_buf),
- "%s/lib/modules/%s", root,
+ "%s" MODULE_DIRECTORY "/%s", root,
kversion);
dirname = dirname_buf;
}
+++ /dev/null
-/*
- * kmod-remove - remove modules from the kernel.
- *
- * Copyright (C) 2015 Intel Corporation. All rights reserved.
- * Copyright (C) 2011-2013 ProFUSION embedded systems
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <errno.h>
-#include <getopt.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <libkmod/libkmod.h>
-
-#include "kmod.h"
-
-static const char cmdopts_s[] = "h";
-static const struct option cmdopts[] = {
- {"help", no_argument, 0, 'h'},
- { }
-};
-
-static void help(void)
-{
- printf("Usage:\n"
- "\t%s remove [options] module\n"
- "Options:\n"
- "\t-h, --help show this help\n",
- program_invocation_short_name);
-}
-
-static int check_module_inuse(struct kmod_module *mod) {
- struct kmod_list *holders;
- int state, ret;
-
- state = kmod_module_get_initstate(mod);
-
- if (state == KMOD_MODULE_BUILTIN) {
- ERR("Module %s is builtin.\n", kmod_module_get_name(mod));
- return -ENOENT;
- } else if (state < 0) {
- ERR("Module %s is not currently loaded\n",
- kmod_module_get_name(mod));
- return -ENOENT;
- }
-
- holders = kmod_module_get_holders(mod);
- if (holders != NULL) {
- struct kmod_list *itr;
-
- ERR("Module %s is in use by:", kmod_module_get_name(mod));
-
- kmod_list_foreach(itr, holders) {
- struct kmod_module *hm = kmod_module_get_module(itr);
- fprintf(stderr, " %s", kmod_module_get_name(hm));
- kmod_module_unref(hm);
- }
- fputc('\n', stderr);
-
- kmod_module_unref_list(holders);
- return -EBUSY;
- }
-
- 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 ret;
-}
-
-static int do_remove(int argc, char *argv[])
-{
- struct kmod_ctx *ctx;
- struct kmod_module *mod;
- const char *name;
- int err, r = EXIT_SUCCESS;
-
- for (;;) {
- int c, idx =0;
- c = getopt_long(argc, argv, cmdopts_s, cmdopts, &idx);
- if (c == -1)
- break;
- switch (c) {
- case 'h':
- help();
- return EXIT_SUCCESS;
-
- default:
- ERR("Unexpected getopt_long() value '%c'.\n", c);
- return EXIT_FAILURE;
- }
- }
-
- if (optind >= argc) {
- ERR("Missing module name\n");
- return EXIT_FAILURE;
- }
-
- ctx = kmod_new(NULL, NULL);
- if (!ctx) {
- ERR("kmod_new() failed!\n");
- return EXIT_FAILURE;
- }
-
- name = argv[optind];
- err = kmod_module_new_from_name(ctx, name, &mod);
- if (err < 0) {
- ERR("Could not remove module %s: %s\n", name, strerror(-err));
- goto end;
- }
-
- err = check_module_inuse(mod);
- if (err < 0)
- goto unref;
-
- err = kmod_module_remove_module(mod, 0);
- if (err < 0)
- goto unref;
-
-unref:
- kmod_module_unref(mod);
-
-end:
- kmod_unref(ctx);
- if (err < 0) {
- r = EXIT_FAILURE;
- ERR("Could not remove module %s: %s\n", name, strerror(-err));
- }
- return r;
-}
-
-const struct kmod_cmd kmod_cmd_remove = {
- .name = "remove",
- .cmd = do_remove,
- .help = "remove module from kernel",
-};
goto finish;
}
- snprintf(modules, sizeof(modules), "/lib/modules/%s/modules.devname", kernel.release);
+ snprintf(modules, sizeof(modules), MODULE_DIRECTORY "/%s/modules.devname", kernel.release);
in = fopen(modules, "re");
if (in == NULL) {
if (errno == ENOENT) {
- fprintf(stderr, "Warning: /lib/modules/%s/modules.devname not found - ignoring\n",
+ fprintf(stderr, "Warning: " MODULE_DIRECTORY "/%s/modules.devname not found - ignoring\n",
kernel.release);
ret = EXIT_SUCCESS;
} else {
- fprintf(stderr, "Error: could not open /lib/modules/%s/modules.devname - %m\n",
+ fprintf(stderr, "Error: could not open " MODULE_DIRECTORY "/%s/modules.devname - %m\n",
kernel.release);
ret = EXIT_FAILURE;
}