File kabi-checks of Package kernel-source

#!/bin/bash
# Tool to do kABI checks.
# (c) Kurt Garloff <garloff@suse.de>, GNU GPL, 11/2005
# $Id$
#
# This tool looks at the generated symvers and compares it to the
# reference file (if existent). It prints warnings for changed symbol
# versions.
#
# Return value:
# 0 -- no changes
# 1 -- usage/input error
# 2 -- internal error
# 4 -- only additions
# >= 8 -- removed or changed symbols (see below)
#
# Severity classification:
# - 8 -- 15: if it's not found in a list (commonsyms or usedsyms)
#	The score depends on the source; symbols in vmlinux are more
#	likely to be used by anyone.
# - 16 -- 23: symbol is found in the list usedsyms
# - 24 -- 31: symbol is found in the list commonsyms

severities="
#			unimportant  ---.	 .---  important
#					v	 v

drivers/base/*					13
drivers/char/ipmi/*				10
drivers/char/tpm/tpm				 9
drivers/hwmon/*					10
drivers/i2c/i2c-core				 9
drivers/md/*					13
drivers/message/fusion/*		6
drivers/pci/*					12
drivers/pci/hotplug/pci_hotplug			10
drivers/scsi/libata				12
drivers/scsi/scsi*				12
drivers/scsi/*/scsi_transport_*			12
drivers/scsi/libiscsi*				12
drivers/ide/ide-core				11
drivers/usb/core/usbcore			10
drivers/usb/serial/usbserial			 9
fs/dmapi/dmapi					11
fs/fat/fat					11
fs/jbd/jbd					11
net/ipv4/netfilter/ip_tables			 9
vmlinux						15
"

# Turning off UTF-8 processing provides a major speedup.
export LC_ALL=C

echo "${0##*/} $@"

unset quiet verbose
if [ "$1" = "-q" ]; then
    shift
    quiet=1
fi
if [ "$1" = "-v" ]; then
    shift
    verbose=1
fi

if [ $# -lt 2 -o $# -gt 4 ]; then
    echo "Usage: ${0##*/} [-q] [-v] reference symvers [commonsyms [usedsyms]]" >&2
    exit 1
fi
for file in "$@"; do
    [ -r "$file" ] && continue
    echo "Cannot read from '$file'" >&2
    exit 1
done

declare_symbol_severity() {
    declare severity=$1

    while [ $# -ge 2 ]; do
	if ! eval "severity_of_${2//[^a-zA-Z0-9_]/_}=$severity"; then
	    echo "Internal error" >&2
	    exit 2
	fi
	shift
    done
}

consistency_check() {
    declare_symbol_severity 16 consistency_check_foo
    check_modified_symbols >/dev/null <<-EOF
	consistency_check_foo -0x12345678 consistency/check/foo +0x98765432 consistency/check/foo
	EOF
    if [ $? -ne 31 ]; then
	echo "Internal error" >&2
	exit 2
    fi
}

#set -x
eval '
severity() {
    case $2 in
'"$(

	( echo "$severities"
	  echo "consistency/check/* 15" # For the consistency test
	) \
	| sed -e '/^#/d' -e '/^$/d' \
	| while read glob severity; do
	    echo "	($glob) _rc=$severity ;;"
	done

)"'
	(*) _rc=8 ;;
    esac

    # Is a particular severity defined for this symbol?
    declare severity=severity_of_$1
    if [ -n "${!severity}" ]; then
	((_rc += ${!severity}))
    fi

    return $_rc
}'
#set +x

grab_symvers_from_rpm() {(
    # (Run in subshell to make trap work.)

    tmpdir=$(mktemp -t -d ${0##*/}.XXXXXX)
    trap "cd /; rm -rf $tmpdir" EXIT
    cd $tmpdir
    rpm2cpio "$file" \
    | cpio -dim --quiet './boot/symvers-*.gz'
    set -- boot/symvers-*.gz
    if ! [ -e "$1" ]; then
	echo "Failed to extract symvers-*.gz from $file" >&2
	exit 1
    fi
    zcat "$1"
)}

grab_symvers() {
    declare tag=$1 file=$2 pwd tmpdir

    case "$(file -b - <"$file")" in
    gzip*)
	zcat "$file"
	;;
    RPM*)
	grab_symvers_from_rpm "$file"
	;;
    *)
    	cat "$file"
	;;
    esac \
    | sed -e "/^#/d" -e "s/^/$tag/" \
    | sort -k 2
}

filter_out_identical_symbols() {
    # This expression works no matter how many columns the files have.
    grep -v -P '^\S+ -(\S+)( \S+)+ \+\1( \S+)+$'
}

check_modified_symbols() {
    declare -i RC=0 _rc
    declare ignored

    while read symbol tail; do
	# Split in half no matter how many columns the files have.
	set -- $tail ; half=$(($#/2+1))
	version1=$1 ; version2=${!half} ; shift
	source1=$1 ; source2=${!half} ; shift

	case "$version1$version2" in
	-\#*)
	    continue
	    ;;
	-*+* | -*)
	    ignored=
	    case "$version1" in
	    *=\>*)
	    	if [ "${version1#*=>}" = "${version2#+}" ]; then
		    version1="${version1%=>*}"
		    ignored="; ignored"
		fi
		;;
	    esac
	    severity $symbol $source1 && continue
	    _rc=$?
	    if [ -z "$quiet" ]; then
		echo -n "Warning: $source1: $symbol(${version1#-}) "
		if [ -n "$version2" ]; then
		    echo -n "changed to $symbol(${version2#+})"
		    [ "$source1" != "$source2" ] &&
			echo -n " and moved to $source2"
		else
		    echo -n "removed"
		fi
		echo " (badness ${_rc}$ignored)"
	    fi
	    [ -n "$ignored" ] && _rc=0
	    ;;
	*)
	    if [ -n "$verbose" ]; then
		echo "     new symbol $symbol: ${version1#+}"
	    fi
	    _rc=4
	    ;;
	esac
	if [ ${_rc} -gt $RC ]; then RC=${_rc}; fi
    done
    return $RC
}

sort_by_badness() {
    sed -e 's/.*(badness \([0-9]\+\)).*/\1 &/' -e 't' -e 's/^/0 /' \
    | sort -n -r \
    | sed -e 's/^[0-9]* //'
}

consistency_check

[ -n "$4" ] && declare_symbol_severity  8 $(< $4)
[ -n "$3" ] && declare_symbol_severity 16 $(< $3)

join -j 2 -a 1 -a 2 <(grab_symvers - $1) <(grab_symvers + $2) \
| filter_out_identical_symbols \
| check_modified_symbols \
| sort_by_badness

RC=${PIPESTATUS[2]}
echo "kABI verdict: $RC"
exit $RC
openSUSE Build Service is sponsored by