Switch revdep-rebuild to python version.
authorPaul Varner <fuzzyray@gentoo.org>
Tue, 12 Jul 2011 19:41:30 +0000 (14:41 -0500)
committerPaul Varner <fuzzyray@gentoo.org>
Tue, 12 Jul 2011 21:29:01 +0000 (16:29 -0500)
revdep-rebuild.sh is original bash scipt.

bin/revdep-ng [deleted file]
bin/revdep-rebuild
bin/revdep-rebuild.sh [new file with mode: 0755]

diff --git a/bin/revdep-ng b/bin/revdep-ng
deleted file mode 100755 (executable)
index a4c8e11..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2010 Brian Dolbec <brian.dolbec@gmail.com>
-# Copyright 2002-2010 Gentoo Technologies, Inc.
-# Distributed under the terms of the GNU General Public License v2 or later
-#
-# $Header$
-
-"""'analyse' is a flexible utility for Gentoo linux which can display various
-information about installed packages, such as the USE flags used and the
-packages that use them.  It can also be used to help rebuild /etc/portage/package.*
-files in the event of corruption, and possibly more.
-"""
-
-from __future__ import print_function
-
-import sys
-# This block ensures that ^C interrupts are handled quietly.
-try:
-       import signal
-
-       def exithandler(signum,frame):
-               signal.signal(signal.SIGINT, signal.SIG_IGN)
-               signal.signal(signal.SIGTERM, signal.SIG_IGN)
-               print()
-               sys.exit(1)
-
-       signal.signal(signal.SIGINT, exithandler)
-       signal.signal(signal.SIGTERM, exithandler)
-       signal.signal(signal.SIGPIPE, signal.SIG_DFL)
-
-
-except KeyboardInterrupt:
-       print()
-       sys.exit(1)
-
-from gentoolkit import errors
-from gentoolkit.revdep_rebuild import rebuild
-
-try:
-       success = rebuild.main(rebuild.parse_options())
-       sys.exit(success)
-except errors.GentoolkitException as err:
-       if '--debug' in sys.argv:
-               raise
-       else:
-               from gentoolkit import pprinter as pp
-               sys.stderr.write(pp.error(str(err)))
-               print()
-               print("Add '--debug' to global options for traceback.")
-               sys.exit(1)
index f00b7914fad0188d041bcfd0a88532d8a5a54f3a..a4c8e11404a47f7731f8875324315c5bd9f26da0 100755 (executable)
-#!/bin/bash
-# Copyright 1999-2010 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:
-
-# Must-be-blank:
-unset GREP_OPTIONS
-
-# Readonly variables:
-declare -r APP_NAME="${0##*/}" # The name of this application
-declare -r VERSION="svn"
-declare -r OIFS="$IFS"         # Save the IFS
-declare -r     ENV_FILE=0_env.rr     # Contains environment variables
-declare -r   FILES_FILE=1_files.rr   # Contains a list of files to search
-declare -r  LDPATH_FILE=2_ldpath.rr  # Contains the LDPATH
-declare -r  BROKEN_FILE=3_broken.rr  # Contains the list of broken files
-declare -r  ERRORS_FILE=3_errors.rr  # Contains the ldd error output
-declare -r     RAW_FILE=4_raw.rr     # Contains the raw list of packages
-declare -r  OWNERS_FILE=4_owners.rr  # Contains the file owners
-declare -r    PKGS_FILE=4_pkgs.rr    # Contains the unsorted bare package names
-declare -r EBUILDS_FILE=4_ebuilds.rr # Contains the unsorted atoms
-                                     # (Appropriately slotted or versioned)
-declare -r   ORDER_FILE=5_order.rr   # Contains the sorted atoms
-declare -r  STATUS_FILE=6_status.rr  # Contains the ldd error output
-declare -ra FILES=(
-       "$ENV_FILE"
-       "$FILES_FILE"
-       "$LDPATH_FILE"
-       "$BROKEN_FILE"
-       "$ERRORS_FILE"
-       "$RAW_FILE"
-       "$OWNERS_FILE"
-       "$PKGS_FILE"
-       "$EBUILDS_FILE"
-       "$ORDER_FILE"
-       "$STATUS_FILE"
-)
-
-# "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.
+#!/usr/bin/python
 #
-# 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 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 SKIP_LIST              # Array of atoms that cannot be emerged (masked?)
-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 WORKING_DIR            # Working directory where cache files are kept
-
-main() {
-       # preliminary setup
-       portage_settings
-       get_opts "$@"
-       setup_portage
-       setup_search_paths_and_masks
-       get_search_env
-       [[ $QUIET -ne 1 ]] && echo
-
-       # Search for broken binaries
-       get_files
-       get_ldpath
-       main_checks
-
-       # Associate broken binaries with packages to rebuild
-       if [[ $PACKAGE_NAMES ]]; then
-               get_packages
-               clean_packages
-               assign_packages_to_ebuilds
-       else
-               get_exact_ebuilds
-       fi
-
-       # Rebuild packages owning broken binaries
-       get_build_order
-       rebuild
-
-       # All done
-       cleanup
-}
-##
-# Refuse to delete anything before we cd to our tmpdir
-# (See mkdir_and_cd_to_tmpdir()
-rm() {
-       eerror "I was instructed to rm '$@'"
-       die 1 "Refusing to delete anything before changing to temporary directory."
-}
-: <<'EW'
-##
-# GNU find has -executable, but if our users' finds do not have that flag
-# we emulate it with this function. Also emulates -writable and -readable.
-# 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 find itself should be executable.
-       local testsubject="$(type -P find)"
-       if [[ $(command find "$testsubject" -executable 2> /dev/null) ]]; then
-               unset -f find # We can just use the command find
-       elif [[ $(command find "$testsubject" -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 "$testsubject" -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 '{}' \; -print})
-                       a=(${a[@]//-writable/-exec test -w '{}' \; -print})
-                       a=(${a[@]//-readable/-exec test -r '{}' \; -print})
-                       command find "${a[@]}"
-               }
-       fi
-       find "$@"
-}
-EW
-
-print_usage() {
-cat << EOF
-${APP_NAME}: (${VERSION})
-
-Copyright (C) 2003-2010 Gentoo Foundation, Inc.
-This is free software; see the source for copying conditions.
-
-Usage: $APP_NAME [OPTIONS] [--] [EMERGE_OPTIONS]
-
-Broken reverse dependency rebuilder.
-
-  -C, --nocolor        Turn off colored output
-  -d, --debug          Print way too much information (uses bash's set -xv)
-  -e, --exact          Emerge based on exact package version
-  -h, --help           Print this usage
-  -i, --ignore         Ignore temporary files from previous runs
-  -k, --keep-temp      Do not delete temporary files on exit
-  -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)
-  -l, --no-ld-path     Do not set LD_LIBRARY_PATH
-  -o, --no-order       Do not check the build order
-                       (Saves time, but may cause breakage.)
-  -p, --pretend        Do a trial run without actually emerging anything
-                       (also passed to emerge command)
-  -P, --no-progress    Turn off the progress meter
-  -q, --quiet          Be less verbose (also passed to emerge command)
-  -v, --verbose        Be more verbose (also passed to emerge command)
-
-Calls emerge, options after -- are ignored by $APP_NAME
-and passed directly to emerge.
-
-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.'
-}
-##
-# Replace whitespace with linebreaks, normalize repeated '/' chars, and sort -u
-# (If any libs have whitespace in their filenames, someone needs punishment.)
-clean_var() {
-       gawk 'BEGIN         {RS="[[:space:]]"}
-            /-\*/         {exit}
-            /[^[:space:]]/ {gsub(/\/\/+/, "/"); print}' | sort -u
-}
-##
-# Exit and optionally output to sterr
-die() {
-       local status=$1
-       shift
-
-       # Check if eerror has been loaded.
-       # Its loaded _after_ opt parsing but not before due to RC_NOCOLOR.
-       type eerror &> /dev/null
-
-       if [[ $? -eq 0 ]];
-       then
-               eerror "$@"
-       else
-               echo " * ${@}" >> /dev/stderr
-       fi
-       exit $status
-}
-##
-# What to do when dynamic linking is consistent
-clean_exit() {
-       if [[ ! $KEEP_TEMP ]]; then
-               rm -f "${FILES[@]}"
-               if [[ "$WORKING_DIR" != "/var/cache/${APP_NAME}" ]]; then
-                       # Remove the working directory
-                       builtin cd; rmdir "$WORKING_DIR"
-               fi
-       fi
-       if [[ $QUIET -ne 1 ]];
-       then
-               echo
-               einfo "$OK_TEXT... All done. "
-       fi
-       exit 0
-}
-##
-# Get the name of the package that owns a file or list of files given as args.
-# NOTE: depends on app-misc/realpath!
-get_file_owner() {
-       local IFS=$'\n'
-
-       rpath=$(realpath "${*}" 2>/dev/null)
-       # To ensure we always have something in rpath...
-       [[ -z $rpath ]] && rpath=${*}
-
-       # Workaround for bug 280341
-       mlib=$(echo ${*}|sed 's:/lib/:/lib64/:')
-       [[ "${*}" == "${mlib}" ]] && mlib=$(echo ${*}|sed 's:/lib64/:/lib/:')
-
-       # Add a space to the end of each object name to prevent false
-       # matches, for example /usr/bin/dia matching /usr/bin/dialog (bug #196460).
-       # The same for "${rpath} ".
-       # Don't match an entry with a '-' at the start of the package name. This
-       # prevents us from matching invalid -MERGING entries. (bug #338031)
-       find -L /var/db/pkg -type f -name CONTENTS -print0 |
-               xargs -0 grep -m 1 -Fl -e "${*} " -e "${rpath} " -e "${mlib} " |
-               sed 's:/var/db/pkg/\(.*\)/\([^-].*\)/CONTENTS:\1/\2:'
-}
-##
-# Normalize some EMERGE_OPTIONS
-normalize_emerge_opts() {
-       # Normalize some EMERGE_OPTIONS
-       EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-p/--pretend})
-       EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-f/--fetchonly})
-       EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-v/--verbose})
-}
-##
-# Use the color preference from portage
-setup_color() {
-       # This should still work if NOCOLOR is set by the -C flag or in the user's
-       # environment.
-       [[ $NOCOLOR = yes || $NOCOLOR = true ]] && export RC_NOCOLOR=yes # HACK! (grr)
-       . /etc/init.d/functions.sh
-}
-##
-# Die if an argument is missing.
-die_if_missing_arg() {
-       [[ ! $2 || $2 = -* ]] && die 1 "Missing expected argument to $1"
-}
-##
-# Die because an option is not recognized.
-die_invalid_option() {
-       # Can't use eerror and einfo because this gets called before function.sh
-       # is sourced
-       echo
-       echo  "Encountered unrecognized option $1." >&2
-       echo
-       echo  "$APP_NAME no longer automatically passes unrecognized options to portage."
-       echo  "Separate emerge-only options from revdep-rebuild options with the -- flag."
-       echo
-       echo  "For example, $APP_NAME -v -- --ask"
-       echo
-       echo  "See the man page or $APP_NAME -h for more detail."
-       echo
-       exit 1
-}
-##
-# Warn about deprecated options.
-warn_deprecated_opt() {
-       # Can't use eerror and einfo because this gets called before function.sh
-       # is sourced
-       echo
-       echo "Encountered deprecated option $1." >&2
-       [[ $2 ]] && echo "Please use $2 instead." >&2
-}
-##
-# Get whole-word commandline options preceded by two dashes.
-get_longopts() {
-       case $1 in
-                                              --nocolor) export NOCOLOR="yes";;
-                                             --no-color) warn_deprecated_opt "$1" "--nocolor"
-                                                         export NOCOLOR="yes";;
-                                                --debug) set -xv;;
-                                                --exact) unset PACKAGE_NAMES;;
-                                                 --help) print_usage
-                                                         exit 0;;
-                                               --ignore) RM_OLD_TEMPFILES=1;;
-                                            --keep-temp) KEEP_TEMP=1;;
-                                            --library=*) # TODO: check for invalid values
-                                                         SONAME="${1#*=}"
-                                                         unset SEARCH_BROKEN;;
-                           --soname=*|--soname-regexp=*) # TODO: check for invalid values
-                                                         warn_deprecated_opt "${1%=*}" "--library"
-                                                         SONAME="${1#*=}"
-                                                         unset SEARCH_BROKEN;;
-                                              --library) # TODO: check for invalid values
-                                                         die_if_missing_arg $1 $2
-                                                         shift
-                                                         SONAME="$1"
-                                                         unset SEARCH_BROKEN;;
-                               --soname|--soname-regexp) # TODO: check for invalid values
-                                                         warn_deprecated_opt "$1" "--library"
-                                                         die_if_missing_arg $1 $2
-                                                         shift
-                                                         SONAME="$1"
-                                                         unset SEARCH_BROKEN;;
-                                           --no-ld-path) unset FULL_LD_PATH;;
-                                             --no-order) unset ORDER_PKGS;;
-                                          --no-progress) progress() { :; };;
-                                              --pretend) EMERGE_OPTIONS+=("--pretend")
-                                                         PRETEND=1;;
-                                                --quiet) progress() { :; }
-                                                         QUIET=1
-                                                         EMERGE_OPTIONS+=($1);;
-                                              --verbose) VERBOSE=1
-                                                         EMERGE_OPTIONS+=("--verbose");;
-                                        --extra-verbose) warn_deprecated_opt "$1" "--verbose"
-                                                         VERBOSE=1
-                                                         EMERGE_OPTIONS+=("--verbose");;
-                                        --package-names) # No longer used, since it is the
-                                                         # default. We accept it for
-                                                         # backwards compatibility.
-                                                         warn_deprecated_opt "$1"
-                                                         PACKAGE_NAMES=1;;
-                                                      *) die_invalid_option $1;;
-       esac
-}
-
-##
-# Get single-letter commandline options preceded by a single dash.
-get_shortopts() {
-       local OPT OPTSTRING OPTARG OPTIND
-       while getopts ":CdehikL:loPpqu:vX" OPT; do
-               case "$OPT" in
-                       C) # TODO: Match syntax with the rest of gentoolkit
-                          export NOCOLOR="yes";;
-                       d) set -xv;;
-                       e) unset PACKAGE_NAMES;;
-                       h) print_usage
-                          exit 0;;
-                       i) RM_OLD_TEMPFILES=1;;
-                       k) KEEP_TEMP=1;;
-                       L) # TODO: Check for invalid values
-                          SONAME="${OPTARG#*=}"
-                          unset SEARCH_BROKEN;;
-                       l) unset FULL_LD_PATH;;
-                       o) unset ORDER_PKGS;;
-                       P) progress() { :; };;
-                       p) EMERGE_OPTIONS+=("--pretend")
-                          PRETEND=1;;
-                       q) progress() { :; }
-                          QUIET=1
-                          EMERGE_OPTIONS+=("--quiet");;
-                       v) VERBOSE=1
-                          EMERGE_OPTIONS+=("--verbose");;
-                       X) # No longer used, since it is the default.
-                          # We accept it for backwards compatibility.
-                          warn_deprecated_opt "-X"
-                          PACKAGE_NAMES=1;;
-                       *) die_invalid_option "-$OPTARG";;
-               esac
-       done
-}
-##
-# Get command-line options.
-get_opts() {
-       local avoid_utils
-       local -a 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
-       while [[ $1 ]]; do
-               case $1 in
-                       --) shift
-                           EMERGE_OPTIONS+=("$@")
-                           break;;
-                       -*) while true; do
-                             args+=("$1")
-                             shift
-                             [[ ${1:--} = -* ]] && break
-                           done
-                           if [[ ${args[0]} = --* ]]; then
-                             get_longopts  "${args[@]}"
-                           else
-                             get_shortopts "${args[@]}"
-                           fi;;
-                        *) die_invalid_option "$1";;
-               esac
-               unset args
-       done
-
-       setup_color
-       normalize_emerge_opts
-
-       # If the user is not super, add --pretend to EMERGE_OPTIONS
-       if [[ ${EMERGE_OPTIONS[@]} != *--pretend* && $UID -ne 0 ]]; then
-               ewarn "You are not superuser. Adding --pretend to emerge options."
-               EMERGE_OPTIONS+=(--pretend)
-       fi
-}
-##
-# Is there a --pretend or --fetchonly flag in the EMERGE_OPTIONS array?
-is_real_merge() {
-       [[ ${EMERGE_OPTIONS[@]} != *--pretend* &&
-          ${EMERGE_OPTIONS[@]} != *--fetchonly* ]]
-}
-##
-# Clean up temporary files and exit
-cleanup_and_die() {
-       rm -f "$@"
-       die 1 "  ...terminated. Removing incomplete $@."
-}
-##
-# Clean trap
-clean_trap() {
-       trap "cleanup_and_die $*" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
-       rm -f "$@"
-}
-##
-# Returns 0 if the first arg is found in the remaining args, 1 otherwise
-# (Returns 2 if given fewer than 2 arguments)
-has() {
-       (( $# > 1 )) || return 2
-       local IFS=$'\a' target="$1"
-       shift
-       [[ $'\a'"$*"$'\a' = *$'\a'$target$'\a'* ]]
-}
-##
-# Dies when it can't change directories
-cd() {
-       if builtin cd -P "$@"; then
-               if [[ $1 != $PWD ]]; then
-                       # Some symlink malfeasance is going on
-                       die 1 "Working directory expected to be $1, but it is $PWD"
-               fi
-       else
-               die 1 "Unable to change working directory to '$@'"
-       fi
-}
-##
-# Tries not to delete any files or directories it shouldn't
-setup_rm() {
-       ##
-       # Anything in the FILES array in tmpdir is fair game for removal
-       rm() {
-               local i IFS=$'\a'
-               [[ $APP_NAME ]] || die 1 '$APP_NAME is not defined! (This is a bug.)'
-               case $@ in
-                       */*|*-r*|*-R*) die 1 "Oops, I'm not allowed to delete that. ($@)";;
-               esac
-               for i; do
-                       # Don't delete files that are not listed in the array
-                       # Allow no slashes or recursive deletes at all.
-                       case $i in
-                               */*|-*r*|-*R*) :;;        # Not OK
-                                          -*) continue;; # OK
-                       esac
-                       has "$i" "${FILES[@]}" && continue
-                       die 1 "Oops, I'm not allowed to delete that. ($@)"
-               done
-               command rm "$@"
-       }
-       # delete this setup function so it's harmless to re-run
-       setup_rm() { :; }
-}
-##
-# Make our temporary files directory
-# $1 - directory name
-# $2 - user name
-verify_tmpdir() {
-       if [[ ! $1 ]]; then
-               die 1 'Temporary file path is unset! (This is a bug.)'
-       elif [[ -d $1 ]]; then
-               cd "$1"
-       else
-               die 1 "Unable to find a satisfactory location for temporary files ($1)"
-       fi
-       [[ $VERBOSE ]] && einfo "Temporary cache files are located in $PWD"
-       setup_rm
-}
-get_search_env() {
-       local new_env
-       local old_env
-       local uid=$(python -c 'import os; import pwd; print(pwd.getpwuid(os.getuid())[0])')
-       # Find a place to put temporary files
-       if [[ "$uid" == "root" ]]; then
-               local tmp_target="/var/cache/${APP_NAME}"
-       else
-               local tmp_target="$(mktemp -d -t revdep-rebuild.XXXXXXXXXX)"
-       fi
-
-       # From here on all work is done inside the temporary directory
-       verify_tmpdir "$tmp_target"
-       WORKING_DIR="$tmp_target"
-
-       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
-               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 . -maxdepth 1 -type f -name '*.rr' -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 "$ENV_FILE" && -s "$ENV_FILE" ]]; then
-               old_env=$(<"$ENV_FILE")
-               if [[ $old_env != $new_env ]]; then
-                       ewarn 'Environment mismatch from previous run, deleting temporary files...'
-                       RM_OLD_TEMPFILES=1
-               fi
-       else
-               # No env file found, silently delete any other tempfiles that may exist
-               RM_OLD_TEMPFILES=1
-       fi
-
-       # If we should remove old tempfiles, do so
-       if [[ $RM_OLD_TEMPFILES ]]; then
-               rm -f "${FILES[@]}"
-       else
-               for file in "${FILES[@]}"; do
-                       if [ -e "$file" ]; then
-                               chown ${uid}:portage "$file"
-                               chmod 600 "$file"
-                       fi
-               done
-       fi
-
-       # Save the environment in a file for next time
-       echo "$new_env" > "$ENV_FILE"
-
-       [[ $VERBOSE ]] && echo $'\n'"$APP_NAME environment:"$'\n'"$new_env"
-
-       if [[ $QUIET -ne 1 ]];
-       then
-               echo
-               einfo "Checking reverse dependencies"
-               einfo "Packages containing binaries and libraries $HEAD_TEXT"
-               einfo "will be emerged."
-       fi
-}
-
-get_files() {
-       [[ $QUIET -ne 1 ]] && einfo "Collecting system binaries and libraries"
-       if [[ -r "$FILES_FILE" && -s "$FILES_FILE" ]]; then
-               [[ $QUIET -ne 1 ]] && einfo "Found existing $FILES_FILE"
-       else
-               # Be safe and remove any extraneous temporary files
-               # Don't remove 0_env.rr - The first file in the array
-               rm -f "${FILES[@]:1}"
-
-               clean_trap "$FILES_FILE"
-
-               if [[ $SEARCH_DIRS_MASK ]]; then
-                       findMask=($SEARCH_DIRS_MASK)
-                       findMask="${findMask[@]/#/-o -path }"
-                       findMask="( ${findMask#-o } ) -prune -o"
-               fi
-               # TODO: Check this -- afaict SEARCH_DIRS isn't an array, so this should just be $SEARCH_DIRS?
-               find ${SEARCH_DIRS[@]} $findMask -type f \( -perm -u+x -o -perm -g+x -o -perm -o+x -o \
-                       -name '*.so' -o -name '*.so.*' -o -name '*.la' \) -print 2> /dev/null |
-                       sort -u > "$FILES_FILE" ||
-                       die $? "find failed to list binary files (This is a bug.)"
-               [[ $QUIET -ne 1 ]] && einfo "Generated new $FILES_FILE"
-       fi
-}
-parse_ld_so_conf() {
-       # FIXME: not safe for paths with spaces
-       local include
-       for path in $(sed '/^#/d;s/#.*$//' < /etc/ld.so.conf); do
-               if [[ $include = true ]]; then
-                       for include_path in $(sed '/^#/d;s/#.*$//' /etc/${path} 2>/dev/null); do
-                               echo $include_path
-                       done
-                       include=""
-                       continue
-               fi
-               if [[ $path != include ]]; then
-                       echo $path
-               else
-                       include="true"
-                       continue
-               fi
-       done
-}
-get_ldpath() {
-       local COMPLETE_LD_LIBRARY_PATH
-       [[ $SEARCH_BROKEN && $FULL_LD_PATH ]] || return
-       [[ $QUIET -ne 1 ]] && einfo 'Collecting complete LD_LIBRARY_PATH'
-       if [[ -r "$LDPATH_FILE" && -s "$LDPATH_FILE" ]]; then
-               [[ $QUIET -ne 1 ]] && einfo "Found existing $LDPATH_FILE."
-       else
-               clean_trap "$LDPATH_FILE"
-               # Ensure that the "trusted" lib directories are at the start of the path
-               COMPLETE_LD_LIBRARY_PATH=(
-                       /lib*
-                       /usr/lib*
-                       $(parse_ld_so_conf)
-                       $(sed 's:/[^/]*$::' < "$FILES_FILE" | sort -ru)
-               )
-               IFS=':'
-               COMPLETE_LD_LIBRARY_PATH="${COMPLETE_LD_LIBRARY_PATH[*]}"
-               IFS="$OIFS"
-               echo "$COMPLETE_LD_LIBRARY_PATH" > "$LDPATH_FILE"
-               [[ $QUIET -ne 1 ]] && einfo "Generated new $LDPATH_FILE"
-       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 "$LDPATH_FILE" && -s "$LDPATH_FILE" ]] ||
-                       die 1 "Unable to find $LDPATH_FILE"
-               COMPLETE_LD_LIBRARY_PATH=$(<"$LDPATH_FILE")
-       fi
-       [[ $QUIET -ne 1 ]] && einfo "Checking dynamic linking $WORKING_TEXT"
-       if [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]]; then
-               [[ $QUIET -ne 1 ]] && einfo "Found existing $BROKEN_FILE."
-       else
-               clean_trap "$BROKEN_FILE" "$ERRORS_FILE"
-               files=($(<"$FILES_FILE"))
-               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>> "$ERRORS_FILE" | 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 -E "$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 -E "$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" >> "$BROKEN_FILE"
-                                                               echo_v "  broken $target_file (requires $MISSING_LIBS)"
-                                                       fi
-                                               fi
-                                       else
-                                               # FIXME: I hate duplicating code
-                                               # Only rebuild for direct dependencies
-                                               MISSING_LIBS=$(
-                                                       expr="s/^[[:space:]]*\([^[:space:]]*\).*$/\1/p"
-                                                       sort -u <<< "$ldd_output" | grep -E "$SONAME" | 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" >> "$BROKEN_FILE"
-                                                       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
-                               la_SEARCH_DIRS="$SEARCH_DIRS"
-                               la_search_dir=""
-                               la_broken=""
-                               la_lib=""
-                               for depend in $(
-                                       gawk -F"[=']" '/^dependency_libs/{
-                                               print $3
-                                       }' "$target_file"
-                               ); do
-                                       if [[ $depend = /* && ! -e $depend ]]; then
-                                               echo "obj $target_file" >> "$BROKEN_FILE"
-                                               echo_v "  broken $target_file (requires $depend)"
-                                       elif [[ $depend = -[LR]/* ]]; then
-                                               if ! [[ $'\n'${la_SEARCH_DIRS}$'\n' == *$'\n'${depend#-?}$'\n'* ]]; then
-                                                       la_SEARCH_DIRS+=$'\n'"${depend#-?}"
-                                               fi
-                                       elif [[ $depend = "-l"* ]]; then
-                                               la_lib="lib${depend#-l}"
-                                               la_broken="yes"
-                                               IFS=$'\n'
-                                               for la_search_dir in $la_SEARCH_DIRS; do
-                                                       if [[ -e ${la_search_dir}/${la_lib}.so || -e ${la_search_dir}/${la_lib}.a ]]; then
-                                                               la_broken="no"
-                                                       fi
-                                               done
-                                               IFS="$OIFS"
-                                               if [[ $la_broken = yes ]]; then
-                                                       echo "obj $target_file" >> "$BROKEN_FILE"
-                                                       echo_v "  broken $target_file (requires $depend)"
-                                               fi
-                                       fi
-                               done
-                               unset la_SEARCH_DIRS la_search_dir la_broken la_lib
-                       fi
-                       [[ $VERBOSE ]] &&
-                               progress $((++i)) $numFiles $target_file ||
-                               progress $((++i)) $numFiles
-               done
-               if [[ $SEARCH_BROKEN && -f $ERRORS_FILE ]]; then
-                       # Look for missing version
-                       while read target_file; do
-                               echo "obj $target_file" >> "$BROKEN_FILE"
-                               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'/|}"
-                               gawk -v ldmask="(${LD_LIBRARY_MASK//./\\\.})" '
-                                       /no version information available/ && $0 !~ ldmask {
-                                               gsub(/[()]/, "", $NF)
-                                               if (seen[$NF]++)  next
-                                               print $NF
-                                       }' "$ERRORS_FILE"
-                       )
-               fi
-               [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]] || clean_exit
-               sort -u "$BROKEN_FILE" -o "$BROKEN_FILE"
-               [[ $QUIET -ne 1 ]] && einfo "Generated new $BROKEN_FILE"
-       fi
-}
-get_packages() {
-       local target_file
-       local EXACT_PKG
-       local PKG
-       local obj
-       einfo 'Assigning files to packages'
-       if [[ -r "$RAW_FILE" && -s "$RAW_FILE" ]]; then
-               einfo "Found existing $RAW_FILE"
-       else
-               clean_trap "$RAW_FILE" "$OWNERS_FILE"
-               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" >> "$RAW_FILE"
-                               echo "$target_file -> $EXACT_PKG" >> "$OWNERS_FILE"
-                               echo_v "  $target_file -> $PKG"
-                       else
-                               ewarn " !!! $target_file not owned by any package is broken !!!"
-                               echo "$target_file -> (none)" >> "$OWNERS_FILE"
-                               echo_v "  $target_file -> (none)"
-                       fi
-               done < "$BROKEN_FILE"
-               [[ $QUIET -ne 1 ]] && einfo "Generated new $RAW_FILE and $OWNERS_FILE"
-       fi
-       # if we find '(none)' on every line, exit out
-       if ! grep -qvF '(none)' "$OWNERS_FILE"; 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 $OWNERS_FILE"
-               if [[ $VERBOSE ]]; then
-                       ewarn "The broken files are:"
-                       while read filename junk; do
-                               ewarn "  $filename"
-                       done < "$OWNERS_FILE"
-               fi
-               exit 0 # FIXME: Should we exit 1 here?
-       fi
-}
-clean_packages() {
-       [[ $QUIET -ne 1 ]] && einfo 'Cleaning list of packages to rebuild'
-       if [[ -r "$PKGS_FILE" && -s "$PKGS_FILE" ]]; then
-               [[ $QUIET -ne 1 ]] && einfo "Found existing $PKGS_FILE"
-       else
-               sort -u "$RAW_FILE" > "$PKGS_FILE"
-               [[ $QUIET -ne 1 ]] && einfo "Generated new $PKGS_FILE"
-       fi
-}
-assign_packages_to_ebuilds() {
-       local EXACT_PKG
-       local PKG
-       local SLOT
-       einfo 'Assigning packages to ebuilds'
-       if [[ -r "$EBUILDS_FILE" && -s "$EBUILDS_FILE" ]]; then
-               einfo "Found existing $EBUILDS_FILE"
-       elif [[ -r "$PKGS_FILE" && -s "$PKGS_FILE" ]]; then
-                       clean_trap "$EBUILDS_FILE"
-                       while read EXACT_PKG; do
-                               # Get the slot
-                               PKG="${EXACT_PKG%%-r[[:digit:]]*}"
-                               PKG="${PKG%-*}"
-                               SLOT=$(</var/db/pkg/$EXACT_PKG/SLOT)
-                               echo "$PKG:$SLOT"
-                       done < "$PKGS_FILE" > "$EBUILDS_FILE"
-                       [[ $QUIET -ne 1 ]] && einfo "Generated new $EBUILDS_FILE"
-       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 $EBUILDS_FILE && -s $EBUILDS_FILE ]]; then
-               einfo "Found existing $EBUILDS_FILE"
-       elif [[ -r $BROKEN_FILE && -s $BROKEN_FILE ]]; then
-               rebuildList=" $(<"$BROKEN_FILE") "
-               rebuildList=(${rebuildList//[[:space:]]obj[[:space:]]/ })
-               get_file_owner "${rebuildList[@]}" | sed 's/^/=/' > "$EBUILDS_FILE"
-               [[ $QUIET -ne 1 ]] && einfo "Generated new $EBUILDS_FILE"
-       else
-               einfo 'Nothing to rebuild.'
-               die 1 '(The program should have already quit, so this is a minor bug.)'
-       fi
-}
-list_skipped_packages() {
-       ewarn
-       ewarn 'Portage could not find any version of the following packages it could build:'
-       ewarn "${SKIP_LIST[@]}"
-       ewarn
-       ewarn '(Perhaps they are masked, blocked, or removed from portage.)'
-       ewarn 'Try to emerge them manually.'
-       ewarn
-}
-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
-       [[ $QUIET -ne 1 ]] && einfo 'Evaluating package order'
-       if [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" ]]; then
-               einfo "Found existing $ORDER_FILE"
-       else
-               clean_trap "$ORDER_FILE"
-               RAW_REBUILD_LIST=$(<"$EBUILDS_FILE")
-               if [[ $RAW_REBUILD_LIST ]]; then
-                       export EMERGE_DEFAULT_OPTS="--nospinner --pretend --oneshot --quiet"
-                       RAW_REBUILD_LIST=($RAW_REBUILD_LIST) # convert into array
-                       # If PACKAGE_NAMES is defined we're using slots, not versions
-                       if [[ $PACKAGE_NAMES ]]; then
-                               # Eliminate atoms that can't be built
-                               for i in "${!RAW_REBUILD_LIST[@]}"; do
-                                       if [[ "${RAW_REBUILD_LIST[i]}" = *[A-Za-z]* ]]; then
-                                               portageq best_visible "$PORTAGE_ROOT" "${RAW_REBUILD_LIST[i]}" >/dev/null && continue
-                                               SKIP_LIST+=("${RAW_REBUILD_LIST[i]}")
-                                       fi
-                                       unset RAW_REBUILD_LIST[i]
-                               done
-                               # If RAW_REBUILD_LIST is empty, then we have nothing to build.
-                               if (( ${#RAW_REBUILD_LIST[@]} == 0 )); then
-                                       if (( ${#SKIP_LIST[@]} == 0 )); then
-                                               ewarn "The list of packages to skip is empty, but there are no"
-                                               ewarn "packages listed to rebuild either. (This is a bug.)"
-                                       else
-                                               list_skipped_packages
-                                       fi
-                                       die 1 'Warning: Portage cannot rebuild any of the necessary packages.'
-                               fi
-                       fi
-                       RAW_REBUILD_LIST="${RAW_REBUILD_LIST[@]}"
-
-                       # We no longer determine the package order ourselves.  Instead we call emerge
-                       # with --complete-graph=y in the rebuild function.
-                       if false ; then
-                               REBUILD_GREP=$(emerge --nodeps $RAW_REBUILD_LIST | sed 's/\[[^]]*\]//g')
-                               if (( ${PIPESTATUS[0]} == 0 )); then
-                                       emerge --deep $RAW_REBUILD_LIST |
-                                               sed 's/\[[^]]*\]//g' |
-                                               grep -F "$REBUILD_GREP" > "$ORDER_FILE"
-                               fi
-
-                               # Here we use the PIPESTATUS from the second emerge, the --deep one.
-                               if (( ${PIPESTATUS[0]} != 0 )); then
-                                       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 "$ORDER_FILE"
-                               fi
-                       else
-                               echo "$RAW_REBUILD_LIST" > "$ORDER_FILE"
-                       fi
-                       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 "$ORDER_FILE" && -s "$ORDER_FILE" && $QUIET -ne 1 ]] && einfo "Generated new $ORDER_FILE"
-}
-
-show_unowned_files() {
-       if grep -qF '(none)' "$OWNERS_FILE"; 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 < "$OWNERS_FILE" | gawk '!s[$0]++' # (omit dupes)
-       fi
-}
-
-# Get multiple portage variables at once to speedup revdep-rebuild.
-portage_settings() {
-       local ORIG_SEARCH_DIRS="$SEARCH_DIRS"
-       local ORIG_SEARCH_DIRS_MASK="$SEARCH_DIRS_MASK"
-       local ORIG_LD_LIBRARY_MASK="$LD_LIBRARY_MASK"
-       unset SEARCH_DIRS
-       unset SEARCH_DIRS_MASK
-       unset LD_LIBRARY_MASK
-
-       eval $(portageq envvar -v PORTAGE_ROOT PORTAGE_NICENESS EMERGE_DEFAULT_OPTS NOCOLOR SEARCH_DIRS SEARCH_DIRS_MASK LD_LIBRARY_MASK)
-       export NOCOLOR
-
-       SEARCH_DIRS="$ORIG_SEARCH_DIRS $SEARCH_DIRS"
-       SEARCH_DIRS_MASK="$ORIG_SEARCH_DIRS_MASK $SEARCH_DIRS_MASK"
-       LD_LIBRARY_MASK="$ORIG_LD_LIBRARY_MASK $LD_LIBRARY_MASK"
-}
-
-##
-# Setup portage and the search paths
-setup_portage() {
-       # Obey PORTAGE_NICENESS (which is incremental to the current nice value)
-       if [[ $PORTAGE_NICENESS ]]; then
-               current_niceness=$(nice)
-               let PORTAGE_NICENESS=${current_niceness}+${PORTAGE_NICENESS}
-               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="${PORTAGE_ROOT:-/}"
-}
-
-##
-# Setup the paths to search (and filter the ones to avoid)
-setup_search_paths_and_masks() {
-       local configfile sdir mdir skip_me filter_SEARCH_DIRS
-
-       [[ $QUIET -ne 1 ]] && einfo "Configuring search environment for $APP_NAME"
-
-       # 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 configfile in /etc/revdep-rebuild/*; do
-                       SEARCH_DIRS+=" "$(. $configfile; echo $SEARCH_DIRS)
-                       SEARCH_DIRS_MASK+=" "$(. $configfile; echo $SEARCH_DIRS_MASK)
-                       LD_LIBRARY_MASK+=" "$(. $configfile; echo $LD_LIBRARY_MASK)
-               done
-       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+=" "$(parse_ld_so_conf)
-       fi
-
-       # Set the final variables
-       SEARCH_DIRS=$(clean_var <<< "$SEARCH_DIRS")
-       SEARCH_DIRS_MASK=$(clean_var <<< "$SEARCH_DIRS_MASK")
-       LD_LIBRARY_MASK=$(clean_var <<< "$LD_LIBRARY_MASK")
-       # Filter masked paths from SEARCH_DIRS
-       for sdir in ${SEARCH_DIRS} ; do
-               skip_me=
-               for mdir in ${SEARCH_DIRS_MASK}; do
-                       [[ ${sdir} == ${mdir}/* ]] && skip_me=1 && break
-               done
-               [[ -n ${skip_me} ]] || filter_SEARCH_DIRS+=" ${sdir}"
-       done
-       SEARCH_DIRS=$(clean_var <<< "${filter_SEARCH_DIRS}")
-       [[ $SEARCH_DIRS ]] || die 1 "No search defined -- this is a bug."
-}
-##
-# Rebuild packages owning broken binaries
-rebuild() {
-       if [[ -r $ORDER_FILE && -s $ORDER_FILE ]]; then
-               # The rebuild list contains category/package:slot atoms.
-               # Do not prepend with an '=' sign.
-               # REBUILD_LIST=( $(<"$ORDER_FILE") )
-               # REBUILD_LIST="${REBUILD_LIST[@]/#/=}"
-               REBUILD_LIST=$(<"$ORDER_FILE")
-       else
-               REBUILD_LIST=$(sort -u "$EBUILDS_FILE")
-       fi
-
-       trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
-
-       [[ $QUIET -ne 1 ]] && einfo 'All prepared. Starting rebuild'
-       echo "emerge --complete-graph=y --oneshot ${EMERGE_DEFAULT_OPTS} ${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 --complete-graph=y --oneshot ${EMERGE_DEFAULT_OPTS} ${EMERGE_OPTIONS[@]} $REBUILD_LIST <&6
-               echo $? > "$STATUS_FILE"
-       } &
-       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<&-
-}
-##
-# Finish up
-cleanup() {
-       if [[ (( $(<"$STATUS_FILE") != 0 )) && ! is_real_merge ]]; 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 $ORDER_FILE 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 ${WORKING_DIR}/*.rr"
-               show_unowned_files
-               exit $EMERGE_STATUS
-       elif is_real_merge; then
-               trap_cmd() {
-                       eerror "terminated. Please remove the temporary files manually:"
-                       eerror "rm ${WORKING_DIR}/*.rr"
-                       exit 1
-               }
-               [[ "${SKIP_LIST[@]}" != "" ]] && list_skipped_packages
-               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. Possible reasons for remaining inconsistencies include:'
-               einfo '  orphaned files'
-               einfo '  deep dependencies'
-               einfo "  packages installed outside of portage's control"
-               einfo '  specially-evaluated libraries'
-               if [[ -r "$OWNERS_FILE" && -s "$OWNERS_FILE" ]]; then
-                       show_unowned_files
-               fi
-               [[ $KEEP_TEMP ]] || rm -f "${FILES[@]}"
-       else
-               einfo 'Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.'
-       fi
-}
-
-main "$@"
+# Copyright 2010 Brian Dolbec <brian.dolbec@gmail.com>
+# Copyright 2002-2010 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2 or later
+#
+# $Header$
+
+"""'analyse' is a flexible utility for Gentoo linux which can display various
+information about installed packages, such as the USE flags used and the
+packages that use them.  It can also be used to help rebuild /etc/portage/package.*
+files in the event of corruption, and possibly more.
+"""
+
+from __future__ import print_function
+
+import sys
+# This block ensures that ^C interrupts are handled quietly.
+try:
+       import signal
+
+       def exithandler(signum,frame):
+               signal.signal(signal.SIGINT, signal.SIG_IGN)
+               signal.signal(signal.SIGTERM, signal.SIG_IGN)
+               print()
+               sys.exit(1)
+
+       signal.signal(signal.SIGINT, exithandler)
+       signal.signal(signal.SIGTERM, exithandler)
+       signal.signal(signal.SIGPIPE, signal.SIG_DFL)
+
+
+except KeyboardInterrupt:
+       print()
+       sys.exit(1)
+
+from gentoolkit import errors
+from gentoolkit.revdep_rebuild import rebuild
+
+try:
+       success = rebuild.main(rebuild.parse_options())
+       sys.exit(success)
+except errors.GentoolkitException as err:
+       if '--debug' in sys.argv:
+               raise
+       else:
+               from gentoolkit import pprinter as pp
+               sys.stderr.write(pp.error(str(err)))
+               print()
+               print("Add '--debug' to global options for traceback.")
+               sys.exit(1)
diff --git a/bin/revdep-rebuild.sh b/bin/revdep-rebuild.sh
new file mode 100755 (executable)
index 0000000..f00b791
--- /dev/null
@@ -0,0 +1,1195 @@
+#!/bin/bash
+# Copyright 1999-2010 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:
+
+# Must-be-blank:
+unset GREP_OPTIONS
+
+# Readonly variables:
+declare -r APP_NAME="${0##*/}" # The name of this application
+declare -r VERSION="svn"
+declare -r OIFS="$IFS"         # Save the IFS
+declare -r     ENV_FILE=0_env.rr     # Contains environment variables
+declare -r   FILES_FILE=1_files.rr   # Contains a list of files to search
+declare -r  LDPATH_FILE=2_ldpath.rr  # Contains the LDPATH
+declare -r  BROKEN_FILE=3_broken.rr  # Contains the list of broken files
+declare -r  ERRORS_FILE=3_errors.rr  # Contains the ldd error output
+declare -r     RAW_FILE=4_raw.rr     # Contains the raw list of packages
+declare -r  OWNERS_FILE=4_owners.rr  # Contains the file owners
+declare -r    PKGS_FILE=4_pkgs.rr    # Contains the unsorted bare package names
+declare -r EBUILDS_FILE=4_ebuilds.rr # Contains the unsorted atoms
+                                     # (Appropriately slotted or versioned)
+declare -r   ORDER_FILE=5_order.rr   # Contains the sorted atoms
+declare -r  STATUS_FILE=6_status.rr  # Contains the ldd error output
+declare -ra FILES=(
+       "$ENV_FILE"
+       "$FILES_FILE"
+       "$LDPATH_FILE"
+       "$BROKEN_FILE"
+       "$ERRORS_FILE"
+       "$RAW_FILE"
+       "$OWNERS_FILE"
+       "$PKGS_FILE"
+       "$EBUILDS_FILE"
+       "$ORDER_FILE"
+       "$STATUS_FILE"
+)
+
+# "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 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 SKIP_LIST              # Array of atoms that cannot be emerged (masked?)
+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 WORKING_DIR            # Working directory where cache files are kept
+
+main() {
+       # preliminary setup
+       portage_settings
+       get_opts "$@"
+       setup_portage
+       setup_search_paths_and_masks
+       get_search_env
+       [[ $QUIET -ne 1 ]] && echo
+
+       # Search for broken binaries
+       get_files
+       get_ldpath
+       main_checks
+
+       # Associate broken binaries with packages to rebuild
+       if [[ $PACKAGE_NAMES ]]; then
+               get_packages
+               clean_packages
+               assign_packages_to_ebuilds
+       else
+               get_exact_ebuilds
+       fi
+
+       # Rebuild packages owning broken binaries
+       get_build_order
+       rebuild
+
+       # All done
+       cleanup
+}
+##
+# Refuse to delete anything before we cd to our tmpdir
+# (See mkdir_and_cd_to_tmpdir()
+rm() {
+       eerror "I was instructed to rm '$@'"
+       die 1 "Refusing to delete anything before changing to temporary directory."
+}
+: <<'EW'
+##
+# GNU find has -executable, but if our users' finds do not have that flag
+# we emulate it with this function. Also emulates -writable and -readable.
+# 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 find itself should be executable.
+       local testsubject="$(type -P find)"
+       if [[ $(command find "$testsubject" -executable 2> /dev/null) ]]; then
+               unset -f find # We can just use the command find
+       elif [[ $(command find "$testsubject" -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 "$testsubject" -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 '{}' \; -print})
+                       a=(${a[@]//-writable/-exec test -w '{}' \; -print})
+                       a=(${a[@]//-readable/-exec test -r '{}' \; -print})
+                       command find "${a[@]}"
+               }
+       fi
+       find "$@"
+}
+EW
+
+print_usage() {
+cat << EOF
+${APP_NAME}: (${VERSION})
+
+Copyright (C) 2003-2010 Gentoo Foundation, Inc.
+This is free software; see the source for copying conditions.
+
+Usage: $APP_NAME [OPTIONS] [--] [EMERGE_OPTIONS]
+
+Broken reverse dependency rebuilder.
+
+  -C, --nocolor        Turn off colored output
+  -d, --debug          Print way too much information (uses bash's set -xv)
+  -e, --exact          Emerge based on exact package version
+  -h, --help           Print this usage
+  -i, --ignore         Ignore temporary files from previous runs
+  -k, --keep-temp      Do not delete temporary files on exit
+  -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)
+  -l, --no-ld-path     Do not set LD_LIBRARY_PATH
+  -o, --no-order       Do not check the build order
+                       (Saves time, but may cause breakage.)
+  -p, --pretend        Do a trial run without actually emerging anything
+                       (also passed to emerge command)
+  -P, --no-progress    Turn off the progress meter
+  -q, --quiet          Be less verbose (also passed to emerge command)
+  -v, --verbose        Be more verbose (also passed to emerge command)
+
+Calls emerge, options after -- are ignored by $APP_NAME
+and passed directly to emerge.
+
+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.'
+}
+##
+# Replace whitespace with linebreaks, normalize repeated '/' chars, and sort -u
+# (If any libs have whitespace in their filenames, someone needs punishment.)
+clean_var() {
+       gawk 'BEGIN         {RS="[[:space:]]"}
+            /-\*/         {exit}
+            /[^[:space:]]/ {gsub(/\/\/+/, "/"); print}' | sort -u
+}
+##
+# Exit and optionally output to sterr
+die() {
+       local status=$1
+       shift
+
+       # Check if eerror has been loaded.
+       # Its loaded _after_ opt parsing but not before due to RC_NOCOLOR.
+       type eerror &> /dev/null
+
+       if [[ $? -eq 0 ]];
+       then
+               eerror "$@"
+       else
+               echo " * ${@}" >> /dev/stderr
+       fi
+       exit $status
+}
+##
+# What to do when dynamic linking is consistent
+clean_exit() {
+       if [[ ! $KEEP_TEMP ]]; then
+               rm -f "${FILES[@]}"
+               if [[ "$WORKING_DIR" != "/var/cache/${APP_NAME}" ]]; then
+                       # Remove the working directory
+                       builtin cd; rmdir "$WORKING_DIR"
+               fi
+       fi
+       if [[ $QUIET -ne 1 ]];
+       then
+               echo
+               einfo "$OK_TEXT... All done. "
+       fi
+       exit 0
+}
+##
+# Get the name of the package that owns a file or list of files given as args.
+# NOTE: depends on app-misc/realpath!
+get_file_owner() {
+       local IFS=$'\n'
+
+       rpath=$(realpath "${*}" 2>/dev/null)
+       # To ensure we always have something in rpath...
+       [[ -z $rpath ]] && rpath=${*}
+
+       # Workaround for bug 280341
+       mlib=$(echo ${*}|sed 's:/lib/:/lib64/:')
+       [[ "${*}" == "${mlib}" ]] && mlib=$(echo ${*}|sed 's:/lib64/:/lib/:')
+
+       # Add a space to the end of each object name to prevent false
+       # matches, for example /usr/bin/dia matching /usr/bin/dialog (bug #196460).
+       # The same for "${rpath} ".
+       # Don't match an entry with a '-' at the start of the package name. This
+       # prevents us from matching invalid -MERGING entries. (bug #338031)
+       find -L /var/db/pkg -type f -name CONTENTS -print0 |
+               xargs -0 grep -m 1 -Fl -e "${*} " -e "${rpath} " -e "${mlib} " |
+               sed 's:/var/db/pkg/\(.*\)/\([^-].*\)/CONTENTS:\1/\2:'
+}
+##
+# Normalize some EMERGE_OPTIONS
+normalize_emerge_opts() {
+       # Normalize some EMERGE_OPTIONS
+       EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-p/--pretend})
+       EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-f/--fetchonly})
+       EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-v/--verbose})
+}
+##
+# Use the color preference from portage
+setup_color() {
+       # This should still work if NOCOLOR is set by the -C flag or in the user's
+       # environment.
+       [[ $NOCOLOR = yes || $NOCOLOR = true ]] && export RC_NOCOLOR=yes # HACK! (grr)
+       . /etc/init.d/functions.sh
+}
+##
+# Die if an argument is missing.
+die_if_missing_arg() {
+       [[ ! $2 || $2 = -* ]] && die 1 "Missing expected argument to $1"
+}
+##
+# Die because an option is not recognized.
+die_invalid_option() {
+       # Can't use eerror and einfo because this gets called before function.sh
+       # is sourced
+       echo
+       echo  "Encountered unrecognized option $1." >&2
+       echo
+       echo  "$APP_NAME no longer automatically passes unrecognized options to portage."
+       echo  "Separate emerge-only options from revdep-rebuild options with the -- flag."
+       echo
+       echo  "For example, $APP_NAME -v -- --ask"
+       echo
+       echo  "See the man page or $APP_NAME -h for more detail."
+       echo
+       exit 1
+}
+##
+# Warn about deprecated options.
+warn_deprecated_opt() {
+       # Can't use eerror and einfo because this gets called before function.sh
+       # is sourced
+       echo
+       echo "Encountered deprecated option $1." >&2
+       [[ $2 ]] && echo "Please use $2 instead." >&2
+}
+##
+# Get whole-word commandline options preceded by two dashes.
+get_longopts() {
+       case $1 in
+                                              --nocolor) export NOCOLOR="yes";;
+                                             --no-color) warn_deprecated_opt "$1" "--nocolor"
+                                                         export NOCOLOR="yes";;
+                                                --debug) set -xv;;
+                                                --exact) unset PACKAGE_NAMES;;
+                                                 --help) print_usage
+                                                         exit 0;;
+                                               --ignore) RM_OLD_TEMPFILES=1;;
+                                            --keep-temp) KEEP_TEMP=1;;
+                                            --library=*) # TODO: check for invalid values
+                                                         SONAME="${1#*=}"
+                                                         unset SEARCH_BROKEN;;
+                           --soname=*|--soname-regexp=*) # TODO: check for invalid values
+                                                         warn_deprecated_opt "${1%=*}" "--library"
+                                                         SONAME="${1#*=}"
+                                                         unset SEARCH_BROKEN;;
+                                              --library) # TODO: check for invalid values
+                                                         die_if_missing_arg $1 $2
+                                                         shift
+                                                         SONAME="$1"
+                                                         unset SEARCH_BROKEN;;
+                               --soname|--soname-regexp) # TODO: check for invalid values
+                                                         warn_deprecated_opt "$1" "--library"
+                                                         die_if_missing_arg $1 $2
+                                                         shift
+                                                         SONAME="$1"
+                                                         unset SEARCH_BROKEN;;
+                                           --no-ld-path) unset FULL_LD_PATH;;
+                                             --no-order) unset ORDER_PKGS;;
+                                          --no-progress) progress() { :; };;
+                                              --pretend) EMERGE_OPTIONS+=("--pretend")
+                                                         PRETEND=1;;
+                                                --quiet) progress() { :; }
+                                                         QUIET=1
+                                                         EMERGE_OPTIONS+=($1);;
+                                              --verbose) VERBOSE=1
+                                                         EMERGE_OPTIONS+=("--verbose");;
+                                        --extra-verbose) warn_deprecated_opt "$1" "--verbose"
+                                                         VERBOSE=1
+                                                         EMERGE_OPTIONS+=("--verbose");;
+                                        --package-names) # No longer used, since it is the
+                                                         # default. We accept it for
+                                                         # backwards compatibility.
+                                                         warn_deprecated_opt "$1"
+                                                         PACKAGE_NAMES=1;;
+                                                      *) die_invalid_option $1;;
+       esac
+}
+
+##
+# Get single-letter commandline options preceded by a single dash.
+get_shortopts() {
+       local OPT OPTSTRING OPTARG OPTIND
+       while getopts ":CdehikL:loPpqu:vX" OPT; do
+               case "$OPT" in
+                       C) # TODO: Match syntax with the rest of gentoolkit
+                          export NOCOLOR="yes";;
+                       d) set -xv;;
+                       e) unset PACKAGE_NAMES;;
+                       h) print_usage
+                          exit 0;;
+                       i) RM_OLD_TEMPFILES=1;;
+                       k) KEEP_TEMP=1;;
+                       L) # TODO: Check for invalid values
+                          SONAME="${OPTARG#*=}"
+                          unset SEARCH_BROKEN;;
+                       l) unset FULL_LD_PATH;;
+                       o) unset ORDER_PKGS;;
+                       P) progress() { :; };;
+                       p) EMERGE_OPTIONS+=("--pretend")
+                          PRETEND=1;;
+                       q) progress() { :; }
+                          QUIET=1
+                          EMERGE_OPTIONS+=("--quiet");;
+                       v) VERBOSE=1
+                          EMERGE_OPTIONS+=("--verbose");;
+                       X) # No longer used, since it is the default.
+                          # We accept it for backwards compatibility.
+                          warn_deprecated_opt "-X"
+                          PACKAGE_NAMES=1;;
+                       *) die_invalid_option "-$OPTARG";;
+               esac
+       done
+}
+##
+# Get command-line options.
+get_opts() {
+       local avoid_utils
+       local -a 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
+       while [[ $1 ]]; do
+               case $1 in
+                       --) shift
+                           EMERGE_OPTIONS+=("$@")
+                           break;;
+                       -*) while true; do
+                             args+=("$1")
+                             shift
+                             [[ ${1:--} = -* ]] && break
+                           done
+                           if [[ ${args[0]} = --* ]]; then
+                             get_longopts  "${args[@]}"
+                           else
+                             get_shortopts "${args[@]}"
+                           fi;;
+                        *) die_invalid_option "$1";;
+               esac
+               unset args
+       done
+
+       setup_color
+       normalize_emerge_opts
+
+       # If the user is not super, add --pretend to EMERGE_OPTIONS
+       if [[ ${EMERGE_OPTIONS[@]} != *--pretend* && $UID -ne 0 ]]; then
+               ewarn "You are not superuser. Adding --pretend to emerge options."
+               EMERGE_OPTIONS+=(--pretend)
+       fi
+}
+##
+# Is there a --pretend or --fetchonly flag in the EMERGE_OPTIONS array?
+is_real_merge() {
+       [[ ${EMERGE_OPTIONS[@]} != *--pretend* &&
+          ${EMERGE_OPTIONS[@]} != *--fetchonly* ]]
+}
+##
+# Clean up temporary files and exit
+cleanup_and_die() {
+       rm -f "$@"
+       die 1 "  ...terminated. Removing incomplete $@."
+}
+##
+# Clean trap
+clean_trap() {
+       trap "cleanup_and_die $*" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
+       rm -f "$@"
+}
+##
+# Returns 0 if the first arg is found in the remaining args, 1 otherwise
+# (Returns 2 if given fewer than 2 arguments)
+has() {
+       (( $# > 1 )) || return 2
+       local IFS=$'\a' target="$1"
+       shift
+       [[ $'\a'"$*"$'\a' = *$'\a'$target$'\a'* ]]
+}
+##
+# Dies when it can't change directories
+cd() {
+       if builtin cd -P "$@"; then
+               if [[ $1 != $PWD ]]; then
+                       # Some symlink malfeasance is going on
+                       die 1 "Working directory expected to be $1, but it is $PWD"
+               fi
+       else
+               die 1 "Unable to change working directory to '$@'"
+       fi
+}
+##
+# Tries not to delete any files or directories it shouldn't
+setup_rm() {
+       ##
+       # Anything in the FILES array in tmpdir is fair game for removal
+       rm() {
+               local i IFS=$'\a'
+               [[ $APP_NAME ]] || die 1 '$APP_NAME is not defined! (This is a bug.)'
+               case $@ in
+                       */*|*-r*|*-R*) die 1 "Oops, I'm not allowed to delete that. ($@)";;
+               esac
+               for i; do
+                       # Don't delete files that are not listed in the array
+                       # Allow no slashes or recursive deletes at all.
+                       case $i in
+                               */*|-*r*|-*R*) :;;        # Not OK
+                                          -*) continue;; # OK
+                       esac
+                       has "$i" "${FILES[@]}" && continue
+                       die 1 "Oops, I'm not allowed to delete that. ($@)"
+               done
+               command rm "$@"
+       }
+       # delete this setup function so it's harmless to re-run
+       setup_rm() { :; }
+}
+##
+# Make our temporary files directory
+# $1 - directory name
+# $2 - user name
+verify_tmpdir() {
+       if [[ ! $1 ]]; then
+               die 1 'Temporary file path is unset! (This is a bug.)'
+       elif [[ -d $1 ]]; then
+               cd "$1"
+       else
+               die 1 "Unable to find a satisfactory location for temporary files ($1)"
+       fi
+       [[ $VERBOSE ]] && einfo "Temporary cache files are located in $PWD"
+       setup_rm
+}
+get_search_env() {
+       local new_env
+       local old_env
+       local uid=$(python -c 'import os; import pwd; print(pwd.getpwuid(os.getuid())[0])')
+       # Find a place to put temporary files
+       if [[ "$uid" == "root" ]]; then
+               local tmp_target="/var/cache/${APP_NAME}"
+       else
+               local tmp_target="$(mktemp -d -t revdep-rebuild.XXXXXXXXXX)"
+       fi
+
+       # From here on all work is done inside the temporary directory
+       verify_tmpdir "$tmp_target"
+       WORKING_DIR="$tmp_target"
+
+       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
+               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 . -maxdepth 1 -type f -name '*.rr' -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 "$ENV_FILE" && -s "$ENV_FILE" ]]; then
+               old_env=$(<"$ENV_FILE")
+               if [[ $old_env != $new_env ]]; then
+                       ewarn 'Environment mismatch from previous run, deleting temporary files...'
+                       RM_OLD_TEMPFILES=1
+               fi
+       else
+               # No env file found, silently delete any other tempfiles that may exist
+               RM_OLD_TEMPFILES=1
+       fi
+
+       # If we should remove old tempfiles, do so
+       if [[ $RM_OLD_TEMPFILES ]]; then
+               rm -f "${FILES[@]}"
+       else
+               for file in "${FILES[@]}"; do
+                       if [ -e "$file" ]; then
+                               chown ${uid}:portage "$file"
+                               chmod 600 "$file"
+                       fi
+               done
+       fi
+
+       # Save the environment in a file for next time
+       echo "$new_env" > "$ENV_FILE"
+
+       [[ $VERBOSE ]] && echo $'\n'"$APP_NAME environment:"$'\n'"$new_env"
+
+       if [[ $QUIET -ne 1 ]];
+       then
+               echo
+               einfo "Checking reverse dependencies"
+               einfo "Packages containing binaries and libraries $HEAD_TEXT"
+               einfo "will be emerged."
+       fi
+}
+
+get_files() {
+       [[ $QUIET -ne 1 ]] && einfo "Collecting system binaries and libraries"
+       if [[ -r "$FILES_FILE" && -s "$FILES_FILE" ]]; then
+               [[ $QUIET -ne 1 ]] && einfo "Found existing $FILES_FILE"
+       else
+               # Be safe and remove any extraneous temporary files
+               # Don't remove 0_env.rr - The first file in the array
+               rm -f "${FILES[@]:1}"
+
+               clean_trap "$FILES_FILE"
+
+               if [[ $SEARCH_DIRS_MASK ]]; then
+                       findMask=($SEARCH_DIRS_MASK)
+                       findMask="${findMask[@]/#/-o -path }"
+                       findMask="( ${findMask#-o } ) -prune -o"
+               fi
+               # TODO: Check this -- afaict SEARCH_DIRS isn't an array, so this should just be $SEARCH_DIRS?
+               find ${SEARCH_DIRS[@]} $findMask -type f \( -perm -u+x -o -perm -g+x -o -perm -o+x -o \
+                       -name '*.so' -o -name '*.so.*' -o -name '*.la' \) -print 2> /dev/null |
+                       sort -u > "$FILES_FILE" ||
+                       die $? "find failed to list binary files (This is a bug.)"
+               [[ $QUIET -ne 1 ]] && einfo "Generated new $FILES_FILE"
+       fi
+}
+parse_ld_so_conf() {
+       # FIXME: not safe for paths with spaces
+       local include
+       for path in $(sed '/^#/d;s/#.*$//' < /etc/ld.so.conf); do
+               if [[ $include = true ]]; then
+                       for include_path in $(sed '/^#/d;s/#.*$//' /etc/${path} 2>/dev/null); do
+                               echo $include_path
+                       done
+                       include=""
+                       continue
+               fi
+               if [[ $path != include ]]; then
+                       echo $path
+               else
+                       include="true"
+                       continue
+               fi
+       done
+}
+get_ldpath() {
+       local COMPLETE_LD_LIBRARY_PATH
+       [[ $SEARCH_BROKEN && $FULL_LD_PATH ]] || return
+       [[ $QUIET -ne 1 ]] && einfo 'Collecting complete LD_LIBRARY_PATH'
+       if [[ -r "$LDPATH_FILE" && -s "$LDPATH_FILE" ]]; then
+               [[ $QUIET -ne 1 ]] && einfo "Found existing $LDPATH_FILE."
+       else
+               clean_trap "$LDPATH_FILE"
+               # Ensure that the "trusted" lib directories are at the start of the path
+               COMPLETE_LD_LIBRARY_PATH=(
+                       /lib*
+                       /usr/lib*
+                       $(parse_ld_so_conf)
+                       $(sed 's:/[^/]*$::' < "$FILES_FILE" | sort -ru)
+               )
+               IFS=':'
+               COMPLETE_LD_LIBRARY_PATH="${COMPLETE_LD_LIBRARY_PATH[*]}"
+               IFS="$OIFS"
+               echo "$COMPLETE_LD_LIBRARY_PATH" > "$LDPATH_FILE"
+               [[ $QUIET -ne 1 ]] && einfo "Generated new $LDPATH_FILE"
+       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 "$LDPATH_FILE" && -s "$LDPATH_FILE" ]] ||
+                       die 1 "Unable to find $LDPATH_FILE"
+               COMPLETE_LD_LIBRARY_PATH=$(<"$LDPATH_FILE")
+       fi
+       [[ $QUIET -ne 1 ]] && einfo "Checking dynamic linking $WORKING_TEXT"
+       if [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]]; then
+               [[ $QUIET -ne 1 ]] && einfo "Found existing $BROKEN_FILE."
+       else
+               clean_trap "$BROKEN_FILE" "$ERRORS_FILE"
+               files=($(<"$FILES_FILE"))
+               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>> "$ERRORS_FILE" | 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 -E "$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 -E "$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" >> "$BROKEN_FILE"
+                                                               echo_v "  broken $target_file (requires $MISSING_LIBS)"
+                                                       fi
+                                               fi
+                                       else
+                                               # FIXME: I hate duplicating code
+                                               # Only rebuild for direct dependencies
+                                               MISSING_LIBS=$(
+                                                       expr="s/^[[:space:]]*\([^[:space:]]*\).*$/\1/p"
+                                                       sort -u <<< "$ldd_output" | grep -E "$SONAME" | 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" >> "$BROKEN_FILE"
+                                                       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
+                               la_SEARCH_DIRS="$SEARCH_DIRS"
+                               la_search_dir=""
+                               la_broken=""
+                               la_lib=""
+                               for depend in $(
+                                       gawk -F"[=']" '/^dependency_libs/{
+                                               print $3
+                                       }' "$target_file"
+                               ); do
+                                       if [[ $depend = /* && ! -e $depend ]]; then
+                                               echo "obj $target_file" >> "$BROKEN_FILE"
+                                               echo_v "  broken $target_file (requires $depend)"
+                                       elif [[ $depend = -[LR]/* ]]; then
+                                               if ! [[ $'\n'${la_SEARCH_DIRS}$'\n' == *$'\n'${depend#-?}$'\n'* ]]; then
+                                                       la_SEARCH_DIRS+=$'\n'"${depend#-?}"
+                                               fi
+                                       elif [[ $depend = "-l"* ]]; then
+                                               la_lib="lib${depend#-l}"
+                                               la_broken="yes"
+                                               IFS=$'\n'
+                                               for la_search_dir in $la_SEARCH_DIRS; do
+                                                       if [[ -e ${la_search_dir}/${la_lib}.so || -e ${la_search_dir}/${la_lib}.a ]]; then
+                                                               la_broken="no"
+                                                       fi
+                                               done
+                                               IFS="$OIFS"
+                                               if [[ $la_broken = yes ]]; then
+                                                       echo "obj $target_file" >> "$BROKEN_FILE"
+                                                       echo_v "  broken $target_file (requires $depend)"
+                                               fi
+                                       fi
+                               done
+                               unset la_SEARCH_DIRS la_search_dir la_broken la_lib
+                       fi
+                       [[ $VERBOSE ]] &&
+                               progress $((++i)) $numFiles $target_file ||
+                               progress $((++i)) $numFiles
+               done
+               if [[ $SEARCH_BROKEN && -f $ERRORS_FILE ]]; then
+                       # Look for missing version
+                       while read target_file; do
+                               echo "obj $target_file" >> "$BROKEN_FILE"
+                               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'/|}"
+                               gawk -v ldmask="(${LD_LIBRARY_MASK//./\\\.})" '
+                                       /no version information available/ && $0 !~ ldmask {
+                                               gsub(/[()]/, "", $NF)
+                                               if (seen[$NF]++)  next
+                                               print $NF
+                                       }' "$ERRORS_FILE"
+                       )
+               fi
+               [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]] || clean_exit
+               sort -u "$BROKEN_FILE" -o "$BROKEN_FILE"
+               [[ $QUIET -ne 1 ]] && einfo "Generated new $BROKEN_FILE"
+       fi
+}
+get_packages() {
+       local target_file
+       local EXACT_PKG
+       local PKG
+       local obj
+       einfo 'Assigning files to packages'
+       if [[ -r "$RAW_FILE" && -s "$RAW_FILE" ]]; then
+               einfo "Found existing $RAW_FILE"
+       else
+               clean_trap "$RAW_FILE" "$OWNERS_FILE"
+               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" >> "$RAW_FILE"
+                               echo "$target_file -> $EXACT_PKG" >> "$OWNERS_FILE"
+                               echo_v "  $target_file -> $PKG"
+                       else
+                               ewarn " !!! $target_file not owned by any package is broken !!!"
+                               echo "$target_file -> (none)" >> "$OWNERS_FILE"
+                               echo_v "  $target_file -> (none)"
+                       fi
+               done < "$BROKEN_FILE"
+               [[ $QUIET -ne 1 ]] && einfo "Generated new $RAW_FILE and $OWNERS_FILE"
+       fi
+       # if we find '(none)' on every line, exit out
+       if ! grep -qvF '(none)' "$OWNERS_FILE"; 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 $OWNERS_FILE"
+               if [[ $VERBOSE ]]; then
+                       ewarn "The broken files are:"
+                       while read filename junk; do
+                               ewarn "  $filename"
+                       done < "$OWNERS_FILE"
+               fi
+               exit 0 # FIXME: Should we exit 1 here?
+       fi
+}
+clean_packages() {
+       [[ $QUIET -ne 1 ]] && einfo 'Cleaning list of packages to rebuild'
+       if [[ -r "$PKGS_FILE" && -s "$PKGS_FILE" ]]; then
+               [[ $QUIET -ne 1 ]] && einfo "Found existing $PKGS_FILE"
+       else
+               sort -u "$RAW_FILE" > "$PKGS_FILE"
+               [[ $QUIET -ne 1 ]] && einfo "Generated new $PKGS_FILE"
+       fi
+}
+assign_packages_to_ebuilds() {
+       local EXACT_PKG
+       local PKG
+       local SLOT
+       einfo 'Assigning packages to ebuilds'
+       if [[ -r "$EBUILDS_FILE" && -s "$EBUILDS_FILE" ]]; then
+               einfo "Found existing $EBUILDS_FILE"
+       elif [[ -r "$PKGS_FILE" && -s "$PKGS_FILE" ]]; then
+                       clean_trap "$EBUILDS_FILE"
+                       while read EXACT_PKG; do
+                               # Get the slot
+                               PKG="${EXACT_PKG%%-r[[:digit:]]*}"
+                               PKG="${PKG%-*}"
+                               SLOT=$(</var/db/pkg/$EXACT_PKG/SLOT)
+                               echo "$PKG:$SLOT"
+                       done < "$PKGS_FILE" > "$EBUILDS_FILE"
+                       [[ $QUIET -ne 1 ]] && einfo "Generated new $EBUILDS_FILE"
+       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 $EBUILDS_FILE && -s $EBUILDS_FILE ]]; then
+               einfo "Found existing $EBUILDS_FILE"
+       elif [[ -r $BROKEN_FILE && -s $BROKEN_FILE ]]; then
+               rebuildList=" $(<"$BROKEN_FILE") "
+               rebuildList=(${rebuildList//[[:space:]]obj[[:space:]]/ })
+               get_file_owner "${rebuildList[@]}" | sed 's/^/=/' > "$EBUILDS_FILE"
+               [[ $QUIET -ne 1 ]] && einfo "Generated new $EBUILDS_FILE"
+       else
+               einfo 'Nothing to rebuild.'
+               die 1 '(The program should have already quit, so this is a minor bug.)'
+       fi
+}
+list_skipped_packages() {
+       ewarn
+       ewarn 'Portage could not find any version of the following packages it could build:'
+       ewarn "${SKIP_LIST[@]}"
+       ewarn
+       ewarn '(Perhaps they are masked, blocked, or removed from portage.)'
+       ewarn 'Try to emerge them manually.'
+       ewarn
+}
+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
+       [[ $QUIET -ne 1 ]] && einfo 'Evaluating package order'
+       if [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" ]]; then
+               einfo "Found existing $ORDER_FILE"
+       else
+               clean_trap "$ORDER_FILE"
+               RAW_REBUILD_LIST=$(<"$EBUILDS_FILE")
+               if [[ $RAW_REBUILD_LIST ]]; then
+                       export EMERGE_DEFAULT_OPTS="--nospinner --pretend --oneshot --quiet"
+                       RAW_REBUILD_LIST=($RAW_REBUILD_LIST) # convert into array
+                       # If PACKAGE_NAMES is defined we're using slots, not versions
+                       if [[ $PACKAGE_NAMES ]]; then
+                               # Eliminate atoms that can't be built
+                               for i in "${!RAW_REBUILD_LIST[@]}"; do
+                                       if [[ "${RAW_REBUILD_LIST[i]}" = *[A-Za-z]* ]]; then
+                                               portageq best_visible "$PORTAGE_ROOT" "${RAW_REBUILD_LIST[i]}" >/dev/null && continue
+                                               SKIP_LIST+=("${RAW_REBUILD_LIST[i]}")
+                                       fi
+                                       unset RAW_REBUILD_LIST[i]
+                               done
+                               # If RAW_REBUILD_LIST is empty, then we have nothing to build.
+                               if (( ${#RAW_REBUILD_LIST[@]} == 0 )); then
+                                       if (( ${#SKIP_LIST[@]} == 0 )); then
+                                               ewarn "The list of packages to skip is empty, but there are no"
+                                               ewarn "packages listed to rebuild either. (This is a bug.)"
+                                       else
+                                               list_skipped_packages
+                                       fi
+                                       die 1 'Warning: Portage cannot rebuild any of the necessary packages.'
+                               fi
+                       fi
+                       RAW_REBUILD_LIST="${RAW_REBUILD_LIST[@]}"
+
+                       # We no longer determine the package order ourselves.  Instead we call emerge
+                       # with --complete-graph=y in the rebuild function.
+                       if false ; then
+                               REBUILD_GREP=$(emerge --nodeps $RAW_REBUILD_LIST | sed 's/\[[^]]*\]//g')
+                               if (( ${PIPESTATUS[0]} == 0 )); then
+                                       emerge --deep $RAW_REBUILD_LIST |
+                                               sed 's/\[[^]]*\]//g' |
+                                               grep -F "$REBUILD_GREP" > "$ORDER_FILE"
+                               fi
+
+                               # Here we use the PIPESTATUS from the second emerge, the --deep one.
+                               if (( ${PIPESTATUS[0]} != 0 )); then
+                                       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 "$ORDER_FILE"
+                               fi
+                       else
+                               echo "$RAW_REBUILD_LIST" > "$ORDER_FILE"
+                       fi
+                       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 "$ORDER_FILE" && -s "$ORDER_FILE" && $QUIET -ne 1 ]] && einfo "Generated new $ORDER_FILE"
+}
+
+show_unowned_files() {
+       if grep -qF '(none)' "$OWNERS_FILE"; 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 < "$OWNERS_FILE" | gawk '!s[$0]++' # (omit dupes)
+       fi
+}
+
+# Get multiple portage variables at once to speedup revdep-rebuild.
+portage_settings() {
+       local ORIG_SEARCH_DIRS="$SEARCH_DIRS"
+       local ORIG_SEARCH_DIRS_MASK="$SEARCH_DIRS_MASK"
+       local ORIG_LD_LIBRARY_MASK="$LD_LIBRARY_MASK"
+       unset SEARCH_DIRS
+       unset SEARCH_DIRS_MASK
+       unset LD_LIBRARY_MASK
+
+       eval $(portageq envvar -v PORTAGE_ROOT PORTAGE_NICENESS EMERGE_DEFAULT_OPTS NOCOLOR SEARCH_DIRS SEARCH_DIRS_MASK LD_LIBRARY_MASK)
+       export NOCOLOR
+
+       SEARCH_DIRS="$ORIG_SEARCH_DIRS $SEARCH_DIRS"
+       SEARCH_DIRS_MASK="$ORIG_SEARCH_DIRS_MASK $SEARCH_DIRS_MASK"
+       LD_LIBRARY_MASK="$ORIG_LD_LIBRARY_MASK $LD_LIBRARY_MASK"
+}
+
+##
+# Setup portage and the search paths
+setup_portage() {
+       # Obey PORTAGE_NICENESS (which is incremental to the current nice value)
+       if [[ $PORTAGE_NICENESS ]]; then
+               current_niceness=$(nice)
+               let PORTAGE_NICENESS=${current_niceness}+${PORTAGE_NICENESS}
+               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="${PORTAGE_ROOT:-/}"
+}
+
+##
+# Setup the paths to search (and filter the ones to avoid)
+setup_search_paths_and_masks() {
+       local configfile sdir mdir skip_me filter_SEARCH_DIRS
+
+       [[ $QUIET -ne 1 ]] && einfo "Configuring search environment for $APP_NAME"
+
+       # 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 configfile in /etc/revdep-rebuild/*; do
+                       SEARCH_DIRS+=" "$(. $configfile; echo $SEARCH_DIRS)
+                       SEARCH_DIRS_MASK+=" "$(. $configfile; echo $SEARCH_DIRS_MASK)
+                       LD_LIBRARY_MASK+=" "$(. $configfile; echo $LD_LIBRARY_MASK)
+               done
+       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+=" "$(parse_ld_so_conf)
+       fi
+
+       # Set the final variables
+       SEARCH_DIRS=$(clean_var <<< "$SEARCH_DIRS")
+       SEARCH_DIRS_MASK=$(clean_var <<< "$SEARCH_DIRS_MASK")
+       LD_LIBRARY_MASK=$(clean_var <<< "$LD_LIBRARY_MASK")
+       # Filter masked paths from SEARCH_DIRS
+       for sdir in ${SEARCH_DIRS} ; do
+               skip_me=
+               for mdir in ${SEARCH_DIRS_MASK}; do
+                       [[ ${sdir} == ${mdir}/* ]] && skip_me=1 && break
+               done
+               [[ -n ${skip_me} ]] || filter_SEARCH_DIRS+=" ${sdir}"
+       done
+       SEARCH_DIRS=$(clean_var <<< "${filter_SEARCH_DIRS}")
+       [[ $SEARCH_DIRS ]] || die 1 "No search defined -- this is a bug."
+}
+##
+# Rebuild packages owning broken binaries
+rebuild() {
+       if [[ -r $ORDER_FILE && -s $ORDER_FILE ]]; then
+               # The rebuild list contains category/package:slot atoms.
+               # Do not prepend with an '=' sign.
+               # REBUILD_LIST=( $(<"$ORDER_FILE") )
+               # REBUILD_LIST="${REBUILD_LIST[@]/#/=}"
+               REBUILD_LIST=$(<"$ORDER_FILE")
+       else
+               REBUILD_LIST=$(sort -u "$EBUILDS_FILE")
+       fi
+
+       trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
+
+       [[ $QUIET -ne 1 ]] && einfo 'All prepared. Starting rebuild'
+       echo "emerge --complete-graph=y --oneshot ${EMERGE_DEFAULT_OPTS} ${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 --complete-graph=y --oneshot ${EMERGE_DEFAULT_OPTS} ${EMERGE_OPTIONS[@]} $REBUILD_LIST <&6
+               echo $? > "$STATUS_FILE"
+       } &
+       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<&-
+}
+##
+# Finish up
+cleanup() {
+       if [[ (( $(<"$STATUS_FILE") != 0 )) && ! is_real_merge ]]; 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 $ORDER_FILE 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 ${WORKING_DIR}/*.rr"
+               show_unowned_files
+               exit $EMERGE_STATUS
+       elif is_real_merge; then
+               trap_cmd() {
+                       eerror "terminated. Please remove the temporary files manually:"
+                       eerror "rm ${WORKING_DIR}/*.rr"
+                       exit 1
+               }
+               [[ "${SKIP_LIST[@]}" != "" ]] && list_skipped_packages
+               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. Possible reasons for remaining inconsistencies include:'
+               einfo '  orphaned files'
+               einfo '  deep dependencies'
+               einfo "  packages installed outside of portage's control"
+               einfo '  specially-evaluated libraries'
+               if [[ -r "$OWNERS_FILE" && -s "$OWNERS_FILE" ]]; then
+                       show_unowned_files
+               fi
+               [[ $KEEP_TEMP ]] || rm -f "${FILES[@]}"
+       else
+               einfo 'Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.'
+       fi
+}
+
+main "$@"