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