2 # Copyright 1999-2007 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
16 # Must-be-blank variables:
20 declare -r APP_NAME="${0##*/}" # The name of this application
21 declare -r OIFS="$IFS" # Save the IFS
23 # "Boolean" variables: Considered "true" if it has any value at all
24 # "True" indicates we should...
25 declare FULL_LD_PATH # ...search across the COMPLETE_LD_LIBRARY_PATH
26 declare KEEP_TEMP # ...not delete tempfiles from the current run
27 declare ORDER_PKGS # ...sort the atoms in deep dependency order
28 declare PACKAGE_NAMES # ...emerge by slot, not by versionated atom
29 declare RM_OLD_TEMPFILES # ...remove tempfiles from prior runs
30 declare SEARCH_BROKEN # ...search for broken libraries and binaries
31 declare VERBOSE # ...give verbose output
33 # Globals that impact portage directly:
34 declare EMERGE_DEFAULT_OPTS # String of options portage assumes to be set
35 declare EMERGE_OPTIONS # Array of options to pass to portage
36 declare PORTAGE_NICENESS # Renice to this value
37 declare PORTAGE_ROOT # The root path for portage
39 # Customizable incremental variables:
40 # These variables can be prepended to either by setting the variable in
41 # your environment prior to execution, or by placing an entry in
44 # An entry of "-*" means to clear the variable from that point forward.
45 # Example: env SEARCH_DIRS="/usr/bin -*" revdep-rebuild will set SEARCH_DIRS
46 # to contain only /usr/bin
47 declare LD_LIBRARY_MASK # Mask of specially evaluated libraries
48 declare SEARCH_DIRS # List of dirs to search for executables and libraries
49 declare SEARCH_DIRS_MASK # List of dirs not to search
52 declare OLDPROG # Previous pass through the progress meter
53 declare EXACT_PKG # Versionated atom to emerge
54 declare HEAD_TEXT # Feedback string about the search
55 declare LIST # Prefix for temporary filenames
56 declare NOCOLOR # Set to "true" not to output term colors
57 declare OK_TEXT # Feedback about a search which found no errors
58 declare RC_NOCOLOR # Hack to insure we respect NOCOLOR
59 declare REBUILD_LIST # Array of atoms to emerge
60 declare SKIP_LIST # Array of atoms that cannot be emerged (masked?)
61 declare SONAME # Soname/soname path pattern given on commandline
62 declare SONAME_SEARCH # Value of SONAME modified to match ldd's output
63 declare WORKING_TEXT # Feedback about the search
64 declare ENV_FILE # A file containing environment variables
68 [[ $LIST && $APP_NAME ]] ||
69 die 1 '$LIST or $APP_NAME is not defined! (This is a bug.)'
71 [[ $i = -* || $i = *.$APP_NAME* ]] ||
72 die 1 "Oops, I'm not allowed to delete that. ($@)"
76 # Somewhat more portable find -executable
77 # FIXME/UNTESTED (I don't have access to all of the different versions of
79 # Usage: find PATH ARGS -- use find like normal, except use -executable instead
80 # of various versions of -perm /+ blah blah and hacks
82 hash find || { die 1 'find not found!'; }
83 # We can be pretty sure find itself should be executable.
84 local testsubject="$(type -P find)"
85 if [[ $(command find "$testsubject" -executable 2> /dev/null) ]]; then
86 unset -f find # We can just use the command find
87 elif [[ $(command find "$testsubject" -perm /u+x 2> /dev/null) ]]; then
89 a=(${@//-executable/-perm \/u+x})
90 a=(${a[@]//-writable/-perm \/u+w})
91 a=(${a[@]//-readable/-perm \/r+w})
92 command find "${a[@]}"
94 elif [[ $(command find "$testsubject" -perm +u+x 2> /dev/null) ]]; then
96 a=(${@//-executable/-perm +u+x})
97 a=(${a[@]//-writable/-perm +u+w})
98 a=(${a[@]//-readable/-perm +r+w})
99 command find "${a[@]}"
103 a=(${@//-executable/-exec test -x '{}' \;})
104 a=(${a[@]//-writable/-exec test -w '{}' \;})
105 a=(${a[@]//-readable/-exec test -r '{}' \;})
106 command find "${a[@]}"
113 Usage: $APP_NAME [OPTIONS] [--] [EMERGE_OPTIONS]
115 Broken reverse dependency rebuilder.
117 -C, --nocolor Turn off colored output
118 -d, --debug Print way too much information (uses bash's set -xv)
119 -e, --exact Emerge based on exact package version
120 -h, --help Print this usage
121 -i, --ignore Ignore temporary files from previous runs
122 -k, --keep-temp Do not delete temporary files on exit
123 -L, --library NAME Emerge existing packages that use the library with NAME
124 --library=NAME NAME can be a full path to the library or a basic
125 regular expression (man grep)
126 -l, --no-ld-path Do not set LD_LIBRARY_PATH
127 -o, --no-order Do not check the build order
128 (Saves time, but may cause breakage.)
129 -p, --pretend Do a trial run without actually emerging anything
130 (also passed to emerge command)
131 -P, --no-progress Turn off the progress meter
132 -q, --quiet Be less verbose (also passed to emerge command)
133 -v, --verbose Be more verbose (also passed to emerge command)
134 -u, --no-util UTIL Do not use features provided by UTIL
135 --no-util=UTIL UTIL can be one of portage-utils or pkgcore
136 or it can be a *quoted* space-delimited list.
138 Calls emerge, options after -- are ignored by $APP_NAME
139 and passed directly to emerge.
141 Report bugs to <http://bugs.gentoo.org>
144 # Usage: progress i n
146 # n: total number of items to process
150 local curProg=$(( $1 * 100 / $2 ))
151 (( curProg == OLDPROG )) && return # no change, output nothing
152 OLDPROG="$curProg" # must be a global variable
153 (( $1 == $2 )) && local lb=$'\n'
154 echo -ne '\r \r'"[ $curProg% ] $lb"
157 else # STDOUT is not a tty. Disable progress meter.
162 # n: number of seconds to count
165 for ((i=1; i<$1; i++)); do
171 # Get the name of a package owning a file on the filesystem using one of several
172 # utilities: This is a placeholder. The function is defined in get_opts()
173 get_file_owner() { :; }
174 # Replace whitespace with linebreaks, normalize repeated '/' chars, and sort -u
175 # (If any libs have whitespace in their filenames, someone needs punishment.)
177 awk 'BEGIN {RS="[[:space:]]"}
179 /[^[:space:]]/ {gsub(/\/\/+/, "/"); print}' | sort -u
181 # Exit and optionally output to sterr
188 # What to do when dynamic linking is consistent
190 [[ $KEEP_TEMP ]] || rm $LIST.?_*
192 einfo "$OK_TEXT... All done. "
197 # Check if various portage utils are allowed and installed
198 setup_get_file_owner() {
199 # portage-utils disabled until it is able to handle category names without
200 # a hyphen. See Bug #210386
201 # if [[ $avoid_utils != *portage-utils* ]] && hash qfile 2> /dev/null; then
202 # get_file_owner() { qfile -qvC "$@"; }
203 if [[ $avoid_utils != *pkgcore* ]] && hash pquery 2> /dev/null; then
204 get_file_owner() { local IFS=,; pquery --nocolor --owns="$*"; }
205 # equery disabled for incompatibility with modern portage.
206 # elif [[ $avoid_utils != *equery* ]] && hash equery 2> /dev/null; then
207 # get_file_owner() { equery -q -C b $@; }
211 # ${*/%/ } adds a space to the end of each object name to prevent false
212 # matches, for example /usr/bin/dia matching /usr/bin/dialog (bug #196460).
213 find -L /var/db/pkg -name CONTENTS -print0 |
214 xargs -0 grep -Fl "${*/%/ }" |
215 sed 's:/var/db/pkg/\(.*\)/CONTENTS:\1:'
221 # Normalize some EMERGE_OPTIONS
222 normalize_emerge_opts() {
223 # Normalize some EMERGE_OPTIONS
224 EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-p/--pretend})
225 EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-f/--fetchonly})
226 EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-f/--verbose})
230 # Use the color preference from portage
232 # This should still work if NOCOLOR is set by the -C flag or in the user's
234 export NOCOLOR=$(portageq envvar NOCOLOR)
235 [[ $NOCOLOR = yes || $NOCOLOR = true ]] && export RC_NOCOLOR=yes # HACK! (grr)
236 . /etc/init.d/functions.sh
240 # Die if an argument is missing.
241 die_if_missing_arg() {
242 [[ ! $2 || $2 = -* ]] && die 1 "Missing expected argument to $1"
246 # Die because an option is not recognized.
247 die_invalid_option() {
248 # We cannot use eerror and einfo because this gets called before function.sh
252 echo "Encountered unrecognized option $1." >&2
254 echo "$APP_NAME no longer automatically passes unrecognized options to portage."
255 echo "Separate emerge-only options from revdep-rebuild options with the -- flag."
261 # Warn about deprecated options.
262 warn_deprecated_opt() {
263 # We cannot use eerror and einfo because this gets called before function.sh
266 echo "Encountered deprecated option $1." >&2
267 [[ $2 ]] && echo "Please use $2 instead." >&2
271 # Get whole-word commandline options preceded by two dashes.
274 --nocolor) export NOCOLOR="yes";;
275 --no-color) warn_deprecated_opt "$1" "--nocolor"
276 export NOCOLOR="yes";;
278 --exact) unset PACKAGE_NAMES;;
281 --ignore) RM_OLD_TEMPFILES=1;;
282 --keep-temp) KEEP_TEMP=1;;
283 --library=*) # TODO: check for invalid values
285 unset SEARCH_BROKEN;;
286 --soname=*|--soname-regexp=*) # TODO: check for invalid values
287 warn_deprecated_opt "${1%=*}" "--library"
289 unset SEARCH_BROKEN;;
290 --library) # TODO: check for invalid values
291 die_if_missing_arg $1 $2
294 unset SEARCH_BROKEN;;
295 --soname|--soname-regexp) # TODO: check for invalid values
296 warn_deprecated_opt "$1" "--library"
297 die_if_missing_arg $1 $2
300 unset SEARCH_BROKEN;;
301 --no-ld-path) unset FULL_LD_PATH;;
302 --no-order) unset ORDER_PKGS;;
303 --no-progress) progress() { :; };;
304 --pretend) EMERGE_OPTIONS+=("--pretend");;
305 --quiet) echo_v() { :; }
308 EMERGE_OPTIONS+=($1);;
309 --no-util=*) # TODO: check for invalid values
310 avoid_utils="${1#*=}";;
311 --no-util) # TODO: check for invalid values
312 die_if_missing_arg $1 $2
316 EMERGE_OPTIONS+=("--verbose");;
317 --extra-verbose) warn_deprecated_opt "$1" "--verbose"
319 EMERGE_OPTIONS+=("--verbose");;
320 --package-names) # No longer used, since it is the
321 # default. We accept it for
322 # backwards compatibility.
323 warn_deprecated_opt "$1"
325 *) die_invalid_option $1;;
330 # Get single-letter commandline options preceded by a single dash.
332 local OPT OPTSTRING OPTARG OPTIND
333 while getopts ":CdehikL:loPpqu:vX" OPT; do
335 C) # TODO: Match syntax with the rest of gentoolkit
336 export NOCOLOR="yes";;
338 e) unset PACKAGE_NAMES;;
341 i) RM_OLD_TEMPFILES=1;;
343 L) # TODO: Check for invalid values
344 SONAME="${OPTARG#*=}"
345 unset SEARCH_BROKEN;;
346 l) unset FULL_LD_PATH;;
347 o) unset ORDER_PKGS;;
348 P) progress() { :; };;
349 p) EMERGE_OPTIONS+=("--pretend");;
353 EMERGE_OPTIONS+=("--quiet");;
354 u) avoid_utils="$1";; # TODO: Check for invalid values
356 EMERGE_OPTIONS+=("--verbose");;
357 X) # No longer used, since it is the default.
358 # We accept it for backwards compatibility.
359 warn_deprecated_opt "-X"
361 *) die_invalid_option "-$OPTARG";;
367 # Get command-line options.
371 echo_v() { ewarn "$@"; }
372 unset VERBOSE KEEP_TEMP EMERGE_OPTIONS RM_OLD_TEMPFILES
381 EMERGE_OPTIONS+=("$@")
386 [[ ${1:--} = -* ]] && break
388 if [[ ${args[0]} = --* ]]; then
389 get_longopts "${args[@]}"
391 get_shortopts "${args[@]}"
393 *) die_invalid_option "$1";;
400 normalize_emerge_opts
402 # If the user is not super, add --pretend to EMERGE_OPTIONS
403 if [[ ${EMERGE_OPTIONS[@]} != *--pretend* && $UID -ne 0 ]]; then
404 ewarn "You are not superuser. Adding --pretend to emerge options."
405 EMERGE_OPTIONS+=(--pretend)
410 [[ ${EMERGE_OPTIONS[@]} != *--pretend* &&
411 ${EMERGE_OPTIONS[@]} != *--fetchonly* ]]
416 einfo "Configuring search environment for $APP_NAME"
418 # Obey PORTAGE_NICENESS
419 PORTAGE_NICENESS=$(portageq envvar PORTAGE_NICENESS)
420 if [[ $PORTAGE_NICENESS ]]; then
421 renice $PORTAGE_NICENESS $$ > /dev/null
422 # Since we have already set our nice value for our processes,
423 # reset PORTAGE_NICENESS to zero to avoid having emerge renice again.
424 export PORTAGE_NICENESS="0"
427 PORTAGE_ROOT=$(portageq envvar ROOT)
428 PORTAGE_ROOT="${PORTAGE_ROOT:-/}"
430 # Update the incremental variables using /etc/profile.env, /etc/ld.so.conf,
431 # portage, and the environment
433 # Read the incremental variables from environment and portage
434 # Until such time as portage supports these variables as incrementals
435 # The value will be what is in /etc/make.conf
436 SEARCH_DIRS+=" "$(unset SEARCH_DIRS; portageq envvar SEARCH_DIRS)
437 SEARCH_DIRS_MASK+=" "$(unset SEARCH_DIRS_MASK; portageq envvar SEARCH_DIRS_MASK)
438 LD_LIBRARY_MASK+=" "$(unset LD_LIBRARY_MASK; portageq envvar LD_LIBRARY_MASK)
441 if [[ -d /etc/revdep-rebuild ]]; then
442 for ENV_FILE in /etc/revdep-rebuild/*; do
443 SEARCH_DIRS+=" "$(. $ENV_FILE; echo $SEARCH_DIRS)
444 SEARCH_DIRS_MASK+=" "$(. $ENV_FILE; echo $SEARCH_DIRS_MASK)
445 LD_LIBRARY_MASK+=" "$(. $ENV_FILE; echo $LD_LIBRARY_MASK)
447 unset ENV_FILE # HACK
449 SEARCH_DIRS+=" /bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*"
450 SEARCH_DIRS_MASK+=" /opt/OpenOffice /usr/lib/openoffice"
451 LD_LIBRARY_MASK+=" libodbcinst.so libodbc.so libjava.so libjvm.so"
454 # Get the ROOTPATH and PATH from /etc/profile.env
455 if [[ -r "/etc/profile.env" && -s "/etc/profile.env" ]]; then
456 SEARCH_DIRS+=" "$(. /etc/profile.env; /usr/bin/tr ':' ' ' <<< "$ROOTPATH $PATH")
459 # Get the directories from /etc/ld.so.conf
460 if [[ -r /etc/ld.so.conf && -s /etc/ld.so.conf ]]; then
461 SEARCH_DIRS+=" "$(sed '/^#/d;s/#.*$//' /etc/ld.so.conf)
464 # Set the final variables
465 SEARCH_DIRS=$(clean_var <<< "$SEARCH_DIRS")
466 SEARCH_DIRS_MASK=$(clean_var <<< "$SEARCH_DIRS_MASK")
467 LD_LIBRARY_MASK=$(clean_var <<< "$LD_LIBRARY_MASK")
468 # Filter masked paths from SEARCH_DIRS
470 for sdir in ${SEARCH_DIRS} ; do
472 for mdir in ${SEARCH_DIRS_MASK} ; do
473 [[ ${sdir} == ${mdir}/* ]] \
474 && skip_me=1 && break
476 [[ -n ${skip_me} ]] || filter_SEARCH_DIRS+=" ${sdir}"
478 SEARCH_DIRS=$(clean_var <<< "${filter_SEARCH_DIRS}")
479 unset sdir mdir skip_me filter_SEARCH_DIRS
480 [[ $SEARCH_DIRS ]] || die 1 "No search defined -- this is a bug."
483 trap "rm_temp $1" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
487 die 1 $' ...terminated. Removing incomplete '"$1."
492 # Find a place to put temporary files
493 # TODO; let the user choose where to put tempfiles
494 # gfind $HOME/ /var/tmp/ /tmp/ -writable -print -quit
495 # HACK: This is a rather noisy, but portable way to implement -quit
498 done < <(find $HOME/ /var/tmp/ /tmp/ -writable -print)
500 die 1 "Unable to find a satisfactory location for temporary files"
503 if [[ $SEARCH_BROKEN ]]; then
504 SONAME_SEARCH="$SONAME"
505 HEAD_TEXT="broken by a package update"
506 OK_TEXT="Dynamic linking on your system is consistent"
507 WORKING_TEXT="consistency"
509 # first case is needed to test against /path/to/foo.so
510 if [[ $SONAME = /* ]]; then
511 # Set to "<space>$SONAME<space>"
512 SONAME_SEARCH=" $SONAME "
513 # Escape the "/" characters
514 SONAME_SEARCH="${SONAME_SEARCH//\//\\/}"
516 # Set to "<tab>$SONAME<space>"
517 SONAME_SEARCH=$'\t'"$SONAME "
519 local uuid="${SONAME##*/}"
520 uuid="${uuid//[[:space:]]}"
522 HEAD_TEXT="using $SONAME"
523 OK_TEXT="There are no dynamic links to $SONAME"
527 # If any of our temporary files are older than 1 day, remove them all
528 if [[ ! $KEEP_TEMP ]]; then
532 done < <(find -L "$LIST."* -maxdepth 0 -type f -mmin +1440 -print 2>/dev/null)
535 # Compare old and new environments
536 # Don't use our previous files if environment doesn't match
538 # We do not care if these emerge options change
539 EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--pretend/})
540 EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--fetchonly/})
541 EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--verbose/})
543 SEARCH_DIRS="$SEARCH_DIRS"
544 SEARCH_DIRS_MASK="$SEARCH_DIRS_MASK"
545 LD_LIBRARY_MASK="$LD_LIBRARY_MASK"
546 PORTAGE_ROOT="$PORTAGE_ROOT"
547 EMERGE_OPTIONS="${EMERGE_OPTIONS[@]}"
548 ORDER_PKGS="$ORDER_PKGS"
549 FULL_LD_PATH="$FULL_LD_PATH"
552 if [[ -r $LIST.0_env && -s $LIST.0_env ]]; then
553 old_env=$(<"$LIST.0_env")
554 if [[ $old_env != $new_env ]]; then
555 ewarn 'Environment mismatch from previous run, deleting temporary files...'
559 # No 0_env file found, silently delete any other tempfiles that may exist
563 # If we should remove old tempfiles, do so
564 [[ $RM_OLD_TEMPFILES ]] && rm -f "$LIST."*
566 # Save the environment in a file for next time
567 echo "$new_env" > "$LIST.0_env"
569 [[ $VERBOSE ]] && echo $'\n'"$APP_NAME environment:"$'\n'"$new_env"
572 einfo "Checking reverse dependencies"
573 einfo "Packages containing binaries and libraries $HEAD_TEXT"
574 einfo "will be emerged."
577 einfo "Collecting system binaries and libraries"
578 if [[ -r $LIST.1_files && -s $LIST.1_files ]]; then
579 einfo "Found existing $LIST.1_files"
581 # Be safe and remove any extraneous temporary files
586 if [[ $SEARCH_DIRS_MASK ]]; then
587 findMask=($SEARCH_DIRS_MASK)
588 findMask="${findMask[@]/#/-o -path }"
589 findMask="( ${findMask#-o } ) -prune -o"
591 find ${SEARCH_DIRS[@]} $findMask -type f \( -executable -o \
592 -name '*.so' -o -name '*.so.*' -o -name '*.la' \) -print 2> /dev/null |
593 sort -u > "$LIST.1_files" ||
594 die $? "find failed to list binary files (This is a bug.)"
595 einfo "Generated new $LIST.1_files"
599 local COMPLETE_LD_LIBRARY_PATH
600 [[ $SEARCH_BROKEN && $FULL_LD_PATH ]] || return
601 einfo 'Collecting complete LD_LIBRARY_PATH'
602 if [[ -r $LIST.2_ldpath && -s $LIST.2_ldpath ]] ; then
603 einfo "Found existing $LIST.2_ldpath."
605 set_trap "$LIST.2_ldpath"
606 # Ensure that the "trusted" lib directories are at the start of the path
607 COMPLETE_LD_LIBRARY_PATH=(
610 $(sed '/^#/d;s/#.*$//' < /etc/ld.so.conf)
611 $(sed 's:/[^/]*$::' < "$LIST.1_files" | sort -ru)
614 COMPLETE_LD_LIBRARY_PATH="${COMPLETE_LD_LIBRARY_PATH[*]}"
616 echo "$COMPLETE_LD_LIBRARY_PATH" > "$LIST.2_ldpath"
617 einfo "Generated new $LIST.2_ldpath"
627 local COMPLETE_LD_LIBRARY_PATH
628 if [[ $SEARCH_BROKEN && $FULL_LD_PATH ]]; then
629 [[ -r $LIST.2_ldpath && -s $LIST.2_ldpath ]] || die 1 "unable to find $LIST.2_ldpath"
630 COMPLETE_LD_LIBRARY_PATH=$(<"$LIST.2_ldpath")
632 einfo "Checking dynamic linking $WORKING_TEXT"
633 if [[ -r $LIST.3_rebuild && -s $LIST.3_rebuild ]]; then
634 einfo "Found existing $LIST.3_rebuild."
636 [[ $LIST ]] || die 1 "$LIST" 'is undefined! (This is a bug.)'
637 set_trap "$LIST.3_rebuild"
638 set_trap "$LIST.3_ldd_errors"
640 files=($(<"$LIST.1_files"))
641 numFiles="${#files[@]}"
642 for target_file in "${files[@]}"; do
643 if [[ $target_file != *.la ]]; then
644 # Note: double checking seems to be faster than single with complete path
645 # (special add ons are rare).
646 ldd_output=$(ldd "$target_file" 2>> "$LIST.3_ldd_errors" | sort -u)
647 ldd_status=$? # TODO: Check this for problems with sort
648 # HACK: if LD_LIBRARY_MASK is null or undefined grep -vF doesn't work
649 if grep -vF "${LD_LIBRARY_MASK:=$'\a'}" <<< "$ldd_output" |
650 grep -q "$SONAME_SEARCH"; then
651 if [[ $SEARCH_BROKEN && $FULL_LD_PATH ]]; then
652 if LD_LIBRARY_PATH="$COMPLETE_LD_LIBRARY_PATH" ldd "$target_file" 2>/dev/null |
653 grep -vF "$LD_LIBRARY_MASK" | grep -q "$SONAME_SEARCH"; then
654 # FIXME: I hate duplicating code
655 # Only build missing direct dependencies
657 expr='s/[[:space:]]*\([^[:space:]]*\) => not found/\1/p'
658 sed -n "$expr" <<< "$ldd_output"
661 expr='s/^[[:space:]]*NEEDED[[:space:]]*\([^[:space:]]*\).*/\1/p';
662 objdump -x "$target_file" | grep NEEDED | sed "$expr" | sort -u
664 MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS")
665 if [[ $MISSING_LIBS ]]; then
666 echo "obj $target_file" >> "$LIST.3_rebuild"
667 echo_v " broken $target_file (requires $MISSING_LIBS)"
671 # FIXME: I hate duplicating code
672 # Only rebuild for direct dependencies
674 expr="/$SONAME_SEARCH/s/^[[:space:]]*\([^[:space:]]*\).*$/\1/p"
675 sort -u <<< "$ldd_output" | sed -n "$expr"
678 expr='s/^[[:space:]]*NEEDED[[:space:]]*\([^[:space:]]*\).*/\1/p';
679 objdump -x "$target_file" | grep NEEDED | sed "$expr" | sort -u
681 MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS")
682 if [[ $MISSING_LIBS ]]; then
683 echo "obj $target_file" >> "$LIST.3_rebuild"
684 if [[ $SEARCH_BROKEN ]]; then
685 echo_v " broken $target_file (requires $MISSING_LIBS)"
687 echo_v " found $target_file"
692 elif [[ $SEARCH_BROKEN ]]; then
693 # Look for broken .la files
695 awk -F"[=']" '/^dependency_libs/{
696 gsub("^-[^[:space:]]*", "", $3);
697 gsub("[[:space:]]-[^[:space:]]*", "", $3);
701 if [[ $depend = /* && ! -e $depend ]]; then
702 echo "obj $target_file" >> "$LIST.3_rebuild"
703 echo_v " broken $target_file (requires $depend)"
708 progress $((++i)) $numFiles $target_file ||
709 progress $((++i)) $numFiles
711 if [[ $SEARCH_BROKEN ]]; then
712 # Look for missing version
713 while read target_file; do
714 echo "obj $target_file" >> "$LIST.3_rebuild"
715 echo_v " broken $target_file (no version information available)"
717 # Regexify LD_LIBRARY_MASK. Exclude it from the search.
718 LD_LIBRARY_MASK="${LD_LIBRARY_MASK//$'\n'/|}"
719 awk -v ldmask="(${LD_LIBRARY_MASK//./\\\.})" '
720 /no version information available/ && $0 !~ ldmask {
721 gsub(/[()]/, "", $NF)
722 if (seen[$NF]++) next
724 }' "$LIST.3_ldd_errors"
727 [[ -r $LIST.3_rebuild && -s $LIST.3_rebuild ]] || clean_exit
728 einfo "Generated new $LIST.3_rebuild"
736 einfo 'Assigning files to packages'
737 if [[ -r $LIST.4_packages_raw && -s $LIST.4_packages_raw ]]; then
738 einfo "Found existing $LIST.4_packages_raw"
740 set_trap "$LIST.4_packages*"
742 while read obj target_file; do
743 EXACT_PKG=$(get_file_owner $target_file)
744 if [[ $EXACT_PKG ]]; then
745 # Strip version information
746 PKG="${EXACT_PKG%%-r[[:digit:]]*}"
748 echo "$EXACT_PKG" >> $LIST.4_packages_raw
749 echo "$target_file -> $EXACT_PKG" >> $LIST.4_package_owners
750 echo_v " $target_file -> $PKG"
752 ewarn " !!! $target_file not owned by any package is broken !!!"
753 echo "$target_file -> (none)" >> $LIST.4_package_owners
754 echo_v " $target_file -> (none)"
756 done < "$LIST.3_rebuild"
757 einfo "Generated new $LIST.4_packages_raw and $LIST.4_package_owners"
759 # if we find '(none)' on every line, exit out
760 if ! grep -qvF '(none)' "$LIST.4_package_owners"; then
761 ewarn "Found some broken files, but none of them were associated with known packages"
762 ewarn "Unable to proceed with automatic repairs."
763 ewarn "The broken files are listed in $LIST.4_package_owners"
764 if [[ $VERBOSE ]]; then
765 ewarn "The broken files are:"
766 while read filename junk; do
768 done < "$LIST.4_package_owners"
770 exit 0 # FIXME: Should we exit 1 here?
774 einfo 'Cleaning list of packages to rebuild'
775 if [[ -r $LIST.4_packages && -s $LIST.4_packages ]]; then
776 einfo "Found existing $LIST.4_packages"
778 sort -u $LIST.4_packages_raw > $LIST.4_packages
779 einfo "Generated new $LIST.4_packages"
782 assign_packages_to_ebuilds() {
786 einfo 'Assigning packages to ebuilds'
787 if [[ -r $LIST.4_ebuilds && -s $LIST.4_ebuilds ]]; then
788 einfo "Found existing $LIST.4_ebuilds"
789 elif [[ -r $LIST.4_packages && -s $LIST.4_packages ]]; then
790 set_trap "$LIST.4_ebuilds"
791 while read EXACT_PKG; do
793 PKG="${EXACT_PKG%%-r[[:digit:]]*}"
795 SLOT=$(</var/db/pkg/$EXACT_PKG/SLOT)
797 done < "$LIST.4_packages" > "$LIST.4_ebuilds"
798 einfo "Generated new $LIST.4_ebuilds"
800 einfo 'Nothing to rebuild.'
801 die 1 '(The program should have already quit, so this is a minor bug.)'
804 get_exact_ebuilds() {
805 einfo 'Assigning files to ebuilds'
806 if [[ -r $LIST.4_ebuilds && -s $LIST.4_ebuilds ]]; then
807 einfo "Found existing $LIST.4_ebuilds"
808 elif [[ -r $LIST.3_rebuild && -s $LIST.3_rebuild ]]; then
809 rebuildList=" $(<"$LIST.3_rebuild") "
810 rebuildList=(${rebuildList//[[:space:]]obj[[:space:]]/ })
811 get_file_owner "${rebuildList[@]}" | sed 's/^/=/' > "$LIST.4_ebuilds"
812 einfo "Generated new $LIST.4_ebuilds"
814 einfo 'Nothing to rebuild.'
815 die 1 '(The program should have already quit, so this is a minor bug.)'
818 list_skipped_packages() {
820 ewarn 'Portage could not find any version of the following packages it could build:'
821 ewarn "${SKIP_LIST[@]}"
823 ewarn '(Perhaps they are masked, blocked, or removed from portage.)'
824 ewarn 'Try to emerge them manually.'
828 local -r OLD_EMERGE_DEFAULT_OPTS="$EMERGE_DEFAULT_OPTS"
829 local RAW_REBUILD_LIST
832 if [[ ! $ORDER_PKGS ]]; then
833 einfo 'Skipping package ordering'
836 einfo 'Evaluating package order'
837 if [[ -r $LIST.5_order && -s $LIST.5_order ]]; then
838 einfo "Found existing $LIST.5_order"
840 set_trap "$LIST.5_order"
841 RAW_REBUILD_LIST=$(<"$LIST.4_ebuilds")
842 if [[ $RAW_REBUILD_LIST ]]; then
843 export EMERGE_DEFAULT_OPTS="--nospinner --pretend --oneshot --quiet"
844 RAW_REBUILD_LIST=($RAW_REBUILD_LIST) # convert into array
845 # If PACKAGE_NAMES is defined we're using slots, not versions
846 if [[ $PACKAGE_NAMES ]]; then
847 # Eliminate atoms that can't be built
848 for i in "${!RAW_REBUILD_LIST[@]}"; do
849 if [[ "${RAW_REBUILD_LIST[i]}" = *[A-Za-z]* ]]; then
850 portageq best_visible "$PORTAGE_ROOT" "${RAW_REBUILD_LIST[i]}" >/dev/null && continue
851 SKIP_LIST+=("${RAW_REBUILD_LIST[i]}")
853 unset RAW_REBUILD_LIST[i]
855 # If RAW_REBUILD_LIST is empty, then we have nothing to build.
856 if (( ${#RAW_REBUILD_LIST[@]} == 0 )); then
857 if (( ${#SKIP_LIST[@]} == 0 )); then
858 ewarn "The list of packages to skip is empty, but there are no"
859 ewarn "packages listed to rebuild either. This is a bug."
861 list_skipped_packages
863 die 1 'Warning: Portage cannot rebuild any of the necessary packages.'
866 RAW_REBUILD_LIST=("${RAW_REBUILD_LIST[@]/#/=}")
868 RAW_REBUILD_LIST="${RAW_REBUILD_LIST[@]}"
869 REBUILD_GREP=$(emerge --nodeps $RAW_REBUILD_LIST | sed 's/\[[^]]*\]//g')
870 if (( ${PIPESTATUS[0]} == 0 )); then
871 emerge --deep $RAW_REBUILD_LIST |
872 sed 's/\[[^]]*\]//g' |
873 grep -F "$REBUILD_GREP" > $LIST.5_order
876 # Here we use the PIPESTATUS from the second emerge, the --deep one.
877 if (( ${PIPESTATUS[0]} != 0 )); then
879 eerror 'Warning: Failed to resolve package order.'
880 eerror 'Will merge in arbitrary order'
884 - An ebuild is no longer in the portage tree.
885 - An ebuild is masked, use /etc/portage/packages.keyword
886 and/or /etc/portage/package.unmask to unmask it
889 rm -f "$LIST.5_order"
891 export EMERGE_DEFAULT_OPTS="$OLD_EMERGE_DEFAULT_OPTS"
893 einfo 'Nothing to rebuild.'
894 die 1 '(The program should have already quit, so this is a minor bug.)'
897 [[ -r $LIST.5_order && -s $LIST.5_order ]] && einfo "Generated new $LIST.5_order"
908 if [[ $PACKAGE_NAMES ]]; then
913 assign_packages_to_ebuilds
921 # Clean up no longer needed environment variables
922 unset SEARCH_DIRS SEARCH_DIRS_MASK LD_LIBRARY_MASK PORTAGE_ROOT
924 if [[ -r $LIST.5_order && -s $LIST.5_order ]]; then
925 REBUILD_LIST=( $(<"$LIST.5_order") )
926 REBUILD_LIST="${REBUILD_LIST[@]/#/=}"
928 REBUILD_LIST=$(sort -u "$LIST.4_ebuilds")
931 trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
933 einfo 'All prepared. Starting rebuild'
934 echo "emerge --oneshot ${EMERGE_OPTIONS[@]} $REBUILD_LIST"
936 is_real_merge && countdown 10
938 # Link file descriptor #6 with stdin so --ask will work
941 # Run in background to correctly handle Ctrl-C
943 EMERGE_DEFAULT_OPTS="--oneshot ${EMERGE_OPTIONS[@]}" emerge $REBUILD_LIST <&6
944 echo $? > $LIST.6_status
948 # Now restore stdin from fd #6, where it had been saved, and close fd #6 ( 6<&- ) to free it for other processes to use.
951 show_unowned_files() {
952 if grep -qF '(none)' "$LIST.4_package_owners"; then
953 ewarn "Found some broken files that weren't associated with known packages"
954 ewarn "The broken files are:"
955 while read filename junk; do
956 [[ $junk = *none* ]] && ewarn " $filename"
957 done < "$LIST.4_package_owners" | awk '!s[$0]++' # (omit dupes)
961 if (( $(<"$LIST.6_status") != 0 )); then
963 ewarn "$APP_NAME failed to emerge all packages."
964 ewarn 'you have the following choices:'
965 einfo "- If emerge failed during the build, fix the problems and re-run $APP_NAME."
966 einfo '- Use /etc/portage/package.keywords to unmask a newer version of the package.'
967 einfo " (and remove $LIST.5_order to be evaluated again)"
968 einfo '- Modify the above emerge command and run it manually.'
969 einfo '- Compile or unmerge unsatisfied packages manually,'
970 einfo ' remove temporary files, and try again.'
971 einfo ' (you can edit package/ebuild list first)'
973 einfo 'To remove temporary files, please run:'
974 einfo "rm $LIST*.?_*"
977 elif is_real_merge; then
979 eerror "terminated. Please remove the temporary files manually:"
980 eerror "rm $LIST*.?_*"
983 (( "${#SKIP_LIST[@]}" != 0 )) && list_skipped_packages
984 trap trap_cmd SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
985 einfo 'Build finished correctly. Removing temporary files...'
987 einfo 'You can re-run revdep-rebuild to verify that all libraries and binaries'
988 einfo 'are fixed. If some inconsistency remains, it can be orphaned file, deep'
989 einfo 'dependency, binary package or specially evaluated library.'
990 if [[ -r "$LIST.4_package_owners" && -s "$LIST.4_package_owners" ]]; then
993 [[ $KEEP_TEMP ]] || rm $LIST*.?_*
995 einfo 'Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.'