aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/revdep-rebuild/revdep-rebuild-sh')
-rwxr-xr-xsrc/revdep-rebuild/revdep-rebuild-sh332
1 files changed, 332 insertions, 0 deletions
diff --git a/src/revdep-rebuild/revdep-rebuild-sh b/src/revdep-rebuild/revdep-rebuild-sh
new file mode 100755
index 0000000..c7acdc6
--- /dev/null
+++ b/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 <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}"