#!/bin/bash # Copyright 1999-2007 Gentoo Foundation # revdep-rebuild: Reverse dependency rebuilder. # Original Author: Stanislav Brabec # Current Maintainer: Paul Varner source /etc/init.d/functions.sh # TODO: # - Use more /etc/init.d/functions.sh # 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 declare -r oIFS="$IFS" rm() { [[ $LIST && $appname ]] || die 1 '$LIST or $appname is not defined! (This is a bug.)' for i in $@; do [[ $i = -* || $i = *.$appname* ]] || 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: $0 [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.) -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, pkgcore, or equery 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 [[ $quiet ]]; then progress() { :; } else progress() { (( $1 == $2 )) && local lb=$'\n' echo -ne '\r \r' echo -n "[ $(( $1 * 100 / $2 ))% ] $lb" } progress $@ fi } # 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 ${@%%-\**}) # 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.?_* set_color green die 0 $'\n'"$OK_TEXT... All done. " } get_args() { appname="${0##*/}" echo_v() { ewarn "$@"; } unset VERBOSE KEEP_TEMP EMERGE_OPTIONS remove_old_tempfiles order_packages=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_packages ;; -q|--quiet) echo_v() { : ; } 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) # TODO: Does this variable do anything now that the main color functions are removed? export NOCOLOR=1 ;; -l|-np|--no-ld-path) unset FULL_LD_PATH ;; -i|--ignore) remove_old_tempfiles=1 ;; -k|--keep-temp) KEEP_TEMP=1 ;; -vv|--extra-verbose|-v|--verbose) VERBOSE=1 EMERGE_OPTIONS+=($1) ;; --) ;; *) EMERGE_OPTIONS+=($1) ;; esac shift done # Check if various utils are allowed and installed if [[ $avoid_utils != *portage-utils* ]] && hash q 2> /dev/null; then PORTAGE_UTILS=1 elif [[ $avoid_utils != *pkgcore* ]] && hash pquery 2> /dev/null; then PKGCORE=1 elif [[ $avoid_utils != *equery* ]] && hash equery 2> /dev/null; then EQUERY=1 fi EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-p/--pretend}) EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-f/--fetchonly}) 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 $appname" # 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 file in /etc/revdep-rebuild/*; do SEARCH_DIRS+=" "$(. $file; echo $SEARCH_DIRS) SEARCH_DIRS_MASK+=" "$(. $file; echo $SEARCH_DIRS_MASK) LD_LIBRARY_MASK+=" "$(. $file; echo $LD_LIBRARY_MASK) done else SEARCH_DIRS+=" /bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*" SEARCH_DIRS_MASK+=" /opt/OpenOffice /usr/lib/openoffice" LD_LIBRARY_MASK+=" libodbcinst.so libodbc.so libjava.so libjvm.so" fi # Get the ROOTPATH and PATH from /etc/profile.env if [[ -rs "/etc/profile.env" ]]; then SEARCH_DIRS+=" "$(. /etc/profile.env; /usr/bin/tr ':' ' ' <<< "$ROOTPATH $PATH") fi # Get the directories from /etc/ld.so.conf if [[ -rs /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") # Use the color preference from portage NOCOLOR=$(portageq envvar NOCOLOR) # Find a place to put temporary files # TODO; let the user choose where to put tempfiles # gfind $HOME/ /var/tmp/ /tmp/ -writable -print -quit # TODO: This is a rather noisy, but portable way to implement -quit LIST=$( find $HOME/ /var/tmp/ /tmp/ -writable | while read LIST; do echo "$LIST.$appname" break done ) if [[ $LIST = .$appname ]]; then die 1 "!!! Unable to find a satisfactory location for temporary files !!!" fi [[ $remove_old_tempfiles ]] && rm -f $LIST.* function set_trap () { trap "rm_temp $1" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM } function rm_temp () { rm $1 die 1 $' ...terminated. Removing incomplete '"$1." } get_search_env() { 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 " else # Set to "$SONAME" SONAME_SEARCH=$'\t'"$SONAME " fi # NOTE: Using a redirect instead of echo is good, but it will cause a minor # incompatibility with older versions of revdep-rebuild, because the # string sent to md5sum will no longer have a newline at the end. SOMD5=$(md5sum <<< "$SONAME_SEARCH$SONAME") LIST+="_${SOMD5:0:8}" HEAD_TEXT="using $SONAME" OK_TEXT="There are no dynamic links to $SONAME" unset WORKING_TEXT SOMD5 fi [[ $LIST ]] || die 1 $LIST IS NOT DEFINED # If any of our temporary files are older than 1 day, remove them all [[ ! $keep_tempfiles && -r $LIST && $( find -L "$LIST" -type f -mmin +1440 -print | while read; do echo 1; break; done ) ]] && rm -f $LIST.* # Compare old and new environments # Don't use our previous files if environment doesn't match new_env=$( 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_packages="$order_packages" FULL_LD_PATH="$FULL_LD_PATH" EOF ) if [[ -rs $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 -f "$LIST"* fi else # No 0_env file found, silently delete any other tempfiles that may exist rm -f "$LIST"* fi # Save the environment in a file for next time echo "$new_env" > "$LIST.0_env" [[ $VERBOSE ]] && echo $'\n'"$appname environment:"$'\n'"$new_env" unset 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 [[ -rs $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() { [[ $SEARCH_BROKEN && $FULL_LD_PATH ]] || return einfo 'Collecting complete LD_LIBRARY_PATH' if [[ -rs $LIST.2_ldpath ]] ; then einfo "Found existing $LIST.2_ldpath." COMPLETE_LD_LIBRARY_PATH=$(<"$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() { einfo "Checking dynamic linking $WORKING_TEXT" if [[ -rs $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" rm -f $LIST.3* files=($(<"$LIST.1_files")) numFiles=${#files[@]}; i=0 for FILE in ${files[@]}; do if [[ $FILE != *.la ]]; then # Note: double checking seems to be faster than single with complete path # (special add ons are rare). ldd_output=$(ldd "$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 "$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 "$FILE" | sed "$expr" | sort -u ) MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS") if [[ $MISSING_LIBS ]]; then echo "obj $FILE" >> "$LIST.3_rebuild" echo_v " broken $FILE (requires $MISSING_LIBS)" fi fi else # FIXME: I hate duplicating code # Only rebuild for direct dependencies MISSING_LIBS=$( expr="/$SONAME_SEARCH/s/^\([^[:space:]]*\).*$/\1/p" sort -u <<< "$ldd_output" | sed -n "$expr" ) REQUIRED_LIBS=$( expr='s/^[[:space:]]*NEEDED[[:space:]]*\([^[:space:]]*\).*/\1/p'; objdump -x "$FILE" | sed "$expr" | sort -u ) MISSING_LIBS=$(grep -F "$REQUIRED_LIBS") if [[ $MISSING_LIBS ]]; then echo "obj $FILE" >> "$LIST.3_rebuild" if [[ $SEARCH_BROKEN ]]; then echo_v " broken $FILE (requires $MISSING_LIBS)" else echo_v " found $FILE" fi fi fi fi elif [[ $SEARCH_BROKEN ]]; then # Look for broken .la files for depend in $( awk -F"[=']" '/^dependency_libs/{ gsub("^-[^[:space:]]*", "", $2); gsub("[[:space:]]-[^[:space:]]*", "", $2); print $2 }' "$FILE" ); do if [[ $depend != /* && ! -e $depend ]]; then echo "obj $FILE" >> "$LIST.3_rebuild" echo_v " broken $FILE (requires $depend)" fi done fi [[ $VERBOSE ]] && progress $((++i)) $numFiles $FILE || progress $((++i)) $numFiles done if [[ $SEARCH_BROKEN ]]; then # Look for missing version for FILE in $( awk '/no version information available/{ gsub("[()]", "", $NF); print $NF }' "$LIST.3_ldd_errors" | sort -u ); do echo "obj $FILE" >> "$LIST.3_rebuild" echo_v " broken $FILE (no version information available)" done fi [[ -rs $LIST.3_rebuild ]] || clean_exit einfo "Generated new $LIST.3_rebuild" fi } get_packages() { einfo 'Assigning files to packages' if [[ -rs $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 FILE; do if [[ $PORTAGE_UTILS ]]; then EXACT_PKG=$(qfile -qvC $FILE) elif [[ $PKGCORE ]]; then EXACT_PKG=$(pquery --nocolor --owns="$FILE") elif [[ $EQUERY ]]; then EXACT_PKG=$(equery -q -C b $FILE) else EXACT_PKG=$( find /var/db/pkg -name CONTENTS | xargs grep -Fl "obj $FILE " | sed -e 's:/var/db/pkg/\(.*\)/CONTENTS:\1:g' ) fi if [[ $EXACT_PKG ]]; then # Strip version information PKG="${EXACT_PKG%%-r[[:digit:]]*}" PKG="${PKG%-*}" echo "$EXACT_PKG" >> $LIST.4_packages_raw echo "$FILE -> $EXACT_PKG" >> $LIST.4_package_owners echo_v " $FILE -> $PKG" else ewarn " !!! $FILE not owned by any package is broken !!!" echo "$FILE -> (none)" >> $LIST.4_package_owners echo_v -n -e "\n $FILE -> (none)" fi done < "$LIST.3_rebuild" einfo "Generated new $LIST.4_packages_raw and $LIST.4_package_owners" fi } clean_packages() { einfo 'Cleaning list of packages to rebuild' if [[ -rs $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() { einfo 'Assigning packages to ebuilds' if [[ -rs $LIST.4_ebuilds ]]; then einfo "Found existing $LIST.4_ebuilds" elif [[ -rs $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 [[ -rs $LIST.4_ebuilds ]]; then einfo "Found existing $LIST.4_ebuilds" elif [[ -rs $LIST.3_rebuild ]]; then rebuildList=" $(<"$LIST.3_rebuild") " rebuildList=(${rebuildList//[[:space:]]obj[[:space:]]/ }) if [[ $PORTAGE_UTILS ]]; then qfile -qvC ${rebuildList[@]} elif [[ $PKGCORE ]]; then IFS=, pquery --nocolor --owns="${rebuildList[*]}" IFS="$oIFS" elif [[ $EQUERY ]]; then equery -q -C b ${rebuildList[@]} else find /var/db/pkg -name CONTENTS | xargs grep -Fl "$rebuildList" | sed 's:/var/db/pkg/\(.*\)/CONTENTS:=\1:' fi > $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() { if [[ ! $order_packages ]]; then einfo 'Skipping package ordering' return fi einfo 'Evaluating package order' if [[ -rs $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 OLD_EMERGE_DEFAULT_OPTS="$EMERGE_DEFAULT_OPTS" export EMERGE_DEFAULT_OPTS="--nospinner --pretend --oneshot --nodeps --quiet" RAW_REBUILD_LIST="=${RAW_REBUILD_LIST//[[:space:]]/ =}" REBUILD_GREP=$(emerge $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 for i in {1..5}; do echo -n -e '\a.' sleep 1 done 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 [[ -rs $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 COMPLETE_LD_LIBRARY_PATH SEARCH_DIRS SEARCH_DIRS_MASK LD_LIBRARY_MASK \ PORTAGE_ROOT [[ -rs $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" if is_real_merge; then for i in {1..10}; do echo -n -e '\a.' sleep 1 done echo fi # 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<&- if (( $(<"$LIST.6_status") != 0 )); then ewarn ewarn "$appname failed to emerge all packages." ewarn 'you have the following choices:' einfo "- If emerge failed during the build, fix the problems and re-run $appname." 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*.?_*" 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.' else einfo 'Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.' fi