/bin/sh version of revdep-rebuild - wrtten by uberlord
authorfuzzyray <fuzzyray@gentoo.org>
Wed, 10 Oct 2007 21:01:19 +0000 (21:01 -0000)
committerfuzzyray <fuzzyray@gentoo.org>
Wed, 10 Oct 2007 21:01:19 +0000 (21:01 -0000)
svn path=/; revision=453

trunk/src/revdep-rebuild/revdep-rebuild
trunk/src/revdep-rebuild/revdep-rebuild-sh [new file with mode: 0755]

index 40ccde7c37125b68b3f3dc62433474607621e58d..f71562fe98be98f7d23dc3183859d5cea79629e6 100755 (executable)
@@ -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 (executable)
index 0000000..92ed29f
--- /dev/null
@@ -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 <http://bugs.gentoo.org>
+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}"