#!/bin/bash # Spit out a portage-compatible list of packages to build because of lib # breakages. print_usage() { cat << EOF Usage: $0 [OPTIONS] Lists packages broken by library changes, upgrades, and missing dependencies. -h, --help Print this usage -e, --exact Emerge based on exact package version -q, --quiet Be less verbose (also passed to emerge command) -u, --no-util UTIL Do not use features provided by UTIL --no-util=UTIL UTIL can be one of portage-utils, pkgcore, or equery or it can be a *quoted* space-delimited list. -L, --library NAME Emerge existing packages that use the library with NAME --library=NAME NAME can be a full path to the library or a basic regular expression (man grep) -b, --check-linking Check dynamic linking for binaries -l, --check-libtool Check *.la files for missing dependencies Calls emerge, all other options are used for it (e. g. -p, --pretend). Report bugs to EOF } get_missing_sonames() { local soname IFS=$'\n,' list=($(scanelf -BLpF%n#F)) list=($(sort -u <<< "${list[*]}")) for soname in ${list[@]}; do [[ -e $soname ]] || echo $soname done | sort -u } check_bins() { local missing_sonames broken_pkgs bin libs pv p missing_sonames=$(get_missing_sonames) if [[ $missing_sonames ]] && broken_pkgs=$(scanelf -LBpF "%F %n" | grep -F "$missing_sonames"); then get_packages $( while read bin libs; do feedback=$(grep -oF "$missing_sonames" <<< "$libs") feedback="${feedback##[[:space:]]}"; feedback="${feedback%%[[:space:]]}" echo "$bin is missing ${feedback//[[:space:]]/ and }" >&2 echo "$bin" done <<< "$broken_pkgs" ) | sort -u | slot else echo "Dynamic linking is consistent" >&2 fi } get_all_las() { local IFS paths paths=( /lib* /usr/lib* $(sed '/^#/d;s/#.*$//' < /etc/ld.so.conf | tr -s '/') $(scanelf -BlpF%F | sed 's:/[^/]*$::' | tr -s '/') ) IFS=$'\n' paths=($(sort -u <<< "${paths[*]%/}")) find -L ${paths[@]} -type f -name '*.la' 2> /dev/null | sort -u } get_dependency_libs() { awk -F"[=']" '/^dependency_libs/{ gsub("^-[^[:space:]]*", "", $NF); gsub("[[:space:]]-[^[:space:]]*", "", $NF); print $NF }' "$@" } check_las() { local oIFS="$IFS" local IFS local broken_las=($( while read la; do deps=($(get_dependency_libs "$la")) (( ${#deps[@]} > 0)) || continue IFS=$'\n' deps=($(sort -u <<< "${deps[*]}")) IFS="$oIFS" for dep in ${deps[@]}; do [[ $dep = /* && ! -e $dep ]] || continue echo "$la is missing $dep" >&2 echo "$la" done done < <(get_all_las) | sort -u )) IFS=$'\n' if (( ${#broken_las[@]} > 0)); then get_packages <<< "${broken_las[*]}" | sort -u | slot else echo "No dependencies missing from .la files" >&2 fi } slot() { while read pv; do p="${pv%%-r[[:digit:]]*}" p="${p%-*}" echo "$p:$(&2; print_usage; exit 1;; esac shift done if [[ avoid_utils != *portage-utils* ]] && hash qfile 2> /dev/null; then get_packages() { qfile -qvC "$@"; } elif [[ avoid_utils != *pkgcore* ]] && hash pquery 2> /dev/null; then get_packages() { local IFS=,; pquery --nocolor --owns="$*"; } elif [[ avoid_utils != *equery* ]] && hash equery 2> /dev/null; then get_packages() { equery -q -C b $@; } else get_packages() { local IFS=$'\n' find /var/db/pkg -name CONTENTS -print0 | xargs -0 grep -Fl "$*" | sed 's:/var/db/pkg/\(.*\)/CONTENTS:=\1:' } fi for check in ${checks[@]}; do case $check in linking) check_bins;; libtool) check_las;; esac done } get_args "$@"