#! /bin/bash # This script is only needed to uninstall old KMPs when updating # SLE10 to SLE11+. weak-modules2 is the script what should be used by new # packages unset LANG LC_ALL LC_COLLATE NM= if command -v nm >/dev/null; then NM=nm elif command -v eu-nm >/dev/null; then NM=eu-nm else echo "ERROR: nm not found" >&2 exit 1 fi # Check if MODULE is compatible with kernel release KREL. 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:^0x0*([0-9a-f]+\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/updates ]; then find /lib/modules/$module_krel/updates -name '*.ko' \ | xargs $NM -B \ | sed -nre 's:^0*([0-9a-f]+) A __crc_(.*):\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:^0x0*([0-9a-f]+\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) elif [ "$krel" != "$module_krel" ]; then [ -n "$verbose" ] && echo "Module ${module##*/} from kernel $module_krel is compatible" \ "with kernel $krel" return 0 fi return 1 } # Compute the kernel release of a module. krel_of_module() { declare module=$1 set -- $(/sbin/modinfo -F vermagic "$module") echo "$1" } # Read a list of modules from standard input, convert the filenames into # absolute names, and compute the kernel release of each module. read_modules_list() { local saved_IFS=$IFS IFS=$'\n' modules=($(cat)) IFS=$saved_IFS 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 } doit() { [ -n "$verbose" ] && echo "$@" [ -n "$dry_run" ] || "$@" } usage() { cat <<'EOF' Usage: ${0##*/} [options] {--add-modules|--remove-modules} ${0##*/} [options] {--add-kernel|--remove-kernel} {kernel-release} --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. --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. --verbose Print the commands executed. -dry-run Do not create/remove any files. EOF exit $1 } [ -e /etc/sysconfig/kernel ] && source /etc/sysconfig/kernel unset ${!changed_modules_*} ${!changed_initrd_*} module_has_changed() { declare module=$1 krel=$2 module=${module%.ko} module=${module##*/} eval "changed_modules_${krel//[^a-zA-Z0-9]/_}=$krel" case " $INITRD_MODULES " in *" $module "*) eval "changed_initrd_${krel//[^a-zA-Z0-9]/_}=$krel" ;; esac } options=`getopt -o h --long help,add-modules,remove-modules \ --long add-kernel,remove-kernel,dry-run,verbose -- "$@"` [ $? -eq 0 ] || usage 1 eval set -- "$options" while :; do case "$1" in --add-modules) add_modules=1 ;; --remove-modules) remove_modules=1 ;; --add-kernel) add_kernel=1 ;; --remove-kernel) remove_kernel=1 ;; --dry-run) dry_run=1 ;; --verbose) verbose=1 ;; -h|--help) usage 0 ;; --) shift break ;; esac shift done if [ "$add_modules$remove_modules$add_kernel$remove_kernel" != 1 ]; then usage 1 fi if [ -n "$add_kernel" -o -n "$remove_kernel" ]; then [ $# -gt 1 ] && usage 1 else [ $# -ne 0 ] && usage 1 fi tmpdir=$(mktemp -td ${0##*/}.XXXXXX) trap "rm -rf $tmpdir" EXIT if [ -n "$add_modules" ]; then 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/*) continue ;; esac subpath=${module#/lib/modules/$module_krel/updates} 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" \ | /usr/lib/rpm/rpmsort | head -n 1)" = \ "$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_has_changed $module $krel fi done done fi elif [ -n "$remove_modules" ]; then read_modules_list || exit 1 if [ ${#modules[@]} -gt 0 ]; then krels=($(ls /lib/modules/ | /usr/lib/rpm/rpmsort -r)) for krel in "${krels[@]}"; do [ -e /boot/symvers-$krel.gz ] || continue for ((n = 0; n < ${#modules[@]}; n++)); do module=${modules[n]} [ -e "$module" ] && continue module_krel=${module_krels[n]} subpath=${module#/lib/modules/$module_krel/updates} weak_module=/lib/modules/$krel/weak-updates/${subpath#/} if [ "$(readlink "$weak_module")" = "$module" ]; then [ -n "$verbose" ] && echo \ "Removing compatible module ${subpath#/} from kernel $krel" doit rm -f "$weak_module" for krel2 in "${krels[@]}"; do [ -e /boot/symvers-$krel2.gz ] || continue module=/lib/modules/$krel2/updates/${subpath#/} [ -e "$module" ] || continue if module_is_compatible "$module" "$krel2"; then [ -n "$verbose" ] && echo \ "Adding compatible module ${module##*/} from kernel $krel2 instead" doit ln -s "$module" "$weak_module" break fi done doit rmdir --parents --ignore-fail-on-non-empty \ "$(dirname "$weak_module")" module_has_changed $module $krel fi done done fi elif [ -n "$add_kernel" ]; then 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/ | /usr/lib/rpm/rpmsort -r); do [ "$add_krel" = "$krel" ] && continue [ -d /lib/modules/$krel/updates ] || continue for module in $(find /lib/modules/$krel/updates -name '*.ko'); do subpath=${module#/lib/modules/$krel/updates} weak_module=/lib/modules/$add_krel/weak-updates/${subpath#/} [ -e "$weak_module" ] && continue if module_is_compatible $module $add_krel; then doit mkdir -p $(dirname $weak_module) doit ln -sf $module $weak_module fi done done elif [ -n "$remove_kernel" ]; then remove_krel=${1:-$(uname -r)} weak_modules=/lib/modules/$remove_krel/weak-updates doit rm -rf "$weak_modules" fi for krel in ${!changed_modules_*}; do krel=${!krel} [ -e /boot/System.map-$krel ] || continue /sbin/depmod -ae -F /boot/System.map-$krel $krel done for krel in ${!changed_initrd_*}; do krel=${!krel} [ -e /boot/System.map-$krel ] || continue image= for x in vmlinuz image vmlinux linux bzImage uImage; do if [ -f /boot/$x-$krel ]; then image=$x break fi done if [ -n "$image" ]; then /sbin/mkinitrd -k /boot/$image-$krel -i /boot/initrd-$krel fi done # vim:shiftwidth=4 softtabstop=4