-
Notifications
You must be signed in to change notification settings - Fork 52
/
checkapk.in
157 lines (126 loc) · 4.52 KB
/
checkapk.in
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#!/bin/sh
# checkapk - find ABI breakages in package upgrades
# Copyright (c) 2012 Natanael Copa <natanael.copa@gmail.com>
#
# Distributed under GPL-2.0-only
#
program_version=@VERSION@
sharedir=${ABUILD_SHAREDIR:-@sharedir@}
if ! [ -f "$sharedir/functions.sh" ]; then
echo "$sharedir/functions.sh: not found" >&2
exit 1
fi
. "$sharedir/functions.sh"
usage() {
cat <<-__EOF__
$program $program_version - find ABI breakages in package upgrades
Usage: $program [-h|--help]
Run in the directory of a built package.
Options:
-h, --help Print this help
__EOF__
}
args=$(getopt -o h --long help \
-n "$program" -- "$@")
if [ $? -ne 0 ]; then
usage >&2
exit 2
fi
eval set -- "$args"
while true; do
case $1 in
-h|--help) usage; exit 0;;
--) shift; break;;
*) exit 1;; # getopt error
esac
shift
done
if [ $# -gt 0 ]; then
usage >&2
exit 2
fi
if ! [ -f "$ABUILD_CONF" ] && ! [ -f "$ABUILD_USERCONF" ] && ! [ -f "$ABUILD_DEFCONF" ]; then
die "no abuild.conf found"
fi
if ! [ -f APKBUILD ]; then
die 'must be run in the directory of a built package'
fi
if ! [ -n "$CARCH" ]; then
die "failed to detect CARCH"
fi
. ./APKBUILD
startdir="$PWD"
tmpdir=$(mktemp -d -t checkpkg-script.XXXXXX)
trap "rm -rf '$tmpdir'; exit" INT EXIT
cd "$tmpdir" || die "failed to create temp dir"
# storage for downloaded/copied apks
mkdir -p apks
# default to pigz for unpacking
gunzip="$(command -v pigz || echo gzip) -d"
for i in $pkgname $subpackages; do
_pkgname=${i%%:*}
pkg=${_pkgname}-$pkgver-r$pkgrel
pkgfile=${pkg}.apk
repodir=${startdir%/*}
repo=${repodir##*/}
for filepath in "$PKGDEST"/$pkgfile "$REPODEST"/$repo/$CARCH/$pkgfile "$startdir"/$pkgfile; do
if [ -f "$filepath" ]; then
break
fi
done
[ -f "$filepath" ] || die "can't find $pkgfile"
# generate a temp repositories file with only the http(s) repos
grep -E "^https?:" /etc/apk/repositories > "$tmpdir"/repositories
oldpkg=$(apk fetch --repositories-file "$tmpdir"/repositories --simulate $_pkgname 2>&1 | sed 's/^Downloading //')
if [ "${oldpkg}" = "${pkg}" ]; then
die "the built package ($_pkgname) is already in the repo"
fi
# apk info could return multiple lines if multiple packages share a provide
# (e.g. dnsmasq); filter with the exact package name and take the second line:
# 7zip-23.01-r0 installed size:
# 1668 KiB
newsize="$(apk info --repositories-file /dev/null --repository "$REPODEST"/$repo --size $_pkgname | \
grep -F "$pkg" -A1 | \
tail -n1)"
oldsize="$(apk info --repositories-file "$tmpdir"/repositories --size "$_pkgname" | \
grep -F "$oldpkg" -A1 | \
tail -n1)"
if [ "$oldsize" = "$newsize" ]; then
msg "No size differences for $_pkgname."
else
msg "Size difference for $_pkgname: $oldsize -> $newsize"
fi
apk fetch --quiet --repositories-file "$tmpdir"/repositories --stdout "$_pkgname" > apks/old.apk \
|| msg2 "Old apk for $_pkgname missing. (new package/arch? broken internet?)"
# pre-uncompress to not decompress twice
# we do a decompression + tar -t for the file list, but then later we might do a full extraction for sodiff.
# to not decompress here and then later again, store the intermediate tar
$gunzip -c 2>/dev/null < apks/old.apk > apks/old.tar &
$gunzip -c "$filepath" < "$filepath" > apks/new.tar &
wait
tar -t -f apks/old.tar 2>/dev/null | grep -v '^\.SIGN\.' | sort > "filelist-$_pkgname-old" &
tar -t -f apks/new.tar | grep -v '^\.SIGN\.' | sort > "filelist-$_pkgname-new" &
wait
diff -U3 "filelist-$_pkgname-old" "filelist-$_pkgname-new"
if diff -U0 "filelist-$_pkgname-old" "filelist-$_pkgname-new" | grep -q '\.so'; then
echo "SODIFF:"
mkdir -p "$_pkgname-pkg-old" "$_pkgname-pkg-new"
tar -C "$_pkgname-pkg-old" 2>/dev/null -x -f apks/old.tar > /dev/null &
tar -C "$_pkgname-pkg-new" -x -f apks/new.tar > /dev/null &
wait
# filter to things that start with -+ but strip the header (---/+++)
diff -U0 "filelist-$_pkgname-old" "filelist-$_pkgname-new" | grep -E '^(\+|-)[A-Za-z0-9]+' | grep '\.so' | while read -r diff_sofile; do
case "$diff_sofile" in
-*) path="$_pkgname-pkg-old"; sofile="${diff_sofile#\-}" ;;
+*) path="$_pkgname-pkg-new"; sofile="${diff_sofile#\+}" ;;
esac
# skip symlinks (only adds duplicate output or is dangling), and things that aren't valid elfs
# matching .so above matches anything with .so in the name, e.g. xyz.sourceforge
if ! [ -L "$path"/"$sofile" ] && readelf -h "$path"/"$sofile" >/dev/null 2>&1; then
echo "$diff_sofile: " "$(objdump -p "$path"/"$sofile" | grep SONAME)"
fi
done
else
msg "No soname differences for $_pkgname."
fi
done