#! /bin/bash
#############################################################################
# Copyright (c) 2006-2009 Novell, Inc.
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, contact Novell, Inc.
#
# To contact Novell about this file by physical or electronic mail,
# you may find current contact information at www.novell.com
#############################################################################
usage() {
echo "USAGE: ${0##*/} [--(no-)symvers|--(no-)symsets|--(no-)symtypes] [--filter <filter>] rpm ..."
echo -n "The default is"
$do_symvers && echo -n " --symvers" || echo -n " --no-symvers"
$do_symsets && echo -n " --symsets" || echo -n " --no-symsets"
$do_symtypes && echo -n " --symtypes" || echo -n " --no-symtypes"
echo
}
symsets_are_equal() {
local a=$1 b=$2
cmp -s <(tar tfz $a | sed -e 's:.*/::' | sort) \
<(tar tfz $b | sed -e 's:.*/::' | sort)
}
filters2re() {
local f tail res sep
if test -z "$tail"; then
tail='/[^/]*$'
fi
for f in "$@"; do
case "$f" in
*\*)
f="${f%\*}"
f="^\.?$f"
;;
*)
f="^\.?$f$tail"
esac
res="$res$sep$f"
sep="|"
done
echo "$res"
}
merge_dirs() {
local old=$1 new=$2
find "$old" "$new" -type f -printf '%P\n' | sort -u \
>"$tmpdir/all"
while read f; do
if cmp -s "$old/$f" "$new/$f"; then
continue
fi
if ! echo "$f" | grep -Eq "$re"; then
continue
fi
if test -e "$new/$f"; then
cp "$new/$f" "$old/$f"
echo "$f added to $target"
else
rm "$old/$f"
echo "$f removed from $target"
fi
done <"$tmpdir/all"
}
add_symsets() {
set -- $tmpdir/boot/symsets-*
if [ $# -eq 0 ]; then
echo "No symsets file found in $rpm" >&2
status=1
return
fi
local re=$(tail='\.[0-9a-f]*(\.fake)?$' filters2re "${filters[@]//\//_}")
for symsets in "$@"; do
flavor=${symsets%.tar.gz}
flavor=${flavor##*-}
target=kabi/$arch/symsets-$flavor.tar.gz
if [ -e $target ] && symsets_are_equal "$symsets" $target; then
echo "$target is unchanged"
continue
fi
if $opt_dry_run; then
echo "$target added"
continue
fi
mkdir -p ${target%/*}
if test -z "${filters[*]}"; then
cp "$symsets" $target
else
rm -rf "$tmpdir/symsets"
mkdir "$tmpdir/symsets"
tar xzf "$target" -C "$tmpdir/symsets"
old=$(echo "$tmpdir/symsets"/*)
mkdir "$tmpdir/symsets/new"
tar xzf "$symsets" -C "$tmpdir/symsets/new" --strip-components=1
new="$tmpdir/symsets/new"
merge_dirs "$old" "$new"
tar czf "$target" -C "$tmpdir/symsets" "${old##*/}"
fi
echo "$target added"
done
}
unpack_symtypes() {
local dir="$1"
rpm/modversions --unpack "$dir"
}
pack_symtypes() {
local dir="$1"
rpm/modversions --pack --ext .symref "$dir"
}
unpack_symvers() {
local dir="$1" csum sym mod rest last=
mkdir -p "$dir"
sort -k 3 | while read csum sym mod rest; do
if test "$last" != "$mod"; then
mkdir -p "$dir/${mod%/*}"
exec 3>"$dir/$mod.symvers"
last=$mod
fi
echo -ne "$csum\\t$sym\\t$mod" >&3
if test -n "$rest"; then
echo -ne "\\t$rest" >&3
fi
echo >&3
done
exec 3>&-
}
pack_symvers() {
local dir="$1"
find "$dir" -type f | xargs cat | sort -k 2
}
add_flat_files() {
local type=$1
set -- $tmpdir/boot/$type-*.gz
if [ $# -eq 0 ]; then
set -- $tmpdir/usr/src/linux-*-obj/*/*/Module.$type
fi
if [ $# -eq 0 ]; then
echo "No $type file found in $rpm" >&2
status=1
return
fi
local file flavor target
local re=$(filters2re "${filters[@]}")
for file; do
case "$file" in
*.gz)
gzip -cd "$file" > "${file%.gz}"
file=${file%.gz}
;;
esac
case "$file" in
$tmpdir/boot/*)
flavor=${file##*-}
;;
$tmpdir/usr/src/*/Module.symvers)
flavor=${file##*-obj/}
flavor=${flavor#*/}
flavor=${flavor%/Module.symvers}
;;
esac
target=kabi/$arch/$type-$flavor
if cmp -s "$file" "$target"; then
echo "$target is unchanged"
continue
fi
if $opt_dry_run; then
echo "$target added"
continue
fi
mkdir -p "${target%/*}"
if test -z "${filters[*]}"; then
cp "$file" "$target"
else
rm -rf "$tmpdir/$type"
mkdir -p "$tmpdir/$type"/{old,new}
old="$tmpdir/$type/old"
new="$tmpdir/$type/new"
unpack_$type "$old" <"$target" &
unpack_$type "$new" <"$file" &
wait
merge_dirs "$old" "$new"
pack_$type "$old" >"$target"
fi
echo "$target added"
done
}
unpack_iso()
{
local iso=$1 file name
isoinfo -R -f -i "$iso" | grep -E '/kernel-[^/]*-([2-9]|[1-9][0-9]+)\.[0-9][^/]*\.rpm$' |
while read file; do
name=${file##*/}
case "$name" in
kernel-source-* | kernel-syms-* | kernel-*-debug* | kernel-*-man-*| \
kernel-firmware-* | kernel-coverage-* | kernel-docs-* | \
kernel-*-extra* | *src.rpm)
continue
esac
isoinfo -R -i "$iso" -x "$file" >"$tmpdir/$name"
echo "$tmpdir/$name"
done
}
query_rpm()
{
local rpm=$1
exec 3< <(rpm -qp --qf '%{NAME}\n%{ARCH}\n%{VERSION}\n%{RELEASE}' "$rpm")
read name <&3
read arch <&3
read version <&3
read release <&3
exec 3<&-
}
. rpm/config.sh
case "$IBS_PROJECT" in
SUSE:SLE-9*)
do_symvers=true
do_symsets=false
do_symtypes=false
;;
SUSE:SLE-10-SP[012]*)
do_symvers=true
do_symsets=true
do_symtypes=false
;;
SUSE:SLE-10* | SUSE:SLE-11*)
do_symvers=true
do_symsets=true
do_symtypes=true
;;
*)
do_symvers=true
do_symsets=false
do_symtypes=true
;;
esac
options=`getopt -o h --long symvers,no-symvers,symsets,no-symsets,symtypes,no-symtypes,dry-run,filter:,help -- "$@"`
if [ $? -ne 0 ]; then
usage >&2
exit 1
fi
eval set -- "$options"
opt_dry_run=false
filters=()
while :; do
arg=$1
shift
newval=true
case "$arg" in
--no-*)
newval=false
arg=${arg/--no-/--}
esac
case "$arg" in
--symvers)
do_symvers=$newval
;;
--symsets)
do_symsets=$newval
;;
--symtypes)
do_symtypes=$newval
;;
--dry-run)
opt_dry_run=true
;;
--filter)
filters[${#filters[@]}]=${1%/}
shift
;;
-h|--help)
usage
exit 0
;;
--)
break;
esac
done
if [ $# -eq 0 ]; then
usage >&2
exit 1
fi
tmpdir=$(mktemp -td ${0##*/}.XXXXXX)
trap "rm -rf $tmpdir" EXIT
shopt -s nullglob
echo "Packages to process:"
unset ${!found_rmps_*}
while test $# -gt 0; do
rpm=$1
shift
case "$rpm" in
*.src.rpm | *.nosrc.rpm | *.noarch.rpm | *.delta.rpm)
continue
;;
*.iso)
set -- $(unpack_iso "$rpm") "$@"
continue
;;
esac
# There may be symlinks as well as regular files. Skip duplicates.
for file in "${rpms[@]}"; do
[ "$rpm" -ef "$file" ] && continue 2
done
query_rpm "$rpm"
var=found_rmps_${arch}_${name//-/_}
eval "$var=\"\$$var $rpm\""
rpms[${#rpms[@]}]=$rpm
done
for rpm in ${!found_rmps_*}; do
set -- ${!rpm}
if [ $# -ne 1 ]; then
echo "*** Duplicate: ${*##*/}" >&2
failed=1
fi
done
[ -z "$failed" ] || exit 1
for rpm in ${!found_rmps_*}; do
set -- ${!rpm}
echo ${1##*/}
done
echo
archs_flavors="$(scripts/guards --list < config.conf)"
for rpm in "${rpms[@]}"; do
query_rpm "$rpm"
# skip the main package if there is a base subpackage
base=found_rmps_${arch}_${name//-/_}_base
if [ -n "${!base}" ]; then
continue
fi
# ... and skip both if there is a -devel subpackage
devel=found_rmps_${arch}_${name//-/_}
devel=${devel%_base}_devel
if [ -n "${!devel}" ]; then
continue
fi
build_arch=$arch
case "$arch" in
i?86)
arch=i386 ;;
s390*)
case "$IBS_PROJECT" in
SUSE:SLE-9* | SUSE:SLE-10* | SUSE:SLE-11:*)
arch=s390 ;;
esac
;;
ppc*)
case "$IBS_PROJECT" in
SUSE:SLE-10*)
arch=powerpc ;;
esac
;;
aarch64)
arch=arm64
;;
esac
flavor=${name#kernel-}
flavor=${flavor%-base}
flavor=${flavor%-devel}
if ! echo "$archs_flavors" | grep -q "$arch/$flavor"; then
case "$flavor" in
source | syms | *-extra)
;;
*)
echo "${rpm%%*/}: not a known arch/flavor; skipping" >&2
;;
esac
continue
fi
echo "[$name-$version-$release.$build_arch.rpm]"
rm -rf $tmpdir/{boot,usr}
rpm2cpio "$rpm" \
| ( cd $tmpdir && cpio -dim --quiet './boot/symvers-*' './boot/symsets-*' \
'./boot/symtypes-*' './usr/src/linux-*-obj/*/*/Module.symvers' )
if $do_symvers; then
add_flat_files symvers
fi
if $do_symtypes; then
add_flat_files symtypes
fi
if $do_symsets; then
add_symsets
fi
done
exit $status
# vim:sw=4 et