2 # Copyright 1999-2008 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
22 declare -r ENV_FILE=0_env.rr # Contains environment variables
23 declare -r FILES_FILE=1_files.rr # Contains a list of files to search
24 declare -r LDPATH_FILE=2_ldpath.rr # Contains the LDPATH
25 declare -r BROKEN_FILE=3_broken.rr # Contains the list of broken files
26 declare -r ERRORS_FILE=3_errors.rr # Contains the ldd error output
27 declare -r RAW_FILE=4_raw.rr # Contains the raw list of packages
28 declare -r OWNERS_FILE=4_owners.rr # Contains the file owners
29 declare -r PKGS_FILE=4_pkgs.rr # Contains the unsorted bare package names
30 declare -r EBUILDS_FILE=4_ebuilds.rr # Contains the unsorted atoms
31 # (Appropriately slotted or versioned)
32 declare -r ORDER_FILE=5_order.rr # Contains the sorted atoms
33 declare -r STATUS_FILE=6_status.rr # Contains the ldd error output
48 # "Boolean" variables: Considered "true" if it has any value at all
49 # "True" indicates we should...
50 declare FULL_LD_PATH # ...search across the COMPLETE_LD_LIBRARY_PATH
51 declare KEEP_TEMP # ...not delete tempfiles from the current run
52 declare ORDER_PKGS # ...sort the atoms in deep dependency order
53 declare PACKAGE_NAMES # ...emerge by slot, not by versionated atom
54 declare RM_OLD_TEMPFILES # ...remove tempfiles from prior runs
55 declare SEARCH_BROKEN # ...search for broken libraries and binaries
56 declare VERBOSE # ...give verbose output
58 # Globals that impact portage directly:
59 declare EMERGE_DEFAULT_OPTS # String of options portage assumes to be set
60 declare EMERGE_OPTIONS # Array of options to pass to portage
61 declare PORTAGE_NICENESS # Renice to this value
62 declare PORTAGE_ROOT # The root path for portage
64 # Customizable incremental variables:
65 # These variables can be prepended to either by setting the variable in
66 # your environment prior to execution, or by placing an entry in
69 # An entry of "-*" means to clear the variable from that point forward.
70 # Example: env SEARCH_DIRS="/usr/bin -*" revdep-rebuild will set SEARCH_DIRS
71 # to contain only /usr/bin
72 declare LD_LIBRARY_MASK # Mask of specially evaluated libraries
73 declare SEARCH_DIRS # List of dirs to search for executables and libraries
74 declare SEARCH_DIRS_MASK # List of dirs not to search
77 declare OLDPROG # Previous pass through the progress meter
78 declare EXACT_PKG # Versionated atom to emerge
79 declare HEAD_TEXT # Feedback string about the search
80 declare NOCOLOR # Set to "true" not to output term colors
81 declare OK_TEXT # Feedback about a search which found no errors
82 declare RC_NOCOLOR # Hack to insure we respect NOCOLOR
83 declare REBUILD_LIST # Array of atoms to emerge
84 declare SKIP_LIST # Array of atoms that cannot be emerged (masked?)
85 declare SONAME # Soname/soname path pattern given on commandline
86 declare SONAME_SEARCH # Value of SONAME modified to match ldd's output
87 declare WORKING_TEXT # Feedback about the search
90 # Refuse to delete anything before we cd to our tmpdir
91 # (See mkdir_and_cd_to_tmpdir()
93 eerror "I was instructed to rm '$@'"
94 die 1 "Refusing to delete anything before changing to temporary directory."
96 # Somewhat more portable find -executable
97 # FIXME/UNTESTED (I don't have access to all of the different versions of
99 # Usage: find PATH ARGS -- use find like normal, except use -executable instead
100 # of various versions of -perm /+ blah blah and hacks
102 hash find || { die 1 'find not found!'; }
103 # We can be pretty sure find itself should be executable.
104 local testsubject="$(type -P find)"
105 if [[ $(command find "$testsubject" -executable 2> /dev/null) ]]; then
106 unset -f find # We can just use the command find
107 elif [[ $(command find "$testsubject" -perm /u+x 2> /dev/null) ]]; then
109 a=(${@//-executable/-perm \/u+x})
110 a=(${a[@]//-writable/-perm \/u+w})
111 a=(${a[@]//-readable/-perm \/r+w})
112 command find "${a[@]}"
114 elif [[ $(command find "$testsubject" -perm +u+x 2> /dev/null) ]]; then
116 a=(${@//-executable/-perm +u+x})
117 a=(${a[@]//-writable/-perm +u+w})
118 a=(${a[@]//-readable/-perm +r+w})
119 command find "${a[@]}"
123 a=(${@//-executable/-exec test -x '{}' \; -print})
124 a=(${a[@]//-writable/-exec test -w '{}' \; -print})
125 a=(${a[@]//-readable/-exec test -r '{}' \; -print})
126 command find "${a[@]}"
133 Usage: $APP_NAME [OPTIONS] [--] [EMERGE_OPTIONS]
135 Broken reverse dependency rebuilder.
137 -C, --nocolor Turn off colored output
138 -d, --debug Print way too much information (uses bash's set -xv)
139 -e, --exact Emerge based on exact package version
140 -h, --help Print this usage
141 -i, --ignore Ignore temporary files from previous runs
142 -k, --keep-temp Do not delete temporary files on exit
143 -L, --library NAME Emerge existing packages that use the library with NAME
144 --library=NAME NAME can be a full path to the library or a basic
145 regular expression (man grep)
146 -l, --no-ld-path Do not set LD_LIBRARY_PATH
147 -o, --no-order Do not check the build order
148 (Saves time, but may cause breakage.)
149 -p, --pretend Do a trial run without actually emerging anything
150 (also passed to emerge command)
151 -P, --no-progress Turn off the progress meter
152 -q, --quiet Be less verbose (also passed to emerge command)
153 -v, --verbose Be more verbose (also passed to emerge command)
154 -u, --no-util UTIL Do not use features provided by UTIL
155 --no-util=UTIL UTIL can be one of portage-utils or pkgcore
156 or it can be a *quoted* space-delimited list.
158 Calls emerge, options after -- are ignored by $APP_NAME
159 and passed directly to emerge.
161 Report bugs to <http://bugs.gentoo.org>
164 # Usage: progress i n
166 # n: total number of items to process
170 local curProg=$(( $1 * 100 / $2 ))
171 (( curProg == OLDPROG )) && return # no change, output nothing
172 OLDPROG="$curProg" # must be a global variable
173 (( $1 == $2 )) && local lb=$'\n'
174 echo -ne '\r \r'"[ $curProg% ] $lb"
177 else # STDOUT is not a tty. Disable progress meter.
182 # n: number of seconds to count
185 for ((i=1; i<$1; i++)); do
191 # Get the name of a package owning a file on the filesystem using one of several
192 # utilities: This is a placeholder. The function is defined in get_opts()
193 get_file_owner() { :; }
194 # Replace whitespace with linebreaks, normalize repeated '/' chars, and sort -u
195 # (If any libs have whitespace in their filenames, someone needs punishment.)
197 awk 'BEGIN {RS="[[:space:]]"}
199 /[^[:space:]]/ {gsub(/\/\/+/, "/"); print}' | sort -u
201 # Exit and optionally output to sterr
208 # What to do when dynamic linking is consistent
210 [[ $KEEP_TEMP ]] || rm -f "${FILES[@]}"
212 einfo "$OK_TEXT... All done. "
217 # Check if various portage utils are allowed and installed
218 setup_get_file_owner() {
219 # portage-utils disabled until it is able to handle category names without
220 # a hyphen. See Bug #210386
221 # if [[ $avoid_utils != *portage-utils* ]] && hash qfile 2> /dev/null; then
222 # get_file_owner() { qfile -qvC "$@"; }
223 if [[ $avoid_utils != *pkgcore* ]] && hash pquery 2> /dev/null; then
224 get_file_owner() { local IFS=,; pquery --nocolor --owns="$*"; }
225 # equery disabled for incompatibility with modern portage.
226 # elif [[ $avoid_utils != *equery* ]] && hash equery 2> /dev/null; then
227 # get_file_owner() { equery -q -C b $@; }
231 # ${*/%/ } adds a space to the end of each object name to prevent false
232 # matches, for example /usr/bin/dia matching /usr/bin/dialog (bug #196460).
233 find -L /var/db/pkg -name CONTENTS -print0 |
234 xargs -0 grep -Fl "${*/%/ }" |
235 sed 's:/var/db/pkg/\(.*\)/CONTENTS:\1:'
241 # Normalize some EMERGE_OPTIONS
242 normalize_emerge_opts() {
243 # Normalize some EMERGE_OPTIONS
244 EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-p/--pretend})
245 EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-f/--fetchonly})
246 EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-f/--verbose})
250 # Use the color preference from portage
252 # This should still work if NOCOLOR is set by the -C flag or in the user's
254 export NOCOLOR=$(portageq envvar NOCOLOR)
255 [[ $NOCOLOR = yes || $NOCOLOR = true ]] && export RC_NOCOLOR=yes # HACK! (grr)
256 . /etc/init.d/functions.sh
260 # Die if an argument is missing.
261 die_if_missing_arg() {
262 [[ ! $2 || $2 = -* ]] && die 1 "Missing expected argument to $1"
266 # Die because an option is not recognized.
267 die_invalid_option() {
268 # We cannot use eerror and einfo because this gets called before function.sh
272 echo "Encountered unrecognized option $1." >&2
274 echo "$APP_NAME no longer automatically passes unrecognized options to portage."
275 echo "Separate emerge-only options from revdep-rebuild options with the -- flag."
281 # Warn about deprecated options.
282 warn_deprecated_opt() {
283 # We cannot use eerror and einfo because this gets called before function.sh
286 echo "Encountered deprecated option $1." >&2
287 [[ $2 ]] && echo "Please use $2 instead." >&2
291 # Get whole-word commandline options preceded by two dashes.
294 --nocolor) export NOCOLOR="yes";;
295 --no-color) warn_deprecated_opt "$1" "--nocolor"
296 export NOCOLOR="yes";;
298 --exact) unset PACKAGE_NAMES;;
301 --ignore) RM_OLD_TEMPFILES=1;;
302 --keep-temp) KEEP_TEMP=1;;
303 --library=*) # TODO: check for invalid values
305 unset SEARCH_BROKEN;;
306 --soname=*|--soname-regexp=*) # TODO: check for invalid values
307 warn_deprecated_opt "${1%=*}" "--library"
309 unset SEARCH_BROKEN;;
310 --library) # TODO: check for invalid values
311 die_if_missing_arg $1 $2
314 unset SEARCH_BROKEN;;
315 --soname|--soname-regexp) # TODO: check for invalid values
316 warn_deprecated_opt "$1" "--library"
317 die_if_missing_arg $1 $2
320 unset SEARCH_BROKEN;;
321 --no-ld-path) unset FULL_LD_PATH;;
322 --no-order) unset ORDER_PKGS;;
323 --no-progress) progress() { :; };;
324 --pretend) EMERGE_OPTIONS+=("--pretend");;
325 --quiet) echo_v() { :; }
328 EMERGE_OPTIONS+=($1);;
329 --no-util=*) # TODO: check for invalid values
330 avoid_utils="${1#*=}";;
331 --no-util) # TODO: check for invalid values
332 die_if_missing_arg $1 $2
336 EMERGE_OPTIONS+=("--verbose");;
337 --extra-verbose) warn_deprecated_opt "$1" "--verbose"
339 EMERGE_OPTIONS+=("--verbose");;
340 --package-names) # No longer used, since it is the
341 # default. We accept it for
342 # backwards compatibility.
343 warn_deprecated_opt "$1"
345 *) die_invalid_option $1;;
350 # Get single-letter commandline options preceded by a single dash.
352 local OPT OPTSTRING OPTARG OPTIND
353 while getopts ":CdehikL:loPpqu:vX" OPT; do
355 C) # TODO: Match syntax with the rest of gentoolkit
356 export NOCOLOR="yes";;
358 e) unset PACKAGE_NAMES;;
361 i) RM_OLD_TEMPFILES=1;;
363 L) # TODO: Check for invalid values
364 SONAME="${OPTARG#*=}"
365 unset SEARCH_BROKEN;;
366 l) unset FULL_LD_PATH;;
367 o) unset ORDER_PKGS;;
368 P) progress() { :; };;
369 p) EMERGE_OPTIONS+=("--pretend");;
373 EMERGE_OPTIONS+=("--quiet");;
374 u) avoid_utils="$1";; # TODO: Check for invalid values
376 EMERGE_OPTIONS+=("--verbose");;
377 X) # No longer used, since it is the default.
378 # We accept it for backwards compatibility.
379 warn_deprecated_opt "-X"
381 *) die_invalid_option "-$OPTARG";;
387 # Get command-line options.
391 echo_v() { ewarn "$@"; }
392 unset VERBOSE KEEP_TEMP EMERGE_OPTIONS RM_OLD_TEMPFILES
401 EMERGE_OPTIONS+=("$@")
406 [[ ${1:--} = -* ]] && break
408 if [[ ${args[0]} = --* ]]; then
409 get_longopts "${args[@]}"
411 get_shortopts "${args[@]}"
413 *) die_invalid_option "$1";;
420 normalize_emerge_opts
422 # If the user is not super, add --pretend to EMERGE_OPTIONS
423 if [[ ${EMERGE_OPTIONS[@]} != *--pretend* && $UID -ne 0 ]]; then
424 ewarn "You are not superuser. Adding --pretend to emerge options."
425 EMERGE_OPTIONS+=(--pretend)
430 [[ ${EMERGE_OPTIONS[@]} != *--pretend* &&
431 ${EMERGE_OPTIONS[@]} != *--fetchonly* ]]
436 einfo "Configuring search environment for $APP_NAME"
438 # Obey PORTAGE_NICENESS
439 PORTAGE_NICENESS=$(portageq envvar PORTAGE_NICENESS)
440 if [[ $PORTAGE_NICENESS ]]; then
441 renice $PORTAGE_NICENESS $$ > /dev/null
442 # Since we have already set our nice value for our processes,
443 # reset PORTAGE_NICENESS to zero to avoid having emerge renice again.
444 export PORTAGE_NICENESS="0"
447 PORTAGE_ROOT=$(portageq envvar ROOT)
448 PORTAGE_ROOT="${PORTAGE_ROOT:-/}"
450 # Update the incremental variables using /etc/profile.env, /etc/ld.so.conf,
451 # portage, and the environment
453 # Read the incremental variables from environment and portage
454 # Until such time as portage supports these variables as incrementals
455 # The value will be what is in /etc/make.conf
456 SEARCH_DIRS+=" "$(unset SEARCH_DIRS; portageq envvar SEARCH_DIRS)
457 SEARCH_DIRS_MASK+=" "$(unset SEARCH_DIRS_MASK; portageq envvar SEARCH_DIRS_MASK)
458 LD_LIBRARY_MASK+=" "$(unset LD_LIBRARY_MASK; portageq envvar LD_LIBRARY_MASK)
461 if [[ -d /etc/revdep-rebuild ]]; then
462 for e in /etc/revdep-rebuild/*; do
463 SEARCH_DIRS+=" "$(. $e; echo $SEARCH_DIRS)
464 SEARCH_DIRS_MASK+=" "$(. $e; echo $SEARCH_DIRS_MASK)
465 LD_LIBRARY_MASK+=" "$(. $e; echo $LD_LIBRARY_MASK)
469 SEARCH_DIRS+=" /bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*"
470 SEARCH_DIRS_MASK+=" /opt/OpenOffice /usr/lib/openoffice"
471 LD_LIBRARY_MASK+=" libodbcinst.so libodbc.so libjava.so libjvm.so"
474 # Get the ROOTPATH and PATH from /etc/profile.env
475 if [[ -r "/etc/profile.env" && -s "/etc/profile.env" ]]; then
476 SEARCH_DIRS+=" "$(. /etc/profile.env; /usr/bin/tr ':' ' ' <<< "$ROOTPATH $PATH")
479 # Get the directories from /etc/ld.so.conf
480 if [[ -r /etc/ld.so.conf && -s /etc/ld.so.conf ]]; then
481 SEARCH_DIRS+=" "$(sed '/^#/d;s/#.*$//' /etc/ld.so.conf)
484 # Set the final variables
485 SEARCH_DIRS=$(clean_var <<< "$SEARCH_DIRS")
486 SEARCH_DIRS_MASK=$(clean_var <<< "$SEARCH_DIRS_MASK")
487 LD_LIBRARY_MASK=$(clean_var <<< "$LD_LIBRARY_MASK")
488 # Filter masked paths from SEARCH_DIRS
490 for sdir in ${SEARCH_DIRS} ; do
492 for mdir in ${SEARCH_DIRS_MASK} ; do
493 [[ ${sdir} == ${mdir}/* ]] \
494 && skip_me=1 && break
496 [[ -n ${skip_me} ]] || filter_SEARCH_DIRS+=" ${sdir}"
498 SEARCH_DIRS=$(clean_var <<< "${filter_SEARCH_DIRS}")
499 unset sdir mdir skip_me filter_SEARCH_DIRS
500 [[ $SEARCH_DIRS ]] || die 1 "No search defined -- this is a bug."
503 # Clean up temporary files and exit
506 die 1 " ...terminated. Removing incomplete $@."
511 trap "cleanup_and_die $*" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
515 # Returns 0 if the first arg is found in the remaining args, 1 otherwise
516 # (Returns 2 if given less than 2 arguments)
518 (( $# > 1 )) || return 2
519 local IFS=$'\a' target="$1"
521 [[ $'\a'"$*"$'\a' = *$'\a'$target$'\a'* ]]
526 if builtin cd -P "$@"; then
527 if [[ $1 != $PWD ]]; then
528 # Some symlink malfeasance is going on
529 die 1 "Working directory expected to be $1, but it is $PWD"
532 die 1 "Unable to change working directory to '$@'"
539 # Anything in the FILES array in tmpdir is fair game for removal
542 [[ $APP_NAME ]] || die 1 '$APP_NAME is not defined! (This is a bug.)'
544 */*|*-r*|*-R*) die 1 "Oops, I'm not allowed to delete that. ($@)";;
547 # Don't delete files that are not listed in the array
548 # Allow no slashes or recursive deletes at all.
550 */*|-*r*|-*R*) :;; # Not OK
553 has "$i" "${FILES[@]}" && continue
554 die 1 "Oops, I'm not allowed to delete that. ($@)"
558 # delete this setup function so it's harmless to re-run
562 # Make our temporary files directory
565 die 1 'Temporary file path is unset! (This is a bug.)'
566 elif [[ -d $1 ]]; then
567 # HACK: I hate using find this way
568 if [[ $(find "$1" ! \( -user root -group portage -perm -02770 \) ) ]]; then
569 eerror "Incorrect permissions on $1"
570 eerror "or at least one file in $1."
571 die 1 "Please make sure it's not a symlink and then remove it."
574 elif mkdir -m 02700 "$1" && chown :portage "$1" && chmod 02770 "$1"; then
577 die 1 "Unable to find or create a satisfactory location for temporary files"
579 [[ $VERBOSE ]] && einfo "Temporary files are located in $PWD"
585 # Find a place to put temporary files
586 # Use "${TMPDIR}/revdep-rebuild" or /tmp/revdep-rebuild
587 local tmp_target="${TMPDIR:=/tmp}/$APP_NAME"
589 # From here on all work is done inside the temporary directory
590 setup_tmpdir "$tmp_target"
592 if [[ $SEARCH_BROKEN ]]; then
593 SONAME_SEARCH="$SONAME"
594 HEAD_TEXT="broken by a package update"
595 OK_TEXT="Dynamic linking on your system is consistent"
596 WORKING_TEXT="consistency"
598 # first case is needed to test against /path/to/foo.so
599 if [[ $SONAME = /* ]]; then
600 # Set to "<space>$SONAME<space>"
601 SONAME_SEARCH=" $SONAME "
602 # Escape the "/" characters
603 SONAME_SEARCH="${SONAME_SEARCH//\//\\/}"
605 # Set to "<tab>$SONAME<space>"
606 SONAME_SEARCH=$'\t'"$SONAME "
608 local uuid="${SONAME##*/}"
609 uuid="${uuid//[[:space:]]}"
611 HEAD_TEXT="using $SONAME"
612 OK_TEXT="There are no dynamic links to $SONAME"
617 # If any of our temporary files are older than 1 day, remove them all
618 if [[ ! $KEEP_TEMP ]]; then
622 done < <(find -L . -maxdepth 1 -type f -name '*.rr' -mmin +1440 -print 2>/dev/null)
625 # Compare old and new environments
626 # Don't use our previous files if environment doesn't match
628 # We do not care if these emerge options change
629 EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--pretend/})
630 EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--fetchonly/})
631 EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--verbose/})
633 SEARCH_DIRS="$SEARCH_DIRS"
634 SEARCH_DIRS_MASK="$SEARCH_DIRS_MASK"
635 LD_LIBRARY_MASK="$LD_LIBRARY_MASK"
636 PORTAGE_ROOT="$PORTAGE_ROOT"
637 EMERGE_OPTIONS="${EMERGE_OPTIONS[@]}"
638 ORDER_PKGS="$ORDER_PKGS"
639 FULL_LD_PATH="$FULL_LD_PATH"
642 if [[ -r "$ENV_FILE" && -s "$ENV_FILE" ]]; then
643 old_env=$(<"$ENV_FILE")
644 if [[ $old_env != $new_env ]]; then
645 ewarn 'Environment mismatch from previous run, deleting temporary files...'
649 # No env file found, silently delete any other tempfiles that may exist
653 # If we should remove old tempfiles, do so
654 if [[ $RM_OLD_TEMPFILES ]]; then
657 for file in "${FILES[@]}"; do
658 chown root:portage "$file"
663 # Save the environment in a file for next time
664 echo "$new_env" > "$ENV_FILE"
666 [[ $VERBOSE ]] && echo $'\n'"$APP_NAME environment:"$'\n'"$new_env"
669 einfo "Checking reverse dependencies"
670 einfo "Packages containing binaries and libraries $HEAD_TEXT"
671 einfo "will be emerged."
674 einfo "Collecting system binaries and libraries"
675 if [[ -r "$FILES_FILE" && -s "$FILES_FILE" ]]; then
676 einfo "Found existing $FILES_FILE"
678 # Be safe and remove any extraneous temporary files
681 clean_trap "$FILES_FILE"
683 if [[ $SEARCH_DIRS_MASK ]]; then
684 findMask=($SEARCH_DIRS_MASK)
685 findMask="${findMask[@]/#/-o -path }"
686 findMask="( ${findMask#-o } ) -prune -o"
689 find ${SEARCH_DIRS[@]} $findMask -type f \( -executable -o \
690 -name '*.so' -o -name '*.so.*' -o -name '*.la' \) -print 2> /dev/null |
691 sort -u > "$FILES_FILE" ||
692 die $? "find failed to list binary files (This is a bug.)"
693 einfo "Generated new $FILES_FILE"
697 local COMPLETE_LD_LIBRARY_PATH
698 [[ $SEARCH_BROKEN && $FULL_LD_PATH ]] || return
699 einfo 'Collecting complete LD_LIBRARY_PATH'
700 if [[ -r "$LDPATH_FILE" && -s "$LDPATH_FILE" ]]; then
701 einfo "Found existing $LDPATH_FILE."
703 clean_trap "$LDPATH_FILE"
704 # Ensure that the "trusted" lib directories are at the start of the path
705 COMPLETE_LD_LIBRARY_PATH=(
708 $(sed '/^#/d;s/#.*$//' < /etc/ld.so.conf)
709 $(sed 's:/[^/]*$::' < "$FILES_FILE" | sort -ru)
712 COMPLETE_LD_LIBRARY_PATH="${COMPLETE_LD_LIBRARY_PATH[*]}"
714 echo "$COMPLETE_LD_LIBRARY_PATH" > "$LDPATH_FILE"
715 einfo "Generated new $LDPATH_FILE"
725 local COMPLETE_LD_LIBRARY_PATH
726 if [[ $SEARCH_BROKEN && $FULL_LD_PATH ]]; then
727 [[ -r "$LDPATH_FILE" && -s "$LDPATH_FILE" ]] ||
728 die 1 "Unable to find $LDPATH_FILE"
729 COMPLETE_LD_LIBRARY_PATH=$(<"$LDPATH_FILE")
731 einfo "Checking dynamic linking $WORKING_TEXT"
732 if [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]]; then
733 einfo "Found existing $BROKEN_FILE."
735 clean_trap "$BROKEN_FILE" "$ERRORS_FILE"
736 files=($(<"$FILES_FILE"))
737 numFiles="${#files[@]}"
738 for target_file in "${files[@]}"; do
739 if [[ $target_file != *.la ]]; then
740 # Note: double checking seems to be faster than single with complete path
741 # (special add ons are rare).
742 ldd_output=$(ldd "$target_file" 2>> "$ERRORS_FILE" | sort -u)
743 ldd_status=$? # TODO: Check this for problems with sort
744 # HACK: if LD_LIBRARY_MASK is null or undefined grep -vF doesn't work
745 if grep -vF "${LD_LIBRARY_MASK:=$'\a'}" <<< "$ldd_output" |
746 grep -q "$SONAME_SEARCH"; then
747 if [[ $SEARCH_BROKEN && $FULL_LD_PATH ]]; then
748 if LD_LIBRARY_PATH="$COMPLETE_LD_LIBRARY_PATH" ldd "$target_file" 2>/dev/null |
749 grep -vF "$LD_LIBRARY_MASK" | grep -q "$SONAME_SEARCH"; then
750 # FIXME: I hate duplicating code
751 # Only build missing direct dependencies
753 expr='s/[[:space:]]*\([^[:space:]]*\) => not found/\1/p'
754 sed -n "$expr" <<< "$ldd_output"
757 expr='s/^[[:space:]]*NEEDED[[:space:]]*\([^[:space:]]*\).*/\1/p';
758 objdump -x "$target_file" | grep NEEDED | sed "$expr" | sort -u
760 MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS")
761 if [[ $MISSING_LIBS ]]; then
762 echo "obj $target_file" >> "$BROKEN_FILE"
763 echo_v " broken $target_file (requires $MISSING_LIBS)"
767 # FIXME: I hate duplicating code
768 # Only rebuild for direct dependencies
770 expr="/$SONAME_SEARCH/s/^[[:space:]]*\([^[:space:]]*\).*$/\1/p"
771 sort -u <<< "$ldd_output" | sed -n "$expr"
774 expr='s/^[[:space:]]*NEEDED[[:space:]]*\([^[:space:]]*\).*/\1/p';
775 objdump -x "$target_file" | grep NEEDED | sed "$expr" | sort -u
777 MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS")
778 if [[ $MISSING_LIBS ]]; then
779 echo "obj $target_file" >> "$BROKEN_FILE"
780 if [[ $SEARCH_BROKEN ]]; then
781 echo_v " broken $target_file (requires $MISSING_LIBS)"
783 echo_v " found $target_file"
788 elif [[ $SEARCH_BROKEN ]]; then
789 # Look for broken .la files
791 awk -F"[=']" '/^dependency_libs/{
792 gsub("^-[^[:space:]]*", "", $3);
793 gsub("[[:space:]]-[^[:space:]]*", "", $3);
797 if [[ $depend = /* && ! -e $depend ]]; then
798 echo "obj $target_file" >> "$BROKEN_FILE"
799 echo_v " broken $target_file (requires $depend)"
804 progress $((++i)) $numFiles $target_file ||
805 progress $((++i)) $numFiles
807 if [[ $SEARCH_BROKEN ]]; then
808 # Look for missing version
809 while read target_file; do
810 echo "obj $target_file" >> "$BROKEN_FILE"
811 echo_v " broken $target_file (no version information available)"
813 # Regexify LD_LIBRARY_MASK. Exclude it from the search.
814 LD_LIBRARY_MASK="${LD_LIBRARY_MASK//$'\n'/|}"
815 awk -v ldmask="(${LD_LIBRARY_MASK//./\\\.})" '
816 /no version information available/ && $0 !~ ldmask {
817 gsub(/[()]/, "", $NF)
818 if (seen[$NF]++) next
823 [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]] || clean_exit
824 einfo "Generated new $BROKEN_FILE"
832 einfo 'Assigning files to packages'
833 if [[ -r "$RAW_FILE" && -s "$RAW_FILE" ]]; then
834 einfo "Found existing $RAW_FILE"
836 clean_trap "$RAW_FILE" "$OWNERS_FILE"
837 while read obj target_file; do
838 EXACT_PKG=$(get_file_owner $target_file)
839 if [[ $EXACT_PKG ]]; then
840 # Strip version information
841 PKG="${EXACT_PKG%%-r[[:digit:]]*}"
843 echo "$EXACT_PKG" >> "$RAW_FILE"
844 echo "$target_file -> $EXACT_PKG" >> "$OWNERS_FILE"
845 echo_v " $target_file -> $PKG"
847 ewarn " !!! $target_file not owned by any package is broken !!!"
848 echo "$target_file -> (none)" >> "$OWNERS_FILE"
849 echo_v " $target_file -> (none)"
851 done < "$BROKEN_FILE"
852 einfo "Generated new $RAW_FILE and $OWNERS_FILE"
854 # if we find '(none)' on every line, exit out
855 if ! grep -qvF '(none)' "$OWNERS_FILE"; then
856 ewarn "Found some broken files, but none of them were associated with known packages"
857 ewarn "Unable to proceed with automatic repairs."
858 ewarn "The broken files are listed in $OWNERS_FILE"
859 if [[ $VERBOSE ]]; then
860 ewarn "The broken files are:"
861 while read filename junk; do
863 done < "$OWNERS_FILE"
865 exit 0 # FIXME: Should we exit 1 here?
869 einfo 'Cleaning list of packages to rebuild'
870 if [[ -r "$PKGS_FILE" && -s "$PKGS_FILE" ]]; then
871 einfo "Found existing $PKGS_FILE"
873 sort -u "$RAW_FILE" > "$PKGS_FILE"
874 einfo "Generated new $PKGS_FILE"
877 assign_packages_to_ebuilds() {
881 einfo 'Assigning packages to ebuilds'
882 if [[ -r "$EBUILDS_FILE" && -s "$EBUILDS_FILE" ]]; then
883 einfo "Found existing $EBUILDS_FILE"
884 elif [[ -r "$PKGS_FILE" && -s "$PKGS_FILE" ]]; then
885 clean_trap "$EBUILDS_FILE"
886 while read EXACT_PKG; do
888 PKG="${EXACT_PKG%%-r[[:digit:]]*}"
890 SLOT=$(</var/db/pkg/$EXACT_PKG/SLOT)
892 done < "$PKGS_FILE" > "$EBUILDS_FILE"
893 einfo "Generated new $EBUILDS_FILE"
895 einfo 'Nothing to rebuild.'
896 die 1 '(The program should have already quit, so this is a minor bug.)'
899 get_exact_ebuilds() {
900 einfo 'Assigning files to ebuilds'
901 if [[ -r "$EBUILDS_FILE" && -s "$EBUILDS_FILE" ]]; then
902 einfo "Found existing $EBUILDS_FILE"
903 elif [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]]; then
904 rebuildList=" $(<"$BROKEN_FILE") "
905 rebuildList=(${rebuildList//[[:space:]]obj[[:space:]]/ })
906 get_file_owner "${rebuildList[@]}" | sed 's/^/=/' > "$EBUILDS_FILE"
907 einfo "Generated new $EBUILDS_FILE"
909 einfo 'Nothing to rebuild.'
910 die 1 '(The program should have already quit, so this is a minor bug.)'
913 list_skipped_packages() {
915 ewarn 'Portage could not find any version of the following packages it could build:'
916 ewarn "${SKIP_LIST[@]}"
918 ewarn '(Perhaps they are masked, blocked, or removed from portage.)'
919 ewarn 'Try to emerge them manually.'
923 local -r OLD_EMERGE_DEFAULT_OPTS="$EMERGE_DEFAULT_OPTS"
924 local RAW_REBUILD_LIST
927 if [[ ! $ORDER_PKGS ]]; then
928 einfo 'Skipping package ordering'
931 einfo 'Evaluating package order'
932 if [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" ]]; then
933 einfo "Found existing $ORDER_FILE"
935 clean_trap "$ORDER_FILE"
936 RAW_REBUILD_LIST=$(<"$EBUILDS_FILE")
937 if [[ $RAW_REBUILD_LIST ]]; then
938 export EMERGE_DEFAULT_OPTS="--nospinner --pretend --oneshot --quiet"
939 RAW_REBUILD_LIST=($RAW_REBUILD_LIST) # convert into array
940 # If PACKAGE_NAMES is defined we're using slots, not versions
941 if [[ $PACKAGE_NAMES ]]; then
942 # Eliminate atoms that can't be built
943 for i in "${!RAW_REBUILD_LIST[@]}"; do
944 if [[ "${RAW_REBUILD_LIST[i]}" = *[A-Za-z]* ]]; then
945 portageq best_visible "$PORTAGE_ROOT" "${RAW_REBUILD_LIST[i]}" >/dev/null && continue
946 SKIP_LIST+=("${RAW_REBUILD_LIST[i]}")
948 unset RAW_REBUILD_LIST[i]
950 # If RAW_REBUILD_LIST is empty, then we have nothing to build.
951 if (( ${#RAW_REBUILD_LIST[@]} == 0 )); then
952 if (( ${#SKIP_LIST[@]} == 0 )); then
953 ewarn "The list of packages to skip is empty, but there are no"
954 ewarn "packages listed to rebuild either. This is a bug."
956 list_skipped_packages
958 die 1 'Warning: Portage cannot rebuild any of the necessary packages.'
961 RAW_REBUILD_LIST=("${RAW_REBUILD_LIST[@]/#/=}")
963 RAW_REBUILD_LIST="${RAW_REBUILD_LIST[@]}"
964 REBUILD_GREP=$(emerge --nodeps $RAW_REBUILD_LIST | sed 's/\[[^]]*\]//g')
965 if (( ${PIPESTATUS[0]} == 0 )); then
966 emerge --deep $RAW_REBUILD_LIST |
967 sed 's/\[[^]]*\]//g' |
968 grep -F "$REBUILD_GREP" > "$ORDER_FILE"
971 # Here we use the PIPESTATUS from the second emerge, the --deep one.
972 if (( ${PIPESTATUS[0]} != 0 )); then
974 eerror 'Warning: Failed to resolve package order.'
975 eerror 'Will merge in arbitrary order'
979 - An ebuild is no longer in the portage tree.
980 - An ebuild is masked, use /etc/portage/packages.keyword
981 and/or /etc/portage/package.unmask to unmask it
986 export EMERGE_DEFAULT_OPTS="$OLD_EMERGE_DEFAULT_OPTS"
988 einfo 'Nothing to rebuild.'
989 die 1 '(The program should have already quit, so this is a minor bug.)'
992 [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" ]] && einfo "Generated new $ORDER_FILE"
1003 if [[ $PACKAGE_NAMES ]]; then
1008 assign_packages_to_ebuilds
1016 # Clean up no longer needed environment variables
1017 unset SEARCH_DIRS SEARCH_DIRS_MASK LD_LIBRARY_MASK PORTAGE_ROOT
1019 if [[ -r $ORDER_FILE && -s $ORDER_FILE ]]; then
1020 REBUILD_LIST=( $(<"$ORDER_FILE") )
1021 REBUILD_LIST="${REBUILD_LIST[@]/#/=}"
1023 REBUILD_LIST=$(sort -u "$EBUILDS_FILE")
1026 trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
1028 einfo 'All prepared. Starting rebuild'
1029 echo "emerge --oneshot ${EMERGE_OPTIONS[@]} $REBUILD_LIST"
1031 is_real_merge && countdown 10
1033 # Link file descriptor #6 with stdin so --ask will work
1036 # Run in background to correctly handle Ctrl-C
1038 EMERGE_DEFAULT_OPTS="--oneshot ${EMERGE_OPTIONS[@]}" emerge $REBUILD_LIST <&6
1039 echo $? > "$STATUS_FILE"
1043 # Now restore stdin from fd #6, where it had been saved, and close fd #6 ( 6<&- ) to free it for other processes to use.
1046 show_unowned_files() {
1047 if grep -qF '(none)' "$OWNERS_FILE"; then
1048 ewarn "Found some broken files that weren't associated with known packages"
1049 ewarn "The broken files are:"
1050 while read filename junk; do
1051 [[ $junk = *none* ]] && ewarn " $filename"
1052 done < "$OWNERS_FILE" | awk '!s[$0]++' # (omit dupes)
1056 if (( $(<"$STATUS_FILE") != 0 )); then
1058 ewarn "$APP_NAME failed to emerge all packages."
1059 ewarn 'you have the following choices:'
1060 einfo "- If emerge failed during the build, fix the problems and re-run $APP_NAME."
1061 einfo '- Use /etc/portage/package.keywords to unmask a newer version of the package.'
1062 einfo " (and remove $ORDER_FILE to be evaluated again)"
1063 einfo '- Modify the above emerge command and run it manually.'
1064 einfo '- Compile or unmerge unsatisfied packages manually,'
1065 einfo ' remove temporary files, and try again.'
1066 einfo ' (you can edit package/ebuild list first)'
1068 einfo 'To remove temporary files, please run:'
1069 einfo "rm ${TMPDIR}/$APP_NAME/*.rr"
1072 elif is_real_merge; then
1074 eerror "terminated. Please remove the temporary files manually:"
1075 eerror "rm ${TMPDIR}/$APP_NAME/*.rr"
1078 (( "${#SKIP_LIST[@]}" != 0 )) && list_skipped_packages
1079 trap trap_cmd SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
1080 einfo 'Build finished correctly. Removing temporary files...'
1082 einfo 'You can re-run revdep-rebuild to verify that all libraries and binaries'
1083 einfo 'are fixed. If some inconsistency remains, it can be orphaned file, deep'
1084 einfo 'dependency, binary package or specially evaluated library.'
1085 if [[ -r "$OWNERS_FILE" && -s "$OWNERS_FILE" ]]; then
1088 [[ $KEEP_TEMP ]] || rm "${FILES[@]}"
1090 einfo 'Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.'