From bb71b70f46536eea5fb6587074d15603f0a5527c Mon Sep 17 00:00:00 2001 From: fuzzyray Date: Wed, 10 Oct 2007 21:01:19 +0000 Subject: [PATCH] /bin/sh version of revdep-rebuild - wrtten by uberlord svn path=/; revision=453 --- trunk/src/revdep-rebuild/revdep-rebuild | 16 +- trunk/src/revdep-rebuild/revdep-rebuild-sh | 332 +++++++++++++++++++++ 2 files changed, 338 insertions(+), 10 deletions(-) create mode 100755 trunk/src/revdep-rebuild/revdep-rebuild-sh diff --git a/trunk/src/revdep-rebuild/revdep-rebuild b/trunk/src/revdep-rebuild/revdep-rebuild index 40ccde7..f71562f 100755 --- a/trunk/src/revdep-rebuild/revdep-rebuild +++ b/trunk/src/revdep-rebuild/revdep-rebuild @@ -165,13 +165,9 @@ get_file_owner() { :; } # Replace whitespace with linebreaks, normalize repeated '/' chars, and sort -u # (If any libs have whitespace in their filenames, someone needs punishment.) clean_var() { - [[ $@ = '-*'* ]] && return - shopt -s extglob - local a="$@" - a="${a%%[[:space:]]-\*[[:space:]]*}" # Delete what follows -* - a="${a//+([[:space:]])/$'\n'}" # Turn spaces into linebreaks - a="${a//+(\/\/)//}" # Normalize slashes - sort -u <<< "$a" + awk 'BEGIN {RS="[[:space:]]"} + /-\*/ {exit} + /[^[:space:]]/ {gsub(/\/\/+/, "/"); print}' | sort -u } # Exit and optionally output to sterr die() { @@ -352,9 +348,9 @@ fi # Set the final variables [[ $SEARCH_DIRS ]] || die 1 "No search defined -- this is a bug." -SEARCH_DIRS=$(clean_var "$SEARCH_DIRS") -SEARCH_DIRS_MASK=$(clean_var "$SEARCH_DIRS_MASK") -LD_LIBRARY_MASK=$(clean_var "$LD_LIBRARY_MASK") +SEARCH_DIRS=$(clean_var <<< "$SEARCH_DIRS") +SEARCH_DIRS_MASK=$(clean_var <<< "$SEARCH_DIRS_MASK") +LD_LIBRARY_MASK=$(clean_var <<< "$LD_LIBRARY_MASK") set_trap() { trap "rm_temp $1" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM diff --git a/trunk/src/revdep-rebuild/revdep-rebuild-sh b/trunk/src/revdep-rebuild/revdep-rebuild-sh new file mode 100755 index 0000000..92ed29f --- /dev/null +++ b/trunk/src/revdep-rebuild/revdep-rebuild-sh @@ -0,0 +1,332 @@ +#!/bin/sh +# Copyright 1999-2007 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +appname=${0##*/} + +# If baselayout is broken, define our own functions +[ -r /etc/init.d/functions.sh ] && . /etc/init.d/functions.sh +if ! type eend >/dev/null 2>&1 || ! eend 0 >/dev/null 2>&1; then + einfo() { echo " * $*"; } + eerror() { echo " * $*" >&2; return 1; } + eindent() { :; } + eoutdent() { :; } +fi + +# No temporary files used, so nothing to clean up :) +trap "export RC_EINDENT=; echo; eerror 'Caught interrupt'; exit 1" \ + SIGINT SIGQUIT + +print_usage() { + cat << EOF +Usage: ${appname} [OPTIONS] [--] [EMERGE_OPTIONS] + +Broken reverse dependency rebuilder. + + -h, --help Print this usage + -e, --exact Emerge based on exact package version + -C, --nocolor Turn off colored output + -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) + +Calls emerge, all other options are used for it (e. g. -p, --pretend). + +Report bugs to +EOF +} + +# Have we linked to this library? +elf_linked() { + local f=$1 + shift + while [ -n "$1" ]; do + ldd "${f}" 2>/dev/null | grep -q "=> $1 " && return 0 + shift + done + return 1 +} + +# Work out of we really need this library or not +elf_needed() { + local f=$1 + shift + while [ -n "$1" ]; do + objdump -p "${f}" 2>/dev/null | \ + grep -vF "${ld_mask:=$'\a'}" | \ + grep -q "^ NEEDED ${1##*/}" && return 0 + shift + done + return 1 +} + +elf_broken() { + local lib= + + for lib in $(ldd "$1" 2>/dev/null | \ + sed -n -e 's/[[:space:]]*\(.*\) => not found .*/\1/p'); do + if elf_needed "$1" "${lib}"; then + echo "(missing ${lib})" + return 0 + fi + done + return 1 +} + +# Check that all direct files exist in .la files +la_broken() { + local x= + for x in $(sed -n -e "s/^dependency_libs=\'\(.*\)'\$/\1/p" "$1"); do + case "${x}" in + /*) + if [ ! -e "${x}" ]; then + echo "(missing ${x})" + return 0 + fi + ;; + esac + done + + return 1 +} + +# Return a $PATH style variable based on ld.so.conf +read_so_conf() { + local line= + while read line; do + case "${line}" in + "#"*) ;; + *) printf ":%s" "${line}";; + esac + done < /etc/ld.so.conf +} + +# Check to see if we have already scanned a dir or not +scanned() { + local dir=$1 IFS=: + set -- ${scanned} + + while [ -n "$1" ]; do + [ "$1" = "$dir" ] && return 0 + shift + done + + scanned="${scanned}${scanned:+:}${dir}" + return 1 +} + +# Hit the portage vdb to work out our ebuilds +# If everything is 100% then this happens in one very fast pass +# Otherwise we have to take the slow approach to inform the user which files +# are orphans +get_exact_ebuilds() { + local regex= ebuilds= x= IFS=: + set -- $@ + IFS=" " + + # Hit the vdb in one go - this is fast! + regex=$(printf "%s|" "$@") + regex=${regex%*|} + find /var/db/pkg -name CONTENTS | \ + xargs egrep "^obj (${regex}) " | \ + sed -e 's,/var/db/pkg/\(.*\/.*\)/CONTENTS:.*,=\1,g' | \ + tr '\n' ' ' +} + +# Get our args +libs= +exact=false +order=true +while [ -n "$1" ]; do + case "$1" in + --*=*) + arg1=${1%%=*} + arg2=${1#*=} + shift + set -- ${arg1} ${arg2} $@ + continue + ;; + -h|--help) print_usage; exit 0;; + -L|--library|--soname|--soname-regexp) + if [ -z "$2" ]; then + eerror "Missing expected argument to $1" + exit 1 + fi + libs="${libs}${libs:+ }$2" + shift + ;; + -e|--exact) exact=true;; + -X|--package-names) #compat ;; + --) shift; emerge_opts="$@"; break;; + *) eerror "$0: unknown option $1"; exit 1;; + esac + shift +done + +einfo "Configuring search environment for ${appname}" +# OK, this truely sucks. Paths can have spaces in, but our config format +# is space separated? +sdirs=$(unset SEARCH_DIRS; portageq envvar SEARCH_DIRS) +sdirs_mask=$(unset SEARCH_DIRS_MASK; portageq envvar SEARCH_DIRS_MASK) +ld_mask=$(unset LD_LIBRARY_MASK; portageq envvar LD_LIBRARY_MASK) + +if [ -d /etc/revdep-rebuild ]; then + for x in /etc/revdep-rebuild/*; do + sdirs="${sdirs}${sdirs:+ }$(unset SEARCH_DIRS; . "${x}"; echo "${SEARCH_DIRS}")" + sdirs_mask="${sdirs_mask}${sdirs_mask:+ }$(unset SEARCH_DIRS_MASK; . "${x}" ; echo "${SEARCH_DIRS_MASK}")" + ld_mask="${ld_mask}${ld_mask:+ }$(unset LD_LIBRARY_MASK; . "${x}"; echo "${LD_LIBRARY_MASK}")" + done +else + sdirs="${sdirs}${sdirs:+ }/bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*" + sdirs_mask="${sdirs_mask}${sdirs_mask:+ }/opt/OpenOffice /usr/lib/openoffice" + ld_mask="${ld_mask}${ld_mask:+ }libodbcinst.so libodbc.so libjava.so libjvm.so" +fi + +sdirs=$(find ${sdirs} -type d) + +einfo "Starting scan" +eindent +# Mark our masked dirs already scanned +scanned= +for dir in ${sdirs_mask}; do + scanned "${dir}" +done + +# Now scan our dirs +for dir in ${sdirs}; do + scanned "${dir}" && continue + + einfo "in ${dir}" + eindent + for x in "${dir}"/*; do + [ -d "${x}" ] && continue + [ -L "${x}" ] && continue + + scan=true + process=false + reason= + case "${x}" in + *.so|*.so.*) process=true;; + *.la) + scan=false + if [ -z "${libs}" ]; then + reason=$(la_broken "${x}") + [ $? = 0 ] && process=true + fi + ;; + esac + [ -x "${x}" ] && ${scan} && process=true + ${process} || continue + + if ${scan}; then + process=false + if [ -n "${libs}" ]; then + for lib in ${libs}; do + if [ "${lib#/}" != "${lib}" ]; then + # If lib starts with / then check if the exact + # lib is linked + elf_linked "${x}" "${lib}" || continue + fi + if elf_needed "${x}" ${lib}; then + process=true + break + fi + done + else + reason=$(elf_broken "${x}") + [ $? = 0 ] && process=true + fi + fi + + ${process} || continue + einfo "found ${x} ${reason}" + files="${files}${files:+:}${x}" + done + eoutdent +done +eoutdent + +if [ -z "${files}" ]; then + if [ -z "${libs}" ]; then + einfo "Nothing found that needs rebuilding" + else + einfo "No dynamic binaries found with these libraries" + fi + exit 0 +fi + +einfo "Assigning files to packages" +eindent +ebuilds=$(get_exact_ebuilds "${files}") + +if [ -z "${ebuilds}" ]; then + eerror "No packages own these files" + exit 1 +fi + +# Work out the best visible package for the slot +if ! ${exact}; then + root=$(portageq envvar ROOT) + root=${root:-/} + + set -- ${ebuilds} + ebuilds= + for x in "$@"; do + x=${x#=*} + pkg=${x%-r[0-9]*} + pkg=${pkg%-*} + slot=$(cat "/var/db/pkg/${x}/SLOT") + ebd=$(portageq best_visible "${root}" "${pkg}:${slot}") + if [ -z "${ebd}" ]; then + eerror "Cannot find an ebuild visible for ${x}" + else + ebuilds="${ebuilds}${ebuilds:+ }=${ebd}" + fi + done +fi +eoutdent + +# Work out the build order +if ${order}; then + einfo "Ordering packages" + order="$(EMERGE_DEFAULT_OPTS="" \ + emerge --nospinner --pretend --deep --quiet ${ebuilds})" + if [ $? = 0 ]; then + ebuilds=$(echo "${order}" | \ + sed -e 's:^\[.*\] \([^ ]*\)[ ].*$:=\1:' | \ + grep -F "$(printf "%s\n" ${ebuilds})" | \ + tr '\n' ' ') + else + eerror "Unable to order packages!" + fi +fi + +if [ -z "${ebuilds}" ]; then + eerror "Don't know how to find which package owns what file :/" + exit 1 +fi + +echo +einfo "About to execute" +echo "emerge --oneshot ${emerge_opts} ${ebuilds}" +echo + +i=5 +printf "in" +while [ ${i} -gt 0 ]; do + printf " ${i}" + sleep 1 + i=$((${i} - 1)) +done +printf "\n\n" + +EMERGE_DEFAULT_OPTS="" emerge --oneshot ${emerge_opts} ${ebuilds} +retval=$? + +if [ "${retval}" = 0 ]; then + einfo "All done" + exit 0 +fi + +eerror "There was an error trying to emerge the broken packages" +exit "${retval}" -- 2.26.2