forked from pool/suse-module-tools
d3ade7a35c
should have been part of 141930 OBS-URL: https://build.opensuse.org/request/show/142369 OBS-URL: https://build.opensuse.org/package/show/Base:System/suse-module-tools?expand=0&rev=1
315 lines
6.9 KiB
Bash
315 lines
6.9 KiB
Bash
#!/bin/bash
|
|
|
|
VERSION="0.5"
|
|
MAINTAINER="Michal Marek <mmarek@suse.cz>"
|
|
USAGE="Usage: ${0##*/} [-o|--out output-file]"
|
|
|
|
errors=0
|
|
warnings=0
|
|
|
|
trap 'rm -rf "$tmp"' EXIT
|
|
tmp=$(mktemp -d)
|
|
|
|
rpm()
|
|
{
|
|
# rpm tends to send localized error messages to stdout :-(
|
|
LC_ALL=C command rpm "$@"
|
|
}
|
|
|
|
file_owner()
|
|
{
|
|
local f=$1
|
|
|
|
if (cd "$tmp/rpms"; grep -lFx "$f" *); then
|
|
return
|
|
fi
|
|
rpm -qf "$f"
|
|
}
|
|
|
|
_explain_called=()
|
|
explain()
|
|
{
|
|
local caller=${BASH_LINENO[0]}
|
|
|
|
if test -n "${_explain_called[$caller]}"; then
|
|
return
|
|
fi
|
|
_explain_called[$caller]=1
|
|
echo "$*"
|
|
}
|
|
|
|
error()
|
|
{
|
|
echo "ERROR: $*"
|
|
let errors++
|
|
}
|
|
|
|
warning()
|
|
{
|
|
echo "warning: $*" >&2
|
|
let warnings++
|
|
}
|
|
|
|
check_system()
|
|
{
|
|
if test ! -x /usr/lib/module-init-tools/weak-modules2; then
|
|
echo "This tool only works on SLE11 and later systems" >&2
|
|
exit 1
|
|
fi
|
|
if ! zypper search >/dev/null; then
|
|
echo "Cannot run zypper, please correct the above problem" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_rpm()
|
|
{
|
|
local rpm=$1 name=${1%-*-*}
|
|
|
|
# ignore changes to %config and %doc files and ignore changed mtimes
|
|
if rpm -V "$rpm" | grep -Ev '^[^ ]{8,} [cd] |^\.{7}T\.* '; then
|
|
error "$rpm was not installed correctly (see above)"
|
|
fi
|
|
# this is ugly. Apparently zypper insist on the progress messages and
|
|
# the ascii table, so grep for the table row.
|
|
if ! LC_ALL=C zypper -A search -t package -u -s --match-exact "$name" \
|
|
| grep -qe ---; then
|
|
error "$rpm: no update repositories found"
|
|
fi
|
|
}
|
|
|
|
check_kernel_package()
|
|
{
|
|
local kernel=$1
|
|
|
|
if ! rpm -q --qf '%{description}\n' "$kernel" | grep -q '^GIT '; then
|
|
error "$kernel does not look like a SUSE kernel package (no commit id)"
|
|
fi
|
|
if ! rpm -q --qf '%{postin}\n' "$kernel" | grep -q 'weak-modules2'; then
|
|
error "$kernel does not look like a SUSE kernel package (wrong %post script)"
|
|
fi
|
|
}
|
|
|
|
check_krel()
|
|
{
|
|
local krel=$1 system_map module_symvers msg res args bad=false
|
|
local mit_version
|
|
|
|
system_map="/boot/System.map-$krel"
|
|
module_symvers="/boot/symvers-$krel.gz"
|
|
if ! test -e "$system_map"; then
|
|
error "$system_map not found"
|
|
bad=true
|
|
fi
|
|
if ! test -e "$module_symvers"; then
|
|
error "$module_symvers not found"
|
|
bad=true
|
|
fi
|
|
if $bad; then
|
|
explain "Each kernel must install /boot/System.map-\$version and /boot/symvers-\$version.gz to be able to check module dependencies."
|
|
return
|
|
fi
|
|
set -- $(/sbin/depmod --version | sed -rn 's/.* ([0-9]+)\.([0-9]+)(\..*)?/\1 \2/p')
|
|
if test -n "$1" -a -n "$2"; then
|
|
let "mit_version = $1 * 100 + $2"
|
|
else
|
|
warning "Cannot determine module-init-tools version, this is a bug in the script"
|
|
mit_version=0
|
|
fi
|
|
# depmod -E was introduced in 3.10
|
|
if test "$mit_version" -ge 310; then
|
|
gzip -cd <"$module_symvers" >"$tmp/symvers"
|
|
args=(-E "$tmp/symvers")
|
|
else
|
|
args=(-F "$system_map")
|
|
fi
|
|
msg=$(/sbin/depmod -n -e "${args[@]}" "$krel" 2>&1 >/dev/null)
|
|
res=$?
|
|
if test -n "$msg" -o "$res" -ne 0; then
|
|
echo "$msg"
|
|
error "depmod $krel returned errors (exit code $res)"
|
|
explain "depmod must pass without errors otherwise KMP scripts will break"
|
|
fi
|
|
|
|
}
|
|
|
|
req_re='^(kernel\([^:]*:kernel[[:alnum:]_]*\)|ksym\([^:]*:(struct_module|module_layout)\)) = [0-9a-f]+'
|
|
check_kmp()
|
|
{
|
|
local kmp=$1 prefix prev_krel krel path found_module=false
|
|
|
|
if ! rpm -q --qf '%{postin}\n' "$kmp" | grep -q 'weak-modules2'; then
|
|
error "$kmp does not look like a SUSE kernel module package (wrong %post)"
|
|
fi
|
|
if ! rpm -q -R "$kmp" | grep -Eq "$req_re"; then
|
|
error "$kmp does not have proper dependencies"
|
|
fi
|
|
exec 3< <(sed -rn 's:^(/lib/modules)?/([^/]*)/(.*\.ko)$:\1 \2 \3:p' \
|
|
"$tmp/rpms/$kmp")
|
|
while read prefix krel path <&3; do
|
|
found_module=true
|
|
if test "$prefix" != "/lib/modules"; then
|
|
error "$kmp installs modules outside of /lib/modules"
|
|
continue
|
|
fi
|
|
if test -z "$prev_krel"; then
|
|
prev_krel=$krel
|
|
elif test "$prev_krel" != "$krel"; then
|
|
error "$kmp installs modules for multiple kernel versions"
|
|
fi
|
|
case "$path" in
|
|
updates/* | extra/*)
|
|
;;
|
|
weak-updates/*)
|
|
error "$kmp installs modules in weak-updates/ instead of updates/ or extra/"
|
|
explain "The weak-modules directory is reserved for automatically generated symlinks"
|
|
;;
|
|
*)
|
|
error "$kmp installs modules in an invalid directory"
|
|
explain \
|
|
"KMPs must install modules in the updates/ or extra/ subdirectories for the
|
|
weak-modules2 script to work"
|
|
;;
|
|
esac
|
|
|
|
done
|
|
if ! $found_module; then
|
|
error "$kmp does not contain any modules"
|
|
explain \
|
|
"A KMP must contain it's modules in the rpm filelist, otherwise weak-modules2
|
|
will not work"
|
|
fi
|
|
}
|
|
|
|
check_ko()
|
|
{
|
|
local ko=$1 kmp bad=false
|
|
|
|
case "$ko" in
|
|
*/weak-updates/*)
|
|
if test -L "$ko"; then
|
|
return
|
|
fi
|
|
esac
|
|
kmp=$(file_owner "$ko")
|
|
case "$kmp" in
|
|
kernel-* | *-kmp-*) ;;
|
|
*not\ owned\ by\ any\ package)
|
|
error "$ko is not owned by any package"
|
|
bad=true
|
|
;;
|
|
*)
|
|
error "$ko is not packaged as a KMP"
|
|
bad=true
|
|
;;
|
|
esac
|
|
if $bad; then
|
|
explain \
|
|
"External kernel modules must be packaged as KMPs, see
|
|
http://developer.novell.com/wiki/index.php/Kernel_Module_Packages_Manuals"
|
|
fi
|
|
}
|
|
|
|
options=$(getopt -n "${0##*/}" -o o:h --long out:,help -- "$@")
|
|
if test "$?" -ne 0; then
|
|
echo "$USAGE" >&2
|
|
exit 1
|
|
fi
|
|
eval set -- "$options"
|
|
logfile="driver-check-report.txt"
|
|
while :; do
|
|
case "$1" in
|
|
-o | --out)
|
|
logfile="$2"
|
|
shift 2
|
|
;;
|
|
-h | --help)
|
|
echo "${0##*/} $VERSION"
|
|
echo "$USAGE"
|
|
echo
|
|
echo "Please report bugs and enhancement requests to $MAINTAINER"
|
|
exit 0
|
|
;;
|
|
--)
|
|
shift
|
|
break
|
|
;;
|
|
esac
|
|
done
|
|
if test $# -gt 0; then
|
|
echo "Unrecognized arguments: $*" >&2
|
|
echo "$USAGE" >&2
|
|
exit 1
|
|
fi
|
|
|
|
check_system
|
|
|
|
# set up redirection
|
|
if test $logfile != "-"; then
|
|
if test -e "$logfile"; then
|
|
mv -f "$logfile" "$logfile~"
|
|
fi
|
|
if test -e /proc/self; then
|
|
exec 99> >(cat >"$logfile")
|
|
exec 1>&99
|
|
exec 2> >(tee -a /proc/self/fd/99 >&2)
|
|
else
|
|
exec 1>"$logfile"
|
|
exec 2>"$logfile"
|
|
warning "/proc not mounted"
|
|
fi
|
|
fi
|
|
echo "${0##*/} $VERSION started at $(date -R)" >&2
|
|
|
|
check_rpm $(rpm -q --qf '%{n}-%{v}-%{r}\n' module-init-tools)
|
|
|
|
mkdir -p "$tmp/rpms"
|
|
found_kernel=false
|
|
for rpm in $(rpm -qa --qf '%{n}-%{v}-%{r}\n' 'kernel-*' '*-kmp-*' | \
|
|
/usr/lib/rpm/rpmsort); do
|
|
case "$rpm" in
|
|
kernel-source-* | kernel-syms-* | kernel-*-debug* | kernel-*-man-* | \
|
|
kernel-*-devel-* | kernel-firmware-* | kernel-coverage-* | \
|
|
kernel-docs-* | kernel-devel-*)
|
|
continue
|
|
esac
|
|
# store the filelist to speed up file_owner()
|
|
rpm -ql "$rpm" >"$tmp/rpms/$rpm"
|
|
check_rpm "$rpm"
|
|
case "$rpm" in
|
|
kernel-*)
|
|
check_kernel_package "$rpm"
|
|
found_kernel=true
|
|
;;
|
|
*-kmp-*)
|
|
check_kmp "$rpm"
|
|
;;
|
|
esac
|
|
done
|
|
if ! $found_kernel; then
|
|
warning "no kernel package found"
|
|
fi
|
|
|
|
for krel in /lib/modules/*/kernel; do
|
|
krel=${krel%/kernel}
|
|
krel=${krel##*/}
|
|
check_krel "$krel"
|
|
done
|
|
|
|
modules=($(find /lib/modules/ -name '*.ko'))
|
|
for module in "${modules[@]}"; do
|
|
check_ko "$module"
|
|
done
|
|
|
|
echo "Found $errors error(s) and $warnings warning(s)" >&2
|
|
if test "$logfile" != -; then
|
|
echo "Report written to $logfile at $(date -R)" >&2
|
|
else
|
|
echo "Report finished at $(date -R)" >&2
|
|
fi
|
|
if test $errors -eq 0; then
|
|
exit 0
|
|
else
|
|
exit 1
|
|
fi
|