Move revdep-rebuild-rewrite to revdep-rebuild. Change Makefile to only install new...
authorfuzzyray <fuzzyray@gentoo.org>
Wed, 19 Sep 2007 18:12:02 +0000 (18:12 -0000)
committerfuzzyray <fuzzyray@gentoo.org>
Wed, 19 Sep 2007 18:12:02 +0000 (18:12 -0000)
svn path=/; revision=445

trunk/src/revdep-rebuild/Makefile
trunk/src/revdep-rebuild/revdep-rebuild
trunk/src/revdep-rebuild/revdep-rebuild-old [new file with mode: 0755]
trunk/src/revdep-rebuild/revdep-rebuild-rewrite [deleted file]

index 59c97c731588ba76094308d11e9ceab6e6828f4e..d5096811e215611864866d3bb7373c50ea0ce3be 100644 (file)
@@ -11,14 +11,11 @@ all:
 
 dist:
        mkdir -p ../../$(distdir)/src/revdep-rebuild
-       cp  Makefile AUTHORS README TODO ChangeLog revdep-rebuild revdep-rebuild.1 revdep-rebuild-rewrite find_pkgs.py 99revdep-rebuild ../../$(distdir)/src/revdep-rebuild/
+       cp  Makefile AUTHORS README TODO ChangeLog revdep-rebuild revdep-rebuild.1 99revdep-rebuild ../../$(distdir)/src/revdep-rebuild/
 
 install:
 
-       install -m 0755 revdep-rebuild-rewrite $(bindir)/revdep-rebuild
-       install -d $(DESTDIR)/usr/lib/gentoolkit/bin/
-       install -m 0755 find_pkgs.py $(DESTDIR)/usr/lib/gentoolkit/bin/
-       install -m 0755 revdep-rebuild $(DESTDIR)/usr/lib/gentoolkit/bin/
+       install -m 0755 revdep-rebuild $(bindir)/
        install -d $(docdir)/revdep-rebuild     
        install -m 0644 AUTHORS README TODO $(docdir)/revdep-rebuild/
        install -m 0644 revdep-rebuild.1 $(mandir)/
index 3115eb9a695e881b6cc1fe751a8c1f0fcf9174d4..19de90dc512ce369800e942785f63fe022992128 100755 (executable)
@@ -1,27 +1,39 @@
-#!/bin/bash 
+#!/bin/bash
 # Copyright 1999-2007 Gentoo Foundation
-# $Header$
 
 # revdep-rebuild: Reverse dependency rebuilder.
 # Original Author: Stanislav Brabec
+# Rewrite Author: Michael A. Smith
 # Current Maintainer: Paul Varner <fuzzyray@gentoo.org>
 
-# Known problems:
-#
-# In exact ebuild mode revdep-rebuild can fail to properly order packages,
-# which are not up to date.
-# http://bugs.gentoo.org/show_bug.cgi?id=23018
-#
-# Rebuilding using --package-names mode should be default, but emerge has no
-# feature to update to latest version of defined SLOT.
-# http://bugs.gentoo.org/show_bug.cgi?id=4698
-
-# Customizable variables:
-#
-# LD_LIBRARY_MASK - Mask of specially evaluated libraries
-# SEARCH_DIRS - List of directories to search for executables and libraries
-# SEARCH_DIRS_MASK - List of directories to not search
-#
+# TODO:
+# - Use more /etc/init.d/functions.sh
+# - Try to reduce the number of global vars
+
+##
+# Global Variables:
+
+# Readonly variables:
+declare -r APP_NAME="${0##*/}" # The name of this application
+declare -r OIFS="$IFS"         # Save the IFS
+
+# "Boolean" variables: Considered "true" if it has any value at all
+# "True" indicates we should...
+declare FULL_LD_PATH           # ...search across the COMPLETE_LD_LIBRARY_PATH
+declare KEEP_TEMP              # ...not delete tempfiles from the current run
+declare ORDER_PKGS             # ...sort the atoms in deep dependency order
+declare PACKAGE_NAMES          # ...emerge by slot, not by versionated atom
+declare RM_OLD_TEMPFILES       # ...remove tempfiles from prior runs
+declare SEARCH_BROKEN          # ...search for broken libraries and binaries
+declare VERBOSE                # ...give verbose output
+
+# Globals that impact portage directly:
+declare EMERGE_DEFAULT_OPTS    # String of options portage assumes to be set
+declare EMERGE_OPTIONS         # Array of options to pass to portage
+declare PORTAGE_NICENESS       # Renice to this value
+declare PORTAGE_ROOT           # The root path for portage
+
+# Customizable incremental variables:
 # These variables can be prepended to either by setting the variable in 
 # your environment prior to execution, or by placing an entry in
 # /etc/make.conf.
 # An entry of "-*" means to clear the variable from that point forward.
 # Example: env SEARCH_DIRS="/usr/bin -*" revdep-rebuild will set SEARCH_DIRS
 # to contain only /usr/bin
-
-if [ "$1" = "-h" -o "$1" = "--help" ]
-then
-       echo "Usage: $0 [OPTIONS] [--] [EMERGE_OPTIONS]"
-       echo
-       echo "Broken reverse dependency rebuilder."
-       echo
-       echo "  -X, --package-names  Emerge based on package names, not exact versions"
-       echo "      --library NAME   Emerge existing packages that use the library with NAME"
-       echo "      --library=NAME   NAME can be a full path to the library or a basic"
-       echo "                       regular expression (man grep)"
-       echo " -np, --no-ld-path     Do not set LD_LIBRARY_PATH"
-       echo " -nc, --nocolor        Turn off colored output"
-       echo "  -i, --ignore         Ignore temporary files from previous runs"
-       echo "  -q, --quiet          Be less verbose (also passed to emerge command)"
-       echo " -vv, --extra-verbose  Be extra verbose"
-       echo
-       echo "Calls emerge, all other options are used for it (e. g. -p, --pretend)."
+declare LD_LIBRARY_MASK  # Mask of specially evaluated libraries
+declare SEARCH_DIRS      # List of dirs to search for executables and libraries
+declare SEARCH_DIRS_MASK # List of dirs not to search
+
+# Other globals:
+declare OLDPROG                # Previous pass through the progress meter
+declare EXACT_PKG              # Versionated atom to emerge
+declare HEAD_TEXT              # Feedback string about the search
+declare LIST                   # Prefix for temporary filenames
+declare NOCOLOR                # Set to "true" not to output term colors
+declare OK_TEXT                # Feedback about a search which found no errors
+declare RC_NOCOLOR             # Hack to insure we respect NOCOLOR
+declare REBUILD_LIST           # Array of atoms to emerge
+declare SONAME                 # Soname/soname path pattern given on commandline
+declare SONAME_SEARCH          # Value of SONAME modified to match ldd's output
+declare WORKING_TEXT           # Feedback about the search
+declare ENV_FILE               # A file containing environment variables
+
+rm() {
+       local i
+       [[ $LIST && $APP_NAME ]] ||
+               die 1 '$LIST or $APP_NAME is not defined! (This is a bug.)'
+       for i; do
+               [[ $i = -* || $i = *.$APP_NAME* ]] || 
+                       die 1 "Oops, I'm not allowed to delete that. ($@)"
+       done
+       command rm "$@"
+}
+# Somewhat more portable find -executable
+# FIXME/UNTESTED (I don't have access to all of the different versions of 
+# find.)
+# Usage: find PATH ARGS -- use find like normal, except use -executable instead 
+# of various versions of -perm /+ blah blah and hacks
+find() {
+       hash find || { die 1 'find not found!'; }
+       # We can be pretty sure "$0" should be executable.
+       if [[ $(command find "$0" -executable 2> /dev/null) ]]; then
+               unset -f find # We can just use the command find
+       elif [[ $(command find "$0" -perm /u+x 2> /dev/null) ]]; then
+               find() {
+                       a=(${@//-executable/-perm \/u+x})
+                       a=(${a[@]//-writable/-perm \/u+w})
+                       a=(${a[@]//-readable/-perm \/r+w})
+                       command find "${a[@]}"
+               }
+       elif [[ $(command find "$0" -perm +u+x 2> /dev/null) ]]; then
+               find() {
+                       a=(${@//-executable/-perm +u+x})
+                       a=(${a[@]//-writable/-perm +u+w})
+                       a=(${a[@]//-readable/-perm +r+w})
+                       command find "${a[@]}"
+               }
+       else # Last resort
+               find() {
+                       a=(${@//-executable/-exec test -x '{}' \;})
+                       a=(${a[@]//-writable/-exec test -w '{}' \;})
+                       a=(${a[@]//-readable/-exec test -r '{}' \;})
+                       command find "${a[@]}"
+               }
+       fi
+       find "$@"
+}
+print_usage() {
+cat << EOF
+Usage: $APP_NAME [OPTIONS] [--] [EMERGE_OPTIONS]
+
+Broken reverse dependency rebuilder.
+
+  -h, --help           Print this usage
+  -k, --keep-temp      Do not delete temporary files on exit
+  -e, --exact          Emerge based on exact package version
+  -l, --no-ld-path     Do not set LD_LIBRARY_PATH
+  -C, --nocolor        Turn off colored output
+  -i, --ignore         Ignore temporary files from previous runs
+  -o, --no-order       Do not check the build order
+                       (Saves time, but may cause breakage.)
+  -P, --no-progress    Turn off the progress meter
+  -q, --quiet          Be less verbose (also passed to emerge command)
+  -v, --verbose        Be more verbose
+  -u, --no-util UTIL   Do not use features provided by UTIL
+      --no-util=UTIL   UTIL can be one of portage-utils or pkgcore
+                       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)
+
+Calls emerge, all other options are used for it (e. g. -p, --pretend).
+
+Report bugs to <http://bugs.gentoo.org>
+EOF
+}
+# Usage: progress i n
+#        i: current item
+#        n: total number of items to process
+progress() {
+       if [[ -t 1 ]]; then
+               progress() {
+                       local curProg=$(( $1 * 100 / $2 ))
+                       (( curProg == OLDPROG )) && return # no change, output nothing
+                       OLDPROG="$curProg" # must be a global variable
+                       (( $1 == $2 )) && local lb=$'\n'
+                       echo -ne '\r                         \r'"[ $curProg% ] $lb"
+               }
+               progress $@
+       else # STDOUT is not a tty. Disable progress meter.
+               progress() { :; }
+       fi
+}
+# Usage: countdown n
+#        n: number of seconds to count
+countdown() {
+       local i
+       for ((i=1; i<$1; i++)); do
+               echo -ne '\a.'
+               ((i<$1)) && sleep 1
+       done
+       echo -e '\a.'
+}
+# Get the name of a package owning a file on the filesystem using one of several
+# utilities: This is a placeholder. The function is defined in get_args()
+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() {
+       local a=$(echo ${@%%[[:space:]]-\*[[:space:]]*}) # Deliberately unquoted
+       # A benchmark shows this loop is faster than piping to sed,
+       # as long as there aren't more than a handful of '/' chars.
+       while [[ $a = *//* ]]; do a="${a//\/\///}"; done
+       sort -u <<< "${a// /$'\n'}"
+}
+# Exit and optionally output to sterr
+die() {
+       local status=$1
+       shift
+       eerror "$@"
+       exit $status
+}
+# What to do when dynamic linking is consistent
+clean_exit() {
+       [[ $KEEP_TEMP ]] || rm $LIST.?_*
        echo
-       echo "Report bugs to <http://bugs.gentoo.org>"
+       einfo "$OK_TEXT... All done. "
        exit 0
-fi
+}
+get_args() {
+       echo_v() { ewarn "$@"; }
+       unset VERBOSE KEEP_TEMP EMERGE_OPTIONS RM_OLD_TEMPFILES
+       ORDER_PKGS=1
+       PACKAGE_NAMES=1
+       SONAME="not found"
+       SEARCH_BROKEN=1
+       FULL_LD_PATH=1
+       local avoid_utils
+       while [[ $1 ]]; do
+               case $1 in
+               -h|--help)
+                       print_usage
+                       exit 0
+                       ;;
+               -e|--exact)
+                       unset PACKAGE_NAMES
+                       ;;
+               -o|--no-order)
+                       unset ORDER_PKGS
+                       ;;
+               -P|--no-progress)
+                       progress() { :; }
+                       ;;
+               -q|--quiet)
+                       echo_v() { :; }
+                       progress() { :; }
+                       quiet=1
+                       EMERGE_OPTIONS+=($1)
+                       ;;
+               -L=*|--library=*|--soname=*|--soname-regexp=*)
+                       SONAME="${1#*=}"
+                       unset SEARCH_BROKEN
+                       ;;
+               -L|--library|--soname|--soname-regexp)
+                       [[ ! $2 || $2 = -* ]] && die 1 "Missing expected argument to $1"
+                       shift
+                       SONAME="$1"
+                       unset SEARCH_BROKEN
+                       ;;
+               -u=*|--no-util=*)
+                       # TODO: check for invalid values
+                       avoid_utils="${1#*=}"
+                       ;;
+               -u|--no-util)
+                       [[ ! $2 || $2 = -* ]] && die 1 "Missing expected argument to $1"
+                       shift
+                       avoid_utils="$1"
+                       ;;
+               -nc|-C|--no-color|--nocolor)
+                       export NOCOLOR=yes
+                       ;;
+               -l|-np|--no-ld-path)
+                       unset FULL_LD_PATH
+                       ;;
+               -i|--ignore)
+                       RM_OLD_TEMPFILES=1
+                       ;;
+               -k|--keep-temp)
+                       KEEP_TEMP=1
+                       ;;
+               -vv|--extra-verbose|-v|--verbose)
+                       VERBOSE=1
+                       EMERGE_OPTIONS+=($1)
+                       ;;
+               -X|--package-names)
+                       # No longer used, since it is the default.
+                       # We accept it for backwards compatibility
+                       PACKAGE_NAMES=1
+                       ;;
+               --)
+                       ;;
+               *)
+                       EMERGE_OPTIONS+=($1)
+                       ;;
+               esac
+               shift
+       done
+       # Check if various utils are allowed and installed
+       if [[ $avoid_utils != *portage-utils* ]] && hash qfile 2> /dev/null; then
+               get_file_owner() { qfile -qvC "$@"; }
+       elif [[ $avoid_utils != *pkgcore* ]] && hash pquery 2> /dev/null; then
+               get_file_owner() { local IFS=,; pquery --nocolor --owns="$*"; }
+       # equery disabled for incompatibility with modern portage.
+       # elif [[ $avoid_utils != *equery* ]] && hash equery 2> /dev/null; then
+       #       get_file_owner() { equery -q -C b $@; }
+       else
+               get_file_owner() {
+                       local IFS=$'\n'
+                       find /var/db/pkg -name CONTENTS -print0 |
+                               xargs -0 grep -Fl "$*" |
+                               sed 's:/var/db/pkg/\(.*\)/CONTENTS:\1:'
+               }
+       fi
 
-echo "Configuring search environment for revdep-rebuild"
+       # Use the color preference from portage
+       export NOCOLOR=$(portageq envvar NOCOLOR)
+       [[ $NOCOLOR = yes || $NOCOLOR = true ]] && export RC_NOCOLOR=yes # HACK! (grr)
+       source /etc/init.d/functions.sh
+       
+       # Normalize some EMERGE_OPTIONS
+       EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-p/--pretend})
+       EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-f/--fetchonly})
+       EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-f/--verbose})
+       if [[ ${EMERGE_OPTIONS[@]} != *--pretend* && $UID -ne 0 ]]; then
+               ewarn "You are not superuser. Adding --pretend to emerge options."
+               EMERGE_OPTIONS+=(--pretend)
+       fi
+}
+is_real_merge() [[
+       ${EMERGE_OPTIONS[@]} != *--pretend* && ${EMERGE_OPTIONS[@]} != *--fetchonly*
+]]
+
+get_args "$@"
+
+einfo "Configuring search environment for $APP_NAME"
 
 # Obey PORTAGE_NICENESS
 PORTAGE_NICENESS=$(portageq envvar PORTAGE_NICENESS)
-if [ ! -z "$PORTAGE_NICENESS" ]
-then
+if [[ $PORTAGE_NICENESS ]]; then
        renice $PORTAGE_NICENESS $$ > /dev/null
        # Since we have already set our nice value for our processes,
        # reset PORTAGE_NICENESS to zero to avoid having emerge renice again.
@@ -65,7 +312,7 @@ then
 fi
 
 PORTAGE_ROOT=$(portageq envvar ROOT)
-[ -z "$PORTAGE_ROOT" ] && PORTAGE_ROOT="/"
+PORTAGE_ROOT="${PORTAGE_ROOT:-/}"
 
 # Update the incremental variables using /etc/profile.env, /etc/ld.so.conf,
 # portage, and the environment
@@ -73,675 +320,511 @@ PORTAGE_ROOT=$(portageq envvar ROOT)
 # Read the incremental variables from environment and portage
 # Until such time as portage supports these variables as incrementals
 # The value will be what is in /etc/make.conf
-PRELIMINARY_SEARCH_DIRS="$SEARCH_DIRS $(unset SEARCH_DIRS; portageq envvar SEARCH_DIRS)"
-PRELIMINARY_SEARCH_DIRS_MASK="$SEARCH_DIRS_MASK $(unset SEARCH_DIRS_MASK; portageq envvar SEARCH_DIRS_MASK)"
-PRELIMINARY_LD_LIBRARY_MASK="$LD_LIBRARY_MASK $(unset LD_LIBRARY_MASK; portageq envvar LD_LIBRARY_MASK)"
+SEARCH_DIRS+=" "$(unset SEARCH_DIRS; portageq envvar SEARCH_DIRS)
+SEARCH_DIRS_MASK+=" "$(unset SEARCH_DIRS_MASK; portageq envvar SEARCH_DIRS_MASK)
+LD_LIBRARY_MASK+=" "$(unset LD_LIBRARY_MASK; portageq envvar LD_LIBRARY_MASK)
 
 # Add the defaults
-if [ -d /etc/revdep-rebuild ]
-then
-       for file in $(ls /etc/revdep-rebuild)
-       do
-               PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS $(. /etc/revdep-rebuild/${file}; echo $SEARCH_DIRS)"
-               PRELIMINARY_SEARCH_DIRS_MASK="$PRELIMINARY_SEARCH_DIRS_MASK $(. /etc/revdep-rebuild/${file}; echo $SEARCH_DIRS_MASK)"
-               PRELIMINARY_LD_LIBRARY_MASK="$PRELIMINARY_LD_LIBRARY_MASK $(. /etc/revdep-rebuild/${file}; echo $LD_LIBRARY_MASK)"
+if [[ -d /etc/revdep-rebuild ]]; then
+       for ENV_FILE in /etc/revdep-rebuild/*; do
+               SEARCH_DIRS+=" "$(. $ENV_FILE; echo $SEARCH_DIRS)
+               SEARCH_DIRS_MASK+=" "$(. $ENV_FILE; echo $SEARCH_DIRS_MASK)
+               LD_LIBRARY_MASK+=" "$(. $ENV_FILE; echo $LD_LIBRARY_MASK)
        done
+       unset ENV_FILE # HACK
 else
-       PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS /bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*"
-       PRELIMINARY_SEARCH_DIRS_MASK="$PRELIMINARY_SEARCH_DIRS_MASK /opt/OpenOffice /usr/lib/openoffice"
-       PRELIMINARY_LD_LIBRARY_MASK="$PRELIMINARY_LD_LIBRARY_MASK libodbcinst.so libodbc.so libjava.so libjvm.so"
+       SEARCH_DIRS+=" /bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*"
+       SEARCH_DIRS_MASK+=" /opt/OpenOffice /usr/lib/openoffice"
+       LD_LIBRARY_MASK+=" libodbcinst.so libodbc.so libjava.so libjvm.so"
 fi
 
 # Get the ROOTPATH and PATH from /etc/profile.env
-if [ -e "/etc/profile.env" ]
-then
-       PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS $((. /etc/profile.env; echo ${ROOTPATH}:${PATH}) | tr ':' ' ')"
+if [[ -r "/etc/profile.env" && -s "/etc/profile.env" ]]; then
+       SEARCH_DIRS+=" "$(. /etc/profile.env; /usr/bin/tr ':' ' ' <<< "$ROOTPATH $PATH")
 fi
 
 # Get the directories from /etc/ld.so.conf
-if [ -e /etc/ld.so.conf ]
-then
-       PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS $(grep -v "^#" /etc/ld.so.conf | tr '\n' ' ')"
-fi     
-
-# Set the final variables
-# Note: Using $(echo $variable) removes extraneous spaces from variable assignment
-unset SEARCH_DIRS
-for i in $(echo $PRELIMINARY_SEARCH_DIRS)
-do
-       [ "$i" = "-*" ] && break
-       # Append a / at the end so that links and directories are treated the same by find
-       # Remove any existing trailing slashes to prevent double-slashes
-       SEARCH_DIRS="$(echo $SEARCH_DIRS ${i/%\//}/)"
-done
-# Remove any double-slashes from the path
-SEARCH_DIRS="$(echo $SEARCH_DIRS | sed 's:/\+:/:g')"
-
-unset SEARCH_DIRS_MASK
-for i in $(echo $PRELIMINARY_SEARCH_DIRS_MASK)
-do
-       [ "$i" = "-*" ] && break
-       SEARCH_DIRS_MASK="$(echo $SEARCH_DIRS_MASK $i)"
-done
-
-unset LD_LIBRARY_MASK
-for i in $(echo $PRELIMINARY_LD_LIBRARY_MASK)
-do
-       [ "$i" = "-*" ] && break
-       LD_LIBRARY_MASK="$(echo $LD_LIBRARY_MASK $i)"
-done
-
-# Use the color preference from portage
-NOCOLOR=$(portageq envvar NOCOLOR)
-
-# Base of temporary files names.
-touch ${HOME}/.revdep-rebuild_0.test 2>/dev/null
-if [ $? -eq 0 ]
-then
-       LIST="${HOME}/.revdep-rebuild"
-       rm ~/.revdep-rebuild_0.test
-else
-       # Try to use /var/tmp since $HOME is not available
-       touch /var/tmp/.revdep-rebuild_0.test 2>/dev/null
-       if [ $? -eq 0 ]
-       then
-               LIST="/var/tmp/.revdep-rebuild"
-               rm /var/tmp/.revdep-rebuild_0.test
-       else
-               echo
-               echo "!!! Unable to write temporary files to either $HOME or /var/tmp !!!"
-               echo
-               exit 1
-       fi
-fi
-
-shopt -s nullglob
-shopt -s expand_aliases
-unalias -a
-
-# Color Definitions
-NO="\x1b[0m"
-BR="\x1b[0;01m"
-CY="\x1b[36;01m"
-GR="\x1b[32;01m"
-RD="\x1b[31;01m"
-YL="\x1b[33;01m"
-BL="\x1b[34;01m"
-
-# Check if portage-utils are installed
-portageq has_version $PORTAGE_ROOT  portage-utils
-if [ "$?" -eq 0 ]
-then
-       PORTAGE_UTILS=true
-else
-       PORTAGE_UTILS=false
-fi
-
-alias echo_v=echo
-
-PACKAGE_NAMES=false
-SONAME="not found"
-SONAME_GREP=grep
-SEARCH_BROKEN=true
-EXTRA_VERBOSE=false
-KEEP_TEMP=false
-FULL_LD_PATH=true
-
-EMERGE_OPTIONS=""
-PRELIMINARY_CALLED_OPTIONS=""
-while [ ! -z "$1" ] ; do
-       case "$1" in
-       -X | --package-names )
-               PACKAGE_NAMES=true
-               PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --package_names"
-               shift
-               ;;
-       -q | --quiet )
-               alias echo_v=:
-               EMERGE_OPTIONS="${EMERGE_OPTIONS} $1"
-               shift
-               ;;
-       --library=* | --soname=* | --soname-regexp=* )
-               SONAME="${1#*=}"
-               SEARCH_BROKEN=false
-               PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --library=${SONAME}"
-               shift
-               ;;
-       --library | --soname | --soname-regexp )
-               SONAME="$2"
-               SEARCH_BROKEN=false
-               PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --library=${SONAME}"
-               shift 2
-               ;;
-       -nc | --no-color | --nocolor )
-               NOCOLOR=true
-               shift
-               ;;
-       -np | --no-ld-path )
-               FULL_LD_PATH=false
-               PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --no-ld-path"
-               shift
-               ;;
-       -i | --ignore )
-               rm -f ${LIST}*
-               shift
-               ;;
-       --keep-temp )
-               KEEPTEMP=true
-               shift
-               ;;
-       -vv | --extra-verbose )
-               EXTRA_VERBOSE=true
-               shift
-               ;;
-       -- )
-               shift
-               ;;
-       * )
-               EMERGE_OPTIONS="${EMERGE_OPTIONS} $1"
-               shift
-               ;;
-       esac
-done
-
-EMERGE_OPTIONS=$(echo $EMERGE_OPTIONS | sed 's/^ //')
-
-if [ -z "$PRELIMINARY_CALLED_OPTIONS" ]
-then
-       CALLED_OPTIONS=""
-else
-       for i in $(echo $PRELIMINARY_CALLED_OPTIONS | tr ' ' '\n'| sort)
-       do
-               CALLED_OPTIONS="$(echo $CALLED_OPTIONS $i)"
-       done
-fi
-
-if [ "$NOCOLOR" = "yes" -o "$NOCOLOR" = "true" ]
-then
-       NOCOLOR=true
-else
-       NOCOLOR=false
+if [[ -r /etc/ld.so.conf && -s /etc/ld.so.conf ]]; then
+       SEARCH_DIRS+=" "$(sed '/^#/d;s/#.*$//' /etc/ld.so.conf)
 fi
 
-# Make the NOCOLOR variable visible to emerge
-export NOCOLOR
-
-if $NOCOLOR
-then
-       NO=""
-       BR=""
-       CY=""
-       GR=""
-       RD=""
-       YL=""
-       BL=""
-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")
 
-function set_trap () {
+set_trap() {
        trap "rm_temp $1" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
 }
-
-function rm_temp () {
-       echo " terminated."
-       echo "Removing incomplete $1."
+rm_temp() {
        rm $1
-       echo
-       exit 1
+       die 1 $'  ...terminated. Removing incomplete '"$1."
 }
-
-if $SEARCH_BROKEN ; then
-       SONAME_SEARCH="$SONAME"
-       LLIST=$LIST
-       HEAD_TEXT="broken by a package update"
-       OK_TEXT="Dynamic linking on your system is consistent"
-       WORKING_TEXT=" consistency"
-else
-       # first case is needed to test against /path/to/foo.so
-       if [ ${SONAME:0:1} == '/' ] ; then 
-               # Set to "<space>$SONAME<space>"
-               SONAME_SEARCH=" $SONAME "
+get_search_env() {
+       local new_env
+       local old_env
+       # Find a place to put temporary files
+       # TODO; let the user choose where to put tempfiles
+       # gfind $HOME/ /var/tmp/ /tmp/ -writable -print -quit
+       # HACK: This is a rather noisy, but portable way to implement -quit
+       while read LIST; do
+               break # Set LIST
+       done < <(find $HOME/ /var/tmp/ /tmp/ -writable)
+       [[ $LIST ]] ||
+               die 1 "Unable to find a satisfactory location for temporary files"
+
+       LIST+=".$APP_NAME"
+       if [[ $SEARCH_BROKEN ]]; then
+               SONAME_SEARCH="$SONAME"
+               HEAD_TEXT="broken by a package update"
+               OK_TEXT="Dynamic linking on your system is consistent"
+               WORKING_TEXT="consistency"
        else
-               # Set to "<tab>$SONAME<space>"
-               SONAME_SEARCH=" $SONAME "
+               # first case is needed to test against /path/to/foo.so
+               if [[ $SONAME = /* ]]; then
+                       # Set to "<space>$SONAME<space>"
+                       SONAME_SEARCH=" $SONAME "
+                       # Escape the "/" characters
+                       SONAME_SEARCH="${SONAME_SEARCH//\//\\/}"
+               else
+                       # Set to "<tab>$SONAME<space>"
+                       SONAME_SEARCH=$'\t'"$SONAME "
+               fi
+               local uuid="${SONAME##*/}"
+               uuid="${uuid//[[:space:]]}"
+               LIST+="_$uuid"
+               HEAD_TEXT="using $SONAME"
+               OK_TEXT="There are no dynamic links to $SONAME"
+               unset WORKING_TEXT
        fi
-       LLIST=${LIST}_$(echo "$SONAME_SEARCH$SONAME" | md5sum | head -c 8)
-       HEAD_TEXT="using $SONAME"
-       OK_TEXT="There are no dynamic links to $SONAME"
-       WORKING_TEXT=""
-fi
 
-# If any of our temporary files are older than 1 day, remove them all
-[ "$(find "${LIST%/*}/." ! -name . -prune -name "${LIST##*/}*" -type f -mmin +1440)" != "" ] && rm -f ${LIST}*
-
-# Don't use our previous files if environment doesn't match
-if [ -f $LIST.0_env ]
-then
-       PREVIOUS_SEARCH_DIRS=$(. ${LIST}.0_env; echo "$SEARCH_DIRS")
-       PREVIOUS_SEARCH_DIRS_MASK=$(. ${LIST}.0_env; echo "$SEARCH_DIRS_MASK")
-       PREVIOUS_LD_LIBRARY_MASK=$(. ${LIST}.0_env; echo "$LD_LIBRARY_MASK")
-       PREVIOUS_PORTAGE_ROOT=$(. ${LIST}.0_env; echo "$PORTAGE_ROOT")
-       PREVIOUS_OPTIONS=$(. ${LIST}.0_env; echo "$CALLED_OPTIONS")
-       if [ "$PREVIOUS_SEARCH_DIRS" != "$SEARCH_DIRS" ] || \
-          [ "$PREVIOUS_SEARCH_DIRS_MASK" != "$SEARCH_DIRS_MASK" ] || \
-          [ "$PREVIOUS_LD_LIBRARY_MASK" != "$LD_LIBRARY_MASK" ] || \
-          [ "$PREVIOUS_PORTAGE_ROOT" != "$PORTAGE_ROOT" ] || \
-          [ "$PREVIOUS_OPTIONS" != "$CALLED_OPTIONS" ] 
-       then
-               echo
-               echo "Environment mismatch from previous run, deleting temporary files..."
-               rm -f ${LIST}*
+       # If any of our temporary files are older than 1 day, remove them all
+       if [[ ! $KEEP_TEMP ]]; then
+               while read; do
+                       RM_OLD_TEMPFILES=1
+                       break
+               done < <(find -L "$LIST."* -maxdepth 0 -type f -mmin +1440 -print 2>/dev/null)
        fi
-fi
-
-# Clean up no longer needed environment variables
-unset PREVIOUS_SEARCH_DIRS PREVIOUS_SEARCH_DIRS_MASK PREVIOUS_LD_LIBRARY_MASK PREVIOUS_PORTAGE_ROOT PREVIOUS_OPTIONS
-unset PRELIMINARY_SEARCH_DIRS PRELIMINARY_SEARCH_DIRS_MASK PRELIMINARY_LD_LIBRARY_MASK PRELIMINARY_CALLED_OPTIONS
-
-# Log our environment
-echo "SEARCH_DIRS=\"$SEARCH_DIRS\"" > $LIST.0_env
-echo "SEARCH_DIRS_MASK=\"$SEARCH_DIRS_MASK\"" >> $LIST.0_env
-echo "LD_LIBRARY_MASK=\"$LD_LIBRARY_MASK\"" >> $LIST.0_env
-echo "PORTAGE_ROOT=\"$PORTAGE_ROOT\"" >> $LIST.0_env
-echo "CALLED_OPTIONS=\"$CALLED_OPTIONS\"" >> $LIST.0_env
-echo "EMERGE_OPTIONS=\"$EMERGE_OPTIONS\"" >> $LIST.0_env
-
-if $EXTRA_VERBOSE
-then
-       echo
-       echo "revdep-rebuild environment:"
-       cat $LIST.0_env
-fi
-
-echo
-echo "Checking reverse dependencies..."
-echo
-echo "Packages containing binaries and libraries $HEAD_TEXT"
-echo "will be emerged."
-
-echo
-echo -n -e "${GR}Collecting system binaries and libraries...${NO}"
 
-if [ -f $LIST.1_files ]
-then
-       echo " using existing $LIST.1_files."
-else
-       # Be safe and remove any extraneous temporary files
-       rm -f ${LIST}.[1-9]_*
-
-       set_trap "$LIST.1_*"
-
-       # Hack for the different versions of find.
-       # Be extra paranoid and pipe results through sed to remove multiple slashes
-       find_results=$(find /usr/bin/revdep-rebuild -type f -perm /u+x 2>/dev/null)
-       if [ -z $find_results ]
-       then
-               find_results=$(find /usr/bin/revdep-rebuild -type f -perm +u+x 2>/dev/null)
-               if [ -z $find_results ]
-               then
-                       echo -e "\n"
-                       echo -e "${RD}Unable to determine how to use find to locate executable files${NO}"
-                       echo -e "${RD}Open a bug at http://bugs.gentoo.org${NO}"
-                       echo
-                       exit 1
-               else
-                       # using -perm +u+x for find command
-                       find $SEARCH_DIRS -type f \( -perm +u+x -o -name '*.so' -o -name '*.so.*' -o -name '*.la' \) 2>/dev/null | sort | uniq | sed 's:/\+:/:g' >$LIST.0_files
+       # Compare old and new environments
+       # Don't use our previous files if environment doesn't match
+       new_env=$(
+               # We do not care if these emerge options change
+               EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--pretend/})
+               EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--fetchonly/})
+               EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--verbose/})
+               cat <<- EOF
+                       SEARCH_DIRS="$SEARCH_DIRS"
+                       SEARCH_DIRS_MASK="$SEARCH_DIRS_MASK"
+                       LD_LIBRARY_MASK="$LD_LIBRARY_MASK"
+                       PORTAGE_ROOT="$PORTAGE_ROOT"
+                       EMERGE_OPTIONS="${EMERGE_OPTIONS[@]}"
+                       ORDER_PKGS="$ORDER_PKGS"
+                       FULL_LD_PATH="$FULL_LD_PATH"
+               EOF
+       )
+       if [[ -r $LIST.0_env && -s $LIST.0_env ]]; then
+               old_env=$(<"$LIST.0_env")
+               if [[ $old_env != $new_env ]]; then
+                       ewarn 'Environment mismatch from previous run, deleting temporary files...'
+                       RM_OLD_TEMPFILES=1
                fi
        else
-               # using -perm /u+x for find command
-               find $SEARCH_DIRS -type f \( -perm /u+x -o -name '*.so' -o -name '*.so.*' -o -name '*.la' \) 2>/dev/null | sort | uniq | sed 's:/\+:/:g' >$LIST.0_files
+               # No 0_env file found, silently delete any other tempfiles that may exist
+               RM_OLD_TEMPFILES=1
        fi
 
-       # Remove files that match SEARCH_DIR_MASK
-       for dir in $SEARCH_DIRS_MASK
-       do
-               grep -v "^$dir" $LIST.0_files > $LIST.1_files
-               mv $LIST.1_files $LIST.0_files
-       done
+       # If we should remove old tempfiles, do so
+       [[ $RM_OLD_TEMPFILES ]] && rm -f "$LIST."*
        
-       mv $LIST.0_files $LIST.1_files
-       echo -e " done.\n  ($LIST.1_files)"
-fi
+       # Save the environment in a file for next time
+       echo "$new_env" > "$LIST.0_env"
+
+       [[ $VERBOSE ]] && echo $'\n'"$APP_NAME environment:"$'\n'"$new_env"
 
-if $SEARCH_BROKEN && $FULL_LD_PATH ; then
        echo
-       echo -n -e "${GR}Collecting complete LD_LIBRARY_PATH...${NO}"
-       if [ -f $LIST.2_ldpath ] ; then
-               echo " using existing $LIST.2_ldpath."
+       einfo "Checking reverse dependencies"
+       einfo "Packages containing binaries and libraries $HEAD_TEXT"
+       einfo "will be emerged."
+}
+get_files() {
+       einfo "Collecting system binaries and libraries"
+       if [[ -r $LIST.1_files && -s $LIST.1_files ]]; then
+               einfo "Found existing $LIST.1_files"
+       else
+               # Be safe and remove any extraneous temporary files
+               rm -f $LIST.[1-9]_*
+
+               set_trap "$LIST.1_*"
+
+               if [[ $SEARCH_DIRS_MASK ]]; then
+                       findMask=($SEARCH_DIRS_MASK)
+                       findMask="${findMask[@]/#/-o -path }"
+                       findMask="( ${findMask#-o } ) -prune -o"
+               fi
+               find ${SEARCH_DIRS[@]} $findMask -type f \( -executable -o \
+                       -name '*.so' -o -name '*.so.*' -o -name '*.la' \) -print 2> /dev/null |
+                       sort -u > "$LIST.1_files" ||
+                       die $? "find failed to list binary files (This is a bug.)"
+               einfo "Generated new $LIST.1_files"
+       fi
+}
+get_ldpath() {
+       local COMPLETE_LD_LIBRARY_PATH
+       [[ $SEARCH_BROKEN && $FULL_LD_PATH ]] || return
+       einfo 'Collecting complete LD_LIBRARY_PATH'
+       if [[ -r $LIST.2_ldpath && -s $LIST.2_ldpath ]] ; then
+               einfo "Found existing $LIST.2_ldpath."
        else
                set_trap "$LIST.2_ldpath"
                # Ensure that the "trusted" lib directories are at the start of the path
-               (
-                       echo /lib* /usr/lib* | sed 's/ /:/g'
-                       sed '/^#/d;s/#.*$//' </etc/ld.so.conf
-                       sed 's:/[^/]*$::' <$LIST.1_files | sort -ru
-               ) | tr '\n' : | tr -d '\r' | sed 's/:$//' >$LIST.2_ldpath
-               echo -e " done.\n  ($LIST.2_ldpath)"
+               COMPLETE_LD_LIBRARY_PATH=(
+                       /lib*
+                       /usr/lib*
+                       $(sed '/^#/d;s/#.*$//' < /etc/ld.so.conf)
+                       $(sed 's:/[^/]*$::' < "$LIST.1_files" | sort -ru)
+               )
+               IFS=':'
+               COMPLETE_LD_LIBRARY_PATH="${COMPLETE_LD_LIBRARY_PATH[*]}"
+               IFS="$OIFS"
+               echo "$COMPLETE_LD_LIBRARY_PATH" > "$LIST.2_ldpath"
+               einfo "Generated new $LIST.2_ldpath"
        fi
-       COMPLETE_LD_LIBRARY_PATH="$(cat $LIST.2_ldpath)"
-fi
-
-echo
-echo -n -e "${GR}Checking dynamic linking$WORKING_TEXT...${NO}"
-if [ -f $LLIST.3_rebuild ] ; then
-       echo " using existing $LLIST.3_rebuild."
-else
-       echo_v
-       set_trap "$LLIST.3_rebuild"
-       LD_MASK="\\(    $(echo "$LD_LIBRARY_MASK" | sed 's/\./\\./g;s/ / \\|    /g') \\)"
-       echo -n >$LLIST.3_rebuild
-       echo -n >$LLIST.3_ldd_errors
-       cat $LIST.1_files | egrep -v '*\.la$' | while read FILE ; do
-       # Note: double checking seems to be faster than single
-       # with complete path (special add ons are rare).
-       if ldd "$FILE" 2>>$LLIST.3_ldd_errors | grep -v "$LD_MASK" | $SONAME_GREP -q "$SONAME_SEARCH" ; then
-               if $SEARCH_BROKEN && $FULL_LD_PATH ; then
-                       if LD_LIBRARY_PATH="$COMPLETE_LD_LIBRARY_PATH" ldd "$FILE" 2>/dev/null | grep -v "$LD_MASK" | $SONAME_GREP -q "$SONAME_SEARCH" ; then
-                               # FIX: I hate duplicating code
-                               # Only build missing direct dependencies
-                               ALL_MISSING_LIBS=$(ldd "$FILE" 2>/dev/null | sort -u | sed -n 's/       \(.*\) => not found/\1/p' | tr '\n' ' ' | sed 's/ $//' )
-                               REQUIRED_LIBS=$(objdump -x $FILE | grep NEEDED | awk '{print $2}' | tr '\n' ' ' | sed 's/ $//')
-                               MISSING_LIBS=""
-                               for lib in $ALL_MISSING_LIBS
-                               do
-                                       if echo $REQUIRED_LIBS | grep -q $lib
-                                       then
-                                               MISSING_LIBS="$MISSING_LIBS $lib"
+}
+main_checks() {
+       local target_file
+       local -a files
+       local i=0
+       local ldd_output
+       local ldd_status
+       local numFiles
+       local COMPLETE_LD_LIBRARY_PATH
+       if [[ $SEARCH_BROKEN && $FULL_LD_PATH ]]; then
+               [[ -r $LIST.2_ldpath && -s $LIST.2_ldpath ]] || die 1 "unable to find $LIST.2_ldpath"
+               COMPLETE_LD_LIBRARY_PATH=$(<"$LIST.2_ldpath")
+       fi
+       einfo "Checking dynamic linking $WORKING_TEXT"
+       if [[ -r $LIST.3_rebuild && -s $LIST.3_rebuild ]]; then
+               einfo "Found existing $LIST.3_rebuild."
+       else
+               [[ $LIST ]] || die 1 "$LIST" 'is undefined! (This is a bug.)'
+               set_trap "$LIST.3_rebuild"
+               set_trap "$LIST.3_ldd_errors"
+               rm -f "$LIST.3"*
+               files=($(<"$LIST.1_files"))
+               numFiles="${#files[@]}"
+               for target_file in "${files[@]}"; do
+                       if [[ $target_file != *.la ]]; then
+                               # Note: double checking seems to be faster than single with complete path
+                               # (special add ons are rare).
+                               ldd_output=$(ldd "$target_file" 2>> "$LIST.3_ldd_errors" | sort -u)
+                               ldd_status=$? # TODO: Check this for problems with sort
+                               # HACK: if LD_LIBRARY_MASK is null or undefined grep -vF doesn't work
+                               if grep -vF "${LD_LIBRARY_MASK:=$'\a'}" <<< "$ldd_output" |
+                                       grep -q "$SONAME_SEARCH"; then
+                                       if [[ $SEARCH_BROKEN && $FULL_LD_PATH ]]; then
+                                               if LD_LIBRARY_PATH="$COMPLETE_LD_LIBRARY_PATH" ldd "$target_file" 2>/dev/null |
+                                                       grep -vF "$LD_LIBRARY_MASK" | grep -q "$SONAME_SEARCH"; then
+                                                       # FIXME: I hate duplicating code
+                                                       # Only build missing direct dependencies
+                                                       MISSING_LIBS=$(
+                                                               expr='s/[[:space:]]*\([^[:space:]]*\) => not found/\1/p'
+                                                               sed -n "$expr" <<< "$ldd_output"
+                                                       )
+                                                       REQUIRED_LIBS=$(
+                                                               expr='s/^[[:space:]]*NEEDED[[:space:]]*\([^[:space:]]*\).*/\1/p';
+                                                               objdump -x "$target_file" | grep NEEDED | sed "$expr" | sort -u
+                                                       )
+                                                       MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS")
+                                                       if [[ $MISSING_LIBS ]]; then
+                                                               echo "obj $target_file" >> "$LIST.3_rebuild"
+                                                               echo_v "  broken $target_file (requires $MISSING_LIBS)"
+                                                       fi
+                                               fi
+                                       else
+                                               # FIXME: I hate duplicating code
+                                               # Only rebuild for direct dependencies
+                                               MISSING_LIBS=$(
+                                                       expr="/$SONAME_SEARCH/s/^[[:space:]]*\([^[:space:]]*\).*$/\1/p"
+                                                       sort -u <<< "$ldd_output" | sed -n "$expr"
+                                               )
+                                               REQUIRED_LIBS=$(
+                                                       expr='s/^[[:space:]]*NEEDED[[:space:]]*\([^[:space:]]*\).*/\1/p';
+                                                       objdump -x "$target_file" | grep NEEDED | sed "$expr" | sort -u
+                                               )
+                                               MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS")
+                                               if [[ $MISSING_LIBS ]]; then
+                                                       echo "obj $target_file" >> "$LIST.3_rebuild"
+                                                       if [[ $SEARCH_BROKEN ]]; then
+                                                               echo_v "  broken $target_file (requires $MISSING_LIBS)"
+                                                       else
+                                                               echo_v "  found $target_file"
+                                                       fi
+                                               fi
                                        fi
-                               done
-                               if [ "$MISSING_LIBS" != "" ]
-                               then
-                                       echo "obj $FILE" >>$LLIST.3_rebuild
-                                       echo_v "  broken $FILE (requires ${MISSING_LIBS})"
-                               fi
-                       fi
-               else
-                       # FIX: I hate duplicating code
-                       # Only rebuild for direct dependencies
-                       ALL_MISSING_LIBS=$(ldd "$FILE" 2>/dev/null | sort -u | $SONAME_GREP "$SONAME_SEARCH" | awk '{print $1}' | tr '\n' ' ' | sed 's/ $//' )
-                       REQUIRED_LIBS=$(objdump -x $FILE | grep NEEDED | awk '{print $2}' | tr '\n' ' ' | sed 's/ $//')
-                       MISSING_LIBS=""
-                       for lib in $ALL_MISSING_LIBS
-                       do
-                               if echo $REQUIRED_LIBS | grep -q $lib
-                               then
-                                       MISSING_LIBS="$MISSING_LIBS $lib"
-                               fi
-                       done
-                       if [ "$MISSING_LIBS" != "" ]
-                       then
-                               echo "obj $FILE" >>$LLIST.3_rebuild
-                               if $SEARCH_BROKEN ; then
-                                       echo_v "  broken $FILE (requires ${MISSING_LIBS})"
-                               else
-                                       echo_v "  found $FILE"
                                fi
+                       elif [[ $SEARCH_BROKEN ]]; then
+                               # Look for broken .la files
+                               for depend in $(
+                                       awk -F"[=']" '/^dependency_libs/{
+                                               gsub("^-[^[:space:]]*", "", $3);
+                                               gsub("[[:space:]]-[^[:space:]]*", "", $3);
+                                               print $3
+                                       }' "$target_file"
+                               ); do
+                                       if [[ $depend = /* && ! -e $depend ]]; then
+                                               echo "obj $target_file" >> "$LIST.3_rebuild"
+                                               echo_v "  broken $target_file (requires $depend)"
+                                       fi
+                               done
                        fi
-               fi
-       fi
-       done
-       if $SEARCH_BROKEN ; then
-               # Look for missing version
-               for FILE in $(grep "no version information available" $LLIST.3_ldd_errors | awk '{print $NF}' | sed 's/[()]//g' | sort -u) ; do
-                       echo "obj $FILE" >>$LLIST.3_rebuild
-                       echo_v "  broken $FILE (no version information available)"
-               done
-               # Look for broken .la files
-               cat $LIST.1_files | egrep '*\.la$' | while read FILE ; do
-                       for depend in $(grep '^dependency_libs' $FILE | awk -F'=' '{print $2}' | sed "s/'//g") ; do
-                               [ ${depend:0:1} != '/' ] && continue
-                               if [ ! -e $depend ] ; then
-                                       echo "obj $FILE" >>$LLIST.3_rebuild
-                                       echo_v "  broken $FILE (requires ${depend})"
-                               fi
-                       done
+                       [[ $VERBOSE ]] &&
+                               progress $((++i)) $numFiles $target_file ||
+                               progress $((++i)) $numFiles
                done
+               if [[ $SEARCH_BROKEN ]]; then
+                       # Look for missing version
+                       while read target_file; do
+                               echo "obj $target_file" >> "$LIST.3_rebuild"
+                               echo_v "  broken $target_file (no version information available)"
+                       done < <(
+                               # Regexify LD_LIBRARY_MASK. Exclude it from the search.
+                               LD_LIBRARY_MASK="${LD_LIBRARY_MASK//$'\n'/|}"
+                               awk -v ldmask="(${LD_LIBRARY_MASK//./\\\.})" '
+                                       /no version information available/ && $0 !~ ldmask {
+                                               gsub(/[()]/, "", $NF)
+                                               if (seen[$NF]++)  next
+                                               print $NF
+                                       }' "$LIST.3_ldd_errors"
+                       )
+               fi
+               [[ -r $LIST.3_rebuild && -s $LIST.3_rebuild ]] || clean_exit
+               einfo "Generated new $LIST.3_rebuild"
        fi
-       echo -e " done.\n  ($LLIST.3_rebuild)"
-fi
-
-if $PACKAGE_NAMES ; then
-       EXACT_EBUILDS=false
-
-       echo
-       echo -n -e "${GR}Assigning files to packages...${NO}"
-       if [ -f $LLIST.4_packages_raw ] ; then
-               echo " using existing $LLIST.4_packages_raw."
+}
+get_packages() {
+       local target_file
+       local EXACT_PKG
+       local PKG
+       local obj
+       einfo 'Assigning files to packages'
+       if [[ -r $LIST.4_packages_raw && -s $LIST.4_packages_raw ]]; then
+               einfo "Found existing $LIST.4_packages_raw"
        else
-               set_trap "$LLIST.4_packages*"
-               echo -n >$LLIST.4_packages_raw
-               echo -n >$LLIST.4_package_owners
-               cat $LLIST.3_rebuild | while read obj FILE ; do
-                       if $PORTAGE_UTILS ; then
-                               EXACT_PKG="$(qfile -qvC ${FILE} )"
+               set_trap "$LIST.4_packages*"
+               rm -f $LIST.4*
+               while read obj target_file; do
+                       EXACT_PKG=$(get_file_owner $target_file)
+                       if [[ $EXACT_PKG ]]; then
+                               # Strip version information
+                               PKG="${EXACT_PKG%%-r[[:digit:]]*}"
+                               PKG="${PKG%-*}"
+                               echo "$EXACT_PKG" >> $LIST.4_packages_raw
+                               echo "$target_file -> $EXACT_PKG" >> $LIST.4_package_owners
+                               echo_v "  $target_file -> $PKG"
                        else
-                               EXACT_PKG=$(find /var/db/pkg -name CONTENTS | xargs fgrep -l "obj $FILE " | sed -e 's:/var/db/pkg/\(.*\)/CONTENTS:\1:g')
+                               ewarn " !!! $target_file not owned by any package is broken !!!"
+                               echo "$target_file -> (none)" >> $LIST.4_package_owners
+                               echo_v "  $target_file -> (none)"
                        fi
-                       # Ugly sed hack to strip version information
-                       PKG="$(echo $EXACT_PKG | sed 's/-r[0-9].*$//;s/\(^.*\/*\)-.*$/\1/')"
-                       if [ -z "$PKG" ] ; then
-                               echo -n -e "\n  ${RD}*** $FILE not owned by any package is broken! ***${NO}"
-                               echo "$FILE -> (none)" >> $LLIST.4_package_owners
-                               echo_v -n -e "\n  $FILE -> (none)"
-                       else
-                               echo "$EXACT_PKG" >> $LLIST.4_packages_raw
-                               echo "$FILE -> $EXACT_PKG" >> $LLIST.4_package_owners
-                               echo_v -n -e "\n  $FILE -> $PKG"
-                       fi
-               done
-               echo_v
-               echo -e " done.\n  ($LLIST.4_packages_raw, $LLIST.4_package_owners)"
+               done < "$LIST.3_rebuild"
+               einfo "Generated new $LIST.4_packages_raw and $LIST.4_package_owners"
        fi
-
-       echo
-       echo -n -e "${GR}Cleaning list of packages to rebuild...${NO}"
-       if [ -f $LLIST.4_packages ] ; then
-               echo " using existing $LLIST.4_packages."
-       else
-               sort -u $LLIST.4_packages_raw >$LLIST.4_packages
-               echo -e " done.\n  ($LLIST.4_packages)"
+       # if we find '(none)' on every line, exit out
+       if ! grep -qvF '(none)' "$LIST.4_package_owners"; then
+               ewarn "Found some broken files, but none of them were associated with known packages"
+               ewarn "Unable to proceed with automatic repairs."
+               ewarn "The broken files are listed in $LIST.4_package_owners"
+               if [[ $VERBOSE ]]; then
+                       ewarn "The broken files are:"
+                       while read filename junk; do
+                               ewarn "  $filename"
+                       done < "$LIST.4_package_owners"
+               fi
+               exit 0 # FIXME: Should we exit 1 here?
        fi
-
-       echo
-       echo -n -e "${GR}Assigning packages to ebuilds...${NO}"
-       if [ -f $LLIST.4_ebuilds ] ; then
-               echo " using existing $LLIST.4_ebuilds."
+}
+clean_packages() {
+       einfo 'Cleaning list of packages to rebuild'
+       if [[ -r $LIST.4_packages && -s $LIST.4_packages ]]; then
+               einfo "Found existing $LIST.4_packages"
        else
-               if [ -s "$LLIST.4_packages" ]
-               then
-                       set_trap "$LLIST.4_ebuilds"
-                       cat $LLIST.4_packages | while read EXACT_PKG
-                       do
+               sort -u $LIST.4_packages_raw > $LIST.4_packages
+               einfo "Generated new $LIST.4_packages"
+       fi
+}
+assign_packages_to_ebuilds() {
+       local EXACT_PKG
+       local PKG
+       local SLOT
+       einfo 'Assigning packages to ebuilds'
+       if [[ -r $LIST.4_ebuilds && -s $LIST.4_ebuilds ]]; then
+               einfo "Found existing $LIST.4_ebuilds"
+       elif [[ -r $LIST.4_packages && -s $LIST.4_packages ]]; then
+                       set_trap "$LIST.4_ebuilds"
+                       while read EXACT_PKG; do
                                # Get the slot
-                               PKG="$(echo $EXACT_PKG | sed 's/-r[0-9].*$//;s/\(^.*\/*\)-.*$/\1/')"
-                               SLOT=$(cat /var/db/pkg/${EXACT_PKG}/SLOT)
-                               OTHER_VERSIONS=$(/usr/lib/gentoolkit/bin/find_pkgs.py $PKG | grep -v "($SLOT)" | awk '{print $2}')
-                               # If SLOT is equal to 0, then just see what portage says is latest version
-                               if [ "$SLOT" = "0" -o "x$OTHER_VERSIONS" = "x" ]
-                               then
-                                       best_visible=$(portageq best_visible $PORTAGE_ROOT $PKG)
-                                       [ "x" != "x$best_visible" ] && echo $best_visible
-                                       continue
-                               fi
-                               # Otherwise mask the other SLOTTED versions and check for latest
-                               if [ -e /etc/portage/package.mask ]
-                               then
-                                       mv -f /etc/portage/package.mask /etc/portage/package.mask.revdep-rebuild.backup
-                               else
-                                       # Make sure that /etc/portage/package.mask exists
-                                       mkdir -p /etc/portage
-                                       touch /etc/portage/package.mask
-                               fi
-                               for pkg_version in $(echo $OTHER_VERSIONS | tr '\n' ' ') 
-                               do
-                                       echo "=${PKG}-${pkg_version}" >> /etc/portage/package.mask
-                               done
-                               best_visible=$(portageq best_visible $PORTAGE_ROOT $PKG)
-                               [ "x" != "x$best_visible" ] && echo $best_visible
-                               rm -f /etc/portage/package.mask
-                               if [ -e /etc/portage/package.mask.revdep-rebuild.backup ]
-                               then
-                                       mv -f /etc/portage/package.mask.revdep-rebuild.backup /etc/portage/package.mask
-                               fi
-                       done > $LLIST.4_ebuilds
-                       echo -e " done.\n  ($LLIST.4_ebuilds)"
-               else
-                       echo " Nothing to rebuild"
-                       echo -n > $LLIST.4_ebuilds
-               fi
+                               PKG="${EXACT_PKG%%-r[[:digit:]]*}"
+                               PKG="${PKG%-*}"
+                               SLOT=$(</var/db/pkg/$EXACT_PKG/SLOT)
+                               portageq best_visible $PORTAGE_ROOT $PKG:$SLOT
+                       done < "$LIST.4_packages" > "$LIST.4_ebuilds"
+                       einfo "Generated new $LIST.4_ebuilds"
+       else
+               einfo 'Nothing to rebuild.'
+               die 1 '(The program should have already quit, so this is a minor bug.)'
        fi
-else
-       EXACT_EBUILDS=true
-
-       echo
-       echo -n -e "${GR}Assigning files to ebuilds...${NO}"
-       if [ -f $LLIST.4_ebuilds ] ; then
-               echo " using existing $LLIST.4_ebuilds."
+}
+get_exact_ebuilds() {
+       einfo 'Assigning files to ebuilds'
+       if [[ -r $LIST.4_ebuilds && -s $LIST.4_ebuilds ]]; then
+               einfo "Found existing $LIST.4_ebuilds"
+       elif [[ -r $LIST.3_rebuild && -s $LIST.3_rebuild ]]; then
+               rebuildList=" $(<"$LIST.3_rebuild") "
+               rebuildList=(${rebuildList//[[:space:]]obj[[:space:]]/ })
+               get_file_owner "${rebuildList[@]}" > $LIST.4_ebuilds
+               einfo "Generated new $LIST.4_ebuilds"
        else
-               if [ -s "$LLIST.3_rebuild" ] ; then
-                       set_trap "$LLIST.4_ebuilds"
-                       find /var/db/pkg -name CONTENTS | xargs fgrep -l -f $LLIST.3_rebuild |
-                       sed 's:/var/db/pkg/\(.*\)/CONTENTS:\1:' > $LLIST.4_ebuilds
-                       echo -e " done.\n  ($LLIST.4_ebuilds)"
+               einfo 'Nothing to rebuild.'
+               die 1 '(The program should have already quit, so this is a minor bug.)'
+       fi
+}
+get_build_order() {
+       local -r OLD_EMERGE_DEFAULT_OPTS="$EMERGE_DEFAULT_OPTS"
+       local RAW_REBUILD_LIST
+       local REBUILD_GREP
+       local i
+       if [[ ! $ORDER_PKGS ]]; then
+               einfo 'Skipping package ordering'
+               return
+       fi
+       einfo 'Evaluating package order'
+       if [[ -r $LIST.5_order && -s $LIST.5_order ]]; then
+               einfo "Found existing $LIST.5_order"
+       else
+               set_trap "$LIST.5_order"
+               RAW_REBUILD_LIST=$(<"$LIST.4_ebuilds")
+               if [[ $RAW_REBUILD_LIST ]]; then
+                       export EMERGE_DEFAULT_OPTS="--nospinner --pretend --oneshot --quiet"
+                       RAW_REBUILD_LIST=($RAW_REBUILD_LIST)
+                       RAW_REBUILD_LIST="${RAW_REBUILD_LIST[@]/#/=}"
+                       REBUILD_GREP=$(emerge --nodeps $RAW_REBUILD_LIST | sed 's/\[[^]]*\]//g') &&
+                               emerge --deep $RAW_REBUILD_LIST | sed 's/\[[^]]*\]//g' |
+                               grep -F "$REBUILD_GREP" > $LIST.5_order || {
+                                       eerror
+                                       eerror 'Warning: Failed to resolve package order.'
+                                       eerror 'Will merge in arbitrary order'
+                                       eerror
+                                       cat <<- EOF
+                                               Possible reasons:
+                                               - An ebuild is no longer in the portage tree.
+                                               - An ebuild is masked, use /etc/portage/packages.keyword
+                                                       and/or /etc/portage/package.unmask to unmask it
+                                       EOF
+                                       countdown 5
+                                       rm -f "$LIST.5_order"
+                               }
+                       export EMERGE_DEFAULT_OPTS="$OLD_EMERGE_DEFAULT_OPTS"
                else
-                       echo " Nothing to rebuild"
-                       echo -n > $LLIST.4_ebuilds
+                       einfo 'Nothing to rebuild.'
+                       die 1 '(The program should have already quit, so this is a minor bug.)'
                fi
        fi
+       [[ -r $LIST.5_order && -s $LIST.5_order ]] && einfo "Generated new $LIST.5_order"
+}
 
-fi
-
+get_search_env
+echo
+get_files
 echo
-echo -n -e "${GR}Evaluating package order...${NO}"
-if [ -f $LLIST.5_order ] ; then
-       echo " using existing $LLIST.5_order."
+get_ldpath
+echo
+main_checks
+echo
+if [[ $PACKAGE_NAMES ]]; then
+       get_packages
+       echo
+       clean_packages
+       echo
+       assign_packages_to_ebuilds
 else
-       set_trap "$LLIST.5_order"
-       RAW_REBUILD_LIST="$(cat $LLIST.4_ebuilds | sed s/^/=/ | tr '\n' ' ')"
-       if [ ! -z "$RAW_REBUILD_LIST" ] ; then
-               REBUILD_GREP="^\\($( (EMERGE_DEFAULT_OPTS="" emerge --nospinner --pretend --oneshot --nodeps --quiet $RAW_REBUILD_LIST ; echo $? >$LLIST.5a_status ) | sed -n 's/\./\\&/g;s/ //g;s/$/\\/;s/\[[^]]*\]//gp' | tr '\n' '|' | sed 's/|$//'))\$"
-               if [ $(cat $LLIST.5a_status) -gt 0 ] ; then
-                       echo ""
-                       echo -e "${RD}Warning: Failed to resolve package order."
-                       echo -e "Will merge in \"random\" order!${NO}"
-                       echo "Possible reasons:"
-                       echo "- An ebuild is no longer in the portage tree."
-                       echo "- An ebuild is masked, use /etc/portage/packages.keyword"
-                       echo "  and/or /etc/portage/package.unmask to unmask it"
-                       for i in . . . . . ; do
-                               echo -n -e '\a.'
-                               sleep 1
-                       done
-                       ln -f $LLIST.4_ebuilds $LLIST.5_order
-               else
-                       (EMERGE_DEFAULT_OPTS="" emerge --nospinner --pretend --oneshot --deep --quiet $RAW_REBUILD_LIST ; echo $? >$LLIST.5b_status ) | sed -n 's/  *$//;s/^\[.*\] //p' | awk '{print $1}' | grep "$REBUILD_GREP" >$LLIST.5_order
-                       if [ $(cat $LLIST.5b_status) -gt 0 ] ; then
-                               echo ""
-                               echo -e "${RD}Warning: Failed to resolve package order."
-                               echo -e "Will merge in \"random\" order!${NO}"
-                               echo "Possible reasons:"
-                               echo "- An ebuild is no longer in the portage tree."
-                               echo "- An ebuild is masked, use /etc/portage/packages.keyword"
-                               echo "  and/or /etc/portage/package.unmask to unmask it"
-                               for i in . . . . . ; do
-                                       echo -n -e '\a.'
-                                       sleep 1
-                               done
-                               rm -f $LLIST.5_order
-                               ln -f $LLIST.4_ebuilds $LLIST.5_order
-                       fi
-               fi
-       else
-               echo -n "" >$LLIST.5_order
-       fi
-       echo -e " done.\n  ($LLIST.5_order)"
+       get_exact_ebuilds
 fi
+echo
+get_build_order
+echo
 
 # Clean up no longer needed environment variables
-unset COMPLETE_LD_LIBRARY_PATH SEARCH_DIRS SEARCH_DIRS_MASK LD_LIBRARY_MASK PORTAGE_ROOT CALLED_OPTIONS
+unset SEARCH_DIRS SEARCH_DIRS_MASK LD_LIBRARY_MASK PORTAGE_ROOT
 
-REBUILD_LIST="$(cat $LLIST.5_order | sed s/^/=/ | tr '\n' ' ')"
+[[ -r $LIST.5_order && -s $LIST.5_order ]] && REBUILD_LIST=($(<"$LIST.5_order")) ||
+       REBUILD_LIST=($(<"$LIST.4_ebuilds"))
 
 trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
 
-if [ -z "$REBUILD_LIST" ] ; then
-       echo -e "\n${GR}$OK_TEXT... All done.${NO} "
-       if [ ! $KEEPTEMP ]
-       then
-               rm $LIST.[0-2]_*
-               rm $LLIST.[3-9]_*
-       fi
-       exit 0
-fi
-
-IS_REAL_MERGE=true
-echo " $EMERGE_OPTIONS " | grep -q '\( -p \| --pretend \| -f \| --fetchonly \)' && IS_REAL_MERGE=false
+REBUILD_LIST="=${REBUILD_LIST[@]}"
+REBUILD_LIST="${REBUILD_LIST//[[:space:]]/ =}"
 
-echo
-echo -e "${GR}All prepared. Starting rebuild...${NO}"
+einfo 'All prepared. Starting rebuild'
+echo "emerge --oneshot ${EMERGE_OPTIONS[@]} $REBUILD_LIST"
 
-echo "emerge --oneshot $EMERGE_OPTIONS $REBUILD_LIST"
-
-if $IS_REAL_MERGE ; then
-       for i in . . . . . . . . . . ; do
-               echo -n -e '\a.'
-               sleep 1
-       done
-       echo
-fi
+is_real_merge && countdown 10
 
-# Link file descriptor #6 with stdin
+# Link file descriptor #6 with stdin so --ask will work
 exec 6<&0
 
 # Run in background to correctly handle Ctrl-C
-(
-       EMERGE_DEFAULT_OPTS="" emerge --oneshot $EMERGE_OPTIONS $REBUILD_LIST <&6
-       echo $? >$LLIST.6_status
-) &
+{
+       EMERGE_DEFAULT_OPTS="--oneshot ${EMERGE_OPTIONS[@]}" emerge $REBUILD_LIST <&6
+       echo $? > $LIST.6_status
+} &
 wait
 
 # Now restore stdin from fd #6, where it had been saved, and close fd #6 ( 6<&- ) to free it for other processes to use.
 exec 0<&6 6<&-
 
-#if $EXACT_EBUILDS ; then
-#      mv -i /usr/portage/profiles/package.mask.hidden /usr/portage/profiles/package.mask
-#      trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
-#fi
+show_unowned_files() {
+       if grep -qF '(none)' "$LIST.4_package_owners"; then
+               ewarn "Found some broken files that weren't associated with known packages"
+               ewarn "The broken files are:"
+               while read filename junk; do
+                       [[ $junk = *none* ]] && ewarn "  $filename"
+               done < "$LIST.4_package_owners"
+       fi
+}
 
-if [ "$(cat $LLIST.6_status)" -gt 0 ] ; then
-       echo
-       echo -e "${RD}revdep-rebuild failed to emerge all packages${NO}"
-       echo -e "${RD}you have the following choices:${NO}"
-       echo
-       echo "- if emerge failed during the build, fix the problems and re-run revdep-rebuild"
-       echo "    or"
-       echo "- use -X or --package-names as first argument (trys to rebuild package, not exact"
-       echo "  ebuild)"
-       echo "    or"
-       echo "- set ACCEPT_KEYWORDS=\"~<your platform>\" and/or /etc/portage/package.unmask"
-       echo "  (and remove $LLIST.5_order to be evaluated again)"
-       echo "    or"
-       echo "- modify the above emerge command and run it manually"
-       echo "    or"
-       echo "- compile or unmerge unsatisfied packages manually, remove temporary files and"
-       echo "  try again (you can edit package/ebuild list first)"
-       echo
-       echo -e "${GR}To remove temporary files, please run:${NO}"
-       echo "rm $LIST*.?_*"
-       exit $(cat $LLIST.6_status)
+if (( $(<"$LIST.6_status") != 0 )); then
+       ewarn
+       ewarn "$APP_NAME failed to emerge all packages."
+       ewarn 'you have the following choices:'
+       einfo "- If emerge failed during the build, fix the problems and re-run $APP_NAME."
+       einfo '- Use /etc/portage/package.keywords to unmask a newer version of the package.'
+       einfo "  (and remove $LIST.5_order to be evaluated again)"
+       einfo '- Modify the above emerge command and run it manually.'
+       einfo '- Compile or unmerge unsatisfied packages manually,'
+       einfo '  remove temporary files, and try again.'
+       einfo '  (you can edit package/ebuild list first)'
+       einfo
+       einfo 'To remove temporary files, please run:'
+       einfo "rm $LIST*.?_*"
+       show_unowned_files
+       exit $EMERGE_STATUS
+elif is_real_merge; then
+       trap_cmd() {
+               eerror "terminated. Please remove the temporary files manually:"
+               eerror "rm $LIST*.?_*"
+               exit 1
+       }
+       trap trap_cmd SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
+       einfo 'Build finished correctly. Removing temporary files...'
+       einfo
+       einfo 'You can re-run revdep-rebuild to verify that all libraries and binaries'
+       einfo 'are fixed. If some inconsistency remains, it can be orphaned file, deep'
+       einfo 'dependency, binary package or specially evaluated library.'
+       show_unowned_files
+       [[ $KEEP_TEMP ]] || rm $LIST*.?_*
 else
-       if $IS_REAL_MERGE ; then
-               trap "echo -e \" terminated. Please remove them manually:\nrm $LIST*.?_*\" ; exit 1" \
-                       SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
-               echo -n -e "${GR}Build finished correctly. Removing temporary files...${NO} "
-               echo
-               rm $LIST.[0-2]_*
-               rm $LLIST.[3-9]_*
-               echo "You can re-run revdep-rebuild to verify that all libraries and binaries"
-               echo "are fixed. If some inconsistency remains, it can be orphaned file, deep"
-               echo "dependency, binary package or specially evaluated library."
-       else
-               echo -e "${GR}Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.${NO}"
-       fi
+       einfo 'Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.'
 fi
-exit 0
+
diff --git a/trunk/src/revdep-rebuild/revdep-rebuild-old b/trunk/src/revdep-rebuild/revdep-rebuild-old
new file mode 100755 (executable)
index 0000000..3115eb9
--- /dev/null
@@ -0,0 +1,747 @@
+#!/bin/bash 
+# Copyright 1999-2007 Gentoo Foundation
+# $Header$
+
+# revdep-rebuild: Reverse dependency rebuilder.
+# Original Author: Stanislav Brabec
+# Current Maintainer: Paul Varner <fuzzyray@gentoo.org>
+
+# Known problems:
+#
+# In exact ebuild mode revdep-rebuild can fail to properly order packages,
+# which are not up to date.
+# http://bugs.gentoo.org/show_bug.cgi?id=23018
+#
+# Rebuilding using --package-names mode should be default, but emerge has no
+# feature to update to latest version of defined SLOT.
+# http://bugs.gentoo.org/show_bug.cgi?id=4698
+
+# Customizable variables:
+#
+# LD_LIBRARY_MASK - Mask of specially evaluated libraries
+# SEARCH_DIRS - List of directories to search for executables and libraries
+# SEARCH_DIRS_MASK - List of directories to not search
+#
+# These variables can be prepended to either by setting the variable in 
+# your environment prior to execution, or by placing an entry in
+# /etc/make.conf.
+#
+# An entry of "-*" means to clear the variable from that point forward.
+# Example: env SEARCH_DIRS="/usr/bin -*" revdep-rebuild will set SEARCH_DIRS
+# to contain only /usr/bin
+
+if [ "$1" = "-h" -o "$1" = "--help" ]
+then
+       echo "Usage: $0 [OPTIONS] [--] [EMERGE_OPTIONS]"
+       echo
+       echo "Broken reverse dependency rebuilder."
+       echo
+       echo "  -X, --package-names  Emerge based on package names, not exact versions"
+       echo "      --library NAME   Emerge existing packages that use the library with NAME"
+       echo "      --library=NAME   NAME can be a full path to the library or a basic"
+       echo "                       regular expression (man grep)"
+       echo " -np, --no-ld-path     Do not set LD_LIBRARY_PATH"
+       echo " -nc, --nocolor        Turn off colored output"
+       echo "  -i, --ignore         Ignore temporary files from previous runs"
+       echo "  -q, --quiet          Be less verbose (also passed to emerge command)"
+       echo " -vv, --extra-verbose  Be extra verbose"
+       echo
+       echo "Calls emerge, all other options are used for it (e. g. -p, --pretend)."
+       echo
+       echo "Report bugs to <http://bugs.gentoo.org>"
+       exit 0
+fi
+
+echo "Configuring search environment for revdep-rebuild"
+
+# Obey PORTAGE_NICENESS
+PORTAGE_NICENESS=$(portageq envvar PORTAGE_NICENESS)
+if [ ! -z "$PORTAGE_NICENESS" ]
+then
+       renice $PORTAGE_NICENESS $$ > /dev/null
+       # Since we have already set our nice value for our processes,
+       # reset PORTAGE_NICENESS to zero to avoid having emerge renice again.
+       export PORTAGE_NICENESS="0"
+fi
+
+PORTAGE_ROOT=$(portageq envvar ROOT)
+[ -z "$PORTAGE_ROOT" ] && PORTAGE_ROOT="/"
+
+# Update the incremental variables using /etc/profile.env, /etc/ld.so.conf,
+# portage, and the environment
+
+# Read the incremental variables from environment and portage
+# Until such time as portage supports these variables as incrementals
+# The value will be what is in /etc/make.conf
+PRELIMINARY_SEARCH_DIRS="$SEARCH_DIRS $(unset SEARCH_DIRS; portageq envvar SEARCH_DIRS)"
+PRELIMINARY_SEARCH_DIRS_MASK="$SEARCH_DIRS_MASK $(unset SEARCH_DIRS_MASK; portageq envvar SEARCH_DIRS_MASK)"
+PRELIMINARY_LD_LIBRARY_MASK="$LD_LIBRARY_MASK $(unset LD_LIBRARY_MASK; portageq envvar LD_LIBRARY_MASK)"
+
+# Add the defaults
+if [ -d /etc/revdep-rebuild ]
+then
+       for file in $(ls /etc/revdep-rebuild)
+       do
+               PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS $(. /etc/revdep-rebuild/${file}; echo $SEARCH_DIRS)"
+               PRELIMINARY_SEARCH_DIRS_MASK="$PRELIMINARY_SEARCH_DIRS_MASK $(. /etc/revdep-rebuild/${file}; echo $SEARCH_DIRS_MASK)"
+               PRELIMINARY_LD_LIBRARY_MASK="$PRELIMINARY_LD_LIBRARY_MASK $(. /etc/revdep-rebuild/${file}; echo $LD_LIBRARY_MASK)"
+       done
+else
+       PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS /bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*"
+       PRELIMINARY_SEARCH_DIRS_MASK="$PRELIMINARY_SEARCH_DIRS_MASK /opt/OpenOffice /usr/lib/openoffice"
+       PRELIMINARY_LD_LIBRARY_MASK="$PRELIMINARY_LD_LIBRARY_MASK libodbcinst.so libodbc.so libjava.so libjvm.so"
+fi
+
+# Get the ROOTPATH and PATH from /etc/profile.env
+if [ -e "/etc/profile.env" ]
+then
+       PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS $((. /etc/profile.env; echo ${ROOTPATH}:${PATH}) | tr ':' ' ')"
+fi
+
+# Get the directories from /etc/ld.so.conf
+if [ -e /etc/ld.so.conf ]
+then
+       PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS $(grep -v "^#" /etc/ld.so.conf | tr '\n' ' ')"
+fi     
+
+# Set the final variables
+# Note: Using $(echo $variable) removes extraneous spaces from variable assignment
+unset SEARCH_DIRS
+for i in $(echo $PRELIMINARY_SEARCH_DIRS)
+do
+       [ "$i" = "-*" ] && break
+       # Append a / at the end so that links and directories are treated the same by find
+       # Remove any existing trailing slashes to prevent double-slashes
+       SEARCH_DIRS="$(echo $SEARCH_DIRS ${i/%\//}/)"
+done
+# Remove any double-slashes from the path
+SEARCH_DIRS="$(echo $SEARCH_DIRS | sed 's:/\+:/:g')"
+
+unset SEARCH_DIRS_MASK
+for i in $(echo $PRELIMINARY_SEARCH_DIRS_MASK)
+do
+       [ "$i" = "-*" ] && break
+       SEARCH_DIRS_MASK="$(echo $SEARCH_DIRS_MASK $i)"
+done
+
+unset LD_LIBRARY_MASK
+for i in $(echo $PRELIMINARY_LD_LIBRARY_MASK)
+do
+       [ "$i" = "-*" ] && break
+       LD_LIBRARY_MASK="$(echo $LD_LIBRARY_MASK $i)"
+done
+
+# Use the color preference from portage
+NOCOLOR=$(portageq envvar NOCOLOR)
+
+# Base of temporary files names.
+touch ${HOME}/.revdep-rebuild_0.test 2>/dev/null
+if [ $? -eq 0 ]
+then
+       LIST="${HOME}/.revdep-rebuild"
+       rm ~/.revdep-rebuild_0.test
+else
+       # Try to use /var/tmp since $HOME is not available
+       touch /var/tmp/.revdep-rebuild_0.test 2>/dev/null
+       if [ $? -eq 0 ]
+       then
+               LIST="/var/tmp/.revdep-rebuild"
+               rm /var/tmp/.revdep-rebuild_0.test
+       else
+               echo
+               echo "!!! Unable to write temporary files to either $HOME or /var/tmp !!!"
+               echo
+               exit 1
+       fi
+fi
+
+shopt -s nullglob
+shopt -s expand_aliases
+unalias -a
+
+# Color Definitions
+NO="\x1b[0m"
+BR="\x1b[0;01m"
+CY="\x1b[36;01m"
+GR="\x1b[32;01m"
+RD="\x1b[31;01m"
+YL="\x1b[33;01m"
+BL="\x1b[34;01m"
+
+# Check if portage-utils are installed
+portageq has_version $PORTAGE_ROOT  portage-utils
+if [ "$?" -eq 0 ]
+then
+       PORTAGE_UTILS=true
+else
+       PORTAGE_UTILS=false
+fi
+
+alias echo_v=echo
+
+PACKAGE_NAMES=false
+SONAME="not found"
+SONAME_GREP=grep
+SEARCH_BROKEN=true
+EXTRA_VERBOSE=false
+KEEP_TEMP=false
+FULL_LD_PATH=true
+
+EMERGE_OPTIONS=""
+PRELIMINARY_CALLED_OPTIONS=""
+while [ ! -z "$1" ] ; do
+       case "$1" in
+       -X | --package-names )
+               PACKAGE_NAMES=true
+               PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --package_names"
+               shift
+               ;;
+       -q | --quiet )
+               alias echo_v=:
+               EMERGE_OPTIONS="${EMERGE_OPTIONS} $1"
+               shift
+               ;;
+       --library=* | --soname=* | --soname-regexp=* )
+               SONAME="${1#*=}"
+               SEARCH_BROKEN=false
+               PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --library=${SONAME}"
+               shift
+               ;;
+       --library | --soname | --soname-regexp )
+               SONAME="$2"
+               SEARCH_BROKEN=false
+               PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --library=${SONAME}"
+               shift 2
+               ;;
+       -nc | --no-color | --nocolor )
+               NOCOLOR=true
+               shift
+               ;;
+       -np | --no-ld-path )
+               FULL_LD_PATH=false
+               PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --no-ld-path"
+               shift
+               ;;
+       -i | --ignore )
+               rm -f ${LIST}*
+               shift
+               ;;
+       --keep-temp )
+               KEEPTEMP=true
+               shift
+               ;;
+       -vv | --extra-verbose )
+               EXTRA_VERBOSE=true
+               shift
+               ;;
+       -- )
+               shift
+               ;;
+       * )
+               EMERGE_OPTIONS="${EMERGE_OPTIONS} $1"
+               shift
+               ;;
+       esac
+done
+
+EMERGE_OPTIONS=$(echo $EMERGE_OPTIONS | sed 's/^ //')
+
+if [ -z "$PRELIMINARY_CALLED_OPTIONS" ]
+then
+       CALLED_OPTIONS=""
+else
+       for i in $(echo $PRELIMINARY_CALLED_OPTIONS | tr ' ' '\n'| sort)
+       do
+               CALLED_OPTIONS="$(echo $CALLED_OPTIONS $i)"
+       done
+fi
+
+if [ "$NOCOLOR" = "yes" -o "$NOCOLOR" = "true" ]
+then
+       NOCOLOR=true
+else
+       NOCOLOR=false
+fi
+
+# Make the NOCOLOR variable visible to emerge
+export NOCOLOR
+
+if $NOCOLOR
+then
+       NO=""
+       BR=""
+       CY=""
+       GR=""
+       RD=""
+       YL=""
+       BL=""
+fi
+
+function set_trap () {
+       trap "rm_temp $1" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
+}
+
+function rm_temp () {
+       echo " terminated."
+       echo "Removing incomplete $1."
+       rm $1
+       echo
+       exit 1
+}
+
+if $SEARCH_BROKEN ; then
+       SONAME_SEARCH="$SONAME"
+       LLIST=$LIST
+       HEAD_TEXT="broken by a package update"
+       OK_TEXT="Dynamic linking on your system is consistent"
+       WORKING_TEXT=" consistency"
+else
+       # first case is needed to test against /path/to/foo.so
+       if [ ${SONAME:0:1} == '/' ] ; then 
+               # Set to "<space>$SONAME<space>"
+               SONAME_SEARCH=" $SONAME "
+       else
+               # Set to "<tab>$SONAME<space>"
+               SONAME_SEARCH=" $SONAME "
+       fi
+       LLIST=${LIST}_$(echo "$SONAME_SEARCH$SONAME" | md5sum | head -c 8)
+       HEAD_TEXT="using $SONAME"
+       OK_TEXT="There are no dynamic links to $SONAME"
+       WORKING_TEXT=""
+fi
+
+# If any of our temporary files are older than 1 day, remove them all
+[ "$(find "${LIST%/*}/." ! -name . -prune -name "${LIST##*/}*" -type f -mmin +1440)" != "" ] && rm -f ${LIST}*
+
+# Don't use our previous files if environment doesn't match
+if [ -f $LIST.0_env ]
+then
+       PREVIOUS_SEARCH_DIRS=$(. ${LIST}.0_env; echo "$SEARCH_DIRS")
+       PREVIOUS_SEARCH_DIRS_MASK=$(. ${LIST}.0_env; echo "$SEARCH_DIRS_MASK")
+       PREVIOUS_LD_LIBRARY_MASK=$(. ${LIST}.0_env; echo "$LD_LIBRARY_MASK")
+       PREVIOUS_PORTAGE_ROOT=$(. ${LIST}.0_env; echo "$PORTAGE_ROOT")
+       PREVIOUS_OPTIONS=$(. ${LIST}.0_env; echo "$CALLED_OPTIONS")
+       if [ "$PREVIOUS_SEARCH_DIRS" != "$SEARCH_DIRS" ] || \
+          [ "$PREVIOUS_SEARCH_DIRS_MASK" != "$SEARCH_DIRS_MASK" ] || \
+          [ "$PREVIOUS_LD_LIBRARY_MASK" != "$LD_LIBRARY_MASK" ] || \
+          [ "$PREVIOUS_PORTAGE_ROOT" != "$PORTAGE_ROOT" ] || \
+          [ "$PREVIOUS_OPTIONS" != "$CALLED_OPTIONS" ] 
+       then
+               echo
+               echo "Environment mismatch from previous run, deleting temporary files..."
+               rm -f ${LIST}*
+       fi
+fi
+
+# Clean up no longer needed environment variables
+unset PREVIOUS_SEARCH_DIRS PREVIOUS_SEARCH_DIRS_MASK PREVIOUS_LD_LIBRARY_MASK PREVIOUS_PORTAGE_ROOT PREVIOUS_OPTIONS
+unset PRELIMINARY_SEARCH_DIRS PRELIMINARY_SEARCH_DIRS_MASK PRELIMINARY_LD_LIBRARY_MASK PRELIMINARY_CALLED_OPTIONS
+
+# Log our environment
+echo "SEARCH_DIRS=\"$SEARCH_DIRS\"" > $LIST.0_env
+echo "SEARCH_DIRS_MASK=\"$SEARCH_DIRS_MASK\"" >> $LIST.0_env
+echo "LD_LIBRARY_MASK=\"$LD_LIBRARY_MASK\"" >> $LIST.0_env
+echo "PORTAGE_ROOT=\"$PORTAGE_ROOT\"" >> $LIST.0_env
+echo "CALLED_OPTIONS=\"$CALLED_OPTIONS\"" >> $LIST.0_env
+echo "EMERGE_OPTIONS=\"$EMERGE_OPTIONS\"" >> $LIST.0_env
+
+if $EXTRA_VERBOSE
+then
+       echo
+       echo "revdep-rebuild environment:"
+       cat $LIST.0_env
+fi
+
+echo
+echo "Checking reverse dependencies..."
+echo
+echo "Packages containing binaries and libraries $HEAD_TEXT"
+echo "will be emerged."
+
+echo
+echo -n -e "${GR}Collecting system binaries and libraries...${NO}"
+
+if [ -f $LIST.1_files ]
+then
+       echo " using existing $LIST.1_files."
+else
+       # Be safe and remove any extraneous temporary files
+       rm -f ${LIST}.[1-9]_*
+
+       set_trap "$LIST.1_*"
+
+       # Hack for the different versions of find.
+       # Be extra paranoid and pipe results through sed to remove multiple slashes
+       find_results=$(find /usr/bin/revdep-rebuild -type f -perm /u+x 2>/dev/null)
+       if [ -z $find_results ]
+       then
+               find_results=$(find /usr/bin/revdep-rebuild -type f -perm +u+x 2>/dev/null)
+               if [ -z $find_results ]
+               then
+                       echo -e "\n"
+                       echo -e "${RD}Unable to determine how to use find to locate executable files${NO}"
+                       echo -e "${RD}Open a bug at http://bugs.gentoo.org${NO}"
+                       echo
+                       exit 1
+               else
+                       # using -perm +u+x for find command
+                       find $SEARCH_DIRS -type f \( -perm +u+x -o -name '*.so' -o -name '*.so.*' -o -name '*.la' \) 2>/dev/null | sort | uniq | sed 's:/\+:/:g' >$LIST.0_files
+               fi
+       else
+               # using -perm /u+x for find command
+               find $SEARCH_DIRS -type f \( -perm /u+x -o -name '*.so' -o -name '*.so.*' -o -name '*.la' \) 2>/dev/null | sort | uniq | sed 's:/\+:/:g' >$LIST.0_files
+       fi
+
+       # Remove files that match SEARCH_DIR_MASK
+       for dir in $SEARCH_DIRS_MASK
+       do
+               grep -v "^$dir" $LIST.0_files > $LIST.1_files
+               mv $LIST.1_files $LIST.0_files
+       done
+       
+       mv $LIST.0_files $LIST.1_files
+       echo -e " done.\n  ($LIST.1_files)"
+fi
+
+if $SEARCH_BROKEN && $FULL_LD_PATH ; then
+       echo
+       echo -n -e "${GR}Collecting complete LD_LIBRARY_PATH...${NO}"
+       if [ -f $LIST.2_ldpath ] ; then
+               echo " using existing $LIST.2_ldpath."
+       else
+               set_trap "$LIST.2_ldpath"
+               # Ensure that the "trusted" lib directories are at the start of the path
+               (
+                       echo /lib* /usr/lib* | sed 's/ /:/g'
+                       sed '/^#/d;s/#.*$//' </etc/ld.so.conf
+                       sed 's:/[^/]*$::' <$LIST.1_files | sort -ru
+               ) | tr '\n' : | tr -d '\r' | sed 's/:$//' >$LIST.2_ldpath
+               echo -e " done.\n  ($LIST.2_ldpath)"
+       fi
+       COMPLETE_LD_LIBRARY_PATH="$(cat $LIST.2_ldpath)"
+fi
+
+echo
+echo -n -e "${GR}Checking dynamic linking$WORKING_TEXT...${NO}"
+if [ -f $LLIST.3_rebuild ] ; then
+       echo " using existing $LLIST.3_rebuild."
+else
+       echo_v
+       set_trap "$LLIST.3_rebuild"
+       LD_MASK="\\(    $(echo "$LD_LIBRARY_MASK" | sed 's/\./\\./g;s/ / \\|    /g') \\)"
+       echo -n >$LLIST.3_rebuild
+       echo -n >$LLIST.3_ldd_errors
+       cat $LIST.1_files | egrep -v '*\.la$' | while read FILE ; do
+       # Note: double checking seems to be faster than single
+       # with complete path (special add ons are rare).
+       if ldd "$FILE" 2>>$LLIST.3_ldd_errors | grep -v "$LD_MASK" | $SONAME_GREP -q "$SONAME_SEARCH" ; then
+               if $SEARCH_BROKEN && $FULL_LD_PATH ; then
+                       if LD_LIBRARY_PATH="$COMPLETE_LD_LIBRARY_PATH" ldd "$FILE" 2>/dev/null | grep -v "$LD_MASK" | $SONAME_GREP -q "$SONAME_SEARCH" ; then
+                               # FIX: I hate duplicating code
+                               # Only build missing direct dependencies
+                               ALL_MISSING_LIBS=$(ldd "$FILE" 2>/dev/null | sort -u | sed -n 's/       \(.*\) => not found/\1/p' | tr '\n' ' ' | sed 's/ $//' )
+                               REQUIRED_LIBS=$(objdump -x $FILE | grep NEEDED | awk '{print $2}' | tr '\n' ' ' | sed 's/ $//')
+                               MISSING_LIBS=""
+                               for lib in $ALL_MISSING_LIBS
+                               do
+                                       if echo $REQUIRED_LIBS | grep -q $lib
+                                       then
+                                               MISSING_LIBS="$MISSING_LIBS $lib"
+                                       fi
+                               done
+                               if [ "$MISSING_LIBS" != "" ]
+                               then
+                                       echo "obj $FILE" >>$LLIST.3_rebuild
+                                       echo_v "  broken $FILE (requires ${MISSING_LIBS})"
+                               fi
+                       fi
+               else
+                       # FIX: I hate duplicating code
+                       # Only rebuild for direct dependencies
+                       ALL_MISSING_LIBS=$(ldd "$FILE" 2>/dev/null | sort -u | $SONAME_GREP "$SONAME_SEARCH" | awk '{print $1}' | tr '\n' ' ' | sed 's/ $//' )
+                       REQUIRED_LIBS=$(objdump -x $FILE | grep NEEDED | awk '{print $2}' | tr '\n' ' ' | sed 's/ $//')
+                       MISSING_LIBS=""
+                       for lib in $ALL_MISSING_LIBS
+                       do
+                               if echo $REQUIRED_LIBS | grep -q $lib
+                               then
+                                       MISSING_LIBS="$MISSING_LIBS $lib"
+                               fi
+                       done
+                       if [ "$MISSING_LIBS" != "" ]
+                       then
+                               echo "obj $FILE" >>$LLIST.3_rebuild
+                               if $SEARCH_BROKEN ; then
+                                       echo_v "  broken $FILE (requires ${MISSING_LIBS})"
+                               else
+                                       echo_v "  found $FILE"
+                               fi
+                       fi
+               fi
+       fi
+       done
+       if $SEARCH_BROKEN ; then
+               # Look for missing version
+               for FILE in $(grep "no version information available" $LLIST.3_ldd_errors | awk '{print $NF}' | sed 's/[()]//g' | sort -u) ; do
+                       echo "obj $FILE" >>$LLIST.3_rebuild
+                       echo_v "  broken $FILE (no version information available)"
+               done
+               # Look for broken .la files
+               cat $LIST.1_files | egrep '*\.la$' | while read FILE ; do
+                       for depend in $(grep '^dependency_libs' $FILE | awk -F'=' '{print $2}' | sed "s/'//g") ; do
+                               [ ${depend:0:1} != '/' ] && continue
+                               if [ ! -e $depend ] ; then
+                                       echo "obj $FILE" >>$LLIST.3_rebuild
+                                       echo_v "  broken $FILE (requires ${depend})"
+                               fi
+                       done
+               done
+       fi
+       echo -e " done.\n  ($LLIST.3_rebuild)"
+fi
+
+if $PACKAGE_NAMES ; then
+       EXACT_EBUILDS=false
+
+       echo
+       echo -n -e "${GR}Assigning files to packages...${NO}"
+       if [ -f $LLIST.4_packages_raw ] ; then
+               echo " using existing $LLIST.4_packages_raw."
+       else
+               set_trap "$LLIST.4_packages*"
+               echo -n >$LLIST.4_packages_raw
+               echo -n >$LLIST.4_package_owners
+               cat $LLIST.3_rebuild | while read obj FILE ; do
+                       if $PORTAGE_UTILS ; then
+                               EXACT_PKG="$(qfile -qvC ${FILE} )"
+                       else
+                               EXACT_PKG=$(find /var/db/pkg -name CONTENTS | xargs fgrep -l "obj $FILE " | sed -e 's:/var/db/pkg/\(.*\)/CONTENTS:\1:g')
+                       fi
+                       # Ugly sed hack to strip version information
+                       PKG="$(echo $EXACT_PKG | sed 's/-r[0-9].*$//;s/\(^.*\/*\)-.*$/\1/')"
+                       if [ -z "$PKG" ] ; then
+                               echo -n -e "\n  ${RD}*** $FILE not owned by any package is broken! ***${NO}"
+                               echo "$FILE -> (none)" >> $LLIST.4_package_owners
+                               echo_v -n -e "\n  $FILE -> (none)"
+                       else
+                               echo "$EXACT_PKG" >> $LLIST.4_packages_raw
+                               echo "$FILE -> $EXACT_PKG" >> $LLIST.4_package_owners
+                               echo_v -n -e "\n  $FILE -> $PKG"
+                       fi
+               done
+               echo_v
+               echo -e " done.\n  ($LLIST.4_packages_raw, $LLIST.4_package_owners)"
+       fi
+
+       echo
+       echo -n -e "${GR}Cleaning list of packages to rebuild...${NO}"
+       if [ -f $LLIST.4_packages ] ; then
+               echo " using existing $LLIST.4_packages."
+       else
+               sort -u $LLIST.4_packages_raw >$LLIST.4_packages
+               echo -e " done.\n  ($LLIST.4_packages)"
+       fi
+
+       echo
+       echo -n -e "${GR}Assigning packages to ebuilds...${NO}"
+       if [ -f $LLIST.4_ebuilds ] ; then
+               echo " using existing $LLIST.4_ebuilds."
+       else
+               if [ -s "$LLIST.4_packages" ]
+               then
+                       set_trap "$LLIST.4_ebuilds"
+                       cat $LLIST.4_packages | while read EXACT_PKG
+                       do
+                               # Get the slot
+                               PKG="$(echo $EXACT_PKG | sed 's/-r[0-9].*$//;s/\(^.*\/*\)-.*$/\1/')"
+                               SLOT=$(cat /var/db/pkg/${EXACT_PKG}/SLOT)
+                               OTHER_VERSIONS=$(/usr/lib/gentoolkit/bin/find_pkgs.py $PKG | grep -v "($SLOT)" | awk '{print $2}')
+                               # If SLOT is equal to 0, then just see what portage says is latest version
+                               if [ "$SLOT" = "0" -o "x$OTHER_VERSIONS" = "x" ]
+                               then
+                                       best_visible=$(portageq best_visible $PORTAGE_ROOT $PKG)
+                                       [ "x" != "x$best_visible" ] && echo $best_visible
+                                       continue
+                               fi
+                               # Otherwise mask the other SLOTTED versions and check for latest
+                               if [ -e /etc/portage/package.mask ]
+                               then
+                                       mv -f /etc/portage/package.mask /etc/portage/package.mask.revdep-rebuild.backup
+                               else
+                                       # Make sure that /etc/portage/package.mask exists
+                                       mkdir -p /etc/portage
+                                       touch /etc/portage/package.mask
+                               fi
+                               for pkg_version in $(echo $OTHER_VERSIONS | tr '\n' ' ') 
+                               do
+                                       echo "=${PKG}-${pkg_version}" >> /etc/portage/package.mask
+                               done
+                               best_visible=$(portageq best_visible $PORTAGE_ROOT $PKG)
+                               [ "x" != "x$best_visible" ] && echo $best_visible
+                               rm -f /etc/portage/package.mask
+                               if [ -e /etc/portage/package.mask.revdep-rebuild.backup ]
+                               then
+                                       mv -f /etc/portage/package.mask.revdep-rebuild.backup /etc/portage/package.mask
+                               fi
+                       done > $LLIST.4_ebuilds
+                       echo -e " done.\n  ($LLIST.4_ebuilds)"
+               else
+                       echo " Nothing to rebuild"
+                       echo -n > $LLIST.4_ebuilds
+               fi
+       fi
+else
+       EXACT_EBUILDS=true
+
+       echo
+       echo -n -e "${GR}Assigning files to ebuilds...${NO}"
+       if [ -f $LLIST.4_ebuilds ] ; then
+               echo " using existing $LLIST.4_ebuilds."
+       else
+               if [ -s "$LLIST.3_rebuild" ] ; then
+                       set_trap "$LLIST.4_ebuilds"
+                       find /var/db/pkg -name CONTENTS | xargs fgrep -l -f $LLIST.3_rebuild |
+                       sed 's:/var/db/pkg/\(.*\)/CONTENTS:\1:' > $LLIST.4_ebuilds
+                       echo -e " done.\n  ($LLIST.4_ebuilds)"
+               else
+                       echo " Nothing to rebuild"
+                       echo -n > $LLIST.4_ebuilds
+               fi
+       fi
+
+fi
+
+echo
+echo -n -e "${GR}Evaluating package order...${NO}"
+if [ -f $LLIST.5_order ] ; then
+       echo " using existing $LLIST.5_order."
+else
+       set_trap "$LLIST.5_order"
+       RAW_REBUILD_LIST="$(cat $LLIST.4_ebuilds | sed s/^/=/ | tr '\n' ' ')"
+       if [ ! -z "$RAW_REBUILD_LIST" ] ; then
+               REBUILD_GREP="^\\($( (EMERGE_DEFAULT_OPTS="" emerge --nospinner --pretend --oneshot --nodeps --quiet $RAW_REBUILD_LIST ; echo $? >$LLIST.5a_status ) | sed -n 's/\./\\&/g;s/ //g;s/$/\\/;s/\[[^]]*\]//gp' | tr '\n' '|' | sed 's/|$//'))\$"
+               if [ $(cat $LLIST.5a_status) -gt 0 ] ; then
+                       echo ""
+                       echo -e "${RD}Warning: Failed to resolve package order."
+                       echo -e "Will merge in \"random\" order!${NO}"
+                       echo "Possible reasons:"
+                       echo "- An ebuild is no longer in the portage tree."
+                       echo "- An ebuild is masked, use /etc/portage/packages.keyword"
+                       echo "  and/or /etc/portage/package.unmask to unmask it"
+                       for i in . . . . . ; do
+                               echo -n -e '\a.'
+                               sleep 1
+                       done
+                       ln -f $LLIST.4_ebuilds $LLIST.5_order
+               else
+                       (EMERGE_DEFAULT_OPTS="" emerge --nospinner --pretend --oneshot --deep --quiet $RAW_REBUILD_LIST ; echo $? >$LLIST.5b_status ) | sed -n 's/  *$//;s/^\[.*\] //p' | awk '{print $1}' | grep "$REBUILD_GREP" >$LLIST.5_order
+                       if [ $(cat $LLIST.5b_status) -gt 0 ] ; then
+                               echo ""
+                               echo -e "${RD}Warning: Failed to resolve package order."
+                               echo -e "Will merge in \"random\" order!${NO}"
+                               echo "Possible reasons:"
+                               echo "- An ebuild is no longer in the portage tree."
+                               echo "- An ebuild is masked, use /etc/portage/packages.keyword"
+                               echo "  and/or /etc/portage/package.unmask to unmask it"
+                               for i in . . . . . ; do
+                                       echo -n -e '\a.'
+                                       sleep 1
+                               done
+                               rm -f $LLIST.5_order
+                               ln -f $LLIST.4_ebuilds $LLIST.5_order
+                       fi
+               fi
+       else
+               echo -n "" >$LLIST.5_order
+       fi
+       echo -e " done.\n  ($LLIST.5_order)"
+fi
+
+# Clean up no longer needed environment variables
+unset COMPLETE_LD_LIBRARY_PATH SEARCH_DIRS SEARCH_DIRS_MASK LD_LIBRARY_MASK PORTAGE_ROOT CALLED_OPTIONS
+
+REBUILD_LIST="$(cat $LLIST.5_order | sed s/^/=/ | tr '\n' ' ')"
+
+trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
+
+if [ -z "$REBUILD_LIST" ] ; then
+       echo -e "\n${GR}$OK_TEXT... All done.${NO} "
+       if [ ! $KEEPTEMP ]
+       then
+               rm $LIST.[0-2]_*
+               rm $LLIST.[3-9]_*
+       fi
+       exit 0
+fi
+
+IS_REAL_MERGE=true
+echo " $EMERGE_OPTIONS " | grep -q '\( -p \| --pretend \| -f \| --fetchonly \)' && IS_REAL_MERGE=false
+
+echo
+echo -e "${GR}All prepared. Starting rebuild...${NO}"
+
+echo "emerge --oneshot $EMERGE_OPTIONS $REBUILD_LIST"
+
+if $IS_REAL_MERGE ; then
+       for i in . . . . . . . . . . ; do
+               echo -n -e '\a.'
+               sleep 1
+       done
+       echo
+fi
+
+# Link file descriptor #6 with stdin
+exec 6<&0
+
+# Run in background to correctly handle Ctrl-C
+(
+       EMERGE_DEFAULT_OPTS="" emerge --oneshot $EMERGE_OPTIONS $REBUILD_LIST <&6
+       echo $? >$LLIST.6_status
+) &
+wait
+
+# Now restore stdin from fd #6, where it had been saved, and close fd #6 ( 6<&- ) to free it for other processes to use.
+exec 0<&6 6<&-
+
+#if $EXACT_EBUILDS ; then
+#      mv -i /usr/portage/profiles/package.mask.hidden /usr/portage/profiles/package.mask
+#      trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
+#fi
+
+if [ "$(cat $LLIST.6_status)" -gt 0 ] ; then
+       echo
+       echo -e "${RD}revdep-rebuild failed to emerge all packages${NO}"
+       echo -e "${RD}you have the following choices:${NO}"
+       echo
+       echo "- if emerge failed during the build, fix the problems and re-run revdep-rebuild"
+       echo "    or"
+       echo "- use -X or --package-names as first argument (trys to rebuild package, not exact"
+       echo "  ebuild)"
+       echo "    or"
+       echo "- set ACCEPT_KEYWORDS=\"~<your platform>\" and/or /etc/portage/package.unmask"
+       echo "  (and remove $LLIST.5_order to be evaluated again)"
+       echo "    or"
+       echo "- modify the above emerge command and run it manually"
+       echo "    or"
+       echo "- compile or unmerge unsatisfied packages manually, remove temporary files and"
+       echo "  try again (you can edit package/ebuild list first)"
+       echo
+       echo -e "${GR}To remove temporary files, please run:${NO}"
+       echo "rm $LIST*.?_*"
+       exit $(cat $LLIST.6_status)
+else
+       if $IS_REAL_MERGE ; then
+               trap "echo -e \" terminated. Please remove them manually:\nrm $LIST*.?_*\" ; exit 1" \
+                       SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
+               echo -n -e "${GR}Build finished correctly. Removing temporary files...${NO} "
+               echo
+               rm $LIST.[0-2]_*
+               rm $LLIST.[3-9]_*
+               echo "You can re-run revdep-rebuild to verify that all libraries and binaries"
+               echo "are fixed. If some inconsistency remains, it can be orphaned file, deep"
+               echo "dependency, binary package or specially evaluated library."
+       else
+               echo -e "${GR}Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.${NO}"
+       fi
+fi
+exit 0
diff --git a/trunk/src/revdep-rebuild/revdep-rebuild-rewrite b/trunk/src/revdep-rebuild/revdep-rebuild-rewrite
deleted file mode 100755 (executable)
index 19de90d..0000000
+++ /dev/null
@@ -1,830 +0,0 @@
-#!/bin/bash
-# Copyright 1999-2007 Gentoo Foundation
-
-# revdep-rebuild: Reverse dependency rebuilder.
-# Original Author: Stanislav Brabec
-# Rewrite Author: Michael A. Smith
-# Current Maintainer: Paul Varner <fuzzyray@gentoo.org>
-
-# TODO:
-# - Use more /etc/init.d/functions.sh
-# - Try to reduce the number of global vars
-
-##
-# Global Variables:
-
-# Readonly variables:
-declare -r APP_NAME="${0##*/}" # The name of this application
-declare -r OIFS="$IFS"         # Save the IFS
-
-# "Boolean" variables: Considered "true" if it has any value at all
-# "True" indicates we should...
-declare FULL_LD_PATH           # ...search across the COMPLETE_LD_LIBRARY_PATH
-declare KEEP_TEMP              # ...not delete tempfiles from the current run
-declare ORDER_PKGS             # ...sort the atoms in deep dependency order
-declare PACKAGE_NAMES          # ...emerge by slot, not by versionated atom
-declare RM_OLD_TEMPFILES       # ...remove tempfiles from prior runs
-declare SEARCH_BROKEN          # ...search for broken libraries and binaries
-declare VERBOSE                # ...give verbose output
-
-# Globals that impact portage directly:
-declare EMERGE_DEFAULT_OPTS    # String of options portage assumes to be set
-declare EMERGE_OPTIONS         # Array of options to pass to portage
-declare PORTAGE_NICENESS       # Renice to this value
-declare PORTAGE_ROOT           # The root path for portage
-
-# Customizable incremental variables:
-# These variables can be prepended to either by setting the variable in 
-# your environment prior to execution, or by placing an entry in
-# /etc/make.conf.
-#
-# An entry of "-*" means to clear the variable from that point forward.
-# Example: env SEARCH_DIRS="/usr/bin -*" revdep-rebuild will set SEARCH_DIRS
-# to contain only /usr/bin
-declare LD_LIBRARY_MASK  # Mask of specially evaluated libraries
-declare SEARCH_DIRS      # List of dirs to search for executables and libraries
-declare SEARCH_DIRS_MASK # List of dirs not to search
-
-# Other globals:
-declare OLDPROG                # Previous pass through the progress meter
-declare EXACT_PKG              # Versionated atom to emerge
-declare HEAD_TEXT              # Feedback string about the search
-declare LIST                   # Prefix for temporary filenames
-declare NOCOLOR                # Set to "true" not to output term colors
-declare OK_TEXT                # Feedback about a search which found no errors
-declare RC_NOCOLOR             # Hack to insure we respect NOCOLOR
-declare REBUILD_LIST           # Array of atoms to emerge
-declare SONAME                 # Soname/soname path pattern given on commandline
-declare SONAME_SEARCH          # Value of SONAME modified to match ldd's output
-declare WORKING_TEXT           # Feedback about the search
-declare ENV_FILE               # A file containing environment variables
-
-rm() {
-       local i
-       [[ $LIST && $APP_NAME ]] ||
-               die 1 '$LIST or $APP_NAME is not defined! (This is a bug.)'
-       for i; do
-               [[ $i = -* || $i = *.$APP_NAME* ]] || 
-                       die 1 "Oops, I'm not allowed to delete that. ($@)"
-       done
-       command rm "$@"
-}
-# Somewhat more portable find -executable
-# FIXME/UNTESTED (I don't have access to all of the different versions of 
-# find.)
-# Usage: find PATH ARGS -- use find like normal, except use -executable instead 
-# of various versions of -perm /+ blah blah and hacks
-find() {
-       hash find || { die 1 'find not found!'; }
-       # We can be pretty sure "$0" should be executable.
-       if [[ $(command find "$0" -executable 2> /dev/null) ]]; then
-               unset -f find # We can just use the command find
-       elif [[ $(command find "$0" -perm /u+x 2> /dev/null) ]]; then
-               find() {
-                       a=(${@//-executable/-perm \/u+x})
-                       a=(${a[@]//-writable/-perm \/u+w})
-                       a=(${a[@]//-readable/-perm \/r+w})
-                       command find "${a[@]}"
-               }
-       elif [[ $(command find "$0" -perm +u+x 2> /dev/null) ]]; then
-               find() {
-                       a=(${@//-executable/-perm +u+x})
-                       a=(${a[@]//-writable/-perm +u+w})
-                       a=(${a[@]//-readable/-perm +r+w})
-                       command find "${a[@]}"
-               }
-       else # Last resort
-               find() {
-                       a=(${@//-executable/-exec test -x '{}' \;})
-                       a=(${a[@]//-writable/-exec test -w '{}' \;})
-                       a=(${a[@]//-readable/-exec test -r '{}' \;})
-                       command find "${a[@]}"
-               }
-       fi
-       find "$@"
-}
-print_usage() {
-cat << EOF
-Usage: $APP_NAME [OPTIONS] [--] [EMERGE_OPTIONS]
-
-Broken reverse dependency rebuilder.
-
-  -h, --help           Print this usage
-  -k, --keep-temp      Do not delete temporary files on exit
-  -e, --exact          Emerge based on exact package version
-  -l, --no-ld-path     Do not set LD_LIBRARY_PATH
-  -C, --nocolor        Turn off colored output
-  -i, --ignore         Ignore temporary files from previous runs
-  -o, --no-order       Do not check the build order
-                       (Saves time, but may cause breakage.)
-  -P, --no-progress    Turn off the progress meter
-  -q, --quiet          Be less verbose (also passed to emerge command)
-  -v, --verbose        Be more verbose
-  -u, --no-util UTIL   Do not use features provided by UTIL
-      --no-util=UTIL   UTIL can be one of portage-utils or pkgcore
-                       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)
-
-Calls emerge, all other options are used for it (e. g. -p, --pretend).
-
-Report bugs to <http://bugs.gentoo.org>
-EOF
-}
-# Usage: progress i n
-#        i: current item
-#        n: total number of items to process
-progress() {
-       if [[ -t 1 ]]; then
-               progress() {
-                       local curProg=$(( $1 * 100 / $2 ))
-                       (( curProg == OLDPROG )) && return # no change, output nothing
-                       OLDPROG="$curProg" # must be a global variable
-                       (( $1 == $2 )) && local lb=$'\n'
-                       echo -ne '\r                         \r'"[ $curProg% ] $lb"
-               }
-               progress $@
-       else # STDOUT is not a tty. Disable progress meter.
-               progress() { :; }
-       fi
-}
-# Usage: countdown n
-#        n: number of seconds to count
-countdown() {
-       local i
-       for ((i=1; i<$1; i++)); do
-               echo -ne '\a.'
-               ((i<$1)) && sleep 1
-       done
-       echo -e '\a.'
-}
-# Get the name of a package owning a file on the filesystem using one of several
-# utilities: This is a placeholder. The function is defined in get_args()
-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() {
-       local a=$(echo ${@%%[[:space:]]-\*[[:space:]]*}) # Deliberately unquoted
-       # A benchmark shows this loop is faster than piping to sed,
-       # as long as there aren't more than a handful of '/' chars.
-       while [[ $a = *//* ]]; do a="${a//\/\///}"; done
-       sort -u <<< "${a// /$'\n'}"
-}
-# Exit and optionally output to sterr
-die() {
-       local status=$1
-       shift
-       eerror "$@"
-       exit $status
-}
-# What to do when dynamic linking is consistent
-clean_exit() {
-       [[ $KEEP_TEMP ]] || rm $LIST.?_*
-       echo
-       einfo "$OK_TEXT... All done. "
-       exit 0
-}
-get_args() {
-       echo_v() { ewarn "$@"; }
-       unset VERBOSE KEEP_TEMP EMERGE_OPTIONS RM_OLD_TEMPFILES
-       ORDER_PKGS=1
-       PACKAGE_NAMES=1
-       SONAME="not found"
-       SEARCH_BROKEN=1
-       FULL_LD_PATH=1
-       local avoid_utils
-       while [[ $1 ]]; do
-               case $1 in
-               -h|--help)
-                       print_usage
-                       exit 0
-                       ;;
-               -e|--exact)
-                       unset PACKAGE_NAMES
-                       ;;
-               -o|--no-order)
-                       unset ORDER_PKGS
-                       ;;
-               -P|--no-progress)
-                       progress() { :; }
-                       ;;
-               -q|--quiet)
-                       echo_v() { :; }
-                       progress() { :; }
-                       quiet=1
-                       EMERGE_OPTIONS+=($1)
-                       ;;
-               -L=*|--library=*|--soname=*|--soname-regexp=*)
-                       SONAME="${1#*=}"
-                       unset SEARCH_BROKEN
-                       ;;
-               -L|--library|--soname|--soname-regexp)
-                       [[ ! $2 || $2 = -* ]] && die 1 "Missing expected argument to $1"
-                       shift
-                       SONAME="$1"
-                       unset SEARCH_BROKEN
-                       ;;
-               -u=*|--no-util=*)
-                       # TODO: check for invalid values
-                       avoid_utils="${1#*=}"
-                       ;;
-               -u|--no-util)
-                       [[ ! $2 || $2 = -* ]] && die 1 "Missing expected argument to $1"
-                       shift
-                       avoid_utils="$1"
-                       ;;
-               -nc|-C|--no-color|--nocolor)
-                       export NOCOLOR=yes
-                       ;;
-               -l|-np|--no-ld-path)
-                       unset FULL_LD_PATH
-                       ;;
-               -i|--ignore)
-                       RM_OLD_TEMPFILES=1
-                       ;;
-               -k|--keep-temp)
-                       KEEP_TEMP=1
-                       ;;
-               -vv|--extra-verbose|-v|--verbose)
-                       VERBOSE=1
-                       EMERGE_OPTIONS+=($1)
-                       ;;
-               -X|--package-names)
-                       # No longer used, since it is the default.
-                       # We accept it for backwards compatibility
-                       PACKAGE_NAMES=1
-                       ;;
-               --)
-                       ;;
-               *)
-                       EMERGE_OPTIONS+=($1)
-                       ;;
-               esac
-               shift
-       done
-       # Check if various utils are allowed and installed
-       if [[ $avoid_utils != *portage-utils* ]] && hash qfile 2> /dev/null; then
-               get_file_owner() { qfile -qvC "$@"; }
-       elif [[ $avoid_utils != *pkgcore* ]] && hash pquery 2> /dev/null; then
-               get_file_owner() { local IFS=,; pquery --nocolor --owns="$*"; }
-       # equery disabled for incompatibility with modern portage.
-       # elif [[ $avoid_utils != *equery* ]] && hash equery 2> /dev/null; then
-       #       get_file_owner() { equery -q -C b $@; }
-       else
-               get_file_owner() {
-                       local IFS=$'\n'
-                       find /var/db/pkg -name CONTENTS -print0 |
-                               xargs -0 grep -Fl "$*" |
-                               sed 's:/var/db/pkg/\(.*\)/CONTENTS:\1:'
-               }
-       fi
-
-       # Use the color preference from portage
-       export NOCOLOR=$(portageq envvar NOCOLOR)
-       [[ $NOCOLOR = yes || $NOCOLOR = true ]] && export RC_NOCOLOR=yes # HACK! (grr)
-       source /etc/init.d/functions.sh
-       
-       # Normalize some EMERGE_OPTIONS
-       EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-p/--pretend})
-       EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-f/--fetchonly})
-       EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-f/--verbose})
-       if [[ ${EMERGE_OPTIONS[@]} != *--pretend* && $UID -ne 0 ]]; then
-               ewarn "You are not superuser. Adding --pretend to emerge options."
-               EMERGE_OPTIONS+=(--pretend)
-       fi
-}
-is_real_merge() [[
-       ${EMERGE_OPTIONS[@]} != *--pretend* && ${EMERGE_OPTIONS[@]} != *--fetchonly*
-]]
-
-get_args "$@"
-
-einfo "Configuring search environment for $APP_NAME"
-
-# Obey PORTAGE_NICENESS
-PORTAGE_NICENESS=$(portageq envvar PORTAGE_NICENESS)
-if [[ $PORTAGE_NICENESS ]]; then
-       renice $PORTAGE_NICENESS $$ > /dev/null
-       # Since we have already set our nice value for our processes,
-       # reset PORTAGE_NICENESS to zero to avoid having emerge renice again.
-       export PORTAGE_NICENESS="0"
-fi
-
-PORTAGE_ROOT=$(portageq envvar ROOT)
-PORTAGE_ROOT="${PORTAGE_ROOT:-/}"
-
-# Update the incremental variables using /etc/profile.env, /etc/ld.so.conf,
-# portage, and the environment
-
-# Read the incremental variables from environment and portage
-# Until such time as portage supports these variables as incrementals
-# The value will be what is in /etc/make.conf
-SEARCH_DIRS+=" "$(unset SEARCH_DIRS; portageq envvar SEARCH_DIRS)
-SEARCH_DIRS_MASK+=" "$(unset SEARCH_DIRS_MASK; portageq envvar SEARCH_DIRS_MASK)
-LD_LIBRARY_MASK+=" "$(unset LD_LIBRARY_MASK; portageq envvar LD_LIBRARY_MASK)
-
-# Add the defaults
-if [[ -d /etc/revdep-rebuild ]]; then
-       for ENV_FILE in /etc/revdep-rebuild/*; do
-               SEARCH_DIRS+=" "$(. $ENV_FILE; echo $SEARCH_DIRS)
-               SEARCH_DIRS_MASK+=" "$(. $ENV_FILE; echo $SEARCH_DIRS_MASK)
-               LD_LIBRARY_MASK+=" "$(. $ENV_FILE; echo $LD_LIBRARY_MASK)
-       done
-       unset ENV_FILE # HACK
-else
-       SEARCH_DIRS+=" /bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*"
-       SEARCH_DIRS_MASK+=" /opt/OpenOffice /usr/lib/openoffice"
-       LD_LIBRARY_MASK+=" libodbcinst.so libodbc.so libjava.so libjvm.so"
-fi
-
-# Get the ROOTPATH and PATH from /etc/profile.env
-if [[ -r "/etc/profile.env" && -s "/etc/profile.env" ]]; then
-       SEARCH_DIRS+=" "$(. /etc/profile.env; /usr/bin/tr ':' ' ' <<< "$ROOTPATH $PATH")
-fi
-
-# Get the directories from /etc/ld.so.conf
-if [[ -r /etc/ld.so.conf && -s /etc/ld.so.conf ]]; then
-       SEARCH_DIRS+=" "$(sed '/^#/d;s/#.*$//' /etc/ld.so.conf)
-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")
-
-set_trap() {
-       trap "rm_temp $1" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
-}
-rm_temp() {
-       rm $1
-       die 1 $'  ...terminated. Removing incomplete '"$1."
-}
-get_search_env() {
-       local new_env
-       local old_env
-       # Find a place to put temporary files
-       # TODO; let the user choose where to put tempfiles
-       # gfind $HOME/ /var/tmp/ /tmp/ -writable -print -quit
-       # HACK: This is a rather noisy, but portable way to implement -quit
-       while read LIST; do
-               break # Set LIST
-       done < <(find $HOME/ /var/tmp/ /tmp/ -writable)
-       [[ $LIST ]] ||
-               die 1 "Unable to find a satisfactory location for temporary files"
-
-       LIST+=".$APP_NAME"
-       if [[ $SEARCH_BROKEN ]]; then
-               SONAME_SEARCH="$SONAME"
-               HEAD_TEXT="broken by a package update"
-               OK_TEXT="Dynamic linking on your system is consistent"
-               WORKING_TEXT="consistency"
-       else
-               # first case is needed to test against /path/to/foo.so
-               if [[ $SONAME = /* ]]; then
-                       # Set to "<space>$SONAME<space>"
-                       SONAME_SEARCH=" $SONAME "
-                       # Escape the "/" characters
-                       SONAME_SEARCH="${SONAME_SEARCH//\//\\/}"
-               else
-                       # Set to "<tab>$SONAME<space>"
-                       SONAME_SEARCH=$'\t'"$SONAME "
-               fi
-               local uuid="${SONAME##*/}"
-               uuid="${uuid//[[:space:]]}"
-               LIST+="_$uuid"
-               HEAD_TEXT="using $SONAME"
-               OK_TEXT="There are no dynamic links to $SONAME"
-               unset WORKING_TEXT
-       fi
-
-       # If any of our temporary files are older than 1 day, remove them all
-       if [[ ! $KEEP_TEMP ]]; then
-               while read; do
-                       RM_OLD_TEMPFILES=1
-                       break
-               done < <(find -L "$LIST."* -maxdepth 0 -type f -mmin +1440 -print 2>/dev/null)
-       fi
-
-       # Compare old and new environments
-       # Don't use our previous files if environment doesn't match
-       new_env=$(
-               # We do not care if these emerge options change
-               EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--pretend/})
-               EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--fetchonly/})
-               EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--verbose/})
-               cat <<- EOF
-                       SEARCH_DIRS="$SEARCH_DIRS"
-                       SEARCH_DIRS_MASK="$SEARCH_DIRS_MASK"
-                       LD_LIBRARY_MASK="$LD_LIBRARY_MASK"
-                       PORTAGE_ROOT="$PORTAGE_ROOT"
-                       EMERGE_OPTIONS="${EMERGE_OPTIONS[@]}"
-                       ORDER_PKGS="$ORDER_PKGS"
-                       FULL_LD_PATH="$FULL_LD_PATH"
-               EOF
-       )
-       if [[ -r $LIST.0_env && -s $LIST.0_env ]]; then
-               old_env=$(<"$LIST.0_env")
-               if [[ $old_env != $new_env ]]; then
-                       ewarn 'Environment mismatch from previous run, deleting temporary files...'
-                       RM_OLD_TEMPFILES=1
-               fi
-       else
-               # No 0_env file found, silently delete any other tempfiles that may exist
-               RM_OLD_TEMPFILES=1
-       fi
-
-       # If we should remove old tempfiles, do so
-       [[ $RM_OLD_TEMPFILES ]] && rm -f "$LIST."*
-       
-       # Save the environment in a file for next time
-       echo "$new_env" > "$LIST.0_env"
-
-       [[ $VERBOSE ]] && echo $'\n'"$APP_NAME environment:"$'\n'"$new_env"
-
-       echo
-       einfo "Checking reverse dependencies"
-       einfo "Packages containing binaries and libraries $HEAD_TEXT"
-       einfo "will be emerged."
-}
-get_files() {
-       einfo "Collecting system binaries and libraries"
-       if [[ -r $LIST.1_files && -s $LIST.1_files ]]; then
-               einfo "Found existing $LIST.1_files"
-       else
-               # Be safe and remove any extraneous temporary files
-               rm -f $LIST.[1-9]_*
-
-               set_trap "$LIST.1_*"
-
-               if [[ $SEARCH_DIRS_MASK ]]; then
-                       findMask=($SEARCH_DIRS_MASK)
-                       findMask="${findMask[@]/#/-o -path }"
-                       findMask="( ${findMask#-o } ) -prune -o"
-               fi
-               find ${SEARCH_DIRS[@]} $findMask -type f \( -executable -o \
-                       -name '*.so' -o -name '*.so.*' -o -name '*.la' \) -print 2> /dev/null |
-                       sort -u > "$LIST.1_files" ||
-                       die $? "find failed to list binary files (This is a bug.)"
-               einfo "Generated new $LIST.1_files"
-       fi
-}
-get_ldpath() {
-       local COMPLETE_LD_LIBRARY_PATH
-       [[ $SEARCH_BROKEN && $FULL_LD_PATH ]] || return
-       einfo 'Collecting complete LD_LIBRARY_PATH'
-       if [[ -r $LIST.2_ldpath && -s $LIST.2_ldpath ]] ; then
-               einfo "Found existing $LIST.2_ldpath."
-       else
-               set_trap "$LIST.2_ldpath"
-               # Ensure that the "trusted" lib directories are at the start of the path
-               COMPLETE_LD_LIBRARY_PATH=(
-                       /lib*
-                       /usr/lib*
-                       $(sed '/^#/d;s/#.*$//' < /etc/ld.so.conf)
-                       $(sed 's:/[^/]*$::' < "$LIST.1_files" | sort -ru)
-               )
-               IFS=':'
-               COMPLETE_LD_LIBRARY_PATH="${COMPLETE_LD_LIBRARY_PATH[*]}"
-               IFS="$OIFS"
-               echo "$COMPLETE_LD_LIBRARY_PATH" > "$LIST.2_ldpath"
-               einfo "Generated new $LIST.2_ldpath"
-       fi
-}
-main_checks() {
-       local target_file
-       local -a files
-       local i=0
-       local ldd_output
-       local ldd_status
-       local numFiles
-       local COMPLETE_LD_LIBRARY_PATH
-       if [[ $SEARCH_BROKEN && $FULL_LD_PATH ]]; then
-               [[ -r $LIST.2_ldpath && -s $LIST.2_ldpath ]] || die 1 "unable to find $LIST.2_ldpath"
-               COMPLETE_LD_LIBRARY_PATH=$(<"$LIST.2_ldpath")
-       fi
-       einfo "Checking dynamic linking $WORKING_TEXT"
-       if [[ -r $LIST.3_rebuild && -s $LIST.3_rebuild ]]; then
-               einfo "Found existing $LIST.3_rebuild."
-       else
-               [[ $LIST ]] || die 1 "$LIST" 'is undefined! (This is a bug.)'
-               set_trap "$LIST.3_rebuild"
-               set_trap "$LIST.3_ldd_errors"
-               rm -f "$LIST.3"*
-               files=($(<"$LIST.1_files"))
-               numFiles="${#files[@]}"
-               for target_file in "${files[@]}"; do
-                       if [[ $target_file != *.la ]]; then
-                               # Note: double checking seems to be faster than single with complete path
-                               # (special add ons are rare).
-                               ldd_output=$(ldd "$target_file" 2>> "$LIST.3_ldd_errors" | sort -u)
-                               ldd_status=$? # TODO: Check this for problems with sort
-                               # HACK: if LD_LIBRARY_MASK is null or undefined grep -vF doesn't work
-                               if grep -vF "${LD_LIBRARY_MASK:=$'\a'}" <<< "$ldd_output" |
-                                       grep -q "$SONAME_SEARCH"; then
-                                       if [[ $SEARCH_BROKEN && $FULL_LD_PATH ]]; then
-                                               if LD_LIBRARY_PATH="$COMPLETE_LD_LIBRARY_PATH" ldd "$target_file" 2>/dev/null |
-                                                       grep -vF "$LD_LIBRARY_MASK" | grep -q "$SONAME_SEARCH"; then
-                                                       # FIXME: I hate duplicating code
-                                                       # Only build missing direct dependencies
-                                                       MISSING_LIBS=$(
-                                                               expr='s/[[:space:]]*\([^[:space:]]*\) => not found/\1/p'
-                                                               sed -n "$expr" <<< "$ldd_output"
-                                                       )
-                                                       REQUIRED_LIBS=$(
-                                                               expr='s/^[[:space:]]*NEEDED[[:space:]]*\([^[:space:]]*\).*/\1/p';
-                                                               objdump -x "$target_file" | grep NEEDED | sed "$expr" | sort -u
-                                                       )
-                                                       MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS")
-                                                       if [[ $MISSING_LIBS ]]; then
-                                                               echo "obj $target_file" >> "$LIST.3_rebuild"
-                                                               echo_v "  broken $target_file (requires $MISSING_LIBS)"
-                                                       fi
-                                               fi
-                                       else
-                                               # FIXME: I hate duplicating code
-                                               # Only rebuild for direct dependencies
-                                               MISSING_LIBS=$(
-                                                       expr="/$SONAME_SEARCH/s/^[[:space:]]*\([^[:space:]]*\).*$/\1/p"
-                                                       sort -u <<< "$ldd_output" | sed -n "$expr"
-                                               )
-                                               REQUIRED_LIBS=$(
-                                                       expr='s/^[[:space:]]*NEEDED[[:space:]]*\([^[:space:]]*\).*/\1/p';
-                                                       objdump -x "$target_file" | grep NEEDED | sed "$expr" | sort -u
-                                               )
-                                               MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS")
-                                               if [[ $MISSING_LIBS ]]; then
-                                                       echo "obj $target_file" >> "$LIST.3_rebuild"
-                                                       if [[ $SEARCH_BROKEN ]]; then
-                                                               echo_v "  broken $target_file (requires $MISSING_LIBS)"
-                                                       else
-                                                               echo_v "  found $target_file"
-                                                       fi
-                                               fi
-                                       fi
-                               fi
-                       elif [[ $SEARCH_BROKEN ]]; then
-                               # Look for broken .la files
-                               for depend in $(
-                                       awk -F"[=']" '/^dependency_libs/{
-                                               gsub("^-[^[:space:]]*", "", $3);
-                                               gsub("[[:space:]]-[^[:space:]]*", "", $3);
-                                               print $3
-                                       }' "$target_file"
-                               ); do
-                                       if [[ $depend = /* && ! -e $depend ]]; then
-                                               echo "obj $target_file" >> "$LIST.3_rebuild"
-                                               echo_v "  broken $target_file (requires $depend)"
-                                       fi
-                               done
-                       fi
-                       [[ $VERBOSE ]] &&
-                               progress $((++i)) $numFiles $target_file ||
-                               progress $((++i)) $numFiles
-               done
-               if [[ $SEARCH_BROKEN ]]; then
-                       # Look for missing version
-                       while read target_file; do
-                               echo "obj $target_file" >> "$LIST.3_rebuild"
-                               echo_v "  broken $target_file (no version information available)"
-                       done < <(
-                               # Regexify LD_LIBRARY_MASK. Exclude it from the search.
-                               LD_LIBRARY_MASK="${LD_LIBRARY_MASK//$'\n'/|}"
-                               awk -v ldmask="(${LD_LIBRARY_MASK//./\\\.})" '
-                                       /no version information available/ && $0 !~ ldmask {
-                                               gsub(/[()]/, "", $NF)
-                                               if (seen[$NF]++)  next
-                                               print $NF
-                                       }' "$LIST.3_ldd_errors"
-                       )
-               fi
-               [[ -r $LIST.3_rebuild && -s $LIST.3_rebuild ]] || clean_exit
-               einfo "Generated new $LIST.3_rebuild"
-       fi
-}
-get_packages() {
-       local target_file
-       local EXACT_PKG
-       local PKG
-       local obj
-       einfo 'Assigning files to packages'
-       if [[ -r $LIST.4_packages_raw && -s $LIST.4_packages_raw ]]; then
-               einfo "Found existing $LIST.4_packages_raw"
-       else
-               set_trap "$LIST.4_packages*"
-               rm -f $LIST.4*
-               while read obj target_file; do
-                       EXACT_PKG=$(get_file_owner $target_file)
-                       if [[ $EXACT_PKG ]]; then
-                               # Strip version information
-                               PKG="${EXACT_PKG%%-r[[:digit:]]*}"
-                               PKG="${PKG%-*}"
-                               echo "$EXACT_PKG" >> $LIST.4_packages_raw
-                               echo "$target_file -> $EXACT_PKG" >> $LIST.4_package_owners
-                               echo_v "  $target_file -> $PKG"
-                       else
-                               ewarn " !!! $target_file not owned by any package is broken !!!"
-                               echo "$target_file -> (none)" >> $LIST.4_package_owners
-                               echo_v "  $target_file -> (none)"
-                       fi
-               done < "$LIST.3_rebuild"
-               einfo "Generated new $LIST.4_packages_raw and $LIST.4_package_owners"
-       fi
-       # if we find '(none)' on every line, exit out
-       if ! grep -qvF '(none)' "$LIST.4_package_owners"; then
-               ewarn "Found some broken files, but none of them were associated with known packages"
-               ewarn "Unable to proceed with automatic repairs."
-               ewarn "The broken files are listed in $LIST.4_package_owners"
-               if [[ $VERBOSE ]]; then
-                       ewarn "The broken files are:"
-                       while read filename junk; do
-                               ewarn "  $filename"
-                       done < "$LIST.4_package_owners"
-               fi
-               exit 0 # FIXME: Should we exit 1 here?
-       fi
-}
-clean_packages() {
-       einfo 'Cleaning list of packages to rebuild'
-       if [[ -r $LIST.4_packages && -s $LIST.4_packages ]]; then
-               einfo "Found existing $LIST.4_packages"
-       else
-               sort -u $LIST.4_packages_raw > $LIST.4_packages
-               einfo "Generated new $LIST.4_packages"
-       fi
-}
-assign_packages_to_ebuilds() {
-       local EXACT_PKG
-       local PKG
-       local SLOT
-       einfo 'Assigning packages to ebuilds'
-       if [[ -r $LIST.4_ebuilds && -s $LIST.4_ebuilds ]]; then
-               einfo "Found existing $LIST.4_ebuilds"
-       elif [[ -r $LIST.4_packages && -s $LIST.4_packages ]]; then
-                       set_trap "$LIST.4_ebuilds"
-                       while read EXACT_PKG; do
-                               # Get the slot
-                               PKG="${EXACT_PKG%%-r[[:digit:]]*}"
-                               PKG="${PKG%-*}"
-                               SLOT=$(</var/db/pkg/$EXACT_PKG/SLOT)
-                               portageq best_visible $PORTAGE_ROOT $PKG:$SLOT
-                       done < "$LIST.4_packages" > "$LIST.4_ebuilds"
-                       einfo "Generated new $LIST.4_ebuilds"
-       else
-               einfo 'Nothing to rebuild.'
-               die 1 '(The program should have already quit, so this is a minor bug.)'
-       fi
-}
-get_exact_ebuilds() {
-       einfo 'Assigning files to ebuilds'
-       if [[ -r $LIST.4_ebuilds && -s $LIST.4_ebuilds ]]; then
-               einfo "Found existing $LIST.4_ebuilds"
-       elif [[ -r $LIST.3_rebuild && -s $LIST.3_rebuild ]]; then
-               rebuildList=" $(<"$LIST.3_rebuild") "
-               rebuildList=(${rebuildList//[[:space:]]obj[[:space:]]/ })
-               get_file_owner "${rebuildList[@]}" > $LIST.4_ebuilds
-               einfo "Generated new $LIST.4_ebuilds"
-       else
-               einfo 'Nothing to rebuild.'
-               die 1 '(The program should have already quit, so this is a minor bug.)'
-       fi
-}
-get_build_order() {
-       local -r OLD_EMERGE_DEFAULT_OPTS="$EMERGE_DEFAULT_OPTS"
-       local RAW_REBUILD_LIST
-       local REBUILD_GREP
-       local i
-       if [[ ! $ORDER_PKGS ]]; then
-               einfo 'Skipping package ordering'
-               return
-       fi
-       einfo 'Evaluating package order'
-       if [[ -r $LIST.5_order && -s $LIST.5_order ]]; then
-               einfo "Found existing $LIST.5_order"
-       else
-               set_trap "$LIST.5_order"
-               RAW_REBUILD_LIST=$(<"$LIST.4_ebuilds")
-               if [[ $RAW_REBUILD_LIST ]]; then
-                       export EMERGE_DEFAULT_OPTS="--nospinner --pretend --oneshot --quiet"
-                       RAW_REBUILD_LIST=($RAW_REBUILD_LIST)
-                       RAW_REBUILD_LIST="${RAW_REBUILD_LIST[@]/#/=}"
-                       REBUILD_GREP=$(emerge --nodeps $RAW_REBUILD_LIST | sed 's/\[[^]]*\]//g') &&
-                               emerge --deep $RAW_REBUILD_LIST | sed 's/\[[^]]*\]//g' |
-                               grep -F "$REBUILD_GREP" > $LIST.5_order || {
-                                       eerror
-                                       eerror 'Warning: Failed to resolve package order.'
-                                       eerror 'Will merge in arbitrary order'
-                                       eerror
-                                       cat <<- EOF
-                                               Possible reasons:
-                                               - An ebuild is no longer in the portage tree.
-                                               - An ebuild is masked, use /etc/portage/packages.keyword
-                                                       and/or /etc/portage/package.unmask to unmask it
-                                       EOF
-                                       countdown 5
-                                       rm -f "$LIST.5_order"
-                               }
-                       export EMERGE_DEFAULT_OPTS="$OLD_EMERGE_DEFAULT_OPTS"
-               else
-                       einfo 'Nothing to rebuild.'
-                       die 1 '(The program should have already quit, so this is a minor bug.)'
-               fi
-       fi
-       [[ -r $LIST.5_order && -s $LIST.5_order ]] && einfo "Generated new $LIST.5_order"
-}
-
-get_search_env
-echo
-get_files
-echo
-get_ldpath
-echo
-main_checks
-echo
-if [[ $PACKAGE_NAMES ]]; then
-       get_packages
-       echo
-       clean_packages
-       echo
-       assign_packages_to_ebuilds
-else
-       get_exact_ebuilds
-fi
-echo
-get_build_order
-echo
-
-# Clean up no longer needed environment variables
-unset SEARCH_DIRS SEARCH_DIRS_MASK LD_LIBRARY_MASK PORTAGE_ROOT
-
-[[ -r $LIST.5_order && -s $LIST.5_order ]] && REBUILD_LIST=($(<"$LIST.5_order")) ||
-       REBUILD_LIST=($(<"$LIST.4_ebuilds"))
-
-trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
-
-REBUILD_LIST="=${REBUILD_LIST[@]}"
-REBUILD_LIST="${REBUILD_LIST//[[:space:]]/ =}"
-
-einfo 'All prepared. Starting rebuild'
-echo "emerge --oneshot ${EMERGE_OPTIONS[@]} $REBUILD_LIST"
-
-is_real_merge && countdown 10
-
-# Link file descriptor #6 with stdin so --ask will work
-exec 6<&0
-
-# Run in background to correctly handle Ctrl-C
-{
-       EMERGE_DEFAULT_OPTS="--oneshot ${EMERGE_OPTIONS[@]}" emerge $REBUILD_LIST <&6
-       echo $? > $LIST.6_status
-} &
-wait
-
-# Now restore stdin from fd #6, where it had been saved, and close fd #6 ( 6<&- ) to free it for other processes to use.
-exec 0<&6 6<&-
-
-show_unowned_files() {
-       if grep -qF '(none)' "$LIST.4_package_owners"; then
-               ewarn "Found some broken files that weren't associated with known packages"
-               ewarn "The broken files are:"
-               while read filename junk; do
-                       [[ $junk = *none* ]] && ewarn "  $filename"
-               done < "$LIST.4_package_owners"
-       fi
-}
-
-if (( $(<"$LIST.6_status") != 0 )); then
-       ewarn
-       ewarn "$APP_NAME failed to emerge all packages."
-       ewarn 'you have the following choices:'
-       einfo "- If emerge failed during the build, fix the problems and re-run $APP_NAME."
-       einfo '- Use /etc/portage/package.keywords to unmask a newer version of the package.'
-       einfo "  (and remove $LIST.5_order to be evaluated again)"
-       einfo '- Modify the above emerge command and run it manually.'
-       einfo '- Compile or unmerge unsatisfied packages manually,'
-       einfo '  remove temporary files, and try again.'
-       einfo '  (you can edit package/ebuild list first)'
-       einfo
-       einfo 'To remove temporary files, please run:'
-       einfo "rm $LIST*.?_*"
-       show_unowned_files
-       exit $EMERGE_STATUS
-elif is_real_merge; then
-       trap_cmd() {
-               eerror "terminated. Please remove the temporary files manually:"
-               eerror "rm $LIST*.?_*"
-               exit 1
-       }
-       trap trap_cmd SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
-       einfo 'Build finished correctly. Removing temporary files...'
-       einfo
-       einfo 'You can re-run revdep-rebuild to verify that all libraries and binaries'
-       einfo 'are fixed. If some inconsistency remains, it can be orphaned file, deep'
-       einfo 'dependency, binary package or specially evaluated library.'
-       show_unowned_files
-       [[ $KEEP_TEMP ]] || rm $LIST*.?_*
-else
-       einfo 'Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.'
-fi
-