#!/bin/bash
-# Copyright 1999-2007 Gentoo Foundation
+# Copyright 1999-2008 Gentoo Foundation
# revdep-rebuild: Reverse dependency rebuilder.
# Original Author: Stanislav Brabec
##
# Global Variables:
-# Must-be-blank variables:
+# Must-be-blank:
unset GREP_OPTIONS
# Readonly variables:
declare -r APP_NAME="${0##*/}" # The name of this application
declare -r OIFS="$IFS" # Save the IFS
+declare -r ENV_FILE=0_env.rr # Contains environment variables
+declare -r FILES_FILE=1_files.rr # Contains a list of files to search
+declare -r LDPATH_FILE=2_ldpath.rr # Contains the LDPATH
+declare -r BROKEN_FILE=3_broken.rr # Contains the list of broken files
+declare -r ERRORS_FILE=3_errors.rr # Contains the ldd error output
+declare -r RAW_FILE=4_raw.rr # Contains the raw list of packages
+declare -r OWNERS_FILE=4_owners.rr # Contains the file owners
+declare -r PKGS_FILE=4_pkgs.rr # Contains the unsorted bare package names
+declare -r EBUILDS_FILE=4_ebuilds.rr # Contains the unsorted atoms
+ # (Appropriately slotted or versioned)
+declare -r ORDER_FILE=5_order.rr # Contains the sorted atoms
+declare -r STATUS_FILE=6_status.rr # Contains the ldd error output
+declare -ra FILES=(
+ "$ENV_FILE"
+ "$FILES_FILE"
+ "$LDPATH_FILE"
+ "$BROKEN_FILE"
+ "$ERRORS_FILE"
+ "$RAW_FILE"
+ "$OWNERS_FILE"
+ "$PKGS_FILE"
+ "$EBUILDS_FILE"
+ "$ORDER_FILE"
+ "$STATUS_FILE"
+)
# "Boolean" variables: Considered "true" if it has any value at all
# "True" indicates we should...
declare PORTAGE_ROOT # The root path for portage
# Customizable incremental variables:
-# These variables can be prepended to either by setting the variable in
+# These variables can be prepended to either by setting the variable in
# your environment prior to execution, or by placing an entry in
# /etc/make.conf.
#
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 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
+declare WORKING_DIR # Working directory where cache files are kept
+main() {
+ # preliminary setup
+ get_opts "$@"
+ setup_portage
+ setup_search_paths_and_masks
+ get_search_env
+ echo
+
+ # Search for broken binaries
+ get_files
+ get_ldpath
+ main_checks
+
+ # Associate broken binaries with packages to rebuild
+ if [[ $PACKAGE_NAMES ]]; then
+ get_packages
+ clean_packages
+ assign_packages_to_ebuilds
+ else
+ get_exact_ebuilds
+ fi
+
+ # Rebuild packages owning broken binaries
+ get_build_order
+ rebuild
+
+ # All done
+ cleanup
+}
+##
+# Refuse to delete anything before we cd to our tmpdir
+# (See mkdir_and_cd_to_tmpdir()
rm() {
- local i
- [[ $LIST && $APP_NAME ]] ||
- die 1 '$LIST or $APP_NAME is not defined! (This is a bug.)'
- for i; do
- [[ $i = -* || $i = *.$APP_NAME* ]] ||
- die 1 "Oops, I'm not allowed to delete that. ($@)"
- done
- command rm "$@"
+ eerror "I was instructed to rm '$@'"
+ die 1 "Refusing to delete anything before changing to temporary directory."
}
-# Somewhat more portable find -executable
-# FIXME/UNTESTED (I don't have access to all of the different versions of
-# find.)
-# Usage: find PATH ARGS -- use find like normal, except use -executable instead
+: <<'EW'
+##
+# GNU find has -executable, but if our users' finds do not have that flag
+# we emulate it with this function. Also emulates -writable and -readable.
+# Usage: find PATH ARGS -- use find like normal, except use -executable instead
# of various versions of -perm /+ blah blah and hacks
find() {
hash find || { die 1 'find not found!'; }
}
else # Last resort
find() {
- a=(${@//-executable/-exec test -x '{}' \;})
- a=(${a[@]//-writable/-exec test -w '{}' \;})
- a=(${a[@]//-readable/-exec test -r '{}' \;})
+ a=(${@//-executable/-exec test -x '{}' \; -print})
+ a=(${a[@]//-writable/-exec test -w '{}' \; -print})
+ a=(${a[@]//-readable/-exec test -r '{}' \; -print})
command find "${a[@]}"
}
fi
find "$@"
}
+EW
+
print_usage() {
cat << EOF
Usage: $APP_NAME [OPTIONS] [--] [EMERGE_OPTIONS]
Broken reverse dependency rebuilder.
+ -C, --nocolor Turn off colored output
+ -d, --debug Print way too much information (uses bash's set -xv)
+ -e, --exact Emerge based on exact package version
-h, --help Print this usage
+ -i, --ignore Ignore temporary files from previous runs
-k, --keep-temp Do not delete temporary files on exit
- -e, --exact Emerge based on exact package version
+ -L, --library NAME Emerge existing packages that use the library with NAME
+ --library=NAME NAME can be a full path to the library or a basic
+ regular expression (man grep)
-l, --no-ld-path Do not set LD_LIBRARY_PATH
- -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, --pretend Do a trial run without actually emerging anything
+ (also passed to emerge command)
-P, --no-progress Turn off the progress meter
-q, --quiet Be less verbose (also passed to emerge command)
- -v, --verbose Be more verbose
- -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)
+ -v, --verbose Be more verbose (also passed to emerge command)
-Calls emerge, all other options are used for it (e. g. -p, --pretend).
+Calls emerge, options after -- are ignored by $APP_NAME
+and passed directly to emerge.
Report bugs to <http://bugs.gentoo.org>
EOF
}
+##
# Usage: progress i n
# i: current item
# n: total number of items to process
progress() { :; }
fi
}
+##
# Usage: countdown n
# n: number of seconds to count
countdown() {
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() {
- awk 'BEGIN {RS="[[:space:]]"}
+ gawk 'BEGIN {RS="[[:space:]]"}
/-\*/ {exit}
/[^[:space:]]/ {gsub(/\/\/+/, "/"); print}' | sort -u
}
+##
# Exit and optionally output to sterr
die() {
local status=$1
eerror "$@"
exit $status
}
+##
# What to do when dynamic linking is consistent
clean_exit() {
- [[ $KEEP_TEMP ]] || rm $LIST.?_*
+ if [[ ! $KEEP_TEMP ]]; then
+ rm -f "${FILES[@]}"
+ if [[ "$WORKING_DIR" != "/var/cache/${APP_NAME}" ]]; then
+ # Remove the working directory
+ builtin cd; rmdir "$WORKING_DIR"
+ fi
+ fi
echo
einfo "$OK_TEXT... All done. "
exit 0
}
-get_args() {
+##
+# Get the name of the package that owns a file or list of files given as args.
+get_file_owner() {
+ local IFS=$'\n'
+ # ${*/%/ } adds a space to the end of each object name to prevent false
+ # matches, for example /usr/bin/dia matching /usr/bin/dialog (bug #196460).
+ find -L /var/db/pkg -name CONTENTS -print0 |
+ xargs -0 grep -Fl "${*/%/ }" |
+ sed 's:/var/db/pkg/\(.*\)/CONTENTS:\1:'
+}
+##
+# Normalize some EMERGE_OPTIONS
+normalize_emerge_opts() {
+ # Normalize some EMERGE_OPTIONS
+ EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-p/--pretend})
+ EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-f/--fetchonly})
+ EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-v/--verbose})
+}
+##
+# Use the color preference from portage
+setup_color() {
+ # This should still work if NOCOLOR is set by the -C flag or in the user's
+ # environment.
+ export NOCOLOR=$(portageq envvar NOCOLOR)
+ [[ $NOCOLOR = yes || $NOCOLOR = true ]] && export RC_NOCOLOR=yes # HACK! (grr)
+ . /etc/init.d/functions.sh
+}
+##
+# Die if an argument is missing.
+die_if_missing_arg() {
+ [[ ! $2 || $2 = -* ]] && die 1 "Missing expected argument to $1"
+}
+##
+# Die because an option is not recognized.
+die_invalid_option() {
+ # Can't use eerror and einfo because this gets called before function.sh
+ # is sourced
+ echo
+ echo "Encountered unrecognized option $1." >&2
+ echo
+ echo "$APP_NAME no longer automatically passes unrecognized options to portage."
+ echo "Separate emerge-only options from revdep-rebuild options with the -- flag."
+ echo
+ echo "For example, $APP_NAME -v -- --ask"
+ echo
+ echo "See the man page or $APP_NAME -h for more detail."
+ echo
+ exit 1
+}
+##
+# Warn about deprecated options.
+warn_deprecated_opt() {
+ # Can't use eerror and einfo because this gets called before function.sh
+ # is sourced
+ echo
+ echo "Encountered deprecated option $1." >&2
+ [[ $2 ]] && echo "Please use $2 instead." >&2
+}
+##
+# Get whole-word commandline options preceded by two dashes.
+get_longopts() {
+ case $1 in
+ --nocolor) export NOCOLOR="yes";;
+ --no-color) warn_deprecated_opt "$1" "--nocolor"
+ export NOCOLOR="yes";;
+ --debug) set -xv;;
+ --exact) unset PACKAGE_NAMES;;
+ --help) print_usage
+ exit 0;;
+ --ignore) RM_OLD_TEMPFILES=1;;
+ --keep-temp) KEEP_TEMP=1;;
+ --library=*) # TODO: check for invalid values
+ SONAME="${1#*=}"
+ unset SEARCH_BROKEN;;
+ --soname=*|--soname-regexp=*) # TODO: check for invalid values
+ warn_deprecated_opt "${1%=*}" "--library"
+ SONAME="${1#*=}"
+ unset SEARCH_BROKEN;;
+ --library) # TODO: check for invalid values
+ die_if_missing_arg $1 $2
+ shift
+ SONAME="$1"
+ unset SEARCH_BROKEN;;
+ --soname|--soname-regexp) # TODO: check for invalid values
+ warn_deprecated_opt "$1" "--library"
+ die_if_missing_arg $1 $2
+ shift
+ SONAME="$1"
+ unset SEARCH_BROKEN;;
+ --no-ld-path) unset FULL_LD_PATH;;
+ --no-order) unset ORDER_PKGS;;
+ --no-progress) progress() { :; };;
+ --pretend) EMERGE_OPTIONS+=("--pretend");;
+ --quiet) echo_v() { :; }
+ progress() { :; }
+ quiet=1
+ EMERGE_OPTIONS+=($1);;
+ --verbose) VERBOSE=1
+ EMERGE_OPTIONS+=("--verbose");;
+ --extra-verbose) warn_deprecated_opt "$1" "--verbose"
+ VERBOSE=1
+ EMERGE_OPTIONS+=("--verbose");;
+ --package-names) # No longer used, since it is the
+ # default. We accept it for
+ # backwards compatibility.
+ warn_deprecated_opt "$1"
+ PACKAGE_NAMES=1;;
+ *) die_invalid_option $1;;
+ esac
+}
+
+##
+# Get single-letter commandline options preceded by a single dash.
+get_shortopts() {
+ local OPT OPTSTRING OPTARG OPTIND
+ while getopts ":CdehikL:loPpqu:vX" OPT; do
+ case "$OPT" in
+ C) # TODO: Match syntax with the rest of gentoolkit
+ export NOCOLOR="yes";;
+ d) set -xv;;
+ e) unset PACKAGE_NAMES;;
+ h) print_usage
+ exit 0;;
+ i) RM_OLD_TEMPFILES=1;;
+ k) KEEP_TEMP=1;;
+ L) # TODO: Check for invalid values
+ SONAME="${OPTARG#*=}"
+ unset SEARCH_BROKEN;;
+ l) unset FULL_LD_PATH;;
+ o) unset ORDER_PKGS;;
+ P) progress() { :; };;
+ p) EMERGE_OPTIONS+=("--pretend");;
+ q) echo_v() { :; }
+ progress() { :; }
+ quiet=1
+ EMERGE_OPTIONS+=("--quiet");;
+ v) VERBOSE=1
+ EMERGE_OPTIONS+=("--verbose");;
+ X) # No longer used, since it is the default.
+ # We accept it for backwards compatibility.
+ warn_deprecated_opt "-X"
+ PACKAGE_NAMES=1;;
+ *) die_invalid_option "-$OPTARG";;
+ esac
+ done
+}
+##
+# Get command-line options.
+get_opts() {
+ local avoid_utils
+ local -a args
echo_v() { ewarn "$@"; }
unset VERBOSE KEEP_TEMP EMERGE_OPTIONS RM_OLD_TEMPFILES
ORDER_PKGS=1
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)
- ;;
+ --) shift
+ EMERGE_OPTIONS+=("$@")
+ break;;
+ -*) while true; do
+ args+=("$1")
+ shift
+ [[ ${1:--} = -* ]] && break
+ done
+ if [[ ${args[0]} = --* ]]; then
+ get_longopts "${args[@]}"
+ else
+ get_shortopts "${args[@]}"
+ fi;;
+ *) die_invalid_option "$1";;
esac
- shift
+ unset args
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'
- # ${*/%/ } adds a space to the end of each object name to prevent false
- # matches, for example /usr/bin/dia matching /usr/bin/dialog (bug #196460).
- find -L /var/db/pkg -name CONTENTS -print0 |
- xargs -0 grep -Fl "${*/%/ }" |
- sed 's:/var/db/pkg/\(.*\)/CONTENTS:\1:'
- }
- fi
- # 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})
+ setup_color
+ normalize_emerge_opts
+
+ # If the user is not super, add --pretend to EMERGE_OPTIONS
if [[ ${EMERGE_OPTIONS[@]} != *--pretend* && $UID -ne 0 ]]; then
ewarn "You are not superuser. Adding --pretend to emerge options."
EMERGE_OPTIONS+=(--pretend)
fi
}
-is_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=$(clean_var <<< "$SEARCH_DIRS")
-SEARCH_DIRS_MASK=$(clean_var <<< "$SEARCH_DIRS_MASK")
-LD_LIBRARY_MASK=$(clean_var <<< "$LD_LIBRARY_MASK")
-# Filter masked paths from SEARCH_DIRS
-filter_SEARCH_DIRS=
-for sdir in ${SEARCH_DIRS} ; do
- unset skip_me
- for mdir in ${SEARCH_DIRS_MASK} ; do
- [[ ${sdir} == ${mdir}/* ]] \
- && skip_me=1 && break
- done
- [[ -n ${skip_me} ]] || filter_SEARCH_DIRS+=" ${sdir}"
-done
-SEARCH_DIRS=$(clean_var "${filter_SEARCH_DIRS}")
-unset sdir mdir skip_me filter_SEARCH_DIRS
-[[ $SEARCH_DIRS ]] || die 1 "No search defined -- this is a bug."
-
-set_trap() {
- trap "rm_temp $1" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
+##
+# Is there a --pretend or --fetchonly flag in the EMERGE_OPTIONS array?
+is_real_merge() {
+ [[ ${EMERGE_OPTIONS[@]} != *--pretend* &&
+ ${EMERGE_OPTIONS[@]} != *--fetchonly* ]]
}
-rm_temp() {
- rm $1
- die 1 $' ...terminated. Removing incomplete '"$1."
+##
+# Clean up temporary files and exit
+cleanup_and_die() {
+ rm -f "$@"
+ die 1 " ...terminated. Removing incomplete $@."
+}
+##
+# Clean trap
+clean_trap() {
+ trap "cleanup_and_die $*" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
+ rm -f "$@"
+}
+##
+# Returns 0 if the first arg is found in the remaining args, 1 otherwise
+# (Returns 2 if given fewer than 2 arguments)
+has() {
+ (( $# > 1 )) || return 2
+ local IFS=$'\a' target="$1"
+ shift
+ [[ $'\a'"$*"$'\a' = *$'\a'$target$'\a'* ]]
+}
+##
+# Dies when it can't change directories
+cd() {
+ if builtin cd -P "$@"; then
+ if [[ $1 != $PWD ]]; then
+ # Some symlink malfeasance is going on
+ die 1 "Working directory expected to be $1, but it is $PWD"
+ fi
+ else
+ die 1 "Unable to change working directory to '$@'"
+ fi
+}
+##
+# Tries not to delete any files or directories it shouldn't
+setup_rm() {
+ ##
+ # Anything in the FILES array in tmpdir is fair game for removal
+ rm() {
+ local i IFS=$'\a'
+ [[ $APP_NAME ]] || die 1 '$APP_NAME is not defined! (This is a bug.)'
+ case $@ in
+ */*|*-r*|*-R*) die 1 "Oops, I'm not allowed to delete that. ($@)";;
+ esac
+ for i; do
+ # Don't delete files that are not listed in the array
+ # Allow no slashes or recursive deletes at all.
+ case $i in
+ */*|-*r*|-*R*) :;; # Not OK
+ -*) continue;; # OK
+ esac
+ has "$i" "${FILES[@]}" && continue
+ die 1 "Oops, I'm not allowed to delete that. ($@)"
+ done
+ command rm "$@"
+ }
+ # delete this setup function so it's harmless to re-run
+ setup_rm() { :; }
+}
+##
+# Make our temporary files directory
+# $1 - directory name
+# $2 - user name
+verify_tmpdir() {
+ umask 007 || die $? "Unable to set umask 007"
+ if [[ ! $1 ]]; then
+ die 1 'Temporary file path is unset! (This is a bug.)'
+ elif [[ -d $1 ]]; then
+ # HACK: I hate using find this way
+ if [[ $(find "$1" -type d ! \( -user $2 -perm -0700 \) ) ]]; then
+ eerror "Incorrect permissions on $1"
+ eerror "or at least one file in $1."
+ die 1 "Please make sure it's not a symlink and then remove it."
+ fi
+ cd "$1"
+ else
+ die 1 "Unable to find a satisfactory location for temporary files ($1)"
+ fi
+ [[ $VERBOSE ]] && einfo "Temporary cache files are located in $PWD"
+ setup_rm
}
get_search_env() {
local new_env
local old_env
+ local uid=$(python -c 'import os; import pwd; print pwd.getpwuid(os.getuid())[0]')
# Find a place to put temporary files
- # TODO; let the user choose where to put tempfiles
- # gfind $HOME/ /var/tmp/ /tmp/ -writable -print -quit
- # HACK: This is a rather noisy, but portable way to implement -quit
- while read LIST; do
- break # Set LIST
- done < <(find $HOME/ /var/tmp/ /tmp/ -writable -print)
- [[ $LIST ]] ||
- die 1 "Unable to find a satisfactory location for temporary files"
-
- LIST+=".$APP_NAME"
+ if [[ "$uid" == "root" ]]; then
+ local tmp_target="/var/cache/${APP_NAME}"
+ else
+ local tmp_target="$(mktemp -d -t revdep-rebuild.XXXXXXXXXX)"
+ fi
+
+ # From here on all work is done inside the temporary directory
+ verify_tmpdir "$tmp_target" "$uid"
+ WORKING_DIR="$tmp_target"
+
if [[ $SEARCH_BROKEN ]]; then
SONAME_SEARCH="$SONAME"
HEAD_TEXT="broken by a package update"
# Set to "<tab>$SONAME<space>"
SONAME_SEARCH=$'\t'"$SONAME "
fi
- local uuid="${SONAME##*/}"
- uuid="${uuid//[[:space:]]}"
- LIST+="_$uuid"
HEAD_TEXT="using $SONAME"
OK_TEXT="There are no dynamic links to $SONAME"
unset WORKING_TEXT
while read; do
RM_OLD_TEMPFILES=1
break
- done < <(find -L "$LIST."* -maxdepth 0 -type f -mmin +1440 -print 2>/dev/null)
+ done < <(find -L . -maxdepth 1 -type f -name '*.rr' -mmin +1440 -print 2>/dev/null)
fi
# Compare old and new environments
FULL_LD_PATH="$FULL_LD_PATH"
EOF
)
- if [[ -r $LIST.0_env && -s $LIST.0_env ]]; then
- old_env=$(<"$LIST.0_env")
+ if [[ -r "$ENV_FILE" && -s "$ENV_FILE" ]]; then
+ old_env=$(<"$ENV_FILE")
if [[ $old_env != $new_env ]]; then
ewarn 'Environment mismatch from previous run, deleting temporary files...'
RM_OLD_TEMPFILES=1
fi
else
- # No 0_env file found, silently delete any other tempfiles that may exist
+ # No env file found, silently delete any other tempfiles that may exist
RM_OLD_TEMPFILES=1
fi
# If we should remove old tempfiles, do so
- [[ $RM_OLD_TEMPFILES ]] && rm -f "$LIST."*
-
+ if [[ $RM_OLD_TEMPFILES ]]; then
+ rm -f "${FILES[@]}"
+ else
+ for file in "${FILES[@]}"; do
+ if [ -e "$file" ]; then
+ chown ${uid}:portage "$file"
+ chmod 700 "$file"
+ fi
+ done
+ fi
+
# Save the environment in a file for next time
- echo "$new_env" > "$LIST.0_env"
+ echo "$new_env" > "$ENV_FILE"
[[ $VERBOSE ]] && echo $'\n'"$APP_NAME environment:"$'\n'"$new_env"
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"
+ if [[ -r "$FILES_FILE" && -s "$FILES_FILE" ]]; then
+ einfo "Found existing $FILES_FILE"
else
# Be safe and remove any extraneous temporary files
- rm -f $LIST.[1-9]_*
+ # Don't remove 0_env.rr - The first file in the array
+ rm -f "${FILES[@]:1}"
- set_trap "$LIST.1_*"
+ clean_trap "$FILES_FILE"
if [[ $SEARCH_DIRS_MASK ]]; then
findMask=($SEARCH_DIRS_MASK)
findMask="${findMask[@]/#/-o -path }"
findMask="( ${findMask#-o } ) -prune -o"
fi
- find ${SEARCH_DIRS[@]} $findMask -type f \( -executable -o \
+ # TODO: Check this -- afaict SEARCH_DIRS isn't an array, so this should just be $SEARCH_DIRS?
+ find ${SEARCH_DIRS[@]} $findMask -type f \( -perm -u+x -o -perm -g+x -o -perm -o+x -o \
-name '*.so' -o -name '*.so.*' -o -name '*.la' \) -print 2> /dev/null |
- sort -u > "$LIST.1_files" ||
+ sort -u > "$FILES_FILE" ||
die $? "find failed to list binary files (This is a bug.)"
- einfo "Generated new $LIST.1_files"
+ einfo "Generated new $FILES_FILE"
fi
}
get_ldpath() {
local COMPLETE_LD_LIBRARY_PATH
[[ $SEARCH_BROKEN && $FULL_LD_PATH ]] || return
einfo 'Collecting complete LD_LIBRARY_PATH'
- if [[ -r $LIST.2_ldpath && -s $LIST.2_ldpath ]] ; then
- einfo "Found existing $LIST.2_ldpath."
+ if [[ -r "$LDPATH_FILE" && -s "$LDPATH_FILE" ]]; then
+ einfo "Found existing $LDPATH_FILE."
else
- set_trap "$LIST.2_ldpath"
+ clean_trap "$LDPATH_FILE"
# Ensure that the "trusted" lib directories are at the start of the path
COMPLETE_LD_LIBRARY_PATH=(
/lib*
/usr/lib*
$(sed '/^#/d;s/#.*$//' < /etc/ld.so.conf)
- $(sed 's:/[^/]*$::' < "$LIST.1_files" | sort -ru)
+ $(sed 's:/[^/]*$::' < "$FILES_FILE" | 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"
+ echo "$COMPLETE_LD_LIBRARY_PATH" > "$LDPATH_FILE"
+ einfo "Generated new $LDPATH_FILE"
fi
}
main_checks() {
local numFiles
local COMPLETE_LD_LIBRARY_PATH
if [[ $SEARCH_BROKEN && $FULL_LD_PATH ]]; then
- [[ -r $LIST.2_ldpath && -s $LIST.2_ldpath ]] || die 1 "unable to find $LIST.2_ldpath"
- COMPLETE_LD_LIBRARY_PATH=$(<"$LIST.2_ldpath")
+ [[ -r "$LDPATH_FILE" && -s "$LDPATH_FILE" ]] ||
+ die 1 "Unable to find $LDPATH_FILE"
+ COMPLETE_LD_LIBRARY_PATH=$(<"$LDPATH_FILE")
fi
einfo "Checking dynamic linking $WORKING_TEXT"
- if [[ -r $LIST.3_rebuild && -s $LIST.3_rebuild ]]; then
- einfo "Found existing $LIST.3_rebuild."
+ if [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]]; then
+ einfo "Found existing $BROKEN_FILE."
else
- [[ $LIST ]] || die 1 "$LIST" 'is undefined! (This is a bug.)'
- set_trap "$LIST.3_rebuild"
- set_trap "$LIST.3_ldd_errors"
- rm -f "$LIST.3"*
- files=($(<"$LIST.1_files"))
+ clean_trap "$BROKEN_FILE" "$ERRORS_FILE"
+ files=($(<"$FILES_FILE"))
numFiles="${#files[@]}"
for target_file in "${files[@]}"; do
if [[ $target_file != *.la ]]; then
# Note: double checking seems to be faster than single with complete path
# (special add ons are rare).
- ldd_output=$(ldd "$target_file" 2>> "$LIST.3_ldd_errors" | sort -u)
+ ldd_output=$(ldd "$target_file" 2>> "$ERRORS_FILE" | sort -u)
ldd_status=$? # TODO: Check this for problems with sort
# HACK: if LD_LIBRARY_MASK is null or undefined grep -vF doesn't work
if grep -vF "${LD_LIBRARY_MASK:=$'\a'}" <<< "$ldd_output" |
)
MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS")
if [[ $MISSING_LIBS ]]; then
- echo "obj $target_file" >> "$LIST.3_rebuild"
+ echo "obj $target_file" >> "$BROKEN_FILE"
echo_v " broken $target_file (requires $MISSING_LIBS)"
fi
fi
)
MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS")
if [[ $MISSING_LIBS ]]; then
- echo "obj $target_file" >> "$LIST.3_rebuild"
+ echo "obj $target_file" >> "$BROKEN_FILE"
if [[ $SEARCH_BROKEN ]]; then
echo_v " broken $target_file (requires $MISSING_LIBS)"
else
elif [[ $SEARCH_BROKEN ]]; then
# Look for broken .la files
for depend in $(
- awk -F"[=']" '/^dependency_libs/{
+ gawk -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 "obj $target_file" >> "$BROKEN_FILE"
echo_v " broken $target_file (requires $depend)"
fi
done
if [[ $SEARCH_BROKEN ]]; then
# Look for missing version
while read target_file; do
- echo "obj $target_file" >> "$LIST.3_rebuild"
+ echo "obj $target_file" >> "$BROKEN_FILE"
echo_v " broken $target_file (no version information available)"
done < <(
# Regexify LD_LIBRARY_MASK. Exclude it from the search.
LD_LIBRARY_MASK="${LD_LIBRARY_MASK//$'\n'/|}"
- awk -v ldmask="(${LD_LIBRARY_MASK//./\\\.})" '
+ gawk -v ldmask="(${LD_LIBRARY_MASK//./\\\.})" '
/no version information available/ && $0 !~ ldmask {
gsub(/[()]/, "", $NF)
if (seen[$NF]++) next
print $NF
- }' "$LIST.3_ldd_errors"
+ }' "$ERRORS_FILE"
)
fi
- [[ -r $LIST.3_rebuild && -s $LIST.3_rebuild ]] || clean_exit
- einfo "Generated new $LIST.3_rebuild"
+ [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]] || clean_exit
+ sort -u "$BROKEN_FILE" -o "$BROKEN_FILE"
+ einfo "Generated new $BROKEN_FILE"
fi
}
get_packages() {
local PKG
local obj
einfo 'Assigning files to packages'
- if [[ -r $LIST.4_packages_raw && -s $LIST.4_packages_raw ]]; then
- einfo "Found existing $LIST.4_packages_raw"
+ if [[ -r "$RAW_FILE" && -s "$RAW_FILE" ]]; then
+ einfo "Found existing $RAW_FILE"
else
- set_trap "$LIST.4_packages*"
- rm -f $LIST.4*
+ clean_trap "$RAW_FILE" "$OWNERS_FILE"
while read obj target_file; do
EXACT_PKG=$(get_file_owner $target_file)
if [[ $EXACT_PKG ]]; then
# Strip version information
PKG="${EXACT_PKG%%-r[[:digit:]]*}"
PKG="${PKG%-*}"
- echo "$EXACT_PKG" >> $LIST.4_packages_raw
- echo "$target_file -> $EXACT_PKG" >> $LIST.4_package_owners
+ echo "$EXACT_PKG" >> "$RAW_FILE"
+ echo "$target_file -> $EXACT_PKG" >> "$OWNERS_FILE"
echo_v " $target_file -> $PKG"
else
ewarn " !!! $target_file not owned by any package is broken !!!"
- echo "$target_file -> (none)" >> $LIST.4_package_owners
+ echo "$target_file -> (none)" >> "$OWNERS_FILE"
echo_v " $target_file -> (none)"
fi
- done < "$LIST.3_rebuild"
- einfo "Generated new $LIST.4_packages_raw and $LIST.4_package_owners"
+ done < "$BROKEN_FILE"
+ einfo "Generated new $RAW_FILE and $OWNERS_FILE"
fi
# if we find '(none)' on every line, exit out
- if ! grep -qvF '(none)' "$LIST.4_package_owners"; then
+ if ! grep -qvF '(none)' "$OWNERS_FILE"; then
ewarn "Found some broken files, but none of them were associated with known packages"
ewarn "Unable to proceed with automatic repairs."
- ewarn "The broken files are listed in $LIST.4_package_owners"
+ ewarn "The broken files are listed in $OWNERS_FILE"
if [[ $VERBOSE ]]; then
ewarn "The broken files are:"
while read filename junk; do
ewarn " $filename"
- done < "$LIST.4_package_owners"
+ done < "$OWNERS_FILE"
fi
exit 0 # FIXME: Should we exit 1 here?
fi
}
clean_packages() {
einfo 'Cleaning list of packages to rebuild'
- if [[ -r $LIST.4_packages && -s $LIST.4_packages ]]; then
- einfo "Found existing $LIST.4_packages"
+ if [[ -r "$PKGS_FILE" && -s "$PKGS_FILE" ]]; then
+ einfo "Found existing $PKGS_FILE"
else
- sort -u $LIST.4_packages_raw > $LIST.4_packages
- einfo "Generated new $LIST.4_packages"
+ sort -u "$RAW_FILE" > "$PKGS_FILE"
+ einfo "Generated new $PKGS_FILE"
fi
}
assign_packages_to_ebuilds() {
local PKG
local SLOT
einfo 'Assigning packages to ebuilds'
- if [[ -r $LIST.4_ebuilds && -s $LIST.4_ebuilds ]]; then
- einfo "Found existing $LIST.4_ebuilds"
- elif [[ -r $LIST.4_packages && -s $LIST.4_packages ]]; then
- set_trap "$LIST.4_ebuilds"
+ if [[ -r "$EBUILDS_FILE" && -s "$EBUILDS_FILE" ]]; then
+ einfo "Found existing $EBUILDS_FILE"
+ elif [[ -r "$PKGS_FILE" && -s "$PKGS_FILE" ]]; then
+ clean_trap "$EBUILDS_FILE"
while read EXACT_PKG; do
# Get the slot
PKG="${EXACT_PKG%%-r[[:digit:]]*}"
PKG="${PKG%-*}"
SLOT=$(</var/db/pkg/$EXACT_PKG/SLOT)
echo "$PKG:$SLOT"
- done < "$LIST.4_packages" > "$LIST.4_ebuilds"
- einfo "Generated new $LIST.4_ebuilds"
+ done < "$PKGS_FILE" > "$EBUILDS_FILE"
+ einfo "Generated new $EBUILDS_FILE"
else
einfo 'Nothing to rebuild.'
die 1 '(The program should have already quit, so this is a minor bug.)'
}
get_exact_ebuilds() {
einfo 'Assigning files to ebuilds'
- if [[ -r $LIST.4_ebuilds && -s $LIST.4_ebuilds ]]; then
- einfo "Found existing $LIST.4_ebuilds"
- elif [[ -r $LIST.3_rebuild && -s $LIST.3_rebuild ]]; then
- rebuildList=" $(<"$LIST.3_rebuild") "
+ if [[ -r $EBUILDS_FILE && -s $EBUILDS_FILE ]]; then
+ einfo "Found existing $EBUILDS_FILE"
+ elif [[ -r $BROKEN_FILE && -s $BROKEN_FILE ]]; then
+ rebuildList=" $(<"$BROKEN_FILE") "
rebuildList=(${rebuildList//[[:space:]]obj[[:space:]]/ })
- get_file_owner "${rebuildList[@]}" > $LIST.4_ebuilds
- einfo "Generated new $LIST.4_ebuilds"
+ get_file_owner "${rebuildList[@]}" | sed 's/^/=/' > "$EBUILDS_FILE"
+ einfo "Generated new $EBUILDS_FILE"
else
einfo 'Nothing to rebuild.'
die 1 '(The program should have already quit, so this is a minor bug.)'
return
fi
einfo 'Evaluating package order'
- if [[ -r $LIST.5_order && -s $LIST.5_order ]]; then
- einfo "Found existing $LIST.5_order"
+ if [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" ]]; then
+ einfo "Found existing $ORDER_FILE"
else
- set_trap "$LIST.5_order"
- RAW_REBUILD_LIST=$(<"$LIST.4_ebuilds")
+ clean_trap "$ORDER_FILE"
+ RAW_REBUILD_LIST=$(<"$EBUILDS_FILE")
if [[ $RAW_REBUILD_LIST ]]; then
export EMERGE_DEFAULT_OPTS="--nospinner --pretend --oneshot --quiet"
- RAW_REBUILD_LIST=($RAW_REBUILD_LIST)
+ RAW_REBUILD_LIST=($RAW_REBUILD_LIST) # convert into array
# If PACKAGE_NAMES is defined we're using slots, not versions
if [[ $PACKAGE_NAMES ]]; then
# Eliminate atoms that can't be built
- for (( i=0; i<${#RAW_REBUILD_LIST[@]}; i++ )); do
- portageq best_visible "$PORTAGE_ROOT" "${RAW_REBUILD_LIST[i]}" >/dev/null && continue
- SKIP_LIST+=("${RAW_REBUILD_LIST[i]}")
+ for i in "${!RAW_REBUILD_LIST[@]}"; do
+ if [[ "${RAW_REBUILD_LIST[i]}" = *[A-Za-z]* ]]; then
+ portageq best_visible "$PORTAGE_ROOT" "${RAW_REBUILD_LIST[i]}" >/dev/null && continue
+ SKIP_LIST+=("${RAW_REBUILD_LIST[i]}")
+ fi
unset RAW_REBUILD_LIST[i]
done
# If RAW_REBUILD_LIST is empty, then we have nothing to build.
if (( ${#RAW_REBUILD_LIST[@]} == 0 )); then
- list_skipped_packages
+ if (( ${#SKIP_LIST[@]} == 0 )); then
+ ewarn "The list of packages to skip is empty, but there are no"
+ ewarn "packages listed to rebuild either. (This is a bug.)"
+ else
+ list_skipped_packages
+ fi
die 1 'Warning: Portage cannot rebuild any of the necessary packages.'
fi
- else
- RAW_REBUILD_LIST=("${RAW_REBUILD_LIST[@]/#/=}")
fi
RAW_REBUILD_LIST="${RAW_REBUILD_LIST[@]}"
REBUILD_GREP=$(emerge --nodeps $RAW_REBUILD_LIST | sed 's/\[[^]]*\]//g')
if (( ${PIPESTATUS[0]} == 0 )); then
emerge --deep $RAW_REBUILD_LIST |
sed 's/\[[^]]*\]//g' |
- grep -F "$REBUILD_GREP" > $LIST.5_order
+ grep -F "$REBUILD_GREP" > "$ORDER_FILE"
fi
# Here we use the PIPESTATUS from the second emerge, the --deep one.
and/or /etc/portage/package.unmask to unmask it
EOF
countdown 5
- rm -f "$LIST.5_order"
+ rm -f "$ORDER_FILE"
fi
export EMERGE_DEFAULT_OPTS="$OLD_EMERGE_DEFAULT_OPTS"
else
die 1 '(The program should have already quit, so this is a minor bug.)'
fi
fi
- [[ -r $LIST.5_order && -s $LIST.5_order ]] && einfo "Generated new $LIST.5_order"
-}
-
-get_search_env
-echo
-get_files
-echo
-get_ldpath
-echo
-main_checks
-echo
-if [[ $PACKAGE_NAMES ]]; then
- get_packages
- echo
- clean_packages
- echo
- assign_packages_to_ebuilds
-else
- get_exact_ebuilds
-fi
-echo
-get_build_order
-echo
+ [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" ]] && einfo "Generated new $ORDER_FILE"
+}
-# Clean up no longer needed environment variables
-unset SEARCH_DIRS SEARCH_DIRS_MASK LD_LIBRARY_MASK PORTAGE_ROOT
+show_unowned_files() {
+ if grep -qF '(none)' "$OWNERS_FILE"; then
+ ewarn "Found some broken files that weren't associated with known packages"
+ ewarn "The broken files are:"
+ while read filename junk; do
+ [[ $junk = *none* ]] && ewarn " $filename"
+ done < "$OWNERS_FILE" | gawk '!s[$0]++' # (omit dupes)
+ fi
+}
+##
+# Setup portage and the search paths
+setup_portage() {
+ local PORTAGE_NICENESS=$(portageq envvar PORTAGE_NICENESS)
+ PORTAGE_ROOT=$(portageq envvar ROOT)
-[[ -r $LIST.5_order && -s $LIST.5_order ]] &&
- REBUILD_LIST=($(<"$LIST.5_order")) ||
- REBUILD_LIST=($(sort -u "$LIST.4_ebuilds"))
+ # Obey PORTAGE_NICENESS
+ if [[ $PORTAGE_NICENESS ]]; then
+ renice $PORTAGE_NICENESS $$ > /dev/null
+ # Since we have already set our nice value for our processes,
+ # reset PORTAGE_NICENESS to zero to avoid having emerge renice again.
+ export PORTAGE_NICENESS="0"
+ fi
-trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
+ PORTAGE_ROOT="${PORTAGE_ROOT:-/}"
+}
-REBUILD_LIST="${REBUILD_LIST[@]}"
-# PACKAGE_NAMES means slots, not versions, so no '=' is required
-[[ $PACKAGE_NAMES ]] || REBUILD_LIST="=${REBUILD_LIST//[[:space:]]/ =}"
+##
+# Setup the paths to search (and filter the ones to avoid)
+setup_search_paths_and_masks() {
+ local configfile sdir mdir skip_me filter_SEARCH_DIRS
-einfo 'All prepared. Starting rebuild'
-echo "emerge --oneshot ${EMERGE_OPTIONS[@]} $REBUILD_LIST"
+ einfo "Configuring search environment for $APP_NAME"
-is_real_merge && countdown 10
+ # Update the incremental variables using /etc/profile.env, /etc/ld.so.conf,
+ # portage, and the environment
-# Link file descriptor #6 with stdin so --ask will work
-exec 6<&0
+ # Read the incremental variables from environment and portage
+ # Until such time as portage supports these variables as incrementals
+ # The value will be what is in /etc/make.conf
+ SEARCH_DIRS+=" "$(unset SEARCH_DIRS; portageq envvar SEARCH_DIRS)
+ SEARCH_DIRS_MASK+=" "$(unset SEARCH_DIRS_MASK; portageq envvar SEARCH_DIRS_MASK)
+ LD_LIBRARY_MASK+=" "$(unset LD_LIBRARY_MASK; portageq envvar LD_LIBRARY_MASK)
-# Run in background to correctly handle Ctrl-C
-{
- EMERGE_DEFAULT_OPTS="--oneshot ${EMERGE_OPTIONS[@]}" emerge $REBUILD_LIST <&6
- echo $? > $LIST.6_status
-} &
-wait
+ # Add the defaults
+ if [[ -d /etc/revdep-rebuild ]]; then
+ for configfile in /etc/revdep-rebuild/*; do
+ SEARCH_DIRS+=" "$(. $configfile; echo $SEARCH_DIRS)
+ SEARCH_DIRS_MASK+=" "$(. $configfile; echo $SEARCH_DIRS_MASK)
+ LD_LIBRARY_MASK+=" "$(. $configfile; echo $LD_LIBRARY_MASK)
+ done
+ else
+ SEARCH_DIRS+=" /bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*"
+ SEARCH_DIRS_MASK+=" /opt/OpenOffice /usr/lib/openoffice"
+ LD_LIBRARY_MASK+=" libodbcinst.so libodbc.so libjava.so libjvm.so"
+ fi
-# Now restore stdin from fd #6, where it had been saved, and close fd #6 ( 6<&- ) to free it for other processes to use.
-exec 0<&6 6<&-
+ # Get the ROOTPATH and PATH from /etc/profile.env
+ if [[ -r "/etc/profile.env" && -s "/etc/profile.env" ]]; then
+ SEARCH_DIRS+=" "$(. /etc/profile.env; /usr/bin/tr ':' ' ' <<< "$ROOTPATH $PATH")
+ fi
-show_unowned_files() {
- if grep -qF '(none)' "$LIST.4_package_owners"; then
- ewarn "Found some broken files that weren't associated with known packages"
- ewarn "The broken files are:"
- while read filename junk; do
- [[ $junk = *none* ]] && ewarn " $filename"
- done < "$LIST.4_package_owners" | awk '!s[$0]++' # (omit dupes)
+ # Get the directories from /etc/ld.so.conf
+ if [[ -r /etc/ld.so.conf && -s /etc/ld.so.conf ]]; then
+ SEARCH_DIRS+=" "$(sed '/^#/d;s/#.*$//' /etc/ld.so.conf)
fi
+
+ # Set the final variables
+ SEARCH_DIRS=$(clean_var <<< "$SEARCH_DIRS")
+ SEARCH_DIRS_MASK=$(clean_var <<< "$SEARCH_DIRS_MASK")
+ LD_LIBRARY_MASK=$(clean_var <<< "$LD_LIBRARY_MASK")
+ # Filter masked paths from SEARCH_DIRS
+ for sdir in ${SEARCH_DIRS} ; do
+ skip_me=
+ for mdir in ${SEARCH_DIRS_MASK}; do
+ [[ ${sdir} == ${mdir}/* ]] && skip_me=1 && break
+ done
+ [[ -n ${skip_me} ]] || filter_SEARCH_DIRS+=" ${sdir}"
+ done
+ SEARCH_DIRS=$(clean_var <<< "${filter_SEARCH_DIRS}")
+ [[ $SEARCH_DIRS ]] || die 1 "No search defined -- this is a bug."
}
+##
+# Rebuild packages owning broken binaries
+rebuild() {
+ if [[ -r $LIST.5_order && -s $LIST.5_order ]]; then
+ REBUILD_LIST=( $(<"$LIST.5_order") )
+ REBUILD_LIST="${REBUILD_LIST[@]/#/=}"
+ else
+ REBUILD_LIST=$(sort -u "$EBUILDS_FILE")
+ fi
-if (( $(<"$LIST.6_status") != 0 )); then
- ewarn
- ewarn "$APP_NAME failed to emerge all packages."
- ewarn 'you have the following choices:'
- einfo "- If emerge failed during the build, fix the problems and re-run $APP_NAME."
- einfo '- Use /etc/portage/package.keywords to unmask a newer version of the package.'
- einfo " (and remove $LIST.5_order to be evaluated again)"
- einfo '- Modify the above emerge command and run it manually.'
- einfo '- Compile or unmerge unsatisfied packages manually,'
- einfo ' remove temporary files, and try again.'
- einfo ' (you can edit package/ebuild list first)'
- einfo
- einfo 'To remove temporary files, please run:'
- einfo "rm $LIST*.?_*"
- show_unowned_files
- exit $EMERGE_STATUS
-elif is_real_merge; then
- trap_cmd() {
- eerror "terminated. Please remove the temporary files manually:"
- eerror "rm $LIST*.?_*"
- exit 1
- }
- (( "${#SKIP_LIST[@]}" != 0 )) && list_skipped_packages
- trap trap_cmd SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
- einfo 'Build finished correctly. Removing temporary files...'
- einfo
- einfo 'You can re-run revdep-rebuild to verify that all libraries and binaries'
- einfo 'are fixed. If some inconsistency remains, it can be orphaned file, deep'
- einfo 'dependency, binary package or specially evaluated library.'
- if [[ -r "$LIST.4_package_owners" && -s "$LIST.4_package_owners" ]]; then
- show_unowned_files
+ trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
+
+ einfo 'All prepared. Starting rebuild'
+ echo "emerge --oneshot ${EMERGE_OPTIONS[@]} $REBUILD_LIST"
+
+ is_real_merge && countdown 10
+
+ # Link file descriptor #6 with stdin so --ask will work
+ exec 6<&0
+
+ # Run in background to correctly handle Ctrl-C
+ {
+ EMERGE_DEFAULT_OPTS="--oneshot ${EMERGE_OPTIONS[@]}" emerge $REBUILD_LIST <&6
+ echo $? > "$STATUS_FILE"
+ } &
+ wait
+
+ # Now restore stdin from fd #6, where it had been saved, and close fd #6 ( 6<&- ) to free it for other processes to use.
+ exec 0<&6 6<&-
+}
+##
+# Finish up
+cleanup() {
+ if (( $(<"$STATUS_FILE") != 0 )); then
+ ewarn
+ ewarn "$APP_NAME failed to emerge all packages."
+ ewarn 'you have the following choices:'
+ einfo "- If emerge failed during the build, fix the problems and re-run $APP_NAME."
+ einfo '- Use /etc/portage/package.keywords to unmask a newer version of the package.'
+ einfo " (and remove $ORDER_FILE to be evaluated again)"
+ einfo '- Modify the above emerge command and run it manually.'
+ einfo '- Compile or unmerge unsatisfied packages manually,'
+ einfo ' remove temporary files, and try again.'
+ einfo ' (you can edit package/ebuild list first)'
+ einfo
+ einfo 'To remove temporary files, please run:'
+ einfo "rm ${WORKING_DIR}/*.rr"
+ show_unowned_files
+ exit $EMERGE_STATUS
+ elif is_real_merge; then
+ trap_cmd() {
+ eerror "terminated. Please remove the temporary files manually:"
+ eerror "rm ${WORKING_DIR}/*.rr"
+ exit 1
+ }
+ [[ "${SKIP_LIST[@]}" != "" ]] && list_skipped_packages
+ trap trap_cmd SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
+ einfo 'Build finished correctly. Removing temporary files...'
+ einfo
+ einfo 'You can re-run revdep-rebuild to verify that all libraries and binaries'
+ einfo 'are fixed. Possible reasons for remaining inconsistencies include:'
+ einfo ' orphaned files'
+ einfo ' deep dependencies'
+ einfo " packages installed outside of portage's control"
+ einfo ' specially-evaluated libraries'
+ if [[ -r "$OWNERS_FILE" && -s "$OWNERS_FILE" ]]; then
+ show_unowned_files
+ fi
+ [[ $KEEP_TEMP ]] || rm "${FILES[@]}"
+ else
+ einfo 'Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.'
fi
- [[ $KEEP_TEMP ]] || rm $LIST*.?_*
-else
- einfo 'Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.'
-fi
+}
+main "$@"