UBUNTU: [Packaging] Move checker scripts to debian/scripts/checks

Tidy up the scripts directory and move all checker scripts to a new
subdirectory.

Signed-off-by: Juerg Haefliger <juerg.haefliger@canonical.com>
Signed-off-by: Andrea Righi <andrea.righi@canonical.com>
This commit is contained in:
Juerg Haefliger
2022-12-08 08:17:28 +01:00
committed by Paolo Pisati
parent f5b739c7d5
commit 78021e8a72
6 changed files with 6 additions and 7 deletions
+139
View File
@@ -0,0 +1,139 @@
#!/usr/bin/python3
#
# Check ABI changes
#
# To skip the ABI checks, add a file
# debian.<foo>/abi/<arch>/ignore.abi
# or
# debian.<foo>/abi/<arch>/<flavor>.ignore.abi
#
# To ignore a list of symbols, add the symbols to the file
# debian.<foo>/abi/abi.ignore
#
import os
import re
import sys
def decode_symline(line):
comps = re.sub(r'\s+', ' ', line).split(' ')
if comps[0].startswith('EXPORT_SYMBOL'):
stype, sloc, shash, sname = comps
else:
stype, shash, sname, sloc = comps[1:]
return sname, {'type': stype, 'loc': sloc, 'hash': shash}
if len(sys.argv) < 4 or len(sys.argv) > 5:
print('Usage: abi-check <flavor> <prev_abidir> <abidir> [<skipabi>]')
sys.exit(2)
flavor, prev_abidir, abidir = sys.argv[1:4] # pylint: disable=W0632
if len(sys.argv) > 4:
skipabi = sys.argv[4].lower() in ['1', 'true', 'yes']
else:
skipabi = False
print('II: Checking ABI for {}...'.format(flavor), end='')
if ((os.path.exists('{}/ignore.abi'.format(prev_abidir)) or
os.path.exists('{}/{}.ignore.abi'.format(prev_abidir, flavor)))):
print('WW: Explicitly ignoring ABI')
print('II: Done')
sys.exit(0)
curr_abi = '{}/{}'.format(abidir, flavor)
prev_abi = '{}/{}'.format(prev_abidir, flavor)
if not os.path.exists(curr_abi) or not os.path.exists(prev_abi):
print('II: Previous or current ABI file missing!')
print(' {}'.format(curr_abi))
print(' {}'.format(prev_abi))
if skipabi:
print('WW: Explicitly asked to ignore failures')
print('II: Done')
sys.exit(0)
print('EE: Missing ABI file')
sys.exit(1)
print()
symbols = {}
symbols_ignore = {}
# See if we have any ignores
print(' Reading symbols to ignore...', end='')
ignore = 0
prev_abi_ignore = '{}/../abi.ignore'.format(prev_abidir)
if os.path.exists(prev_abi_ignore):
with open(prev_abi_ignore) as fh:
for sym in fh:
sym = sym.strip()
if sym.startswith('#'):
continue
symbols_ignore[sym] = 1
ignore += 1
print('read {} symbols.'.format(ignore))
# Read new symbols first
print(' Reading new symbols...', end='')
new_count = 0
with open('{}/{}'.format(abidir, flavor)) as fh:
for line in fh:
sym, vals = decode_symline(line.strip())
symbols[sym] = vals
new_count += 1
print('read {} symbols.'.format(new_count))
# Now the old symbols
print(' Reading old symbols...', end='')
old_count = 0
with open('{}/{}'.format(prev_abidir, flavor)) as fh:
for line in fh:
sym, vals = decode_symline(line.strip())
if sym not in symbols:
symbols[sym] = {}
symbols[sym]['old'] = vals
old_count += 1
print('read {} symbols.'.format(old_count))
print('II: Checking for ABI changes...')
changed_loc = 0
changed_type = 0
error = False
for sym, vals in symbols.items():
# Ignore new symbols
if 'old' not in vals:
continue
# Changes in location don't hurt us, but log it anyway
if vals['loc'] != vals['old']['loc']:
changed_loc += 1
print(' MOVE : {:40} : {} => {}'.format(sym, vals['old']['loc'],
vals['loc']))
# Changes from GPL to non-GPL are bad
if ((vals['old']['type'] == 'EXPORT_SYMBOL_GPL' and
vals['type'] != 'EXPORT_SYMBOL_GPL')):
changed_type += 1
if sym in symbols_ignore or vals['loc'] in symbols_ignore:
ignored = ' (ignore)'
else:
ignored = ''
error = True
print(' TYPE : {:40} : {} => {}{}'.format(sym, vals['old']['type'],
vals['type'], ignored))
if changed_loc > 0:
print('II: {} symbols changed location'.format(changed_loc))
if changed_type > 0:
print('II: {} symbols changed export type'.format(changed_type))
if error:
if skipabi:
print('WW: Explicitly asked to ignore failures')
else:
print('EE: Symbol types changed')
sys.exit(1)
print('II: Done')
sys.exit(0)
+163
View File
@@ -0,0 +1,163 @@
#!/usr/bin/perl
#
# check-config -- check the current config for issues
#
use strict;
use File::Basename;
use File::Spec;
my $P = 'check-config';
my $test = -1;
if ($ARGV[0] eq '--test') {
$test = $ARGV[1] + 0;
} elsif ($#ARGV != 5) {
die "Usage: $P <config> <arch> <flavour> <commonconfig> <warn-only> <enforce-all>\n";
}
my ($configfile, $arch, $flavour, $commonconfig, $warn_only, $enforce_all) = @ARGV;
my %values = ();
# If we are in overridden then still perform the checks and emit the messages
# but do not return failure. Those items marked FATAL will alway trigger
# failure.
my $fail_exit = 1;
$fail_exit = 0 if ($warn_only eq 'true' || $warn_only eq '1');
my $exit_val = 0;
$enforce_all = 0 if $enforce_all eq "no" or $enforce_all eq "false";
# Load up the current configuration values -- FATAL if this fails
print "$P: $configfile: loading config\n";
open(CONFIG, "<$configfile") || die "$P: $configfile: open failed -- $! -- aborting\n";
while (<CONFIG>) {
# Pull out values.
/^#*\s*(CONFIG_\w+)[\s=](.*)$/ or next;
if ($2 eq 'is not set') {
$values{$1} = 'n';
} else {
$values{$1} = $2;
}
}
close(CONFIG);
sub read_annotations {
my ($filename) = @_;
my %annot;
my $form = 1;
my ($config, $value, $options);
# Keep track of the configs that shouldn't be appended because
# they were include_annot from another annotations file.
# That's a hash of undefs, aka a set.
my %noappend;
print "$P: $filename loading annotations\n";
open(my $fd, "<$filename") ||
die "$P: $filename: open failed -- $! -- aborting\n";
while (<$fd>) {
if (/^# FORMAT: (\S+)/) {
die "$P: $1: unknown annotations format\n" if ($1 != 2 && $1 != 3 && $1 != 4);
$form = $1;
}
# Format #3 adds the include directive on top of format #2:
if ($form == 3 && /^\s*include(\s|$)/) {
# Include quoted or unquoted files:
if (/^\s*include\s+"(.*)"\s*$/ || /^\s*include\s+(.*)$/) {
# The include is relative to the current file
my $include_filename = File::Spec->join(dirname($filename), $1);
# Append the include files
my %include_annot = read_annotations($include_filename);
%annot = ( %annot, %include_annot );
# And marked them to not be appended:
my %included_noappend;
# Discard the values and keep only the keys
@included_noappend{keys %include_annot} = ();
%noappend = ( %noappend, %included_noappend );
next;
} else {
die "$P: Invalid include: $_";
}
}
/^#/ && next;
chomp;
/^$/ && next;
/^CONFIG_/ || next;
if ($form == 1) {
($config, $value, $options) = split(' ', $_, 3);
} elsif ($form >= 2) {
($config, $options) = split(' ', $_, 2);
}
if (exists $noappend{$config}) {
delete $annot{$config};
delete $noappend{$config};
}
$annot{$config} = $annot{$config} . ' ' . $options;
}
close($fd);
return %annot;
}
# ANNOTATIONS: check any annotations marked for enforcement
my $annotations = "$commonconfig/annotations";
my %annot = read_annotations($annotations);
my $pass = 0;
my $total = 0;
my ($config, $value, $options, $option, $check, $policy);
for $config (keys %annot) {
$check = $enforce_all;
$options = $annot{$config};
$policy = undef;
while ($options =~ /\s*([^\s<]+)<(.*?)?>/g) {
($option, $value) = ($1, $2);
if ($option eq 'mark' && $value eq 'ENFORCED') {
$check = 1;
} elsif ($option eq 'policy') {
if ($value =~ /^{/) {
$value =~ s/:/=>/g;
$policy = eval($value);
warn "$config: $@" if ($@);
} else {
$policy = undef;
}
}
}
if ($check == 1 && !defined($policy)) {
print "$P: INVALID POLICY (use policy<{...}>) $config$options\n";
$total++;
$check = 0;
}
if ($check) {
# CONFIG_VERSION_SIGNATURE is dynamically set during the build
next if ($config eq "CONFIG_VERSION_SIGNATURE");
my $is = '-';
$is = $values{$config} if (defined $values{$config});
my $value = '-';
for my $which ("$arch-$flavour", "$arch-*", "*-$flavour", "$arch", "*") {
if (defined $policy->{$which}) {
$value = $policy->{$which};
last;
}
}
if ($is eq $value) {
$pass++;
} else {
print "$P: FAIL ($is != $value): $config$options\n";
$exit_val = $fail_exit;
}
$total++;
}
}
print "$P: $pass/$total checks passed -- exit $exit_val\n";
exit $exit_val;
+131
View File
@@ -0,0 +1,131 @@
#!/usr/bin/python3
#
# Check modules changes
#
# To skip the modules check, add a file
# debian.<foo>/abi/<arch>/ignore.modules
# or
# debian.<foo>/abi/<arch>/<flavor>.ignore.modules
#
# To ignore a list of modules, add the modules to the file
# debian.<foo>/abi/modules.ignore
#
import os
import sys
if len(sys.argv) < 4 or len(sys.argv) > 5:
print('Usage: module-check <flavor> <prev_abidir> <abidir> [<skipmodule>]')
sys.exit(2)
flavor, prev_abidir, abidir = sys.argv[1:4] # pylint: disable=W0632
if len(sys.argv) > 4:
skipmodule = sys.argv[4].lower() in ['1', 'true', 'yes']
else:
skipmodule = False
print('II: Checking modules for {}...'.format(flavor), end='')
if ((os.path.exists('{}/ignore.modules'.format(prev_abidir)) or
os.path.exists('{}/{}.ignore.modules'.format(prev_abidir, flavor)))):
print('WW: Explicitly ignoring modules')
print('II: Done')
sys.exit(0)
curr_modules = '{}/{}.modules'.format(abidir, flavor)
prev_modules = '{}/{}.modules'.format(prev_abidir, flavor)
if not os.path.exists(curr_modules) or not os.path.exists(prev_modules):
print('II: Previous or current modules file missing!')
print(' {}'.format(curr_modules))
print(' {}'.format(prev_modules))
if skipmodule:
print('WW: Explicitly asked to ignore failures')
print('II: Done')
sys.exit(0)
print('EE: Missing modules file')
sys.exit(1)
print()
modules = {}
modules_ignore = {}
# See if we have any ignores
print(' Reading modules to ignore...', end='')
ignore = 0
prev_modules_ignore = '{}/../modules.ignore'.format(prev_abidir)
if os.path.exists(prev_modules_ignore):
with open(prev_modules_ignore) as fh:
for mod in fh:
mod = mod.strip()
if mod.startswith('#'):
continue
modules_ignore[mod] = 1
ignore += 1
print('read {} modules.'.format(ignore))
# Read new modules first
print(' Reading new modules...', end='')
new_count = 0
for f in (curr_modules, curr_modules + '.builtin'):
if not os.path.exists(f):
continue
with open(f) as fh:
for mod in fh:
mod = mod.strip()
modules[mod] = {'new': 1}
new_count += 1
print('read {} modules.'.format(new_count))
# Now the old modules
print(' Reading old modules...', end='')
old_count = 0
for f in (prev_modules, prev_modules + '.builtin'):
if not os.path.exists(f):
continue
with open(f) as fh:
for mod in fh:
mod = mod.strip()
if mod not in modules:
modules[mod] = {}
modules[mod]['old'] = 1
old_count += 1
print('read {} modules.'.format(old_count))
print('II: Checking for modules changes...')
new = 0
missing = 0
missing_ignored = 0
error = False
for mod, vals in modules.items():
# New modules
if 'old' not in vals:
print(' NEW: {}'.format(mod))
new += 1
# Missing modules
if 'new' not in vals:
missing += 0
if mod in modules_ignore:
ignored = ' (ignored)'
missing_ignored += 1
else:
ignored = ''
error = True
print(' MISS : {}{}'.format(mod, ignored))
if new > 0:
print('II: {} new modules'.format(new))
if missing > 0:
print('II: {} missing modules ({} ignored)'.format(missing, missing_ignored))
if error:
if skipmodule:
print('WW: Explicitly asked to ignore failures')
else:
print('EE: Missing modules')
sys.exit(1)
print('II: Done')
sys.exit(0)
+76
View File
@@ -0,0 +1,76 @@
#!/bin/bash -eu
flavor="${1}"
mods_dir="${2}"
mods_extra_dir="${3}"
echo "II: Checking signature of staging modules for ${flavor}..."
root=$(dirname "$(realpath -e "${0}")")/../../..
. "${root}"/debian/debian.env
# Collect the signature-inclusion files
sig_incs=()
for d in debian "${DEBIAN}" ; do
if [ -f "${root}"/"${d}"/signature-inclusion ] ; then
sig_incs+=("${root}"/"${d}"/signature-inclusion)
fi
done
if [ "${#sig_incs[@]}" -gt 0 ] ; then
echo "II: Use signature inclusion file(s):"
printf " %s\n" "${sig_incs[@]}"
sig_all=0
else
echo "WW: Signature inclusion file(s) missing"
echo "II: All modules must be signed"
sig_all=1
fi
if ! [ -d "${mods_dir}" ] ; then
echo "EE: Modules directory missing:"
echo " ${mods_dir}"
exit 1
fi
echo "II: Checking modules directory:"
echo " ${mods_dir}"
mods_dirs=("${mods_dir}")
if [ -d "${mods_extra_dir}" ] ; then
echo " ${mods_extra_dir}"
mods_dirs+=("${mods_extra_dir}")
fi
pass=0
fail=0
while IFS= read -r mod ; do
is=0
if /sbin/modinfo "${mod}" | grep -q "^signature:" ; then
# Module is signed
is=1
fi
must=0
if [ ${sig_all} -eq 1 ] || grep -qFx "${mod##*/}" "${sig_incs[@]}" ; then
# Module must be signed
must=1
fi
case "${is}${must}" in
00) echo " PASS (unsigned) : ${mod##*/}" ; pass=$((pass + 1)) ;;
01) echo " FAIL (unsigned) : ${mod##*/}" ; fail=$((fail + 1)) ;;
10) echo " FAIL (signed) : ${mod##*/}" ; fail=$((fail + 1)) ;;
11) echo " PASS (signed) : ${mod##*/}" ; pass=$((pass + 1)) ;;
esac
done < <(find "${mods_dirs[@]}" -path '*/drivers/staging/*.ko' | sort)
echo "II: Checked $((pass + fail)) modules : ${pass} PASS, ${fail} FAIL"
if [ ${fail} -eq 0 ] ; then
echo "II: Done"
exit 0
else
echo "EE: Modules signature failures"
exit 1
fi
+47
View File
@@ -0,0 +1,47 @@
#!/bin/bash
flavour="$1"
prev_abidir="$2"
curr_abidir="$3"
skipretpoline="$4"
echo "II: Checking retpoline indirections for $flavour...";
if [ "$skipretpoline" = 'true' ]; then
echo "manual request ignoring retpoline delta"
fi
if [ -f "$prev_abidir/ignore.retpoline" -o \
-f "$prev_abidir/$flavour.ignore.retpoline" ]; then
echo "explicitly ignoring retpoline delta"
skipretpoline='true'
fi
prev="$prev_abidir/$flavour.retpoline"
curr="$curr_abidir/$flavour.retpoline"
if [ ! -f "$prev" ]; then
echo "previous retpoline file missing!"
echo " $prev"
prev="/dev/null"
fi
if [ ! -f "$curr" ]; then
echo "current retpoline file missing!"
echo " $curr"
curr="/dev/null"
fi
echo "II: retpoline delta in this package..."
rc=0
diff -u "$prev" "$curr" || true
count=$( diff -u "$prev" "$curr" | grep '^+[^+]' | wc -l )
if [ "$count" != 0 ]; then
rc=1
echo "WW: $count new retpoline sequences detected"
fi
echo "II: Done";
if [ "$skipretpoline" = 'true' -a "$rc" -ne 0 ]; then
echo "II: ignoring errors"
exit 0
fi
exit "$rc"