Finish refactoring the code
[gentoolkit.git] / trunk / src / revdep-rebuild / revdep-rebuild
index 03ec38a484467ae27cef8fc7286f97344f09e168..7767990fba78b1755432b84e405ca4a1299f84be 100755 (executable)
@@ -1,5 +1,5 @@
 #!/bin/bash
 #!/bin/bash
-# Copyright 1999-2007 Gentoo Foundation
+# Copyright 1999-2008 Gentoo Foundation
 
 # revdep-rebuild: Reverse dependency rebuilder.
 # Original Author: Stanislav Brabec
 
 # revdep-rebuild: Reverse dependency rebuilder.
 # Original Author: Stanislav Brabec
 ##
 # Global Variables:
 
 ##
 # Global Variables:
 
-# Must-be-blank variables:
+# Must-be-blank:
 unset GREP_OPTIONS
 
 # Readonly variables:
 declare -r APP_NAME="${0##*/}" # The name of this application
 declare -r OIFS="$IFS"         # Save the IFS
 unset GREP_OPTIONS
 
 # Readonly variables:
 declare -r APP_NAME="${0##*/}" # The name of this application
 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...
 
 # "Boolean" variables: Considered "true" if it has any value at all
 # "True" indicates we should...
@@ -37,7 +62,7 @@ declare PORTAGE_NICENESS       # Renice to this value
 declare PORTAGE_ROOT           # The root path for portage
 
 # Customizable incremental variables:
 declare PORTAGE_ROOT           # The root path for portage
 
 # Customizable incremental variables:
-# These variables can be prepended to either by setting the variable in 
+# 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.
 #
 # your environment prior to execution, or by placing an entry in
 # /etc/make.conf.
 #
@@ -52,7 +77,6 @@ declare SEARCH_DIRS_MASK # List of dirs not to search
 declare OLDPROG                # Previous pass through the progress meter
 declare EXACT_PKG              # Versionated atom to emerge
 declare HEAD_TEXT              # Feedback string about the search
 declare OLDPROG                # Previous pass through the progress meter
 declare EXACT_PKG              # Versionated atom to emerge
 declare HEAD_TEXT              # Feedback string about the search
-declare LIST                   # Prefix for temporary filenames
 declare NOCOLOR                # Set to "true" not to output term colors
 declare OK_TEXT                # Feedback about a search which found no errors
 declare RC_NOCOLOR             # Hack to insure we respect NOCOLOR
 declare 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
@@ -61,22 +85,47 @@ 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 SONAME                 # Soname/soname path pattern given on commandline
 declare SONAME_SEARCH          # Value of SONAME modified to match ldd's output
 declare WORKING_TEXT           # Feedback about the search
-declare ENV_FILE               # A file containing environment variables
 
 
+main() {
+       # preliminary setup
+       get_opts "$@"
+       setup_portage
+       setup_search_paths_and_masks
+       get_search_env
+       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() {
 rm() {
-       local i
-       [[ $LIST && $APP_NAME ]] ||
-               die 1 '$LIST or $APP_NAME is not defined! (This is a bug.)'
-       for i; do
-               [[ $i = -* || $i = *.$APP_NAME* ]] || 
-                       die 1 "Oops, I'm not allowed to delete that. ($@)"
-       done
-       command rm "$@"
+       eerror "I was instructed to rm '$@'"
+       die 1 "Refusing to delete anything before changing to temporary directory."
 }
 }
-# Somewhat more portable find -executable
-# FIXME/UNTESTED (I don't have access to all of the different versions of 
-# find.)
-# Usage: find PATH ARGS -- use find like normal, except use -executable instead 
+##
+# 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!'; }
 # of various versions of -perm /+ blah blah and hacks
 find() {
        hash find || { die 1 'find not found!'; }
@@ -100,14 +149,15 @@ find() {
                }
        else # Last resort
                find() {
                }
        else # Last resort
                find() {
-                       a=(${@//-executable/-exec test -x '{}' \;})
-                       a=(${a[@]//-writable/-exec test -w '{}' \;})
-                       a=(${a[@]//-readable/-exec test -r '{}' \;})
+                       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 "$@"
 }
                        command find "${a[@]}"
                }
        fi
        find "$@"
 }
+
 print_usage() {
 cat << EOF
 Usage: $APP_NAME [OPTIONS] [--] [EMERGE_OPTIONS]
 print_usage() {
 cat << EOF
 Usage: $APP_NAME [OPTIONS] [--] [EMERGE_OPTIONS]
@@ -131,9 +181,6 @@ Broken reverse dependency rebuilder.
   -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)
   -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)
-  -u, --no-util UTIL   Do not use features provided by UTIL
-      --no-util=UTIL   UTIL can be one of portage-utils or pkgcore
-                       or it can be a *quoted* space-delimited list.
 
 Calls emerge, options after -- are ignored by $APP_NAME
 and passed directly to emerge.
 
 Calls emerge, options after -- are ignored by $APP_NAME
 and passed directly to emerge.
@@ -141,6 +188,7 @@ and passed directly to emerge.
 Report bugs to <http://bugs.gentoo.org>
 EOF
 }
 Report bugs to <http://bugs.gentoo.org>
 EOF
 }
+##
 # Usage: progress i n
 #        i: current item
 #        n: total number of items to process
 # Usage: progress i n
 #        i: current item
 #        n: total number of items to process
@@ -158,6 +206,7 @@ progress() {
                progress() { :; }
        fi
 }
                progress() { :; }
        fi
 }
+##
 # Usage: countdown n
 #        n: number of seconds to count
 countdown() {
 # Usage: countdown n
 #        n: number of seconds to count
 countdown() {
@@ -168,9 +217,7 @@ countdown() {
        done
        echo -e '\a.'
 }
        done
        echo -e '\a.'
 }
-# Get the name of a package owning a file on the filesystem using one of several
-# utilities: This is a placeholder. The function is defined in get_opts()
-get_file_owner() { :; }
+##
 # Replace whitespace with linebreaks, normalize repeated '/' chars, and sort -u
 # (If any libs have whitespace in their filenames, someone needs punishment.)
 clean_var() {
 # Replace whitespace with linebreaks, normalize repeated '/' chars, and sort -u
 # (If any libs have whitespace in their filenames, someone needs punishment.)
 clean_var() {
@@ -178,6 +225,7 @@ clean_var() {
             /-\*/         {exit}
             /[^[:space:]]/ {gsub(/\/\/+/, "/"); print}' | sort -u
 }
             /-\*/         {exit}
             /[^[:space:]]/ {gsub(/\/\/+/, "/"); print}' | sort -u
 }
+##
 # Exit and optionally output to sterr
 die() {
        local status=$1
 # Exit and optionally output to sterr
 die() {
        local status=$1
@@ -185,36 +233,24 @@ die() {
        eerror "$@"
        exit $status
 }
        eerror "$@"
        exit $status
 }
+##
 # What to do when dynamic linking is consistent
 clean_exit() {
 # What to do when dynamic linking is consistent
 clean_exit() {
-       [[ $KEEP_TEMP ]] || rm $LIST.?_*
+       [[ $KEEP_TEMP ]] || rm -f "${FILES[@]}"
        echo
        einfo "$OK_TEXT... All done. "
        exit 0
 }
        echo
        einfo "$OK_TEXT... All done. "
        exit 0
 }
-
 ##
 ##
-# Check if various portage utils are allowed and installed
-setup_get_file_owner() {
-       if [[ $avoid_utils != *portage-utils* ]] && hash qfile 2> /dev/null; then
-               get_file_owner() { qfile -qvC "$@"; }
-       elif [[ $avoid_utils != *pkgcore* ]] && hash pquery 2> /dev/null; then
-               get_file_owner() { local IFS=,; pquery --nocolor --owns="$*"; }
-       # equery disabled for incompatibility with modern portage.
-       # elif [[ $avoid_utils != *equery* ]] && hash equery 2> /dev/null; then
-       #       get_file_owner() { equery -q -C b $@; }
-       else
-               get_file_owner() {
-                       local IFS=$'\n'
-                       # ${*/%/ } adds a space to the end of each object name to prevent false
-                       # matches, for example /usr/bin/dia matching /usr/bin/dialog (bug #196460).
-                       find -L /var/db/pkg -name CONTENTS -print0 |
-                               xargs -0 grep -Fl "${*/%/ }" |
-                               sed 's:/var/db/pkg/\(.*\)/CONTENTS:\1:'
-               }
-       fi
+# Get the name of the package that owns a file or list of files given as args.
+get_file_owner() {
+       local IFS=$'\n'
+       # ${*/%/ } adds a space to the end of each object name to prevent false
+       # matches, for example /usr/bin/dia matching /usr/bin/dialog (bug #196460).
+       find -L /var/db/pkg -name CONTENTS -print0 |
+               xargs -0 grep -Fl "${*/%/ }" |
+               sed 's:/var/db/pkg/\(.*\)/CONTENTS:\1:'
 }
 }
-
 ##
 # Normalize some EMERGE_OPTIONS
 normalize_emerge_opts() {
 ##
 # Normalize some EMERGE_OPTIONS
 normalize_emerge_opts() {
@@ -223,7 +259,6 @@ normalize_emerge_opts() {
        EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-f/--fetchonly})
        EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-f/--verbose})
 }
        EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-f/--fetchonly})
        EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-f/--verbose})
 }
-
 ##
 # Use the color preference from portage
 setup_color() {
 ##
 # Use the color preference from portage
 setup_color() {
@@ -231,40 +266,39 @@ setup_color() {
        # environment.
        export NOCOLOR=$(portageq envvar NOCOLOR)
        [[ $NOCOLOR = yes || $NOCOLOR = true ]] && export RC_NOCOLOR=yes # HACK! (grr)
        # environment.
        export NOCOLOR=$(portageq envvar NOCOLOR)
        [[ $NOCOLOR = yes || $NOCOLOR = true ]] && export RC_NOCOLOR=yes # HACK! (grr)
-       . /sbin/functions.sh
+       . /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 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() {
 ##
 # Die because an option is not recognized.
 die_invalid_option() {
-       # We cannot use eerror and einfo because this gets called before function.sh 
+       # Can't use eerror and einfo because this gets called before function.sh
        # is sourced
        # is sourced
-       print_usage
        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
        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
 }
        exit 1
 }
-
 ##
 # Warn about deprecated options.
 warn_deprecated_opt() {
 ##
 # Warn about deprecated options.
 warn_deprecated_opt() {
-       # We cannot use eerror and einfo because this gets called before function.sh 
+       # 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
 }
        # 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() {
 ##
 # Get whole-word commandline options preceded by two dashes.
 get_longopts() {
@@ -304,12 +338,6 @@ get_longopts() {
                                                          progress() { :; }
                                                          quiet=1
                                                          EMERGE_OPTIONS+=($1);;
                                                          progress() { :; }
                                                          quiet=1
                                                          EMERGE_OPTIONS+=($1);;
-                                            --no-util=*) # TODO: check for invalid values
-                                                         avoid_utils="${1#*=}";;
-                                              --no-util) # TODO: check for invalid values
-                                                         die_if_missing_arg $1 $2
-                                                         shift
-                                                         avoid_utils="$1";;
                                               --verbose) VERBOSE=1
                                                          EMERGE_OPTIONS+=("--verbose");;
                                         --extra-verbose) warn_deprecated_opt "$1" "--verbose"
                                               --verbose) VERBOSE=1
                                                          EMERGE_OPTIONS+=("--verbose");;
                                         --extra-verbose) warn_deprecated_opt "$1" "--verbose"
@@ -349,7 +377,6 @@ get_shortopts() {
                           progress() { :; }
                           quiet=1
                           EMERGE_OPTIONS+=("--quiet");;
                           progress() { :; }
                           quiet=1
                           EMERGE_OPTIONS+=("--quiet");;
-                       u) avoid_utils="$1";; # TODO: Check for invalid values
                        v) VERBOSE=1
                           EMERGE_OPTIONS+=("--verbose");;
                        X) # No longer used, since it is the default.
                        v) VERBOSE=1
                           EMERGE_OPTIONS+=("--verbose");;
                        X) # No longer used, since it is the default.
@@ -360,7 +387,6 @@ get_shortopts() {
                esac
        done
 }
                esac
        done
 }
-
 ##
 # Get command-line options.
 get_opts() {
 ##
 # Get command-line options.
 get_opts() {
@@ -393,7 +419,6 @@ get_opts() {
                unset args
        done
 
                unset args
        done
 
-       setup_get_file_owner
        setup_color
        normalize_emerge_opts
 
        setup_color
        normalize_emerge_opts
 
@@ -403,101 +428,104 @@ get_opts() {
                EMERGE_OPTIONS+=(--pretend)
        fi
 }
                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* ]]
 }
 is_real_merge() {
        [[ ${EMERGE_OPTIONS[@]} != *--pretend* &&
           ${EMERGE_OPTIONS[@]} != *--fetchonly* ]]
 }
-
-get_opts "$@"
-
-einfo "Configuring search environment for $APP_NAME"
-
-# Obey PORTAGE_NICENESS
-PORTAGE_NICENESS=$(portageq envvar PORTAGE_NICENESS)
-if [[ $PORTAGE_NICENESS ]]; then
-       renice $PORTAGE_NICENESS $$ > /dev/null
-       # Since we have already set our nice value for our processes,
-       # reset PORTAGE_NICENESS to zero to avoid having emerge renice again.
-       export PORTAGE_NICENESS="0"
-fi
-
-PORTAGE_ROOT=$(portageq envvar ROOT)
-PORTAGE_ROOT="${PORTAGE_ROOT:-/}"
-
-# Update the incremental variables using /etc/profile.env, /etc/ld.so.conf,
-# portage, and the environment
-
-# Read the incremental variables from environment and portage
-# Until such time as portage supports these variables as incrementals
-# The value will be what is in /etc/make.conf
-SEARCH_DIRS+=" "$(unset SEARCH_DIRS; portageq envvar SEARCH_DIRS)
-SEARCH_DIRS_MASK+=" "$(unset SEARCH_DIRS_MASK; portageq envvar SEARCH_DIRS_MASK)
-LD_LIBRARY_MASK+=" "$(unset LD_LIBRARY_MASK; portageq envvar LD_LIBRARY_MASK)
-
-# Add the defaults
-if [[ -d /etc/revdep-rebuild ]]; then
-       for ENV_FILE in /etc/revdep-rebuild/*; do
-               SEARCH_DIRS+=" "$(. $ENV_FILE; echo $SEARCH_DIRS)
-               SEARCH_DIRS_MASK+=" "$(. $ENV_FILE; echo $SEARCH_DIRS_MASK)
-               LD_LIBRARY_MASK+=" "$(. $ENV_FILE; echo $LD_LIBRARY_MASK)
-       done
-       unset ENV_FILE # HACK
-else
-       SEARCH_DIRS+=" /bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*"
-       SEARCH_DIRS_MASK+=" /opt/OpenOffice /usr/lib/openoffice"
-       LD_LIBRARY_MASK+=" libodbcinst.so libodbc.so libjava.so libjvm.so"
-fi
-
-# Get the ROOTPATH and PATH from /etc/profile.env
-if [[ -r "/etc/profile.env" && -s "/etc/profile.env" ]]; then
-       SEARCH_DIRS+=" "$(. /etc/profile.env; /usr/bin/tr ':' ' ' <<< "$ROOTPATH $PATH")
-fi
-
-# Get the directories from /etc/ld.so.conf
-if [[ -r /etc/ld.so.conf && -s /etc/ld.so.conf ]]; then
-       SEARCH_DIRS+=" "$(sed '/^#/d;s/#.*$//' /etc/ld.so.conf)
-fi
-
-# Set the final variables
-SEARCH_DIRS=$(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
-filter_SEARCH_DIRS=
-for sdir in ${SEARCH_DIRS} ; do
-       unset 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}")
-unset sdir mdir skip_me filter_SEARCH_DIRS
-[[ $SEARCH_DIRS ]] || die 1 "No search defined -- this is a bug."
-
-set_trap() {
-       trap "rm_temp $1" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
+##
+# 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() { :; }
 }
 }
-rm_temp() {
-       rm $1
-       die 1 $'  ...terminated. Removing incomplete '"$1."
+##
+# Make our temporary files directory
+setup_tmpdir() {
+       umask 007 || die $? "Unable to set umask 007"
+       if [[ ! $1 ]]; then
+               die 1 'Temporary file path is unset! (This is a bug.)'
+       elif [[ -d $1 ]]; then
+               # HACK: I hate using find this way
+               if [[ $(find "$1" -type d ! \( -user $2 -group portage -perm -0700 \) ) ]]; then
+                       eerror "Incorrect permissions on $1"
+                       eerror "or at least one file in $1."
+                       die 1  "Please make sure it's not a symlink and then remove it."
+               fi
+               cd "$1"
+       elif mkdir -m 0700 "$1" && chown :portage "$1"; then
+               cd "$1"
+       else
+               die 1 "Unable to find or create a satisfactory location for temporary files"
+       fi
+       [[ $VERBOSE ]] && einfo "Temporary files are located in $PWD"
+       setup_rm
 }
 get_search_env() {
        local new_env
        local old_env
 }
 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
        # Find a place to put temporary files
-       # TODO; let the user choose where to put tempfiles
-       # gfind $HOME/ /var/tmp/ /tmp/ -writable -print -quit
-       # HACK: This is a rather noisy, but portable way to implement -quit
-       while read LIST; do
-               break # Set LIST
-       done < <(find $HOME/ /var/tmp/ /tmp/ -writable -print)
-       [[ $LIST ]] ||
-               die 1 "Unable to find a satisfactory location for temporary files"
-
-       LIST+=".$APP_NAME"
+       # Use "${TMPDIR}/revdep-rebuild" or /tmp/revdep-rebuild
+       local tmp_target="${TMPDIR:=/tmp}/${APP_NAME}-${uid}"
+
+       # From here on all work is done inside the temporary directory
+       setup_tmpdir "$tmp_target" "$uid"
+
        if [[ $SEARCH_BROKEN ]]; then
                SONAME_SEARCH="$SONAME"
                HEAD_TEXT="broken by a package update"
        if [[ $SEARCH_BROKEN ]]; then
                SONAME_SEARCH="$SONAME"
                HEAD_TEXT="broken by a package update"
@@ -516,10 +544,11 @@ get_search_env() {
                fi
                local uuid="${SONAME##*/}"
                uuid="${uuid//[[:space:]]}"
                fi
                local uuid="${SONAME##*/}"
                uuid="${uuid//[[:space:]]}"
-               LIST+="_$uuid"
+               uuid="${uuid//\*}"
                HEAD_TEXT="using $SONAME"
                OK_TEXT="There are no dynamic links to $SONAME"
                unset WORKING_TEXT
                HEAD_TEXT="using $SONAME"
                OK_TEXT="There are no dynamic links to $SONAME"
                unset WORKING_TEXT
+               setup_tmpdir "$uuid"
        fi
 
        # If any of our temporary files are older than 1 day, remove them all
        fi
 
        # If any of our temporary files are older than 1 day, remove them all
@@ -527,7 +556,7 @@ get_search_env() {
                while read; do
                        RM_OLD_TEMPFILES=1
                        break
                while read; do
                        RM_OLD_TEMPFILES=1
                        break
-               done < <(find -L "$LIST."* -maxdepth 0 -type f -mmin +1440 -print 2>/dev/null)
+               done < <(find -L . -maxdepth 1 -type f -name '*.rr' -mmin +1440 -print 2>/dev/null)
        fi
 
        # Compare old and new environments
        fi
 
        # Compare old and new environments
@@ -547,24 +576,34 @@ get_search_env() {
                        FULL_LD_PATH="$FULL_LD_PATH"
                EOF
        )
                        FULL_LD_PATH="$FULL_LD_PATH"
                EOF
        )
-       if [[ -r $LIST.0_env && -s $LIST.0_env ]]; then
-               old_env=$(<"$LIST.0_env")
+       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
                if [[ $old_env != $new_env ]]; then
                        ewarn 'Environment mismatch from previous run, deleting temporary files...'
                        RM_OLD_TEMPFILES=1
                fi
        else
-               # No 0_env file found, silently delete any other tempfiles that may exist
+               # 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
                RM_OLD_TEMPFILES=1
        fi
 
        # If we should remove old tempfiles, do so
-       [[ $RM_OLD_TEMPFILES ]] && rm -f "$LIST."*
-       
+       if [[ $RM_OLD_TEMPFILES ]]; then
+               rm -f "${FILES[@]}"
+       else
+               for file in "${FILES[@]}"; do
+                       if [ -e "$file" ]; then
+                               chown ${uid}:portage "$file"
+                               chmod 700 "$file"
+                       fi
+               done
+       fi
+
        # Save the environment in a file for next time
        # Save the environment in a file for next time
-       echo "$new_env" > "$LIST.0_env"
+       echo "$new_env" > "$ENV_FILE"
 
 
-       [[ $VERBOSE ]] && echo $'\n'"$APP_NAME environment:"$'\n'"$new_env"
+#      [[ $VERBOSE ]] && echo $'\n'"$APP_NAME environment:"$'\n'"$new_env"
+       [[ $VERBOSE ]] && echo $'\n'"$APP_NAME environment:"$'\n'"$(cat $ENV_FILE)"
 
        echo
        einfo "Checking reverse dependencies"
 
        echo
        einfo "Checking reverse dependencies"
@@ -573,46 +612,48 @@ get_search_env() {
 }
 get_files() {
        einfo "Collecting system binaries and libraries"
 }
 get_files() {
        einfo "Collecting system binaries and libraries"
-       if [[ -r $LIST.1_files && -s $LIST.1_files ]]; then
-               einfo "Found existing $LIST.1_files"
+       if [[ -r "$FILES_FILE" && -s "$FILES_FILE" ]]; then
+               einfo "Found existing $FILES_FILE"
        else
                # Be safe and remove any extraneous temporary files
        else
                # Be safe and remove any extraneous temporary files
-               rm -f $LIST.[1-9]_*
+               # Don't remove -_env.rr - The first file in the array
+               rm -f "${FILES[@]:1}"
 
 
-               set_trap "$LIST.1_*"
+               clean_trap "$FILES_FILE"
 
                if [[ $SEARCH_DIRS_MASK ]]; then
                        findMask=($SEARCH_DIRS_MASK)
                        findMask="${findMask[@]/#/-o -path }"
                        findMask="( ${findMask#-o } ) -prune -o"
                fi
 
                if [[ $SEARCH_DIRS_MASK ]]; then
                        findMask=($SEARCH_DIRS_MASK)
                        findMask="${findMask[@]/#/-o -path }"
                        findMask="( ${findMask#-o } ) -prune -o"
                fi
+               # TODO: Check this
                find ${SEARCH_DIRS[@]} $findMask -type f \( -executable -o \
                        -name '*.so' -o -name '*.so.*' -o -name '*.la' \) -print 2> /dev/null |
                find ${SEARCH_DIRS[@]} $findMask -type f \( -executable -o \
                        -name '*.so' -o -name '*.so.*' -o -name '*.la' \) -print 2> /dev/null |
-                       sort -u > "$LIST.1_files" ||
+                       sort -u > "$FILES_FILE" ||
                        die $? "find failed to list binary files (This is a bug.)"
                        die $? "find failed to list binary files (This is a bug.)"
-               einfo "Generated new $LIST.1_files"
+               einfo "Generated new $FILES_FILE"
        fi
 }
 get_ldpath() {
        local COMPLETE_LD_LIBRARY_PATH
        [[ $SEARCH_BROKEN && $FULL_LD_PATH ]] || return
        einfo 'Collecting complete LD_LIBRARY_PATH'
        fi
 }
 get_ldpath() {
        local COMPLETE_LD_LIBRARY_PATH
        [[ $SEARCH_BROKEN && $FULL_LD_PATH ]] || return
        einfo 'Collecting complete LD_LIBRARY_PATH'
-       if [[ -r $LIST.2_ldpath && -s $LIST.2_ldpath ]] ; then
-               einfo "Found existing $LIST.2_ldpath."
+       if [[ -r "$LDPATH_FILE" && -s "$LDPATH_FILE" ]]; then
+               einfo "Found existing $LDPATH_FILE."
        else
        else
-               set_trap "$LIST.2_ldpath"
+               clean_trap "$LDPATH_FILE"
                # Ensure that the "trusted" lib directories are at the start of the path
                COMPLETE_LD_LIBRARY_PATH=(
                        /lib*
                        /usr/lib*
                        $(sed '/^#/d;s/#.*$//' < /etc/ld.so.conf)
                # Ensure that the "trusted" lib directories are at the start of the path
                COMPLETE_LD_LIBRARY_PATH=(
                        /lib*
                        /usr/lib*
                        $(sed '/^#/d;s/#.*$//' < /etc/ld.so.conf)
-                       $(sed 's:/[^/]*$::' < "$LIST.1_files" | sort -ru)
+                       $(sed 's:/[^/]*$::' < "$FILES_FILE" | sort -ru)
                )
                IFS=':'
                COMPLETE_LD_LIBRARY_PATH="${COMPLETE_LD_LIBRARY_PATH[*]}"
                IFS="$OIFS"
                )
                IFS=':'
                COMPLETE_LD_LIBRARY_PATH="${COMPLETE_LD_LIBRARY_PATH[*]}"
                IFS="$OIFS"
-               echo "$COMPLETE_LD_LIBRARY_PATH" > "$LIST.2_ldpath"
-               einfo "Generated new $LIST.2_ldpath"
+               echo "$COMPLETE_LD_LIBRARY_PATH" > "$LDPATH_FILE"
+               einfo "Generated new $LDPATH_FILE"
        fi
 }
 main_checks() {
        fi
 }
 main_checks() {
@@ -624,24 +665,22 @@ main_checks() {
        local numFiles
        local COMPLETE_LD_LIBRARY_PATH
        if [[ $SEARCH_BROKEN && $FULL_LD_PATH ]]; then
        local numFiles
        local COMPLETE_LD_LIBRARY_PATH
        if [[ $SEARCH_BROKEN && $FULL_LD_PATH ]]; then
-               [[ -r $LIST.2_ldpath && -s $LIST.2_ldpath ]] || die 1 "unable to find $LIST.2_ldpath"
-               COMPLETE_LD_LIBRARY_PATH=$(<"$LIST.2_ldpath")
+               [[ -r "$LDPATH_FILE" && -s "$LDPATH_FILE" ]] ||
+                       die 1 "Unable to find $LDPATH_FILE"
+               COMPLETE_LD_LIBRARY_PATH=$(<"$LDPATH_FILE")
        fi
        einfo "Checking dynamic linking $WORKING_TEXT"
        fi
        einfo "Checking dynamic linking $WORKING_TEXT"
-       if [[ -r $LIST.3_rebuild && -s $LIST.3_rebuild ]]; then
-               einfo "Found existing $LIST.3_rebuild."
+       if [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]]; then
+               einfo "Found existing $BROKEN_FILE."
        else
        else
-               [[ $LIST ]] || die 1 "$LIST" 'is undefined! (This is a bug.)'
-               set_trap "$LIST.3_rebuild"
-               set_trap "$LIST.3_ldd_errors"
-               rm -f "$LIST.3"*
-               files=($(<"$LIST.1_files"))
+               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).
                numFiles="${#files[@]}"
                for target_file in "${files[@]}"; do
                        if [[ $target_file != *.la ]]; then
                                # Note: double checking seems to be faster than single with complete path
                                # (special add ons are rare).
-                               ldd_output=$(ldd "$target_file" 2>> "$LIST.3_ldd_errors" | sort -u)
+                               ldd_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" |
                                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" |
@@ -661,7 +700,7 @@ main_checks() {
                                                        )
                                                        MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS")
                                                        if [[ $MISSING_LIBS ]]; then
                                                        )
                                                        MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS")
                                                        if [[ $MISSING_LIBS ]]; then
-                                                               echo "obj $target_file" >> "$LIST.3_rebuild"
+                                                               echo "obj $target_file" >> "$BROKEN_FILE"
                                                                echo_v "  broken $target_file (requires $MISSING_LIBS)"
                                                        fi
                                                fi
                                                                echo_v "  broken $target_file (requires $MISSING_LIBS)"
                                                        fi
                                                fi
@@ -678,7 +717,7 @@ main_checks() {
                                                )
                                                MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS")
                                                if [[ $MISSING_LIBS ]]; then
                                                )
                                                MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS")
                                                if [[ $MISSING_LIBS ]]; then
-                                                       echo "obj $target_file" >> "$LIST.3_rebuild"
+                                                       echo "obj $target_file" >> "$BROKEN_FILE"
                                                        if [[ $SEARCH_BROKEN ]]; then
                                                                echo_v "  broken $target_file (requires $MISSING_LIBS)"
                                                        else
                                                        if [[ $SEARCH_BROKEN ]]; then
                                                                echo_v "  broken $target_file (requires $MISSING_LIBS)"
                                                        else
@@ -697,7 +736,7 @@ main_checks() {
                                        }' "$target_file"
                                ); do
                                        if [[ $depend = /* && ! -e $depend ]]; then
                                        }' "$target_file"
                                ); do
                                        if [[ $depend = /* && ! -e $depend ]]; then
-                                               echo "obj $target_file" >> "$LIST.3_rebuild"
+                                               echo "obj $target_file" >> "$BROKEN_FILE"
                                                echo_v "  broken $target_file (requires $depend)"
                                        fi
                                done
                                                echo_v "  broken $target_file (requires $depend)"
                                        fi
                                done
@@ -709,7 +748,7 @@ main_checks() {
                if [[ $SEARCH_BROKEN ]]; then
                        # Look for missing version
                        while read target_file; do
                if [[ $SEARCH_BROKEN ]]; then
                        # Look for missing version
                        while read target_file; do
-                               echo "obj $target_file" >> "$LIST.3_rebuild"
+                               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.
                                echo_v "  broken $target_file (no version information available)"
                        done < <(
                                # Regexify LD_LIBRARY_MASK. Exclude it from the search.
@@ -719,11 +758,12 @@ main_checks() {
                                                gsub(/[()]/, "", $NF)
                                                if (seen[$NF]++)  next
                                                print $NF
                                                gsub(/[()]/, "", $NF)
                                                if (seen[$NF]++)  next
                                                print $NF
-                                       }' "$LIST.3_ldd_errors"
+                                       }' "$ERRORS_FILE"
                        )
                fi
                        )
                fi
-               [[ -r $LIST.3_rebuild && -s $LIST.3_rebuild ]] || clean_exit
-               einfo "Generated new $LIST.3_rebuild"
+               [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]] || clean_exit
+               sort -u "$BROKEN_FILE" -o "$BROKEN_FILE"
+               einfo "Generated new $BROKEN_FILE"
        fi
 }
 get_packages() {
        fi
 }
 get_packages() {
@@ -732,49 +772,48 @@ get_packages() {
        local PKG
        local obj
        einfo 'Assigning files to packages'
        local PKG
        local obj
        einfo 'Assigning files to packages'
-       if [[ -r $LIST.4_packages_raw && -s $LIST.4_packages_raw ]]; then
-               einfo "Found existing $LIST.4_packages_raw"
+       if [[ -r "$RAW_FILE" && -s "$RAW_FILE" ]]; then
+               einfo "Found existing $RAW_FILE"
        else
        else
-               set_trap "$LIST.4_packages*"
-               rm -f $LIST.4*
+               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%-*}"
                while read obj target_file; do
                        EXACT_PKG=$(get_file_owner $target_file)
                        if [[ $EXACT_PKG ]]; then
                                # Strip version information
                                PKG="${EXACT_PKG%%-r[[:digit:]]*}"
                                PKG="${PKG%-*}"
-                               echo "$EXACT_PKG" >> $LIST.4_packages_raw
-                               echo "$target_file -> $EXACT_PKG" >> $LIST.4_package_owners
+                               echo "$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_v "  $target_file -> $PKG"
                        else
                                ewarn " !!! $target_file not owned by any package is broken !!!"
-                               echo "$target_file -> (none)" >> $LIST.4_package_owners
+                               echo "$target_file -> (none)" >> "$OWNERS_FILE"
                                echo_v "  $target_file -> (none)"
                        fi
                                echo_v "  $target_file -> (none)"
                        fi
-               done < "$LIST.3_rebuild"
-               einfo "Generated new $LIST.4_packages_raw and $LIST.4_package_owners"
+               done < "$BROKEN_FILE"
+               einfo "Generated new $RAW_FILE and $OWNERS_FILE"
        fi
        # if we find '(none)' on every line, exit out
        fi
        # if we find '(none)' on every line, exit out
-       if ! grep -qvF '(none)' "$LIST.4_package_owners"; then
+       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 "Found some broken files, but none of them were associated with known packages"
                ewarn "Unable to proceed with automatic repairs."
-               ewarn "The broken files are listed in $LIST.4_package_owners"
+               ewarn "The broken files are listed in $OWNERS_FILE"
                if [[ $VERBOSE ]]; then
                        ewarn "The broken files are:"
                        while read filename junk; do
                                ewarn "  $filename"
                if [[ $VERBOSE ]]; then
                        ewarn "The broken files are:"
                        while read filename junk; do
                                ewarn "  $filename"
-                       done < "$LIST.4_package_owners"
+                       done < "$OWNERS_FILE"
                fi
                exit 0 # FIXME: Should we exit 1 here?
        fi
 }
 clean_packages() {
        einfo 'Cleaning list of packages to rebuild'
                fi
                exit 0 # FIXME: Should we exit 1 here?
        fi
 }
 clean_packages() {
        einfo 'Cleaning list of packages to rebuild'
-       if [[ -r $LIST.4_packages && -s $LIST.4_packages ]]; then
-               einfo "Found existing $LIST.4_packages"
+       if [[ -r "$PKGS_FILE" && -s "$PKGS_FILE" ]]; then
+               einfo "Found existing $PKGS_FILE"
        else
        else
-               sort -u $LIST.4_packages_raw > $LIST.4_packages
-               einfo "Generated new $LIST.4_packages"
+               sort -u "$RAW_FILE" > "$PKGS_FILE"
+               einfo "Generated new $PKGS_FILE"
        fi
 }
 assign_packages_to_ebuilds() {
        fi
 }
 assign_packages_to_ebuilds() {
@@ -782,18 +821,18 @@ assign_packages_to_ebuilds() {
        local PKG
        local SLOT
        einfo 'Assigning packages to ebuilds'
        local PKG
        local SLOT
        einfo 'Assigning packages to ebuilds'
-       if [[ -r $LIST.4_ebuilds && -s $LIST.4_ebuilds ]]; then
-               einfo "Found existing $LIST.4_ebuilds"
-       elif [[ -r $LIST.4_packages && -s $LIST.4_packages ]]; then
-                       set_trap "$LIST.4_ebuilds"
+       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"
                        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 < "$LIST.4_packages" > "$LIST.4_ebuilds"
-                       einfo "Generated new $LIST.4_ebuilds"
+                       done < "$PKGS_FILE" > "$EBUILDS_FILE"
+                       einfo "Generated new $EBUILDS_FILE"
        else
                einfo 'Nothing to rebuild.'
                die 1 '(The program should have already quit, so this is a minor bug.)'
        else
                einfo 'Nothing to rebuild.'
                die 1 '(The program should have already quit, so this is a minor bug.)'
@@ -801,13 +840,13 @@ assign_packages_to_ebuilds() {
 }
 get_exact_ebuilds() {
        einfo 'Assigning files to ebuilds'
 }
 get_exact_ebuilds() {
        einfo 'Assigning files to ebuilds'
-       if [[ -r $LIST.4_ebuilds && -s $LIST.4_ebuilds ]]; then
-               einfo "Found existing $LIST.4_ebuilds"
-       elif [[ -r $LIST.3_rebuild && -s $LIST.3_rebuild ]]; then
-               rebuildList=" $(<"$LIST.3_rebuild") "
+       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:]]/ })
                rebuildList=(${rebuildList//[[:space:]]obj[[:space:]]/ })
-               get_file_owner "${rebuildList[@]}" > $LIST.4_ebuilds
-               einfo "Generated new $LIST.4_ebuilds"
+               get_file_owner "${rebuildList[@]}" | sed 's/^/=/' > "$EBUILDS_FILE"
+               einfo "Generated new $EBUILDS_FILE"
        else
                einfo 'Nothing to rebuild.'
                die 1 '(The program should have already quit, so this is a minor bug.)'
        else
                einfo 'Nothing to rebuild.'
                die 1 '(The program should have already quit, so this is a minor bug.)'
@@ -832,36 +871,41 @@ get_build_order() {
                return
        fi
        einfo 'Evaluating package order'
                return
        fi
        einfo 'Evaluating package order'
-       if [[ -r $LIST.5_order && -s $LIST.5_order ]]; then
-               einfo "Found existing $LIST.5_order"
+       if [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" ]]; then
+               einfo "Found existing $ORDER_FILE"
        else
        else
-               set_trap "$LIST.5_order"
-               RAW_REBUILD_LIST=$(<"$LIST.4_ebuilds")
+               clean_trap "$ORDER_FILE"
+               RAW_REBUILD_LIST=$(<"$EBUILDS_FILE")
                if [[ $RAW_REBUILD_LIST ]]; then
                        export EMERGE_DEFAULT_OPTS="--nospinner --pretend --oneshot --quiet"
                if [[ $RAW_REBUILD_LIST ]]; then
                        export EMERGE_DEFAULT_OPTS="--nospinner --pretend --oneshot --quiet"
-                       RAW_REBUILD_LIST=($RAW_REBUILD_LIST)
+                       RAW_REBUILD_LIST=($RAW_REBUILD_LIST) # 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
                        # If PACKAGE_NAMES is defined we're using slots, not versions
                        if [[ $PACKAGE_NAMES ]]; then
                                # Eliminate atoms that can't be built
-                               for (( i=0; i<${#RAW_REBUILD_LIST[@]}; i++ )); do
-                                       portageq best_visible "$PORTAGE_ROOT" "${RAW_REBUILD_LIST[i]}" >/dev/null && continue
-                                       SKIP_LIST+=("${RAW_REBUILD_LIST[i]}")
+                               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
                                        unset RAW_REBUILD_LIST[i]
                                done
                                # If RAW_REBUILD_LIST is empty, then we have nothing to build.
                                if (( ${#RAW_REBUILD_LIST[@]} == 0 )); then
-                                       list_skipped_packages
+                                       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
                                        die 1 'Warning: Portage cannot rebuild any of the necessary packages.'
                                fi
-                       else
-                               RAW_REBUILD_LIST=("${RAW_REBUILD_LIST[@]/#/=}")
                        fi
                        RAW_REBUILD_LIST="${RAW_REBUILD_LIST[@]}"
                        REBUILD_GREP=$(emerge --nodeps $RAW_REBUILD_LIST | sed 's/\[[^]]*\]//g')
                        if (( ${PIPESTATUS[0]} == 0 )); then
                                emerge --deep $RAW_REBUILD_LIST |
                                        sed 's/\[[^]]*\]//g' |
                        fi
                        RAW_REBUILD_LIST="${RAW_REBUILD_LIST[@]}"
                        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" > $LIST.5_order
+                                       grep -F "$REBUILD_GREP" > "$ORDER_FILE"
                        fi
 
                        # Here we use the PIPESTATUS from the second emerge, the --deep one.
                        fi
 
                        # Here we use the PIPESTATUS from the second emerge, the --deep one.
@@ -877,7 +921,7 @@ get_build_order() {
                                                        and/or /etc/portage/package.unmask to unmask it
                                        EOF
                                        countdown 5
                                                        and/or /etc/portage/package.unmask to unmask it
                                        EOF
                                        countdown 5
-                                       rm -f "$LIST.5_order"
+                                       rm -f "$ORDER_FILE"
                        fi
                        export EMERGE_DEFAULT_OPTS="$OLD_EMERGE_DEFAULT_OPTS"
                else
                        fi
                        export EMERGE_DEFAULT_OPTS="$OLD_EMERGE_DEFAULT_OPTS"
                else
@@ -885,104 +929,158 @@ get_build_order() {
                        die 1 '(The program should have already quit, so this is a minor bug.)'
                fi
        fi
                        die 1 '(The program should have already quit, so this is a minor bug.)'
                fi
        fi
-       [[ -r $LIST.5_order && -s $LIST.5_order ]] && einfo "Generated new $LIST.5_order"
-}
-
-get_search_env
-echo
-get_files
-echo
-get_ldpath
-echo
-main_checks
-echo
-if [[ $PACKAGE_NAMES ]]; then
-       get_packages
-       echo
-       clean_packages
-       echo
-       assign_packages_to_ebuilds
-else
-       get_exact_ebuilds
-fi
-echo
-get_build_order
-echo
+       [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" ]] && einfo "Generated new $ORDER_FILE"
+}
 
 
-# Clean up no longer needed environment variables
-unset SEARCH_DIRS SEARCH_DIRS_MASK LD_LIBRARY_MASK PORTAGE_ROOT
+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" | awk '!s[$0]++' # (omit dupes)
+       fi
+}
+##
+# Setup portage and the search paths
+setup_portage() {
+       local PORTAGE_NICENESS=$(portageq envvar PORTAGE_NICENESS)
+       PORTAGE_ROOT=$(portageq envvar ROOT)
 
 
-[[ -r $LIST.5_order && -s $LIST.5_order ]] &&
-       REBUILD_LIST=($(<"$LIST.5_order")) ||
-       REBUILD_LIST=($(sort -u "$LIST.4_ebuilds"))
+       # Obey PORTAGE_NICENESS
+       if [[ $PORTAGE_NICENESS ]]; then
+               renice $PORTAGE_NICENESS $$ > /dev/null
+               # Since we have already set our nice value for our processes,
+               # reset PORTAGE_NICENESS to zero to avoid having emerge renice again.
+               export PORTAGE_NICENESS="0"
+       fi
 
 
-trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
+       PORTAGE_ROOT="${PORTAGE_ROOT:-/}"
+}
 
 
-REBUILD_LIST="${REBUILD_LIST[@]}"
-REBUILD_LIST="=${REBUILD_LIST//[[:space:]]/ =}"
+##
+# 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
 
 
-einfo 'All prepared. Starting rebuild'
-echo "emerge --oneshot ${EMERGE_OPTIONS[@]} $REBUILD_LIST"
+       einfo "Configuring search environment for $APP_NAME"
 
 
-is_real_merge && countdown 10
+       # Update the incremental variables using /etc/profile.env, /etc/ld.so.conf,
+       # portage, and the environment
 
 
-# Link file descriptor #6 with stdin so --ask will work
-exec 6<&0
+       # 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)
 
 
-# Run in background to correctly handle Ctrl-C
-{
-       EMERGE_DEFAULT_OPTS="--oneshot ${EMERGE_OPTIONS[@]}" emerge $REBUILD_LIST <&6
-       echo $? > $LIST.6_status
-} &
-wait
+       # 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
 
 
-# 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<&-
+       # 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
 
 
-show_unowned_files() {
-       if grep -qF '(none)' "$LIST.4_package_owners"; then
-               ewarn "Found some broken files that weren't associated with known packages"
-               ewarn "The broken files are:"
-               while read filename junk; do
-                       [[ $junk = *none* ]] && ewarn "  $filename"
-               done < "$LIST.4_package_owners" | awk '!s[$0]++' # (omit dupes)
+       # Get the directories from /etc/ld.so.conf
+       if [[ -r /etc/ld.so.conf && -s /etc/ld.so.conf ]]; then
+               SEARCH_DIRS+=" "$(sed '/^#/d;s/#.*$//' /etc/ld.so.conf)
        fi
        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
+               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 $LIST.5_order && -s $LIST.5_order ]]; then
+               REBUILD_LIST=( $(<"$LIST.5_order") )
+               REBUILD_LIST="${REBUILD_LIST[@]/#/=}"
+       else
+               REBUILD_LIST=$(sort -u "$EBUILDS_FILE")
+       fi
 
 
-if (( $(<"$LIST.6_status") != 0 )); then
-       ewarn
-       ewarn "$APP_NAME failed to emerge all packages."
-       ewarn 'you have the following choices:'
-       einfo "- If emerge failed during the build, fix the problems and re-run $APP_NAME."
-       einfo '- Use /etc/portage/package.keywords to unmask a newer version of the package.'
-       einfo "  (and remove $LIST.5_order to be evaluated again)"
-       einfo '- Modify the above emerge command and run it manually.'
-       einfo '- Compile or unmerge unsatisfied packages manually,'
-       einfo '  remove temporary files, and try again.'
-       einfo '  (you can edit package/ebuild list first)'
-       einfo
-       einfo 'To remove temporary files, please run:'
-       einfo "rm $LIST*.?_*"
-       show_unowned_files
-       exit $EMERGE_STATUS
-elif is_real_merge; then
-       trap_cmd() {
-               eerror "terminated. Please remove the temporary files manually:"
-               eerror "rm $LIST*.?_*"
-               exit 1
-       }
-       (( "${#SKIP_LIST[@]}" != 0 )) && 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. If some inconsistency remains, it can be orphaned file, deep'
-       einfo 'dependency, binary package or specially evaluated library.'
-       if [[ -r "$LIST.4_package_owners" && -s "$LIST.4_package_owners" ]]; then
-       show_unowned_files
+       trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
+
+       einfo 'All prepared. Starting rebuild'
+       echo "emerge --oneshot ${EMERGE_OPTIONS[@]} $REBUILD_LIST"
+
+       is_real_merge && countdown 10
+
+       # Link file descriptor #6 with stdin so --ask will work
+       exec 6<&0
+
+       # Run in background to correctly handle Ctrl-C
+       {
+               EMERGE_DEFAULT_OPTS="--oneshot ${EMERGE_OPTIONS[@]}" emerge $REBUILD_LIST <&6
+               echo $? > "$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 )); 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 ${TMPDIR}/$APP_NAME/*.rr"
+               show_unowned_files
+               exit $EMERGE_STATUS
+       elif is_real_merge; then
+               trap_cmd() {
+                       eerror "terminated. Please remove the temporary files manually:"
+                       eerror "rm ${TMPDIR}/$APP_NAME/*.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. If some inconsistency remains, it can be orphaned file, deep'
+               einfo 'dependency, binary package or specially evaluated library.'
+               if [[ -r "$OWNERS_FILE" && -s "$OWNERS_FILE" ]]; then
+                       show_unowned_files
+               fi
+               [[ $KEEP_TEMP ]] || rm "${FILES[@]}"
+       else
+               einfo 'Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.'
        fi
        fi
-       [[ $KEEP_TEMP ]] || rm $LIST*.?_*
-else
-       einfo 'Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.'
-fi
+}
 
 
+main "$@"