2 # Copyright 1999-2010 Gentoo Foundation
4 # revdep-rebuild: Reverse dependency rebuilder.
5 # Original Author: Stanislav Brabec
6 # Rewrite Author: Michael A. Smith
7 # Current Maintainer: Paul Varner <fuzzyray@gentoo.org>
10 # - Use more /etc/init.d/functions.sh
11 # - Try to reduce the number of global vars
20 declare -r APP_NAME="${0##*/}" # The name of this application
21 declare -r VERSION="svn"
22 declare -r OIFS="$IFS" # Save the IFS
23 declare -r ENV_FILE=0_env.rr # Contains environment variables
24 declare -r FILES_FILE=1_files.rr # Contains a list of files to search
25 declare -r LDPATH_FILE=2_ldpath.rr # Contains the LDPATH
26 declare -r BROKEN_FILE=3_broken.rr # Contains the list of broken files
27 declare -r ERRORS_FILE=3_errors.rr # Contains the ldd error output
28 declare -r RAW_FILE=4_raw.rr # Contains the raw list of packages
29 declare -r OWNERS_FILE=4_owners.rr # Contains the file owners
30 declare -r PKGS_FILE=4_pkgs.rr # Contains the unsorted bare package names
31 declare -r EBUILDS_FILE=4_ebuilds.rr # Contains the unsorted atoms
32 # (Appropriately slotted or versioned)
33 declare -r ORDER_FILE=5_order.rr # Contains the sorted atoms
34 declare -r STATUS_FILE=6_status.rr # Contains the ldd error output
49 # "Boolean" variables: Considered "true" if it has any value at all
50 # "True" indicates we should...
51 declare FULL_LD_PATH # ...search across the COMPLETE_LD_LIBRARY_PATH
52 declare KEEP_TEMP # ...not delete tempfiles from the current run
53 declare ORDER_PKGS # ...sort the atoms in deep dependency order
54 declare PACKAGE_NAMES # ...emerge by slot, not by versionated atom
55 declare RM_OLD_TEMPFILES # ...remove tempfiles from prior runs
56 declare SEARCH_BROKEN # ...search for broken libraries and binaries
57 declare VERBOSE # ...give verbose output
59 # Globals that impact portage directly:
60 declare EMERGE_DEFAULT_OPTS # String of options portage assumes to be set
61 declare EMERGE_OPTIONS # Array of options to pass to portage
62 declare PORTAGE_NICENESS # Renice to this value
63 declare PORTAGE_ROOT # The root path for portage
65 # Customizable incremental variables:
66 # These variables can be prepended to either by setting the variable in
67 # your environment prior to execution, or by placing an entry in
70 # An entry of "-*" means to clear the variable from that point forward.
71 # Example: env SEARCH_DIRS="/usr/bin -*" revdep-rebuild will set SEARCH_DIRS
72 # to contain only /usr/bin
73 declare LD_LIBRARY_MASK # Mask of specially evaluated libraries
74 declare SEARCH_DIRS # List of dirs to search for executables and libraries
75 declare SEARCH_DIRS_MASK # List of dirs not to search
78 declare OLDPROG # Previous pass through the progress meter
79 declare EXACT_PKG # Versionated atom to emerge
80 declare HEAD_TEXT # Feedback string about the search
81 declare NOCOLOR # Set to "true" not to output term colors
82 declare OK_TEXT # Feedback about a search which found no errors
83 declare RC_NOCOLOR # Hack to insure we respect NOCOLOR
84 declare REBUILD_LIST # Array of atoms to emerge
85 declare SKIP_LIST # Array of atoms that cannot be emerged (masked?)
86 declare SONAME # Soname/soname path pattern given on commandline
87 declare SONAME_SEARCH # Value of SONAME modified to match ldd's output
88 declare WORKING_TEXT # Feedback about the search
89 declare WORKING_DIR # Working directory where cache files are kept
96 setup_search_paths_and_masks
98 [[ $QUIET -ne 1 ]] && echo
100 # Search for broken binaries
105 # Associate broken binaries with packages to rebuild
106 if [[ $PACKAGE_NAMES ]]; then
109 assign_packages_to_ebuilds
114 # Rebuild packages owning broken binaries
122 # Refuse to delete anything before we cd to our tmpdir
123 # (See mkdir_and_cd_to_tmpdir()
125 eerror "I was instructed to rm '$@'"
126 die 1 "Refusing to delete anything before changing to temporary directory."
130 # GNU find has -executable, but if our users' finds do not have that flag
131 # we emulate it with this function. Also emulates -writable and -readable.
132 # Usage: find PATH ARGS -- use find like normal, except use -executable instead
133 # of various versions of -perm /+ blah blah and hacks
135 hash find || { die 1 'find not found!'; }
136 # We can be pretty sure find itself should be executable.
137 local testsubject="$(type -P find)"
138 if [[ $(command find "$testsubject" -executable 2> /dev/null) ]]; then
139 unset -f find # We can just use the command find
140 elif [[ $(command find "$testsubject" -perm /u+x 2> /dev/null) ]]; then
142 a=(${@//-executable/-perm \/u+x})
143 a=(${a[@]//-writable/-perm \/u+w})
144 a=(${a[@]//-readable/-perm \/r+w})
145 command find "${a[@]}"
147 elif [[ $(command find "$testsubject" -perm +u+x 2> /dev/null) ]]; then
149 a=(${@//-executable/-perm +u+x})
150 a=(${a[@]//-writable/-perm +u+w})
151 a=(${a[@]//-readable/-perm +r+w})
152 command find "${a[@]}"
156 a=(${@//-executable/-exec test -x '{}' \; -print})
157 a=(${a[@]//-writable/-exec test -w '{}' \; -print})
158 a=(${a[@]//-readable/-exec test -r '{}' \; -print})
159 command find "${a[@]}"
168 ${APP_NAME}: (${VERSION})
170 Copyright (C) 2003-2010 Gentoo Foundation, Inc.
171 This is free software; see the source for copying conditions.
173 Usage: $APP_NAME [OPTIONS] [--] [EMERGE_OPTIONS]
175 Broken reverse dependency rebuilder.
177 -C, --nocolor Turn off colored output
178 -d, --debug Print way too much information (uses bash's set -xv)
179 -e, --exact Emerge based on exact package version
180 -h, --help Print this usage
181 -i, --ignore Ignore temporary files from previous runs
182 -k, --keep-temp Do not delete temporary files on exit
183 -L, --library NAME Emerge existing packages that use the library with NAME
184 --library=NAME NAME can be a full path to the library or a basic
185 regular expression (man grep)
186 -l, --no-ld-path Do not set LD_LIBRARY_PATH
187 -o, --no-order Do not check the build order
188 (Saves time, but may cause breakage.)
189 -p, --pretend Do a trial run without actually emerging anything
190 (also passed to emerge command)
191 -P, --no-progress Turn off the progress meter
192 -q, --quiet Be less verbose (also passed to emerge command)
193 -v, --verbose Be more verbose (also passed to emerge command)
195 Calls emerge, options after -- are ignored by $APP_NAME
196 and passed directly to emerge.
198 Report bugs to <http://bugs.gentoo.org>
203 # Usage: progress i n
205 # n: total number of items to process
209 local curProg=$(( $1 * 100 / $2 ))
210 (( curProg == OLDPROG )) && return # no change, output nothing
211 OLDPROG="$curProg" # must be a global variable
212 (( $1 == $2 )) && local lb=$'\n'
213 echo -ne '\r \r'"[ $curProg% ] $lb"
216 else # STDOUT is not a tty. Disable progress meter.
222 # n: number of seconds to count
225 for ((i=1; i<$1; i++)); do
232 # Replace whitespace with linebreaks, normalize repeated '/' chars, and sort -u
233 # (If any libs have whitespace in their filenames, someone needs punishment.)
235 gawk 'BEGIN {RS="[[:space:]]"}
237 /[^[:space:]]/ {gsub(/\/\/+/, "/"); print}' | sort -u
240 # Exit and optionally output to sterr
245 # Check if eerror has been loaded.
246 # Its loaded _after_ opt parsing but not before due to RC_NOCOLOR.
247 type eerror &> /dev/null
253 echo " * ${@}" >> /dev/stderr
258 # What to do when dynamic linking is consistent
260 if [[ ! $KEEP_TEMP ]]; then
262 if [[ "$WORKING_DIR" != "/var/cache/${APP_NAME}" ]]; then
263 # Remove the working directory
264 builtin cd; rmdir "$WORKING_DIR"
267 if [[ $QUIET -ne 1 ]];
270 einfo "$OK_TEXT... All done. "
275 # Get the name of the package that owns a file or list of files given as args.
276 # NOTE: depends on app-misc/realpath!
280 rpath=$(realpath "${*}" 2>/dev/null)
281 # To ensure we always have something in rpath...
282 [[ -z $rpath ]] && rpath=${*}
284 # Workaround for bug 280341
285 mlib=$(echo ${*}|sed 's:/lib/:/lib64/:')
286 [[ "${*}" == "${mlib}" ]] && mlib=$(echo ${*}|sed 's:/lib64/:/lib/:')
288 # Add a space to the end of each object name to prevent false
289 # matches, for example /usr/bin/dia matching /usr/bin/dialog (bug #196460).
290 # The same for "${rpath} ".
291 # Don't match an entry with a '-' at the start of the package name. This
292 # prevents us from matching invalid -MERGING entries. (bug #338031)
293 find -L /var/db/pkg -type f -name CONTENTS -print0 |
294 xargs -0 grep -m 1 -Fl -e "${*} " -e "${rpath} " -e "${mlib} " |
295 sed 's:/var/db/pkg/\(.*\)/\([^-].*\)/CONTENTS:\1/\2:'
298 # Normalize some EMERGE_OPTIONS
299 normalize_emerge_opts() {
300 # Normalize some EMERGE_OPTIONS
301 EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-p/--pretend})
302 EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-f/--fetchonly})
303 EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-v/--verbose})
306 # Use the color preference from portage
308 # This should still work if NOCOLOR is set by the -C flag or in the user's
310 [[ $NOCOLOR = yes || $NOCOLOR = true ]] && export RC_NOCOLOR=yes # HACK! (grr)
311 . /etc/init.d/functions.sh
314 # Die if an argument is missing.
315 die_if_missing_arg() {
316 [[ ! $2 || $2 = -* ]] && die 1 "Missing expected argument to $1"
319 # Die because an option is not recognized.
320 die_invalid_option() {
321 # Can't use eerror and einfo because this gets called before function.sh
324 echo "Encountered unrecognized option $1." >&2
326 echo "$APP_NAME no longer automatically passes unrecognized options to portage."
327 echo "Separate emerge-only options from revdep-rebuild options with the -- flag."
329 echo "For example, $APP_NAME -v -- --ask"
331 echo "See the man page or $APP_NAME -h for more detail."
336 # Warn about deprecated options.
337 warn_deprecated_opt() {
338 # Can't use eerror and einfo because this gets called before function.sh
341 echo "Encountered deprecated option $1." >&2
342 [[ $2 ]] && echo "Please use $2 instead." >&2
345 # Get whole-word commandline options preceded by two dashes.
348 --nocolor) export NOCOLOR="yes";;
349 --no-color) warn_deprecated_opt "$1" "--nocolor"
350 export NOCOLOR="yes";;
352 --exact) unset PACKAGE_NAMES;;
355 --ignore) RM_OLD_TEMPFILES=1;;
356 --keep-temp) KEEP_TEMP=1;;
357 --library=*) # TODO: check for invalid values
359 unset SEARCH_BROKEN;;
360 --soname=*|--soname-regexp=*) # TODO: check for invalid values
361 warn_deprecated_opt "${1%=*}" "--library"
363 unset SEARCH_BROKEN;;
364 --library) # TODO: check for invalid values
365 die_if_missing_arg $1 $2
368 unset SEARCH_BROKEN;;
369 --soname|--soname-regexp) # TODO: check for invalid values
370 warn_deprecated_opt "$1" "--library"
371 die_if_missing_arg $1 $2
374 unset SEARCH_BROKEN;;
375 --no-ld-path) unset FULL_LD_PATH;;
376 --no-order) unset ORDER_PKGS;;
377 --no-progress) progress() { :; };;
378 --pretend) EMERGE_OPTIONS+=("--pretend")
380 --quiet) progress() { :; }
382 EMERGE_OPTIONS+=($1);;
384 EMERGE_OPTIONS+=("--verbose");;
385 --extra-verbose) warn_deprecated_opt "$1" "--verbose"
387 EMERGE_OPTIONS+=("--verbose");;
388 --package-names) # No longer used, since it is the
389 # default. We accept it for
390 # backwards compatibility.
391 warn_deprecated_opt "$1"
393 *) die_invalid_option $1;;
398 # Get single-letter commandline options preceded by a single dash.
400 local OPT OPTSTRING OPTARG OPTIND
401 while getopts ":CdehikL:loPpqu:vX" OPT; do
403 C) # TODO: Match syntax with the rest of gentoolkit
404 export NOCOLOR="yes";;
406 e) unset PACKAGE_NAMES;;
409 i) RM_OLD_TEMPFILES=1;;
411 L) # TODO: Check for invalid values
412 SONAME="${OPTARG#*=}"
413 unset SEARCH_BROKEN;;
414 l) unset FULL_LD_PATH;;
415 o) unset ORDER_PKGS;;
416 P) progress() { :; };;
417 p) EMERGE_OPTIONS+=("--pretend")
421 EMERGE_OPTIONS+=("--quiet");;
423 EMERGE_OPTIONS+=("--verbose");;
424 X) # No longer used, since it is the default.
425 # We accept it for backwards compatibility.
426 warn_deprecated_opt "-X"
428 *) die_invalid_option "-$OPTARG";;
433 # Get command-line options.
437 echo_v() { ewarn "$@"; }
438 unset VERBOSE KEEP_TEMP EMERGE_OPTIONS RM_OLD_TEMPFILES
447 EMERGE_OPTIONS+=("$@")
452 [[ ${1:--} = -* ]] && break
454 if [[ ${args[0]} = --* ]]; then
455 get_longopts "${args[@]}"
457 get_shortopts "${args[@]}"
459 *) die_invalid_option "$1";;
465 normalize_emerge_opts
467 # If the user is not super, add --pretend to EMERGE_OPTIONS
468 if [[ ${EMERGE_OPTIONS[@]} != *--pretend* && $UID -ne 0 ]]; then
469 ewarn "You are not superuser. Adding --pretend to emerge options."
470 EMERGE_OPTIONS+=(--pretend)
474 # Is there a --pretend or --fetchonly flag in the EMERGE_OPTIONS array?
476 [[ ${EMERGE_OPTIONS[@]} != *--pretend* &&
477 ${EMERGE_OPTIONS[@]} != *--fetchonly* ]]
480 # Clean up temporary files and exit
483 die 1 " ...terminated. Removing incomplete $@."
488 trap "cleanup_and_die $*" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
492 # Returns 0 if the first arg is found in the remaining args, 1 otherwise
493 # (Returns 2 if given fewer than 2 arguments)
495 (( $# > 1 )) || return 2
496 local IFS=$'\a' target="$1"
498 [[ $'\a'"$*"$'\a' = *$'\a'$target$'\a'* ]]
501 # Dies when it can't change directories
503 if builtin cd -P "$@"; then
504 if [[ $1 != $PWD ]]; then
505 # Some symlink malfeasance is going on
506 die 1 "Working directory expected to be $1, but it is $PWD"
509 die 1 "Unable to change working directory to '$@'"
513 # Tries not to delete any files or directories it shouldn't
516 # Anything in the FILES array in tmpdir is fair game for removal
519 [[ $APP_NAME ]] || die 1 '$APP_NAME is not defined! (This is a bug.)'
521 */*|*-r*|*-R*) die 1 "Oops, I'm not allowed to delete that. ($@)";;
524 # Don't delete files that are not listed in the array
525 # Allow no slashes or recursive deletes at all.
527 */*|-*r*|-*R*) :;; # Not OK
530 has "$i" "${FILES[@]}" && continue
531 die 1 "Oops, I'm not allowed to delete that. ($@)"
535 # delete this setup function so it's harmless to re-run
539 # Make our temporary files directory
540 # $1 - directory name
544 die 1 'Temporary file path is unset! (This is a bug.)'
545 elif [[ -d $1 ]]; then
548 die 1 "Unable to find a satisfactory location for temporary files ($1)"
550 [[ $VERBOSE ]] && einfo "Temporary cache files are located in $PWD"
556 local uid=$(python -c 'import os; import pwd; print(pwd.getpwuid(os.getuid())[0])')
557 # Find a place to put temporary files
558 if [[ "$uid" == "root" ]]; then
559 local tmp_target="/var/cache/${APP_NAME}"
561 local tmp_target="$(mktemp -d -t revdep-rebuild.XXXXXXXXXX)"
564 # From here on all work is done inside the temporary directory
565 verify_tmpdir "$tmp_target"
566 WORKING_DIR="$tmp_target"
568 if [[ $SEARCH_BROKEN ]]; then
569 SONAME_SEARCH="$SONAME"
570 HEAD_TEXT="broken by a package update"
571 OK_TEXT="Dynamic linking on your system is consistent"
572 WORKING_TEXT="consistency"
574 # first case is needed to test against /path/to/foo.so
575 if [[ $SONAME = /* ]]; then
576 # Set to "<space>$SONAME<space>"
577 SONAME_SEARCH=" $SONAME "
578 # Escape the "/" characters
579 SONAME_SEARCH="${SONAME_SEARCH//\//\\/}"
581 # Set to "<tab>$SONAME<space>"
582 SONAME_SEARCH=$'\t'"$SONAME "
584 HEAD_TEXT="using $SONAME"
585 OK_TEXT="There are no dynamic links to $SONAME"
589 # If any of our temporary files are older than 1 day, remove them all
590 if [[ ! $KEEP_TEMP ]]; then
594 done < <(find -L . -maxdepth 1 -type f -name '*.rr' -mmin +1440 -print 2>/dev/null)
597 # Compare old and new environments
598 # Don't use our previous files if environment doesn't match
600 # We do not care if these emerge options change
601 EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--pretend/})
602 EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--fetchonly/})
603 EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--verbose/})
605 SEARCH_DIRS="$SEARCH_DIRS"
606 SEARCH_DIRS_MASK="$SEARCH_DIRS_MASK"
607 LD_LIBRARY_MASK="$LD_LIBRARY_MASK"
608 PORTAGE_ROOT="$PORTAGE_ROOT"
609 EMERGE_OPTIONS="${EMERGE_OPTIONS[@]}"
610 ORDER_PKGS="$ORDER_PKGS"
611 FULL_LD_PATH="$FULL_LD_PATH"
614 if [[ -r "$ENV_FILE" && -s "$ENV_FILE" ]]; then
615 old_env=$(<"$ENV_FILE")
616 if [[ $old_env != $new_env ]]; then
617 ewarn 'Environment mismatch from previous run, deleting temporary files...'
621 # No env file found, silently delete any other tempfiles that may exist
625 # If we should remove old tempfiles, do so
626 if [[ $RM_OLD_TEMPFILES ]]; then
629 for file in "${FILES[@]}"; do
630 if [ -e "$file" ]; then
631 chown ${uid}:portage "$file"
637 # Save the environment in a file for next time
638 echo "$new_env" > "$ENV_FILE"
640 [[ $VERBOSE ]] && echo $'\n'"$APP_NAME environment:"$'\n'"$new_env"
642 if [[ $QUIET -ne 1 ]];
645 einfo "Checking reverse dependencies"
646 einfo "Packages containing binaries and libraries $HEAD_TEXT"
647 einfo "will be emerged."
652 [[ $QUIET -ne 1 ]] && einfo "Collecting system binaries and libraries"
653 if [[ -r "$FILES_FILE" && -s "$FILES_FILE" ]]; then
654 [[ $QUIET -ne 1 ]] && einfo "Found existing $FILES_FILE"
656 # Be safe and remove any extraneous temporary files
657 # Don't remove 0_env.rr - The first file in the array
658 rm -f "${FILES[@]:1}"
660 clean_trap "$FILES_FILE"
662 if [[ $SEARCH_DIRS_MASK ]]; then
663 findMask=($SEARCH_DIRS_MASK)
664 findMask="${findMask[@]/#/-o -path }"
665 findMask="( ${findMask#-o } ) -prune -o"
667 # TODO: Check this -- afaict SEARCH_DIRS isn't an array, so this should just be $SEARCH_DIRS?
668 find ${SEARCH_DIRS[@]} $findMask -type f \( -perm -u+x -o -perm -g+x -o -perm -o+x -o \
669 -name '*.so' -o -name '*.so.*' -o -name '*.la' \) -print 2> /dev/null |
670 sort -u > "$FILES_FILE" ||
671 die $? "find failed to list binary files (This is a bug.)"
672 [[ $QUIET -ne 1 ]] && einfo "Generated new $FILES_FILE"
676 # FIXME: not safe for paths with spaces
678 for path in $(sed '/^#/d;s/#.*$//' < /etc/ld.so.conf); do
679 if [[ $include = true ]]; then
680 for include_path in $(sed '/^#/d;s/#.*$//' /etc/${path} 2>/dev/null); do
686 if [[ $path != include ]]; then
695 local COMPLETE_LD_LIBRARY_PATH
696 [[ $SEARCH_BROKEN && $FULL_LD_PATH ]] || return
697 [[ $QUIET -ne 1 ]] && einfo 'Collecting complete LD_LIBRARY_PATH'
698 if [[ -r "$LDPATH_FILE" && -s "$LDPATH_FILE" ]]; then
699 [[ $QUIET -ne 1 ]] && einfo "Found existing $LDPATH_FILE."
701 clean_trap "$LDPATH_FILE"
702 # Ensure that the "trusted" lib directories are at the start of the path
703 COMPLETE_LD_LIBRARY_PATH=(
707 $(sed 's:/[^/]*$::' < "$FILES_FILE" | sort -ru)
710 COMPLETE_LD_LIBRARY_PATH="${COMPLETE_LD_LIBRARY_PATH[*]}"
712 echo "$COMPLETE_LD_LIBRARY_PATH" > "$LDPATH_FILE"
713 [[ $QUIET -ne 1 ]] && einfo "Generated new $LDPATH_FILE"
723 local COMPLETE_LD_LIBRARY_PATH
724 if [[ $SEARCH_BROKEN && $FULL_LD_PATH ]]; then
725 [[ -r "$LDPATH_FILE" && -s "$LDPATH_FILE" ]] ||
726 die 1 "Unable to find $LDPATH_FILE"
727 COMPLETE_LD_LIBRARY_PATH=$(<"$LDPATH_FILE")
729 [[ $QUIET -ne 1 ]] && einfo "Checking dynamic linking $WORKING_TEXT"
730 if [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]]; then
731 [[ $QUIET -ne 1 ]] && einfo "Found existing $BROKEN_FILE."
733 clean_trap "$BROKEN_FILE" "$ERRORS_FILE"
734 files=($(<"$FILES_FILE"))
735 numFiles="${#files[@]}"
736 for target_file in "${files[@]}"; do
737 if [[ $target_file != *.la ]]; then
738 # Note: double checking seems to be faster than single with complete path
739 # (special add ons are rare).
740 ldd_output=$(ldd "$target_file" 2>> "$ERRORS_FILE" | sort -u)
741 ldd_status=$? # TODO: Check this for problems with sort
742 # HACK: if LD_LIBRARY_MASK is null or undefined grep -vF doesn't work
743 if grep -vF "${LD_LIBRARY_MASK:=$'\a'}" <<< "$ldd_output" |
744 grep -q -E "$SONAME_SEARCH"; then
745 if [[ $SEARCH_BROKEN && $FULL_LD_PATH ]]; then
746 if LD_LIBRARY_PATH="$COMPLETE_LD_LIBRARY_PATH" ldd "$target_file" 2>/dev/null |
747 grep -vF "$LD_LIBRARY_MASK" | grep -q -E "$SONAME_SEARCH"; then
748 # FIXME: I hate duplicating code
749 # Only build missing direct dependencies
751 expr='s/[[:space:]]*\([^[:space:]]*\) => not found/\1/p'
752 sed -n "$expr" <<< "$ldd_output"
755 expr='s/^[[:space:]]*NEEDED[[:space:]]*\([^[:space:]]*\).*/\1/p';
756 objdump -x "$target_file" | grep NEEDED | sed "$expr" | sort -u
758 MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS")
759 if [[ $MISSING_LIBS ]]; then
760 echo "obj $target_file" >> "$BROKEN_FILE"
761 echo_v " broken $target_file (requires $MISSING_LIBS)"
765 # FIXME: I hate duplicating code
766 # Only rebuild for direct dependencies
768 expr="s/^[[:space:]]*\([^[:space:]]*\).*$/\1/p"
769 sort -u <<< "$ldd_output" | grep -E "$SONAME" | sed -n "$expr"
772 expr='s/^[[:space:]]*NEEDED[[:space:]]*\([^[:space:]]*\).*/\1/p';
773 objdump -x "$target_file" | grep NEEDED | sed "$expr" | sort -u
775 MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS")
776 if [[ $MISSING_LIBS ]]; then
777 echo "obj $target_file" >> "$BROKEN_FILE"
778 if [[ $SEARCH_BROKEN ]]; then
779 echo_v " broken $target_file (requires $MISSING_LIBS)"
781 echo_v " found $target_file"
786 elif [[ $SEARCH_BROKEN ]]; then
787 # Look for broken .la files
788 la_SEARCH_DIRS="$SEARCH_DIRS"
793 gawk -F"[=']" '/^dependency_libs/{
797 if [[ $depend = /* && ! -e $depend ]]; then
798 echo "obj $target_file" >> "$BROKEN_FILE"
799 echo_v " broken $target_file (requires $depend)"
800 elif [[ $depend = -[LR]/* ]]; then
801 if ! [[ $'\n'${la_SEARCH_DIRS}$'\n' == *$'\n'${depend#-?}$'\n'* ]]; then
802 la_SEARCH_DIRS+=$'\n'"${depend#-?}"
804 elif [[ $depend = "-l"* ]]; then
805 la_lib="lib${depend#-l}"
808 for la_search_dir in $la_SEARCH_DIRS; do
809 if [[ -e ${la_search_dir}/${la_lib}.so || -e ${la_search_dir}/${la_lib}.a ]]; then
814 if [[ $la_broken = yes ]]; then
815 echo "obj $target_file" >> "$BROKEN_FILE"
816 echo_v " broken $target_file (requires $depend)"
820 unset la_SEARCH_DIRS la_search_dir la_broken la_lib
823 progress $((++i)) $numFiles $target_file ||
824 progress $((++i)) $numFiles
826 if [[ $SEARCH_BROKEN && -f $ERRORS_FILE ]]; then
827 # Look for missing version
828 while read target_file; do
829 echo "obj $target_file" >> "$BROKEN_FILE"
830 echo_v " broken $target_file (no version information available)"
832 # Regexify LD_LIBRARY_MASK. Exclude it from the search.
833 LD_LIBRARY_MASK="${LD_LIBRARY_MASK//$'\n'/|}"
834 gawk -v ldmask="(${LD_LIBRARY_MASK//./\\\.})" '
835 /no version information available/ && $0 !~ ldmask {
836 gsub(/[()]/, "", $NF)
837 if (seen[$NF]++) next
842 [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]] || clean_exit
843 sort -u "$BROKEN_FILE" -o "$BROKEN_FILE"
844 [[ $QUIET -ne 1 ]] && einfo "Generated new $BROKEN_FILE"
852 einfo 'Assigning files to packages'
853 if [[ -r "$RAW_FILE" && -s "$RAW_FILE" ]]; then
854 einfo "Found existing $RAW_FILE"
856 clean_trap "$RAW_FILE" "$OWNERS_FILE"
857 while read obj target_file; do
858 EXACT_PKG=$(get_file_owner $target_file)
859 if [[ $EXACT_PKG ]]; then
860 # Strip version information
861 PKG="${EXACT_PKG%%-r[[:digit:]]*}"
863 echo "$EXACT_PKG" >> "$RAW_FILE"
864 echo "$target_file -> $EXACT_PKG" >> "$OWNERS_FILE"
865 echo_v " $target_file -> $PKG"
867 ewarn " !!! $target_file not owned by any package is broken !!!"
868 echo "$target_file -> (none)" >> "$OWNERS_FILE"
869 echo_v " $target_file -> (none)"
871 done < "$BROKEN_FILE"
872 [[ $QUIET -ne 1 ]] && einfo "Generated new $RAW_FILE and $OWNERS_FILE"
874 # if we find '(none)' on every line, exit out
875 if ! grep -qvF '(none)' "$OWNERS_FILE"; then
876 ewarn "Found some broken files, but none of them were associated with known packages"
877 ewarn "Unable to proceed with automatic repairs."
878 ewarn "The broken files are listed in $OWNERS_FILE"
879 if [[ $VERBOSE ]]; then
880 ewarn "The broken files are:"
881 while read filename junk; do
883 done < "$OWNERS_FILE"
885 exit 0 # FIXME: Should we exit 1 here?
889 [[ $QUIET -ne 1 ]] && einfo 'Cleaning list of packages to rebuild'
890 if [[ -r "$PKGS_FILE" && -s "$PKGS_FILE" ]]; then
891 [[ $QUIET -ne 1 ]] && einfo "Found existing $PKGS_FILE"
893 sort -u "$RAW_FILE" > "$PKGS_FILE"
894 [[ $QUIET -ne 1 ]] && einfo "Generated new $PKGS_FILE"
897 assign_packages_to_ebuilds() {
901 einfo 'Assigning packages to ebuilds'
902 if [[ -r "$EBUILDS_FILE" && -s "$EBUILDS_FILE" ]]; then
903 einfo "Found existing $EBUILDS_FILE"
904 elif [[ -r "$PKGS_FILE" && -s "$PKGS_FILE" ]]; then
905 clean_trap "$EBUILDS_FILE"
906 while read EXACT_PKG; do
908 PKG="${EXACT_PKG%%-r[[:digit:]]*}"
910 SLOT=$(</var/db/pkg/$EXACT_PKG/SLOT)
912 done < "$PKGS_FILE" > "$EBUILDS_FILE"
913 [[ $QUIET -ne 1 ]] && einfo "Generated new $EBUILDS_FILE"
915 einfo 'Nothing to rebuild.'
916 die 1 '(The program should have already quit, so this is a minor bug.)'
919 get_exact_ebuilds() {
920 einfo 'Assigning files to ebuilds'
921 if [[ -r $EBUILDS_FILE && -s $EBUILDS_FILE ]]; then
922 einfo "Found existing $EBUILDS_FILE"
923 elif [[ -r $BROKEN_FILE && -s $BROKEN_FILE ]]; then
924 rebuildList=" $(<"$BROKEN_FILE") "
925 rebuildList=(${rebuildList//[[:space:]]obj[[:space:]]/ })
926 get_file_owner "${rebuildList[@]}" | sed 's/^/=/' > "$EBUILDS_FILE"
927 [[ $QUIET -ne 1 ]] && einfo "Generated new $EBUILDS_FILE"
929 einfo 'Nothing to rebuild.'
930 die 1 '(The program should have already quit, so this is a minor bug.)'
933 list_skipped_packages() {
935 ewarn 'Portage could not find any version of the following packages it could build:'
936 ewarn "${SKIP_LIST[@]}"
938 ewarn '(Perhaps they are masked, blocked, or removed from portage.)'
939 ewarn 'Try to emerge them manually.'
943 local -r OLD_EMERGE_DEFAULT_OPTS="$EMERGE_DEFAULT_OPTS"
944 local RAW_REBUILD_LIST
947 if [[ ! $ORDER_PKGS ]]; then
948 einfo 'Skipping package ordering'
951 [[ $QUIET -ne 1 ]] && einfo 'Evaluating package order'
952 if [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" ]]; then
953 einfo "Found existing $ORDER_FILE"
955 clean_trap "$ORDER_FILE"
956 RAW_REBUILD_LIST=$(<"$EBUILDS_FILE")
957 if [[ $RAW_REBUILD_LIST ]]; then
958 export EMERGE_DEFAULT_OPTS="--nospinner --pretend --oneshot --quiet"
959 RAW_REBUILD_LIST=($RAW_REBUILD_LIST) # convert into array
960 # If PACKAGE_NAMES is defined we're using slots, not versions
961 if [[ $PACKAGE_NAMES ]]; then
962 # Eliminate atoms that can't be built
963 for i in "${!RAW_REBUILD_LIST[@]}"; do
964 if [[ "${RAW_REBUILD_LIST[i]}" = *[A-Za-z]* ]]; then
965 portageq best_visible "$PORTAGE_ROOT" "${RAW_REBUILD_LIST[i]}" >/dev/null && continue
966 SKIP_LIST+=("${RAW_REBUILD_LIST[i]}")
968 unset RAW_REBUILD_LIST[i]
970 # If RAW_REBUILD_LIST is empty, then we have nothing to build.
971 if (( ${#RAW_REBUILD_LIST[@]} == 0 )); then
972 if (( ${#SKIP_LIST[@]} == 0 )); then
973 ewarn "The list of packages to skip is empty, but there are no"
974 ewarn "packages listed to rebuild either. (This is a bug.)"
976 list_skipped_packages
978 die 1 'Warning: Portage cannot rebuild any of the necessary packages.'
981 RAW_REBUILD_LIST="${RAW_REBUILD_LIST[@]}"
982 REBUILD_GREP=$(emerge --nodeps $RAW_REBUILD_LIST | sed 's/\[[^]]*\]//g')
983 if (( ${PIPESTATUS[0]} == 0 )); then
984 emerge --deep $RAW_REBUILD_LIST |
985 sed 's/\[[^]]*\]//g' |
986 grep -F "$REBUILD_GREP" > "$ORDER_FILE"
989 # Here we use the PIPESTATUS from the second emerge, the --deep one.
990 if (( ${PIPESTATUS[0]} != 0 )); then
992 eerror 'Warning: Failed to resolve package order.'
993 eerror 'Will merge in arbitrary order'
997 - An ebuild is no longer in the portage tree.
998 - An ebuild is masked, use /etc/portage/packages.keyword
999 and/or /etc/portage/package.unmask to unmask it
1004 export EMERGE_DEFAULT_OPTS="$OLD_EMERGE_DEFAULT_OPTS"
1006 einfo 'Nothing to rebuild.'
1007 die 1 '(The program should have already quit, so this is a minor bug.)'
1010 [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" && $QUIET -ne 1 ]] && einfo "Generated new $ORDER_FILE"
1013 show_unowned_files() {
1014 if grep -qF '(none)' "$OWNERS_FILE"; then
1015 ewarn "Found some broken files that weren't associated with known packages"
1016 ewarn "The broken files are:"
1017 while read filename junk; do
1018 [[ $junk = *none* ]] && ewarn " $filename"
1019 done < "$OWNERS_FILE" | gawk '!s[$0]++' # (omit dupes)
1023 # Get multiple portage variables at once to speedup revdep-rebuild.
1024 portage_settings() {
1025 local ORIG_SEARCH_DIRS="$SEARCH_DIRS"
1026 local ORIG_SEARCH_DIRS_MASK="$SEARCH_DIRS_MASK"
1027 local ORIG_LD_LIBRARY_MASK="$LD_LIBRARY_MASK"
1029 unset SEARCH_DIRS_MASK
1030 unset LD_LIBRARY_MASK
1032 eval $(portageq envvar -v PORTAGE_ROOT PORTAGE_NICENESS EMERGE_DEFAULT_OPTS NOCOLOR SEARCH_DIRS SEARCH_DIRS_MASK LD_LIBRARY_MASK)
1035 SEARCH_DIRS="$ORIG_SEARCH_DIRS $SEARCH_DIRS"
1036 SEARCH_DIRS_MASK="$ORIG_SEARCH_DIRS_MASK $SEARCH_DIRS_MASK"
1037 LD_LIBRARY_MASK="$ORIG_LD_LIBRARY_MASK $LD_LIBRARY_MASK"
1041 # Setup portage and the search paths
1043 # Obey PORTAGE_NICENESS (which is incremental to the current nice value)
1044 if [[ $PORTAGE_NICENESS ]]; then
1045 current_niceness=$(nice)
1046 let PORTAGE_NICENESS=${current_niceness}+${PORTAGE_NICENESS}
1047 renice $PORTAGE_NICENESS $$ > /dev/null
1048 # Since we have already set our nice value for our processes,
1049 # reset PORTAGE_NICENESS to zero to avoid having emerge renice again.
1050 export PORTAGE_NICENESS="0"
1053 PORTAGE_ROOT="${PORTAGE_ROOT:-/}"
1057 # Setup the paths to search (and filter the ones to avoid)
1058 setup_search_paths_and_masks() {
1059 local configfile sdir mdir skip_me filter_SEARCH_DIRS
1061 [[ $QUIET -ne 1 ]] && einfo "Configuring search environment for $APP_NAME"
1063 # Update the incremental variables using /etc/profile.env, /etc/ld.so.conf,
1064 # portage, and the environment
1066 # Read the incremental variables from environment and portage
1067 # Until such time as portage supports these variables as incrementals
1068 # The value will be what is in /etc/make.conf
1069 # SEARCH_DIRS+=" "$(unset SEARCH_DIRS; portageq envvar SEARCH_DIRS)
1070 # SEARCH_DIRS_MASK+=" "$(unset SEARCH_DIRS_MASK; portageq envvar SEARCH_DIRS_MASK)
1071 # LD_LIBRARY_MASK+=" "$(unset LD_LIBRARY_MASK; portageq envvar LD_LIBRARY_MASK)
1074 if [[ -d /etc/revdep-rebuild ]]; then
1075 for configfile in /etc/revdep-rebuild/*; do
1076 SEARCH_DIRS+=" "$(. $configfile; echo $SEARCH_DIRS)
1077 SEARCH_DIRS_MASK+=" "$(. $configfile; echo $SEARCH_DIRS_MASK)
1078 LD_LIBRARY_MASK+=" "$(. $configfile; echo $LD_LIBRARY_MASK)
1081 SEARCH_DIRS+=" /bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*"
1082 SEARCH_DIRS_MASK+=" /opt/OpenOffice /usr/lib/openoffice"
1083 LD_LIBRARY_MASK+=" libodbcinst.so libodbc.so libjava.so libjvm.so"
1086 # Get the ROOTPATH and PATH from /etc/profile.env
1087 if [[ -r "/etc/profile.env" && -s "/etc/profile.env" ]]; then
1088 SEARCH_DIRS+=" "$(. /etc/profile.env; /usr/bin/tr ':' ' ' <<< "$ROOTPATH $PATH")
1091 # Get the directories from /etc/ld.so.conf
1092 if [[ -r /etc/ld.so.conf && -s /etc/ld.so.conf ]]; then
1093 SEARCH_DIRS+=" "$(parse_ld_so_conf)
1096 # Set the final variables
1097 SEARCH_DIRS=$(clean_var <<< "$SEARCH_DIRS")
1098 SEARCH_DIRS_MASK=$(clean_var <<< "$SEARCH_DIRS_MASK")
1099 LD_LIBRARY_MASK=$(clean_var <<< "$LD_LIBRARY_MASK")
1100 # Filter masked paths from SEARCH_DIRS
1101 for sdir in ${SEARCH_DIRS} ; do
1103 for mdir in ${SEARCH_DIRS_MASK}; do
1104 [[ ${sdir} == ${mdir}/* ]] && skip_me=1 && break
1106 [[ -n ${skip_me} ]] || filter_SEARCH_DIRS+=" ${sdir}"
1108 SEARCH_DIRS=$(clean_var <<< "${filter_SEARCH_DIRS}")
1109 [[ $SEARCH_DIRS ]] || die 1 "No search defined -- this is a bug."
1112 # Rebuild packages owning broken binaries
1114 if [[ -r $ORDER_FILE && -s $ORDER_FILE ]]; then
1115 REBUILD_LIST=( $(<"$ORDER_FILE") )
1116 REBUILD_LIST="${REBUILD_LIST[@]/#/=}"
1118 REBUILD_LIST=$(sort -u "$EBUILDS_FILE")
1121 trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
1123 [[ $QUIET -ne 1 ]] && einfo 'All prepared. Starting rebuild'
1124 echo "emerge --oneshot ${EMERGE_DEFAULT_OPTS} ${EMERGE_OPTIONS[@]} $REBUILD_LIST"
1126 is_real_merge && countdown 10
1128 # Link file descriptor #6 with stdin so --ask will work
1131 # Run in background to correctly handle Ctrl-C
1133 emerge --oneshot ${EMERGE_DEFAULT_OPTS} ${EMERGE_OPTIONS[@]} $REBUILD_LIST <&6
1134 echo $? > "$STATUS_FILE"
1138 # Now restore stdin from fd #6, where it had been saved, and close fd #6 ( 6<&- ) to free it for other processes to use.
1144 if [[ (( $(<"$STATUS_FILE") != 0 )) && ! is_real_merge ]]; then
1146 ewarn "$APP_NAME failed to emerge all packages."
1147 ewarn 'you have the following choices:'
1148 einfo "- If emerge failed during the build, fix the problems and re-run $APP_NAME."
1149 einfo '- Use /etc/portage/package.keywords to unmask a newer version of the package.'
1150 einfo " (and remove $ORDER_FILE to be evaluated again)"
1151 einfo '- Modify the above emerge command and run it manually.'
1152 einfo '- Compile or unmerge unsatisfied packages manually,'
1153 einfo ' remove temporary files, and try again.'
1154 einfo ' (you can edit package/ebuild list first)'
1156 einfo 'To remove temporary files, please run:'
1157 einfo "rm ${WORKING_DIR}/*.rr"
1160 elif is_real_merge; then
1162 eerror "terminated. Please remove the temporary files manually:"
1163 eerror "rm ${WORKING_DIR}/*.rr"
1166 [[ "${SKIP_LIST[@]}" != "" ]] && list_skipped_packages
1167 trap trap_cmd SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
1168 einfo 'Build finished correctly. Removing temporary files...'
1170 einfo 'You can re-run revdep-rebuild to verify that all libraries and binaries'
1171 einfo 'are fixed. Possible reasons for remaining inconsistencies include:'
1172 einfo ' orphaned files'
1173 einfo ' deep dependencies'
1174 einfo " packages installed outside of portage's control"
1175 einfo ' specially-evaluated libraries'
1176 if [[ -r "$OWNERS_FILE" && -s "$OWNERS_FILE" ]]; then
1179 [[ $KEEP_TEMP ]] || rm -f "${FILES[@]}"
1181 einfo 'Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.'