commit 5e1accdd271df8b0d07f8cc0cb0b7af71e5c4a1b Author: overweight <5324761+overweight@user.noreply.gitee.com> Date: Mon Sep 30 10:54:27 2019 -0400 Package init diff --git a/bugfix-kmod-20-8-depmod-Don-t-unlinkat-orig-depfile-and-add-fsync.patch b/bugfix-kmod-20-8-depmod-Don-t-unlinkat-orig-depfile-and-add-fsync.patch new file mode 100644 index 0000000..d23541b --- /dev/null +++ b/bugfix-kmod-20-8-depmod-Don-t-unlinkat-orig-depfile-and-add-fsync.patch @@ -0,0 +1,46 @@ +From 0f3d89015caf91ea96359ba7e2afd2aa8ab67e85 Mon Sep 17 00:00:00 2001 +From: guoxiaoqi +Date: Fri, 25 Jan 2019 17:03:05 +0000 +Subject: [PATCH] ok + +Signed-off-by: guoxiaoqi +--- + tools/depmod.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/tools/depmod.c b/tools/depmod.c +index 989d907..f519679 100644 +--- a/tools/depmod.c ++++ b/tools/depmod.c +@@ -2438,7 +2438,7 @@ static int depmod_output(struct depmod *depmod, FILE *out) + r = itr->cb(depmod, fp); + if (fp == out) + continue; +- ++ fsync(fileno(fp)); + ferr = ferror(fp) | fclose(fp); + + if (r < 0) { +@@ -2451,7 +2451,6 @@ static int depmod_output(struct depmod *depmod, FILE *out) + break; + } + +- unlinkat(dfd, itr->name, 0); + if (renameat(dfd, tmp, dfd, itr->name) != 0) { + err = -errno; + CRIT("renameat(%s, %s, %s, %s): %m\n", +@@ -2467,8 +2466,10 @@ static int depmod_output(struct depmod *depmod, FILE *out) + } + } + +- if (dfd >= 0) ++ if (dfd >= 0) { ++ fsync(dfd); + close(dfd); ++ } + + return err; + } +-- +1.8.3.1 + diff --git a/depmod-prevent-module-dependency-files-corruption-du.patch b/depmod-prevent-module-dependency-files-corruption-du.patch new file mode 100644 index 0000000..c3b932c --- /dev/null +++ b/depmod-prevent-module-dependency-files-corruption-du.patch @@ -0,0 +1,62 @@ +From a06bacf500d56b72b5f9b121ebf7f6af9e3df185 Mon Sep 17 00:00:00 2001 +From: Michal Suchanek +Date: Mon, 17 Dec 2018 23:46:28 +0100 +Subject: [PATCH 16/36] depmod: prevent module dependency files corruption due + to parallel invocation. + +Depmod does not use unique filename for temporary files. There is no +guarantee the user does not attempt to run mutiple depmod processes in +parallel. If that happens a temporary file might be created by +depmod(1st), truncated by depmod(2nd), and renamed to final name by +depmod(1st) resulting in corrupted file seen by user. + +Due to missing mkstempat() this is more complex than it should be. +Adding PID and timestamp to the filename should be reasonably reliable. +Adding O_EXCL as mkstemp does fails creating the file rather than +corrupting existing file. + +Signed-off-by: Michal Suchanek +--- + tools/depmod.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/tools/depmod.c b/tools/depmod.c +index 18c0d61..0f7e33c 100644 +--- a/tools/depmod.c ++++ b/tools/depmod.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -2398,6 +2399,9 @@ static int depmod_output(struct depmod *depmod, FILE *out) + }; + const char *dname = depmod->cfg->dirname; + int dfd, err = 0; ++ struct timeval tv; ++ ++ gettimeofday(&tv, NULL); + + if (out != NULL) + dfd = -1; +@@ -2416,11 +2420,12 @@ static int depmod_output(struct depmod *depmod, FILE *out) + int r, ferr; + + if (fp == NULL) { +- int flags = O_CREAT | O_TRUNC | O_WRONLY; ++ int flags = O_CREAT | O_EXCL | O_WRONLY; + int mode = 0644; + int fd; + +- snprintf(tmp, sizeof(tmp), "%s.tmp", itr->name); ++ snprintf(tmp, sizeof(tmp), "%s.%i.%li.%li", itr->name, getpid(), ++ tv.tv_usec, tv.tv_sec); + fd = openat(dfd, tmp, flags, mode); + if (fd < 0) { + ERR("openat(%s, %s, %o, %o): %m\n", +-- +1.8.3.1 + diff --git a/depmod.conf.dist b/depmod.conf.dist new file mode 100644 index 0000000..7bf69c5 --- /dev/null +++ b/depmod.conf.dist @@ -0,0 +1,6 @@ +# +# depmod.conf +# + +# override default search ordering for kmod packaging +search EulerOS updates extra external built-in weak-updates diff --git a/kmod-25.tar.xz b/kmod-25.tar.xz new file mode 100644 index 0000000..8131248 Binary files /dev/null and b/kmod-25.tar.xz differ diff --git a/kmod.spec b/kmod.spec new file mode 100644 index 0000000..03f6fa2 --- /dev/null +++ b/kmod.spec @@ -0,0 +1,128 @@ +Name: kmod +Version: 25 +Release: 5 +Summary: Kernel module management +# GPLv2+ is used by programs, LGPLv2+ is used for libraries. +License: GPLv2+ and LGPLv2+ +URL: http://git.kernel.org/?p=utils/kernel/kmod/kmod.git;a=summary +Source0: https://www.kernel.org/pub/linux/utils/kernel/kmod/%{name}-%{version}.tar.xz +Source1: weak-modules +Source2: depmod.conf.dist + +Patch9000: bugfix-kmod-20-8-depmod-Don-t-unlinkat-orig-depfile-and-add-fsync.patch +Patch9001: libkmod-module-check-for-NULL-before-accessing-point.patch +Patch9002: depmod-prevent-module-dependency-files-corruption-du.patch + +BuildRequires: gcc chrpath zlib-devel xz-devel libxslt + +Provides: module-init-tools = 4.0-1 +Provides: %{name} = %{version}-%{release} %{name}-libs +Provides: /sbin/modprobe +Obsoletes: %{name}-libs + +%description +The kmod package provides several commands to manage the kernel modules, +such as insmod to load and rmmod to unload the modules. + +%package devel +Summary: Header files for kmod development +Requires: %{name} = %{version}-%{release} + +%description devel +The kmod-devel package provides header files used for loading or unloading +kernel modules. + +%package help +Summary: Documents and man pages for the kmod +Requires: man info + +%description help +The kmod-help package provides several documents and the man pages to help +developers to understand the kmod. + +%prep +%autosetup -n %{name}-%{version} -p1 + +%build +%configure --with-zlib --with-xz +%make_build + +%install +%make_install +pushd $RPM_BUILD_ROOT/%{_mandir}/man5 +ln -s modprobe.d.5.gz modprobe.conf.5.gz +popd + +mkdir -p $RPM_BUILD_ROOT%{_sbindir} +for i in $RPM_BUILD_ROOT%{_sbindir}/modprobe $RPM_BUILD_ROOT%{_sbindir}/modinfo $RPM_BUILD_ROOT%{_sbindir}/insmod \ + $RPM_BUILD_ROOT%{_sbindir}/rmmod $RPM_BUILD_ROOT%{_sbindir}/depmod $RPM_BUILD_ROOT%{_sbindir}/lsmod +do + ln -sf ../bin/kmod $i +done + +mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/modprobe.d +mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/depmod.d +mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/modprobe.d +mkdir -p $RPM_BUILD_ROOT/sbin + +install -m 755 %{SOURCE1} $RPM_BUILD_ROOT%{_sbindir}/weak-modules +install -m 0644 %{SOURCE2} $RPM_BUILD_ROOT%{_sysconfdir}/depmod.d/dist.conf + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%files +%exclude %{_libdir}/*.la + +%dir %{_sysconfdir}/*.d +%dir %{_prefix}/lib/modprobe.d + +%{_bindir}/kmod +%{_sbindir}/* +%{_datadir}/bash-completion/ +%{_sysconfdir}/depmod.d/dist.conf + +%{!?_licensedir:%global license %%doc} +%license COPYING +%{_libdir}/libkmod.so.* + +%files devel +%{_includedir}/libkmod.h +%{_libdir}/pkgconfig/libkmod.pc +%{_libdir}/libkmod.so + +%files help +%attr(0644,root,root) %{_mandir}/man5/*.5* +%attr(0644,root,root) %{_mandir}/man8/*.8* + +%doc TODO NEWS README + +%changelog +* Sat Apr 6 2019 luochunsheng - 25-5 +- Type:enhancement +- ID:NA +- SUG:NA + +* Fri Mar 22 2019 kangenbo - 25-4 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: backport patches from communities + +* Tue Mar 19 2019 hexiaowen - 25-3 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC: add /etc/depmod.d/dist.conf + +* Fri Jan 25 2019 Xiaoqi Guo - 25-2 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:add patches, include + bugfix-kmod-20-8-depmod-Don-t-unlinkat-orig-depfile-and-add-fsync.patch + +* Thu Jan 24 2019 openEuler Buildteam - 25-1 +- Package init + diff --git a/libkmod-module-check-for-NULL-before-accessing-point.patch b/libkmod-module-check-for-NULL-before-accessing-point.patch new file mode 100644 index 0000000..d3914ca --- /dev/null +++ b/libkmod-module-check-for-NULL-before-accessing-point.patch @@ -0,0 +1,126 @@ +From c8f0623ad18194eedfcca69ccae1cbfe6cf5d2a8 Mon Sep 17 00:00:00 2001 +From: Luca Bruno +Date: Wed, 7 Mar 2018 10:51:21 +0000 +Subject: [PATCH 04/36] libkmod-module: check for NULL before accessing + pointers + +This introduces a few missing NULL-checks in public functions, and +align their docstrings with real behavior by getting rid of copy-paste +mistakes. + +Signed-off-by: Luca Bruno +--- + TODO | 5 +++++ + libkmod/libkmod-module.c | 23 ++++++++++------------- + 2 files changed, 15 insertions(+), 13 deletions(-) + +diff --git a/TODO b/TODO +index 537e7e1..3fe06eb 100644 +--- a/TODO ++++ b/TODO +@@ -35,6 +35,11 @@ and libkmod + - kmod_module_symbols_free_list() + - kmod_module_dependency_symbols_free_list() + ++* libkmod API breaking changes: ++ - dedicated error value for all kmod_*_get_crc() functions. Currently there ++ is no way for callers to distinguish between a valid CRC=0 and the error ++ code 0. ++ + * index: drop the "open(), seek(), read()" implementation and use another one + with mmap(). When lookup() is called and the file is not mmaped, mmap it. + Another possibility is to drop the mmap implementation relying on VFS to have +diff --git a/libkmod/libkmod-module.c b/libkmod/libkmod-module.c +index 0a3ef11..ee420f4 100644 +--- a/libkmod/libkmod-module.c ++++ b/libkmod/libkmod-module.c +@@ -2519,7 +2519,7 @@ KMOD_EXPORT const char *kmod_module_version_get_symbol(const struct kmod_list *e + { + struct kmod_module_version *version; + +- if (entry == NULL) ++ if (entry == NULL || entry->data == NULL) + return NULL; + + version = entry->data; +@@ -2532,14 +2532,13 @@ KMOD_EXPORT const char *kmod_module_version_get_symbol(const struct kmod_list *e + * + * Get the crc of a kmod module version. + * +- * Returns: the crc of this kmod module version on success or NULL on +- * failure. The string is owned by the version, do not free it. ++ * Returns: the crc of this kmod module version if available, otherwise default to 0. + */ + KMOD_EXPORT uint64_t kmod_module_version_get_crc(const struct kmod_list *entry) + { + struct kmod_module_version *version; + +- if (entry == NULL) ++ if (entry == NULL || entry->data == NULL) + return 0; + + version = entry->data; +@@ -2660,7 +2659,7 @@ KMOD_EXPORT const char *kmod_module_symbol_get_symbol(const struct kmod_list *en + { + struct kmod_module_symbol *symbol; + +- if (entry == NULL) ++ if (entry == NULL || entry->data == NULL) + return NULL; + + symbol = entry->data; +@@ -2673,14 +2672,13 @@ KMOD_EXPORT const char *kmod_module_symbol_get_symbol(const struct kmod_list *en + * + * Get the crc of a kmod module symbol. + * +- * Returns: the crc of this kmod module symbol on success or NULL on +- * failure. The string is owned by the symbol, do not free it. ++ * Returns: the crc of this kmod module symbol if available, otherwise default to 0. + */ + KMOD_EXPORT uint64_t kmod_module_symbol_get_crc(const struct kmod_list *entry) + { + struct kmod_module_symbol *symbol; + +- if (entry == NULL) ++ if (entry == NULL || entry->data == NULL) + return 0; + + symbol = entry->data; +@@ -2806,7 +2804,7 @@ KMOD_EXPORT const char *kmod_module_dependency_symbol_get_symbol(const struct km + { + struct kmod_module_dependency_symbol *dependency_symbol; + +- if (entry == NULL) ++ if (entry == NULL || entry->data == NULL) + return NULL; + + dependency_symbol = entry->data; +@@ -2819,14 +2817,13 @@ KMOD_EXPORT const char *kmod_module_dependency_symbol_get_symbol(const struct km + * + * Get the crc of a kmod module dependency_symbol. + * +- * Returns: the crc of this kmod module dependency_symbol on success or NULL on +- * failure. The string is owned by the dependency_symbol, do not free it. ++ * Returns: the crc of this kmod module dependency_symbol if available, otherwise default to 0. + */ + KMOD_EXPORT uint64_t kmod_module_dependency_symbol_get_crc(const struct kmod_list *entry) + { + struct kmod_module_dependency_symbol *dependency_symbol; + +- if (entry == NULL) ++ if (entry == NULL || entry->data == NULL) + return 0; + + dependency_symbol = entry->data; +@@ -2846,7 +2843,7 @@ KMOD_EXPORT int kmod_module_dependency_symbol_get_bind(const struct kmod_list *e + { + struct kmod_module_dependency_symbol *dependency_symbol; + +- if (entry == NULL) ++ if (entry == NULL || entry->data == NULL) + return 0; + + dependency_symbol = entry->data; +-- +1.8.3.1 + diff --git a/weak-modules b/weak-modules new file mode 100644 index 0000000..4b621e9 --- /dev/null +++ b/weak-modules @@ -0,0 +1,475 @@ +#!/bin/bash +# +# weak-modules - determine which modules are kABI compatible with installed +# kernels and set up the symlinks in /lib/*/weak-updates. +# +# Changelog: +# +# 2010/01/10 - Further updates for dracut use on Fedora/RHEL (jcm). +# 2009/09/16 - Rebase and add a bunch of updates for dracut (jcm). + +unset LANG LC_ALL LC_COLLATE + +tmpdir=$(mktemp -td ${0##*/}.XXXXXX) +trap "rm -rf $tmpdir" EXIT +unset ${!changed_modules_*} ${!changed_initramfs_*} + +initramfs_prefix="/boot" # can customize here +dracut="/usr/bin/dracut" + +if [ ! -x "$dracut" ] +then + echo "weak-modules: this tool requires a dracut-enabled kernel" + exit 1 +fi + +# doit: +# A wrapper used whenever we're going to perform a real operation. +doit() { + [ -n "$verbose" ] && echo "$@" + [ -n "$dry_run" ] || "$@" +} + +# rpmsort: The sort in coreutils can't sort the RPM list how we want it so we +# instead transform the list into a form it will sort correctly, then sort. +rpmsort() { + local IFS=$' ' + REVERSE="" + rpmlist=($(cat)) + + if [ "-r" == "$1" ]; + then + REVERSE="-r" + fi + + echo ${rpmlist[@]} | \ + sed -e 's/-/../g' | \ + sort ${REVERSE} -n -t"." -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 -k6,6 -k7,7 \ + -k8,8 -k9,9 -k10,10 | \ + sed -e 's/\.\./-/g' +} + +# read_modules_list: +# Read in a list of modules from standard input. Convert the filenames into +# absolute paths and compute the kernel release for each module (either using +# the modinfo section or through the absolute path. +read_modules_list() { + local IFS=$'\n' + modules=($(cat)) + + for ((n = 0; n < ${#modules[@]}; n++)); do + if [ ${modules[n]:0:1} != '/' ]; then + modules[n]="$PWD/${modules[n]}" + fi + if [ -f "${modules[n]}" ]; then + module_krels[n]=$(krel_of_module ${modules[n]}) + else + # Try to extract the kernel release from the path + set -- "${modules[n]#/lib/modules/}" + module_krels[n]=${1%%/*} + fi + done +} + +# read_old_initramfs: +compare_initramfs_modules() { + local old_initramfs=$1 + local new_initramfs=$2 + + rm -rf "$tmpdir/old_initramfs" + rm -rf "$tmpdir/new_initramfs" + mkdir "$tmpdir/old_initramfs" + mkdir "$tmpdir/new_initramfs" + + pushd "$tmpdir/old_initramfs" >/dev/null + zcat "$old_initramfs" | cpio -i 2>/dev/null + n=0; for i in `find . -iname \*.ko|sort`; do + old_initramfs_modules[n]="$i" + n=$((n+1)) + done + popd >/dev/null + + pushd "$tmpdir/new_initramfs" >/dev/null + zcat "$new_initramfs" | cpio -i 2>/dev/null + n=0; for i in `find . -iname \*.ko|sort`; do + new_initramfs_modules[n]="$i" + n=$((n+1)) + done + popd >/dev/null + + if [ "${#old_initramfs_modules[@]}" == "${#new_initramfs_modules[@]}" ]; + then + for ((n = 0; n < ${#old_initramfs_modules[@]}; n++)); do + old_md5=`md5sum $tmpdir/old_initramfs/${old_initramfs_modules[n]}|sed -nre 's:(^\ )* .*:\1:p'` + new_md5=`md5sum $tmpdir/new_initramfs/${new_initramfs_modules[n]}|sed -nre 's:(^\ )* .*:\1:p'` + if [ ! "$old_md5" == "$new_md5" ]; + then + return 1 + fi + done + else + return 1 + fi + + return 0 +} + +# check_initramfs: +# check and possibly also update the initramfs for changed kernels +check_initramfs() { + local kernel=$1 + + # If there is no initramfs already we will not make one here. + if [ -e "$initramfs_prefix/initramfs-$kernel.img" ]; + then + old_initramfs="$initramfs_prefix/initramfs-$kernel.img" + tmp_initramfs="$initramfs_prefix/initramfs-$kernel.tmp" + new_initramfs="$initramfs_prefix/initramfs-$kernel.img" + + $dracut -f "$tmp_initramfs" "$kernel" + + if ! $(compare_initramfs_modules "$old_initramfs" "$tmp_initramfs"); + then + doit mv "$tmp_initramfs" "$new_initramfs" + else + rm -f "$tmp_initramfs" + fi + fi +} + +# krel_of_module: +# Compute the kernel release of a module. +krel_of_module() { + declare module=$1 + /sbin/modinfo -F vermagic "$module" | awk '{print $1}' +} + +# module_is_compatible: +# Determine if a module is compatible with a particular kernel release. Also +# include any symbol deps that might be introduced by other external kmods. +module_is_compatible() { + declare module=$1 krel=$2 module_krel=$(krel_of_module "$module") + + if [ ! -e "$tmpdir/all-symvers-$krel-$module_krel" ]; then + # Symbols exported by the "new" kernel + if [ ! -e $tmpdir/symvers-$krel ]; then + if [ -e /boot/symvers-$krel.gz ]; then + zcat /boot/symvers-$krel.gz \ + | sed -r -ne 's:^(0x[0]*[0-9a-f]{8}\t[0-9a-zA-Z_]+)\t.*:\1:p' + fi > $tmpdir/symvers-$krel + fi + + # Symbols that other add-on modules of the "old" kernel export + # (and that this module may require) + if [ ! -e "$tmpdir/extra-symvers-$module_krel" ]; then + if [ -e /lib/modules/$module_krel/extra ] && \ + [ -n "`find /lib/modules/$module_krel/extra -type f`" ]; then + find /lib/modules/$module_krel/extra -name '*.ko' \ + | xargs nm \ + | sed -nre 's:^[0]*([0-9a-f]{8}) A __crc_(.*):0x\1 \2:p' + fi > $tmpdir/extra-symvers-$module_krel + fi + + sort -u $tmpdir/symvers-$krel $tmpdir/extra-symvers-$module_krel \ + > "$tmpdir/all-symvers-$krel-$module_krel" + fi + + # If the module does not have modversions enabled, $tmpdir/modvers + # will be empty. + /sbin/modprobe --dump-modversions "$module" \ + | sed -r -e 's:^(0x[0]*[0-9a-f]{8}\t.*):\1:' \ + | sort -u \ + > $tmpdir/modvers + + # Only include lines of the second file in the output that don't + # match lines in the first file. (The default separator is + # , so we are matching the whole line.) + join -j 1 -v 2 $tmpdir/all-symvers-$krel-$module_krel \ + $tmpdir/modvers > $tmpdir/join + + if [ ! -s $tmpdir/modvers ]; then + echo "Warning: Module ${module##*/} from kernel $module_krel has no" \ + "modversions, so it cannot be reused for kernel $krel" >&2 + elif [ -s $tmpdir/join ]; then + [ -n "$verbose" ] && + echo "Module ${module##*/} from kernel $module_krel is not compatible" \ "with kernel $krel in symbols:" $(sed -e 's:.* ::' $tmpdir/join) + else + [ -n "$verbose" ] && + echo "Module ${module##*/} from kernel $module_krel is compatible" \ + "with kernel $krel" + return 0 + fi + return 1 +} + +usage() { + echo "Usage: ${0##*/} [options] {--add-modules|--remove-modules}" + echo "${0##*/} [options] {--add-kernel|--remove-kernel} {kernel-release}" + cat <<'EOF' +--add-modules + Add a list of modules read from standard input. Create + symlinks in compatible kernel's weak-updates/ directory. + The list of modules is read from standard input. + +--remove-modules + Remove compatibility symlinks from weak-updates/ directories + for a list of modules. The list of modules is read from + standard input. Optionally specify --delete-modules to + prevent weak-modules from attempting to locate any + compatible modules to replace those being removed. + +--add-kernel + Add compatibility symlinks for all compatible modules to the + specified or running kernel. + +--remove-kernel + Remove all compatibility symlinks for the specified or current + kernel. + +--no-initramfs + Do not generate an initramfs. + +--verbose + Print the commands executed. + +--dry-run + Do not create/remove any files. +EOF + exit $1 +} + +# module_has_changed: +# Mark if an actual change occured that we need to deal with later by calling +# depmod or mkinitramfs against the affected kernel. +module_has_changed() { + + declare module=$1 krel=$2 + + module=${module%.ko} + module=${module##*/} + + eval "changed_modules_${krel//[^a-zA-Z0-9]/_}=$krel" + eval "changed_initramfs_${krel//[^a-zA-Z0-9]/_}=$krel" + +} + +# add_modules: +# Read in a list of modules from stdinput and process them for compatibility +# with installed kernels under /lib/modules. +add_modules() { + read_modules_list || exit 1 + if [ ${#modules[@]} -gt 0 ]; then + for krel in $(ls /lib/modules/); do + [ -e "/boot/symvers-$krel.gz" ] || continue + for ((n = 0; n < ${#modules[@]}; n++)); do + module="${modules[n]}" + module_krel="${module_krels[n]}" + case "$module" in + /lib/modules/$krel/*) + # Module was built against this kernel, update initramfs. + module_has_changed $module $krel + continue ;; + esac + + # Module my also serve as a weak-update built against another + # kernel. We need to create symlinks for compatible kernels + # under /lib/modules and rerun depmod/dracut for those. + + subpath=`echo $module | sed -nre "s:/lib/modules/$module_krel/([^/]*)/(.*):\2:p"` + weak_module="/lib/modules/$krel/weak-updates/${subpath#/}" + if [ -r "$weak_module" ]; then + weak_krel=$(krel_of_module "$weak_module") + if [ "$weak_krel" != "$module_krel" ] && + [ "$(printf "%s\n" "$weak_krel" "$module_krel" \ + | rpmsort | (read input; echo "$input"; \ + while read input; do true; done))" = \ + "$module_krel" ]; then + # Keep modules from more recent kernels. + [ -n "$verbose" ] && echo \ +"Keeping module ${module##*/} from kernel $weak_krel for kernel $krel" + continue + fi + fi + if module_is_compatible $module $krel; then + doit mkdir -p $(dirname $weak_module) + doit ln -sf $module $weak_module + # Module was built against another kernel, update initramfs. + module_has_changed $module $krel + fi + done + done + fi +} + +# remove_modules: +# Read in a list of modules from stdinput and process them for removal. +# Parameter is noreplace to delete modules, otherwise link compat. +remove_modules() { + delete_modules=${1:-replace} + + read_modules_list || exit 1 + if [ ${#modules[@]} -gt 0 ]; then + + # Hunt for all known users of this module in /lib/modules, remove them + # and create symlinks to other compatible modules (downgrade) if + # possible, update initramfs for each modified kernel too. + + krels=($(ls /lib/modules/ | rpmsort -r)) + for krel in "${krels[@]}"; do + [ -e "/boot/symvers-$krel.gz" ] || continue + for ((n = 0; n < ${#modules[@]}; n++)); do + module="${modules[n]}" + module_krel="${module_krels[n]}" + + # Module is going to be removed, update initramfs. + module_has_changed $module $krel + + subpath="${module#/lib/modules/$module_krel/extra}" + weak_module="/lib/modules/$krel/weak-updates/${subpath#/}" + if [ "$module" == "`readlink $weak_module`" ]; then + [ -n "$verbose" ] && echo \ +"Removing compatible module ${module##*/} from kernel $krel" + doit rm -f "$weak_module" + if [ "replace" == "$delete_modules" ]; then + for krel2 in "${krels[@]}"; do + if [ $krel2 != $krel ]; then + module="/lib/modules/$krel2/extra/${subpath#/}" + [ -e "$module" ] || continue + if module_is_compatible "$module" "$krel"; then + [ -n "$verbose" ] && echo \ +"Adding compatible module ${module##*/} from kernel $krel2 instead" + doit ln -s "$module" "$weak_module" + module_has_changed $module $krel + break + fi + fi + done + fi + doit rmdir --parents --ignore-fail-on-non-empty \ + "$(dirname "$weak_module")" + fi + done + done + fi +} + +add_kernel() { + add_krel=${1:-$(uname -r)} + if [ ! -e "/boot/symvers-$add_krel.gz" ]; then + echo "Symvers dump file /boot/symvers-$add_krel.gz" \ + "not found" >&2 + exit 1 + fi + for krel in $(ls /lib/modules/ | rpmsort -r); do + [ "$add_krel" = "$krel" ] && continue + [ -d /lib/modules/$krel/extra ] || continue + for module in $(find /lib/modules/$krel/extra -name '*.ko'); do + subpath="${module#/lib/modules/$krel/extra}" + weak_module="/lib/modules/$add_krel/weak-updates/${subpath#/}" + [ -e "$weak_module" ] && continue + if module_is_compatible $module $add_krel; then + module_has_changed $module $add_krel + doit mkdir -p $(dirname $weak_module) + doit ln -sf $module $weak_module + fi + done + done +} + +remove_kernel() { + remove_krel=${1:-$(uname -r)} + weak_modules="/lib/modules/$remove_krel/weak-updates" + module_has_changed $weak_modules $remove_krel + doit rm -rf "$weak_modules" +} + +################################################################################ +################################## MAIN GUTS ################################### +################################################################################ + +options=`getopt -o h --long help,add-modules,remove-modules \ + --long add-kernel,remove-kernel \ + --long dry-run,no-initramfs,verbose,delete-modules -- "$@"` + +[ $? -eq 0 ] || usage 1 + +eval set -- "$options" + +while :; do + case "$1" in + --add-modules) + do_add_modules=1 + ;; + --remove-modules) + do_remove_modules=1 + ;; + --add-kernel) + do_add_kernel=1 + ;; + --remove-kernel) + do_remove_kernel=1 + ;; + --dry-run) + dry_run=1 + ;; + --no-initramfs) + no_initramfs=1 + ;; + --verbose) + verbose=1 + ;; + --delete-modules) + do_delete_modules=1 + ;; + -h|--help) + usage 0 + ;; + --) + shift + break + ;; + esac + shift +done + +if [ -n "$do_add_modules" ]; then + add_modules + +elif [ -n "$do_remove_modules" ]; then + if [ -n "$do_delete_modules" ]; then + remove_modules "noreplace" + else + remove_modules + fi + +elif [ -n "$do_add_kernel" ]; then + kernel=${1:-$(uname -r)} + add_kernel $kernel + +elif [ -n "$do_remove_kernel" ]; then + kernel=${1:-$(uname -r)} + remove_kernel $kernel + + exit 0 +else + usage 1 +fi + +################################################################################ +###################### CLEANUP POST ADD/REMOVE MODULE/KERNEL ################### +################################################################################ + +# run depmod and dracut as needed +for krel in ${!changed_modules_*}; do + krel=${!krel} + + doit /sbin/depmod -ae -F /boot/System.map-$krel $krel +done + +for krel in ${!changed_initramfs_*}; do + krel=${!krel} + + if [ ! -n "$no_initramfs" ]; then + check_initramfs $krel + fi +done