From: fuzzyray Date: Wed, 19 Sep 2007 18:12:02 +0000 (-0000) Subject: Move revdep-rebuild-rewrite to revdep-rebuild. Change Makefile to only install new... X-Git-Tag: gentoolkit-0.2.4.3~68 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=ce2c13c8161100a7040aef206fb853cc6c0ce25f;p=gentoolkit.git Move revdep-rebuild-rewrite to revdep-rebuild. Change Makefile to only install new revdep-rebuild svn path=/; revision=445 --- diff --git a/trunk/src/revdep-rebuild/Makefile b/trunk/src/revdep-rebuild/Makefile index 59c97c7..d509681 100644 --- a/trunk/src/revdep-rebuild/Makefile +++ b/trunk/src/revdep-rebuild/Makefile @@ -11,14 +11,11 @@ all: dist: mkdir -p ../../$(distdir)/src/revdep-rebuild - cp Makefile AUTHORS README TODO ChangeLog revdep-rebuild revdep-rebuild.1 revdep-rebuild-rewrite find_pkgs.py 99revdep-rebuild ../../$(distdir)/src/revdep-rebuild/ + cp Makefile AUTHORS README TODO ChangeLog revdep-rebuild revdep-rebuild.1 99revdep-rebuild ../../$(distdir)/src/revdep-rebuild/ install: - install -m 0755 revdep-rebuild-rewrite $(bindir)/revdep-rebuild - install -d $(DESTDIR)/usr/lib/gentoolkit/bin/ - install -m 0755 find_pkgs.py $(DESTDIR)/usr/lib/gentoolkit/bin/ - install -m 0755 revdep-rebuild $(DESTDIR)/usr/lib/gentoolkit/bin/ + install -m 0755 revdep-rebuild $(bindir)/ install -d $(docdir)/revdep-rebuild install -m 0644 AUTHORS README TODO $(docdir)/revdep-rebuild/ install -m 0644 revdep-rebuild.1 $(mandir)/ diff --git a/trunk/src/revdep-rebuild/revdep-rebuild b/trunk/src/revdep-rebuild/revdep-rebuild index 3115eb9..19de90d 100755 --- a/trunk/src/revdep-rebuild/revdep-rebuild +++ b/trunk/src/revdep-rebuild/revdep-rebuild @@ -1,27 +1,39 @@ -#!/bin/bash +#!/bin/bash # Copyright 1999-2007 Gentoo Foundation -# $Header$ # revdep-rebuild: Reverse dependency rebuilder. # Original Author: Stanislav Brabec +# Rewrite Author: Michael A. Smith # Current Maintainer: Paul Varner -# 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. @@ -29,35 +41,270 @@ # 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 +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 " + einfo "$OK_TEXT... All done. " exit 0 -fi +} +get_args() { + echo_v() { ewarn "$@"; } + unset VERBOSE KEEP_TEMP EMERGE_OPTIONS RM_OLD_TEMPFILES + ORDER_PKGS=1 + PACKAGE_NAMES=1 + SONAME="not found" + SEARCH_BROKEN=1 + FULL_LD_PATH=1 + local avoid_utils + while [[ $1 ]]; do + case $1 in + -h|--help) + print_usage + exit 0 + ;; + -e|--exact) + unset PACKAGE_NAMES + ;; + -o|--no-order) + unset ORDER_PKGS + ;; + -P|--no-progress) + progress() { :; } + ;; + -q|--quiet) + echo_v() { :; } + progress() { :; } + quiet=1 + EMERGE_OPTIONS+=($1) + ;; + -L=*|--library=*|--soname=*|--soname-regexp=*) + SONAME="${1#*=}" + unset SEARCH_BROKEN + ;; + -L|--library|--soname|--soname-regexp) + [[ ! $2 || $2 = -* ]] && die 1 "Missing expected argument to $1" + shift + SONAME="$1" + unset SEARCH_BROKEN + ;; + -u=*|--no-util=*) + # TODO: check for invalid values + avoid_utils="${1#*=}" + ;; + -u|--no-util) + [[ ! $2 || $2 = -* ]] && die 1 "Missing expected argument to $1" + shift + avoid_utils="$1" + ;; + -nc|-C|--no-color|--nocolor) + export NOCOLOR=yes + ;; + -l|-np|--no-ld-path) + unset FULL_LD_PATH + ;; + -i|--ignore) + RM_OLD_TEMPFILES=1 + ;; + -k|--keep-temp) + KEEP_TEMP=1 + ;; + -vv|--extra-verbose|-v|--verbose) + VERBOSE=1 + EMERGE_OPTIONS+=($1) + ;; + -X|--package-names) + # No longer used, since it is the default. + # We accept it for backwards compatibility + PACKAGE_NAMES=1 + ;; + --) + ;; + *) + EMERGE_OPTIONS+=($1) + ;; + esac + shift + done + # Check if various utils are allowed and installed + if [[ $avoid_utils != *portage-utils* ]] && hash qfile 2> /dev/null; then + get_file_owner() { qfile -qvC "$@"; } + elif [[ $avoid_utils != *pkgcore* ]] && hash pquery 2> /dev/null; then + get_file_owner() { local IFS=,; pquery --nocolor --owns="$*"; } + # equery disabled for incompatibility with modern portage. + # elif [[ $avoid_utils != *equery* ]] && hash equery 2> /dev/null; then + # get_file_owner() { equery -q -C b $@; } + else + get_file_owner() { + local IFS=$'\n' + find /var/db/pkg -name CONTENTS -print0 | + xargs -0 grep -Fl "$*" | + sed 's:/var/db/pkg/\(.*\)/CONTENTS:\1:' + } + fi -echo "Configuring search environment for revdep-rebuild" + # Use the color preference from portage + export NOCOLOR=$(portageq envvar NOCOLOR) + [[ $NOCOLOR = yes || $NOCOLOR = true ]] && export RC_NOCOLOR=yes # HACK! (grr) + source /etc/init.d/functions.sh + + # Normalize some EMERGE_OPTIONS + EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-p/--pretend}) + EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-f/--fetchonly}) + EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-f/--verbose}) + if [[ ${EMERGE_OPTIONS[@]} != *--pretend* && $UID -ne 0 ]]; then + ewarn "You are not superuser. Adding --pretend to emerge options." + EMERGE_OPTIONS+=(--pretend) + fi +} +is_real_merge() [[ + ${EMERGE_OPTIONS[@]} != *--pretend* && ${EMERGE_OPTIONS[@]} != *--fetchonly* +]] + +get_args "$@" + +einfo "Configuring search environment for $APP_NAME" # Obey PORTAGE_NICENESS PORTAGE_NICENESS=$(portageq envvar PORTAGE_NICENESS) -if [ ! -z "$PORTAGE_NICENESS" ] -then +if [[ $PORTAGE_NICENESS ]]; then renice $PORTAGE_NICENESS $$ > /dev/null # Since we have already set our nice value for our processes, # reset PORTAGE_NICENESS to zero to avoid having emerge renice again. @@ -65,7 +312,7 @@ then fi PORTAGE_ROOT=$(portageq envvar ROOT) -[ -z "$PORTAGE_ROOT" ] && PORTAGE_ROOT="/" +PORTAGE_ROOT="${PORTAGE_ROOT:-/}" # Update the incremental variables using /etc/profile.env, /etc/ld.so.conf, # portage, and the environment @@ -73,675 +320,511 @@ PORTAGE_ROOT=$(portageq envvar ROOT) # Read the incremental variables from environment and portage # Until such time as portage supports these variables as incrementals # The value will be what is in /etc/make.conf -PRELIMINARY_SEARCH_DIRS="$SEARCH_DIRS $(unset SEARCH_DIRS; portageq envvar SEARCH_DIRS)" -PRELIMINARY_SEARCH_DIRS_MASK="$SEARCH_DIRS_MASK $(unset SEARCH_DIRS_MASK; portageq envvar SEARCH_DIRS_MASK)" -PRELIMINARY_LD_LIBRARY_MASK="$LD_LIBRARY_MASK $(unset LD_LIBRARY_MASK; portageq envvar LD_LIBRARY_MASK)" +SEARCH_DIRS+=" "$(unset SEARCH_DIRS; portageq envvar SEARCH_DIRS) +SEARCH_DIRS_MASK+=" "$(unset SEARCH_DIRS_MASK; portageq envvar SEARCH_DIRS_MASK) +LD_LIBRARY_MASK+=" "$(unset LD_LIBRARY_MASK; portageq envvar LD_LIBRARY_MASK) # Add the defaults -if [ -d /etc/revdep-rebuild ] -then - for file in $(ls /etc/revdep-rebuild) - do - PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS $(. /etc/revdep-rebuild/${file}; echo $SEARCH_DIRS)" - PRELIMINARY_SEARCH_DIRS_MASK="$PRELIMINARY_SEARCH_DIRS_MASK $(. /etc/revdep-rebuild/${file}; echo $SEARCH_DIRS_MASK)" - PRELIMINARY_LD_LIBRARY_MASK="$PRELIMINARY_LD_LIBRARY_MASK $(. /etc/revdep-rebuild/${file}; echo $LD_LIBRARY_MASK)" +if [[ -d /etc/revdep-rebuild ]]; then + for ENV_FILE in /etc/revdep-rebuild/*; do + SEARCH_DIRS+=" "$(. $ENV_FILE; echo $SEARCH_DIRS) + SEARCH_DIRS_MASK+=" "$(. $ENV_FILE; echo $SEARCH_DIRS_MASK) + LD_LIBRARY_MASK+=" "$(. $ENV_FILE; echo $LD_LIBRARY_MASK) done + unset ENV_FILE # HACK else - PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS /bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*" - PRELIMINARY_SEARCH_DIRS_MASK="$PRELIMINARY_SEARCH_DIRS_MASK /opt/OpenOffice /usr/lib/openoffice" - PRELIMINARY_LD_LIBRARY_MASK="$PRELIMINARY_LD_LIBRARY_MASK libodbcinst.so libodbc.so libjava.so libjvm.so" + SEARCH_DIRS+=" /bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*" + SEARCH_DIRS_MASK+=" /opt/OpenOffice /usr/lib/openoffice" + LD_LIBRARY_MASK+=" libodbcinst.so libodbc.so libjava.so libjvm.so" fi # Get the ROOTPATH and PATH from /etc/profile.env -if [ -e "/etc/profile.env" ] -then - PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS $((. /etc/profile.env; echo ${ROOTPATH}:${PATH}) | tr ':' ' ')" +if [[ -r "/etc/profile.env" && -s "/etc/profile.env" ]]; then + SEARCH_DIRS+=" "$(. /etc/profile.env; /usr/bin/tr ':' ' ' <<< "$ROOTPATH $PATH") fi # Get the directories from /etc/ld.so.conf -if [ -e /etc/ld.so.conf ] -then - PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS $(grep -v "^#" /etc/ld.so.conf | tr '\n' ' ')" -fi - -# Set the final variables -# Note: Using $(echo $variable) removes extraneous spaces from variable assignment -unset SEARCH_DIRS -for i in $(echo $PRELIMINARY_SEARCH_DIRS) -do - [ "$i" = "-*" ] && break - # Append a / at the end so that links and directories are treated the same by find - # Remove any existing trailing slashes to prevent double-slashes - SEARCH_DIRS="$(echo $SEARCH_DIRS ${i/%\//}/)" -done -# Remove any double-slashes from the path -SEARCH_DIRS="$(echo $SEARCH_DIRS | sed 's:/\+:/:g')" - -unset SEARCH_DIRS_MASK -for i in $(echo $PRELIMINARY_SEARCH_DIRS_MASK) -do - [ "$i" = "-*" ] && break - SEARCH_DIRS_MASK="$(echo $SEARCH_DIRS_MASK $i)" -done - -unset LD_LIBRARY_MASK -for i in $(echo $PRELIMINARY_LD_LIBRARY_MASK) -do - [ "$i" = "-*" ] && break - LD_LIBRARY_MASK="$(echo $LD_LIBRARY_MASK $i)" -done - -# Use the color preference from portage -NOCOLOR=$(portageq envvar NOCOLOR) - -# Base of temporary files names. -touch ${HOME}/.revdep-rebuild_0.test 2>/dev/null -if [ $? -eq 0 ] -then - LIST="${HOME}/.revdep-rebuild" - rm ~/.revdep-rebuild_0.test -else - # Try to use /var/tmp since $HOME is not available - touch /var/tmp/.revdep-rebuild_0.test 2>/dev/null - if [ $? -eq 0 ] - then - LIST="/var/tmp/.revdep-rebuild" - rm /var/tmp/.revdep-rebuild_0.test - else - echo - echo "!!! Unable to write temporary files to either $HOME or /var/tmp !!!" - echo - exit 1 - fi -fi - -shopt -s nullglob -shopt -s expand_aliases -unalias -a - -# Color Definitions -NO="\x1b[0m" -BR="\x1b[0;01m" -CY="\x1b[36;01m" -GR="\x1b[32;01m" -RD="\x1b[31;01m" -YL="\x1b[33;01m" -BL="\x1b[34;01m" - -# Check if portage-utils are installed -portageq has_version $PORTAGE_ROOT portage-utils -if [ "$?" -eq 0 ] -then - PORTAGE_UTILS=true -else - PORTAGE_UTILS=false -fi - -alias echo_v=echo - -PACKAGE_NAMES=false -SONAME="not found" -SONAME_GREP=grep -SEARCH_BROKEN=true -EXTRA_VERBOSE=false -KEEP_TEMP=false -FULL_LD_PATH=true - -EMERGE_OPTIONS="" -PRELIMINARY_CALLED_OPTIONS="" -while [ ! -z "$1" ] ; do - case "$1" in - -X | --package-names ) - PACKAGE_NAMES=true - PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --package_names" - shift - ;; - -q | --quiet ) - alias echo_v=: - EMERGE_OPTIONS="${EMERGE_OPTIONS} $1" - shift - ;; - --library=* | --soname=* | --soname-regexp=* ) - SONAME="${1#*=}" - SEARCH_BROKEN=false - PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --library=${SONAME}" - shift - ;; - --library | --soname | --soname-regexp ) - SONAME="$2" - SEARCH_BROKEN=false - PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --library=${SONAME}" - shift 2 - ;; - -nc | --no-color | --nocolor ) - NOCOLOR=true - shift - ;; - -np | --no-ld-path ) - FULL_LD_PATH=false - PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --no-ld-path" - shift - ;; - -i | --ignore ) - rm -f ${LIST}* - shift - ;; - --keep-temp ) - KEEPTEMP=true - shift - ;; - -vv | --extra-verbose ) - EXTRA_VERBOSE=true - shift - ;; - -- ) - shift - ;; - * ) - EMERGE_OPTIONS="${EMERGE_OPTIONS} $1" - shift - ;; - esac -done - -EMERGE_OPTIONS=$(echo $EMERGE_OPTIONS | sed 's/^ //') - -if [ -z "$PRELIMINARY_CALLED_OPTIONS" ] -then - CALLED_OPTIONS="" -else - for i in $(echo $PRELIMINARY_CALLED_OPTIONS | tr ' ' '\n'| sort) - do - CALLED_OPTIONS="$(echo $CALLED_OPTIONS $i)" - done -fi - -if [ "$NOCOLOR" = "yes" -o "$NOCOLOR" = "true" ] -then - NOCOLOR=true -else - NOCOLOR=false +if [[ -r /etc/ld.so.conf && -s /etc/ld.so.conf ]]; then + SEARCH_DIRS+=" "$(sed '/^#/d;s/#.*$//' /etc/ld.so.conf) fi -# Make the NOCOLOR variable visible to emerge -export NOCOLOR - -if $NOCOLOR -then - NO="" - BR="" - CY="" - GR="" - RD="" - YL="" - BL="" -fi +# Set the final variables +[[ $SEARCH_DIRS ]] || die 1 "No search defined -- this is a bug." +SEARCH_DIRS=$(clean_var "$SEARCH_DIRS") +SEARCH_DIRS_MASK=$(clean_var "$SEARCH_DIRS_MASK") +LD_LIBRARY_MASK=$(clean_var "$LD_LIBRARY_MASK") -function set_trap () { +set_trap() { trap "rm_temp $1" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM } - -function rm_temp () { - echo " terminated." - echo "Removing incomplete $1." +rm_temp() { rm $1 - echo - exit 1 + die 1 $' ...terminated. Removing incomplete '"$1." } - -if $SEARCH_BROKEN ; then - SONAME_SEARCH="$SONAME" - LLIST=$LIST - HEAD_TEXT="broken by a package update" - OK_TEXT="Dynamic linking on your system is consistent" - WORKING_TEXT=" consistency" -else - # first case is needed to test against /path/to/foo.so - if [ ${SONAME:0:1} == '/' ] ; then - # Set to "$SONAME" - 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 "$SONAME" - SONAME_SEARCH=" $SONAME " + # first case is needed to test against /path/to/foo.so + if [[ $SONAME = /* ]]; then + # Set to "$SONAME" + SONAME_SEARCH=" $SONAME " + # Escape the "/" characters + SONAME_SEARCH="${SONAME_SEARCH//\//\\/}" + else + # Set to "$SONAME" + 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/#.*$//' $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=$( "$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=\"~\" and/or /etc/portage/package.unmask" - echo " (and remove $LLIST.5_order to be evaluated again)" - echo " or" - echo "- modify the above emerge command and run it manually" - echo " or" - echo "- compile or unmerge unsatisfied packages manually, remove temporary files and" - echo " try again (you can edit package/ebuild list first)" - echo - echo -e "${GR}To remove temporary files, please run:${NO}" - echo "rm $LIST*.?_*" - exit $(cat $LLIST.6_status) +if (( $(<"$LIST.6_status") != 0 )); then + ewarn + ewarn "$APP_NAME failed to emerge all packages." + ewarn 'you have the following choices:' + einfo "- If emerge failed during the build, fix the problems and re-run $APP_NAME." + einfo '- Use /etc/portage/package.keywords to unmask a newer version of the package.' + einfo " (and remove $LIST.5_order to be evaluated again)" + einfo '- Modify the above emerge command and run it manually.' + einfo '- Compile or unmerge unsatisfied packages manually,' + einfo ' remove temporary files, and try again.' + einfo ' (you can edit package/ebuild list first)' + einfo + einfo 'To remove temporary files, please run:' + einfo "rm $LIST*.?_*" + show_unowned_files + exit $EMERGE_STATUS +elif is_real_merge; then + trap_cmd() { + eerror "terminated. Please remove the temporary files manually:" + eerror "rm $LIST*.?_*" + exit 1 + } + trap trap_cmd SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM + einfo 'Build finished correctly. Removing temporary files...' + einfo + einfo 'You can re-run revdep-rebuild to verify that all libraries and binaries' + einfo 'are fixed. If some inconsistency remains, it can be orphaned file, deep' + einfo 'dependency, binary package or specially evaluated library.' + show_unowned_files + [[ $KEEP_TEMP ]] || rm $LIST*.?_* else - if $IS_REAL_MERGE ; then - trap "echo -e \" terminated. Please remove them manually:\nrm $LIST*.?_*\" ; exit 1" \ - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM - echo -n -e "${GR}Build finished correctly. Removing temporary files...${NO} " - echo - rm $LIST.[0-2]_* - rm $LLIST.[3-9]_* - echo "You can re-run revdep-rebuild to verify that all libraries and binaries" - echo "are fixed. If some inconsistency remains, it can be orphaned file, deep" - echo "dependency, binary package or specially evaluated library." - else - echo -e "${GR}Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.${NO}" - fi + einfo 'Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.' fi -exit 0 + diff --git a/trunk/src/revdep-rebuild/revdep-rebuild-old b/trunk/src/revdep-rebuild/revdep-rebuild-old new file mode 100755 index 0000000..3115eb9 --- /dev/null +++ b/trunk/src/revdep-rebuild/revdep-rebuild-old @@ -0,0 +1,747 @@ +#!/bin/bash +# Copyright 1999-2007 Gentoo Foundation +# $Header$ + +# revdep-rebuild: Reverse dependency rebuilder. +# Original Author: Stanislav Brabec +# Current Maintainer: Paul Varner + +# 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 " + 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 "$SONAME" + SONAME_SEARCH=" $SONAME " + else + # Set to "$SONAME" + 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/#.*$//' $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=\"~\" and/or /etc/portage/package.unmask" + echo " (and remove $LLIST.5_order to be evaluated again)" + echo " or" + echo "- modify the above emerge command and run it manually" + echo " or" + echo "- compile or unmerge unsatisfied packages manually, remove temporary files and" + echo " try again (you can edit package/ebuild list first)" + echo + echo -e "${GR}To remove temporary files, please run:${NO}" + echo "rm $LIST*.?_*" + exit $(cat $LLIST.6_status) +else + if $IS_REAL_MERGE ; then + trap "echo -e \" terminated. Please remove them manually:\nrm $LIST*.?_*\" ; exit 1" \ + SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM + echo -n -e "${GR}Build finished correctly. Removing temporary files...${NO} " + echo + rm $LIST.[0-2]_* + rm $LLIST.[3-9]_* + echo "You can re-run revdep-rebuild to verify that all libraries and binaries" + echo "are fixed. If some inconsistency remains, it can be orphaned file, deep" + echo "dependency, binary package or specially evaluated library." + else + echo -e "${GR}Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.${NO}" + fi +fi +exit 0 diff --git a/trunk/src/revdep-rebuild/revdep-rebuild-rewrite b/trunk/src/revdep-rebuild/revdep-rebuild-rewrite deleted file mode 100755 index 19de90d..0000000 --- a/trunk/src/revdep-rebuild/revdep-rebuild-rewrite +++ /dev/null @@ -1,830 +0,0 @@ -#!/bin/bash -# Copyright 1999-2007 Gentoo Foundation - -# revdep-rebuild: Reverse dependency rebuilder. -# Original Author: Stanislav Brabec -# Rewrite Author: Michael A. Smith -# Current Maintainer: Paul Varner - -# 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 -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 "$SONAME" - SONAME_SEARCH=" $SONAME " - # Escape the "/" characters - SONAME_SEARCH="${SONAME_SEARCH//\//\\/}" - else - # Set to "$SONAME" - 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=$( "$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 -