summaryrefslogtreecommitdiffstats
path: root/src/plugins/abrt-action-install-debuginfo
diff options
context:
space:
mode:
authorJiri Moskovcak <jmoskovc@redhat.com>2010-11-29 14:00:41 +0100
committerJiri Moskovcak <jmoskovc@redhat.com>2010-11-29 14:00:41 +0100
commit72a48e59e5898116b88daccfee6370aea81c764c (patch)
tree3ea2057d74e62644091d6188a2f1d640468d6487 /src/plugins/abrt-action-install-debuginfo
parentcf44477e4a1f75ec850192b2cf9c38b07636e8ac (diff)
downloadabrt-72a48e59e5898116b88daccfee6370aea81c764c.tar.gz
abrt-72a48e59e5898116b88daccfee6370aea81c764c.tar.xz
abrt-72a48e59e5898116b88daccfee6370aea81c764c.zip
new debuginfo install script rewritten in python
- using python alows us to use the yum API, so we can read the progress, file sizes, requires disk space, etc.. and seems to be faster the using yum --whatprovides + yumdownloader - it's easier to translate - we can drop dependency on yum-utils
Diffstat (limited to 'src/plugins/abrt-action-install-debuginfo')
-rwxr-xr-xsrc/plugins/abrt-action-install-debuginfo420
1 files changed, 0 insertions, 420 deletions
diff --git a/src/plugins/abrt-action-install-debuginfo b/src/plugins/abrt-action-install-debuginfo
deleted file mode 100755
index 8af9345c..00000000
--- a/src/plugins/abrt-action-install-debuginfo
+++ /dev/null
@@ -1,420 +0,0 @@
-#!/bin/sh
-# Called by abrtd before producing a backtrace.
-# The task of this script is to install debuginfos.
-#
-# Just using [pk-]debuginfo-install does not work well.
-# - they can't install more than one version of debuginfo
-# for a package
-# - their output is unsuitable for scripting
-# - debuginfo-install aborts if yum lock is busy
-# - pk-debuginfo-install was observed to hang
-#
-# Usage: abrt-action-install-debuginfo CORE TEMPDIR [CACHEDIR[:DEBUGINFODIR1:DEBUGINFODIR2...]]
-# If CACHEDIR is specified, debuginfos should be installed there.
-# If not, debuginfos should be installed into TEMPDIR.
-#
-# Currently, we are called with CACHEDIR set to "/var/cache/abrt-di",
-# but in the future it may be omitted or set to something else.
-# Script must be ready for those cases too. Consider, for example,
-# corner cases of "" and "/".
-#
-# Output goes to GUI as debuginfo install log. The script should be careful
-# to give useful, but not overly cluttered info to stdout.
-#
-# Exitcodes:
-# 0 - all debuginfos are installed
-# 0 - not all debuginfos are installed
-# (was 1, but this scares event processing)
-# 2+ - serious problem
-#
-# Algorithm:
-# - Create TEMPDIR
-# - Extract build-ids from coredump
-# - For every build-id, check /usr/lib/debug/.build-id/XX/XXXX.debug
-# and CACHEDIR/usr/lib/debug/.build-id/XX/XXXX.debug
-# - If they all exist, exit 0
-# - Using "yum provides /usr/lib/debug/.build-id/XX/XXXX.debug",
-# figure out which debuginfo packages are needed
-# - Download them using "yumdownloader PACKAGE..."
-# - Unpack them with rpm2cpio | cpio to TEMPDIR
-# - If CACHEDIR is specified, copy usr/lib/debug/.build-id/XX/XXXX.debug
-# to CACHEDIR/usr/lib/debug/.build-id/XX/XXXX.debug and delete TEMPDIR
-# - Report which XX/XXXX.debug are still missing.
-#
-# For better debuggability, eu_unstrip.OUT, yum_provides.OUT etc files
-# are saved in TEMPDIR, and TEMPDIR is not deleted if we exit with exitcode 2
-# ("serious problem").
-
-
-debug=false
-# Useful if you need to see saved rpms, command outputs etc
-keep_tmp=false
-
-
-# Handle options
-if test x"$1" = x"--"; then
- shift
-else
- if test x"$1" = x"-v"; then
- debug=true
- shift
- fi
- if test $# -lt 2 || test x"$1" = x"--help"; then
- echo "Usage:"
- echo
- echo "abrt-action-install-debuginfo [-v] CORE TEMPDIR [CACHEDIR[:DEBUGINFODIR...]]"
- echo
- echo "TEMPDIR must be a name of a new temporary directory. It must not exist."
- echo "If CACHEDIR is specified, debuginfos are installed in CACHEDIR,"
- echo "and TEMPDIR is deleted on exit."
- echo "Otherwise, debuginfos are installed into TEMPDIR, which is not deleted."
- echo
- echo "Options:"
- echo " -v Verbose (for debugging)"
- echo
- exit
- fi
-fi
-
-
-# Parse params
-core="$1"
-tempdir="$2"
-debuginfodirs="${3//:/ }"
-cachedir="${3%%:*}"
-
-
-# stderr may be used for status messages too
-exec 2>&1
-
-
-error_msg_and_die() {
- echo "$*"
- exit 2
-}
-
-count_words() {
- echo $#
-}
-
-print_missing_build_ids() {
- local build_id
- local build_id1
- local build_id2
- local file
- local d
- for build_id in $build_ids; do
- build_id1=${build_id:0:2}
- build_id2=${build_id:2}
- file="usr/lib/debug/.build-id/$build_id1/$build_id2.debug"
- test -f "/$file" && continue
- # On 2nd pass, we may already have some debuginfos in tempdir
- test -f "$tempdir/$file" && continue
- # Check cachedir if we have one
- for d in $debuginfodirs; do
- test -f "$d/$file" && continue 2
- done
- echo -n "$build_id "
- done
-}
-
-# Note: it is run in `backticks`, use >&2 for error messages
-print_missing_debuginfos() {
- local build_id
- local build_id1
- local build_id2
- local file
- local d
- for build_id in $build_ids; do
- build_id1=${build_id:0:2}
- build_id2=${build_id:2}
- file="usr/lib/debug/.build-id/$build_id1/$build_id2.debug"
- test -f "/$file" && continue
- # On 2nd pass, we may already have some debuginfos in tempdir
- test -f "$tempdir/$file" && continue
- # Check cachedir if we have one
- if test x"$cachedir" != x""; then
- for d in $debuginfodirs; do
- test -f "$d/$file" && continue 2
- done
- fi
- echo -n "/$file "
- done
-}
-
-cleanup_and_report_missing() {
-# Which debuginfo files are still missing, including those we just unpacked?
- missing_build_ids=`print_missing_build_ids`
- $debug && echo "missing_build_ids:$missing_build_ids" >&2
-
- # If cachedir is specified, tempdir is just a staging area. Delete it
- if test x"$cachedir" != x""; then
- $keep_tmp && echo "NOT removing $tempdir (keep_tmp debugging is on)" >&2
- $keep_tmp || { $debug && echo "Removing $tempdir" >&2; rm -rf "$tempdir"; }
- fi
-
- # Disabled. We no longer need this, gdb output flags missing debuginfos anyway
- #for missing in $missing_build_ids; do
- # echo "MISSING:$missing" >&2
- #done
-
- test x"$missing_build_ids" != x"" && echo "`count_words $missing_build_ids` debuginfos can't be found" >&2
-}
-
-# $1: iteration (1,2...)
-# Note: it is run in `backticks`, use >&2 for error messages
-print_package_names() {
- # We'll run something like:
- # yum --enablerepo=*debuginfo* --quiet provides \
- # /usr/lib/debug/.build-id/bb/11528d59940983f495e9cb099cafb0cb206051.debug \
- # /usr/lib/debug/.build-id/c5/b84c0ad3676509dc30bfa7d42191574dac5b06.debug ...
- local yumopts=""
- if test x"$1" = x"1"; then
- yumopts="-C"
- echo "`count_words $missing_debuginfo_files` missing debuginfos, getting package list from cache" >&2
- else
- echo "`count_words $missing_debuginfo_files` missing debuginfos, getting package list from repositories" >&2
- fi
- # --showduplicates: do not just show the latest package
- # (tried to use -R2 to abort on stuck yum lock but -R is not about that)
- local cmd="yum $yumopts $yum_repo_opts --showduplicates --quiet provides $missing_debuginfo_files"
- echo "$cmd" >"yum_provides.$1.OUT"
- $debug && echo "Running: $cmd" >&2
- # eval is needed to strip away ''s in $yum_repo_opts; cant remove them and just use
- # unquoted $cmd, that would perform globbing on '*'
- local yum_provides_OUT="`eval $cmd 2>&1`"
- local err=$?
- printf "%s\nyum exitcode:%s\n" "$yum_provides_OUT" $err >>"yum_provides.$1.OUT"
- test $err = 0 || error_msg_and_die "yum provides... exited with $err:
-`head yum_provides.$1.OUT`" >&2
-
- # The output is pretty machine-unfriendly:
- # glibc-debuginfo-2.10.90-24.x86_64 : Debug information for package glibc
- # Repo : rawhide-debuginfo
- # Matched from:
- # Filename : /usr/lib/debug/.build-id/5b/c784c8d63f87dbdeb747a773940956a18ecd2f.debug
- #
- # 1:dbus-debuginfo-1.2.12-2.fc11.x86_64 : Debug information for package dbus
- # Repo : updates-debuginfo
- # Matched from:
- # Filename : /usr/lib/debug/.build-id/bc/da7d09eb6c9ee380dae0ed3d591d4311decc31.debug
- # Need to massage it a lot.
- # There can be duplicates (one package may provide many debuginfos).
- printf "%s\n" "$yum_provides_OUT" \
- | grep -- -debuginfo- \
- | sed 's/^[0-9]*://' \
- | sed -e 's/ .*//' -e 's/:.*//' \
- | sort | uniq | xargs
-}
-
-abort_if_low_on_disk_space() {
- local mb
- # free_blocks * block_size / (1024*1024), careful to not overflow:
- mb=$((`stat -f -c "%a / 8192 * %S / 128" "$tempdir"`))
- if test $mb -lt $1; then
- $debug && echo "Removing $tempdir" >&2
- rm -rf "$tempdir"
- error_msg_and_die "Less than $1 Mb of free space in $tempdir: $mb Mb"
- fi
- if test x"$cachedir" != x"" && test -d "$cachedir"; then
- mb=$((`stat -f -c "%a / 8192 * %S / 128" "$cachedir"`))
- if test $mb -lt $1; then
- $debug && echo "Removing $tempdir" >&2
- rm -rf "$tempdir"
- error_msg_and_die "Less than $1 Mb of free space in $cachedir: $mb Mb"
- fi
- fi
-}
-
-download_packages() {
- local pkg
- local err
- local file
- local build_id
- local build_id1
- local build_id2
- local d
-
- ## Download with one command (too silent):
- ## Redirecting, since progress bar stuff only messes up our output
- ##yumdownloader --enablerepo=*debuginfo* --quiet $packages >yumdownloader.OUT 2>&1
- ##err=$?
- ##echo "exitcode:$err" >>yumdownloader.OUT
- ##test $err = 0 || error_msg_and_die ...
- >yumdownloader.OUT
- i=1
- for pkg in $packages; do
- echo "Download $i/$num_packages: $pkg"
- echo "Download $i/$num_packages: $pkg" >>yumdownloader.OUT
- cmd="yumdownloader $yum_repo_opts --quiet $pkg"
- $debug && echo "Running: $cmd" >&2
- # eval is needed to strip away ''s in $yum_repo_opts
- eval $cmd >>yumdownloader.OUT 2>&1 &
- # using EXIT handler and this, make sure we kill yumdownloader if we exit:
- CHILD_PID=$!
- wait
- err=$?
- CHILD_PID=""
- echo "exitcode:$err" >>yumdownloader.OUT
- echo >>yumdownloader.OUT
- test $err = 0 || echo "Download of $pkg failed!"
- abort_if_low_on_disk_space 256
-
- # Process and delete the *.rpm file just downloaded
- # We do it right after download: some users have smallish disks...
- for file in *.rpm; do
- # Happens if no .rpm's were downloaded (yumdownloader problem)
- # In this case, $f is the literal "*.rpm" string
- test -f "$file" || { echo "No rpm file downloaded"; continue; }
- echo "Unpacking: $file"
- echo "Processing: $file" >>unpack.OUT
- rpm2cpio <"$file" >"unpacked.cpio" 2>>unpack.OUT || error_msg_and_die "Can't convert '$file' to cpio"
- $keep_tmp || rm "$file"
- abort_if_low_on_disk_space 256
- cpio -id <"unpacked.cpio" >>unpack.OUT 2>&1 || error_msg_and_die "Can't unpack '$file' cpio archive"
- rm "unpacked.cpio"
- abort_if_low_on_disk_space 256
- # Copy debuginfo files to cachedir
- if test x"$cachedir" != x"" && test -d "$cachedir"; then
- # For every needed debuginfo, check whether we have it
- for build_id in $build_ids; do
- build_id1=${build_id:0:2}
- build_id2=${build_id:2}
- file="usr/lib/debug/.build-id/$build_id1/$build_id2.debug"
- # Do not copy it if it can be found in any of $debuginfodirs
- test -f "/$file" && continue
- if test x"$cachedir" != x""; then
- for d in $debuginfodirs; do
- test -f "$d/$file" && continue 2
- done
- fi
- if test -f "$file"; then
- # File is one of those we just installed, cache it
- mkdir -p "$cachedir/usr/lib/debug/.build-id/$build_id1"
- # Note: this does not preserve symlinks. This is intentional
- $debug && echo Copying "$file" to "$cachedir/$file" >&2
- echo "Caching debuginfo: $file"
- cp --remove-destination "$file" "$cachedir/$file" || error_msg_and_die "Can't copy $file (disk full?)"
- continue
- fi
- done
- fi
- # Delete remaining files unpacked from .cpio
- # which we didn't need after all
- rm -r etc bin sbin usr var opt 2>/dev/null
- done
- : $((i++))
- done
-}
-
-
-# Sanity checking
-test -f "$core" || error_msg_and_die "not a file: '$core'"
-# cachedir is optional
-test x"$cachedir" = x"" || test -d "$cachedir" || error_msg_and_die "bad cachedir '$cachedir'"
-# tempdir must not exist
-test -e "$tempdir" && error_msg_and_die "tempdir exists: '$tempdir'"
-
-# Intentionally not using -p: we want to abort if tempdir exists
-mkdir -- "$tempdir" || exit 2
-cd "$tempdir" || exit 2
-
-
-abort_if_low_on_disk_space 1024
-
-
-# A hook to stop yumdownloader, in case we are terminated by kill -TERM etc.
-CHILD_PID=""
-trap 'test x"$CHILD_PID" != x"" && kill -- "$CHILD_PID"' EXIT
-
-
-$debug && echo "Downloading rpms to $tempdir"
-
-
-echo "Getting list of build IDs"
-# Observed errors:
-# eu-unstrip: /var/spool/abrt/ccpp-1256301004-2754/coredump: Callback returned failure
-eu_unstrip_OUT=`eu-unstrip "--core=$core" -n 2>eu_unstrip.ERR`
-err=$?
-printf "%s\neu-unstrip exitcode:%s\n" "$eu_unstrip_OUT" $err >eu_unstrip.OUT
-test $err = 0 || error_msg_and_die "eu-unstrip exited with $err:
-`cat eu_unstrip.ERR`
-`head eu_unstrip.OUT`"
-
-# eu-unstrip output example:
-# 0x400000+0x209000 23c77451cf6adff77fc1f5ee2a01d75de6511dda@0x40024c - - [exe]
-# or
-# 0x400000+0x20d000 233aa1a57e9ffda65f53efdaf5e5058657a39993@0x40024c /usr/libexec/im-settings-daemon /usr/lib/debug/usr/libexec/im-settings-daemon.debug [exe]
-# 0x7fff5cdff000+0x1000 0d3eb4326fd7489fcf9b598269f1edc420e2c560@0x7fff5cdff2f8 . - linux-vdso.so.1
-# 0x3d15600000+0x208000 20196628d1bc062279622615cc9955554e5bb227@0x3d156001a0 /usr/lib64/libnotify.so.1.1.3 /usr/lib/debug/usr/lib64/libnotify.so.1.1.3.debug libnotify.so.1
-# 0x7fd8ae931000+0x62d000 dd49f44f958b5a11a1635523b2f09cb2e45c1734@0x7fd8ae9311a0 /usr/lib64/libgtk-x11-2.0.so.0.1600.6 /usr/lib/debug/usr/lib64/libgtk-x11-2.0.so.0.1600.6.debug
-#
-# Get space-separated list of all build-ids
-# There can be duplicates (observed in real world)
-build_ids=`printf "%s\n" "$eu_unstrip_OUT" \
-| while read junk1 build_id binary_file di_file lib_name junk2; do
- build_id=${build_id%%@*}
-
- # This filters out linux-vdso.so, among others
- test x"$lib_name" != x"[exe]" && test x"${binary_file:0:1}" != x"/" && continue
- # Sanitize build_id: must be longer than 2 chars
- test ${#build_id} -le 2 && continue
- # Sanitize build_id: must have only hex digits
- test x"${build_id//[0-9a-f]/}" != x"" && continue
-
- echo "$build_id"
-done | sort | uniq | xargs`
-$debug && echo "build_ids:$build_ids"
-
-
-# Prepare list of repos to use.
-# When we look for debuginfo we need only -debuginfo* repos, we can disable the rest
-# and thus make it faster.
-yum_repo_opts="'--disablerepo=*'"
-#// Disabled. Too often, debuginfo repos have names which do not conform to "foo-debuginfo" scheme,
-#// and users get bad backtraces.
-#// # (Without -C, yum for some reason wants to talk to repos! If one is down, it becomes S..L..O..W)
-#// for enabled_repo in `LANG=C yum -C repolist all | grep 'enabled:' | cut -f1 -d' ' | grep -v -- '-debuginfo'`; do
-#// yum_repo_opts="$yum_repo_opts '--enablerepo=${enabled_repo}-debuginfo*'"
-#// done
-yum_repo_opts="$yum_repo_opts '--enablerepo=*-debug*'"
-
-
-# We try to not run yum without -C unless absolutely necessary.
-# Therefore we loop. yum is run by print_package_names function,
-# on first iteration it is run with -C, on second - without,
-# which usually causes yum to download updated filelists,
-# which in turn takes several minutes and annoys users.
-iter=0
-while test $((++iter)) -le 2; do
- # Analyze $build_ids and check which debuginfos are present
- missing_debuginfo_files=`print_missing_debuginfos`
- # Did print_missing_debuginfos fail?
- test $? = 0 || exit 2
- $debug && echo "missing_debuginfo_files:$missing_debuginfo_files"
-
- test x"$missing_debuginfo_files" = x"" && break
-
- # Map $missing_debuginfo_files to package names.
- # yum is run here.
- packages=`print_package_names $iter`
- # Did print_package_names fail?
- test $? = 0 || exit 2
- $debug && echo "packages ($iter):$packages"
-
- # yum may return "" here if it found no packages (say, if coredump
- # is from a new, unreleased package fresh from koji).
- test x"$packages" = x"" && continue
-
- num_packages=`count_words $packages`
- echo "Downloading $num_packages packages"
- download_packages
-done
-
-cleanup_and_report_missing
-
-# Was exiting with 1, but this stops event processing.
-test x"$missing_build_ids" != x"" && exit 0
-
-echo "All needed debuginfos are present"
-exit 0