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
271 echo "Encountered unrecognized option $1." >&2
273 echo "$APP_NAME no longer automatically passes unrecognized options to portage."
274 echo "Separate emerge-only options from revdep-rebuild options with the -- flag."
276 echo "For example, $APP_NAME -v -- --ask"
278 echo "See the man page or $APP_NAME -h for more detail."
284 # Warn about deprecated options.
285 warn_deprecated_opt() {
286 # We cannot use eerror and einfo because this gets called before function.sh
289 echo "Encountered deprecated option $1." >&2
290 [[ $2 ]] && echo "Please use $2 instead." >&2
294 # Get whole-word commandline options preceded by two dashes.
297 --nocolor) export NOCOLOR="yes";;
298 --no-color) warn_deprecated_opt "$1" "--nocolor"
299 export NOCOLOR="yes";;
301 --exact) unset PACKAGE_NAMES;;
304 --ignore) RM_OLD_TEMPFILES=1;;
305 --keep-temp) KEEP_TEMP=1;;
306 --library=*) # TODO: check for invalid values
308 unset SEARCH_BROKEN;;
309 --soname=*|--soname-regexp=*) # TODO: check for invalid values
310 warn_deprecated_opt "${1%=*}" "--library"
312 unset SEARCH_BROKEN;;
313 --library) # TODO: check for invalid values
314 die_if_missing_arg $1 $2
317 unset SEARCH_BROKEN;;
318 --soname|--soname-regexp) # TODO: check for invalid values
319 warn_deprecated_opt "$1" "--library"
320 die_if_missing_arg $1 $2
323 unset SEARCH_BROKEN;;
324 --no-ld-path) unset FULL_LD_PATH;;
325 --no-order) unset ORDER_PKGS;;
326 --no-progress) progress() { :; };;
327 --pretend) EMERGE_OPTIONS+=("--pretend");;
328 --quiet) echo_v() { :; }
331 EMERGE_OPTIONS+=($1);;
332 --no-util=*) # TODO: check for invalid values
333 avoid_utils="${1#*=}";;
334 --no-util) # TODO: check for invalid values
335 die_if_missing_arg $1 $2
339 EMERGE_OPTIONS+=("--verbose");;
340 --extra-verbose) warn_deprecated_opt "$1" "--verbose"
342 EMERGE_OPTIONS+=("--verbose");;
343 --package-names) # No longer used, since it is the
344 # default. We accept it for
345 # backwards compatibility.
346 warn_deprecated_opt "$1"
348 *) die_invalid_option $1;;
353 # Get single-letter commandline options preceded by a single dash.
355 local OPT OPTSTRING OPTARG OPTIND
356 while getopts ":CdehikL:loPpqu:vX" OPT; do
358 C) # TODO: Match syntax with the rest of gentoolkit
359 export NOCOLOR="yes";;
361 e) unset PACKAGE_NAMES;;
364 i) RM_OLD_TEMPFILES=1;;
366 L) # TODO: Check for invalid values
367 SONAME="${OPTARG#*=}"
368 unset SEARCH_BROKEN;;
369 l) unset FULL_LD_PATH;;
370 o) unset ORDER_PKGS;;
371 P) progress() { :; };;
372 p) EMERGE_OPTIONS+=("--pretend");;
376 EMERGE_OPTIONS+=("--quiet");;
377 u) avoid_utils="$1";; # TODO: Check for invalid values
379 EMERGE_OPTIONS+=("--verbose");;
380 X) # No longer used, since it is the default.
381 # We accept it for backwards compatibility.
382 warn_deprecated_opt "-X"
384 *) die_invalid_option "-$OPTARG";;
390 # Get command-line options.
394 echo_v() { ewarn "$@"; }
395 unset VERBOSE KEEP_TEMP EMERGE_OPTIONS RM_OLD_TEMPFILES
404 EMERGE_OPTIONS+=("$@")
409 [[ ${1:--} = -* ]] && break
411 if [[ ${args[0]} = --* ]]; then
412 get_longopts "${args[@]}"
414 get_shortopts "${args[@]}"
416 *) die_invalid_option "$1";;
423 normalize_emerge_opts
425 # If the user is not super, add --pretend to EMERGE_OPTIONS
426 if [[ ${EMERGE_OPTIONS[@]} != *--pretend* && $UID -ne 0 ]]; then
427 ewarn "You are not superuser. Adding --pretend to emerge options."
428 EMERGE_OPTIONS+=(--pretend)
433 [[ ${EMERGE_OPTIONS[@]} != *--pretend* &&
434 ${EMERGE_OPTIONS[@]} != *--fetchonly* ]]
439 einfo "Configuring search environment for $APP_NAME"
441 # Obey PORTAGE_NICENESS
442 PORTAGE_NICENESS=$(portageq envvar PORTAGE_NICENESS)
443 if [[ $PORTAGE_NICENESS ]]; then
444 renice $PORTAGE_NICENESS $$ > /dev/null
445 # Since we have already set our nice value for our processes,
446 # reset PORTAGE_NICENESS to zero to avoid having emerge renice again.
447 export PORTAGE_NICENESS="0"
450 PORTAGE_ROOT=$(portageq envvar ROOT)
451 PORTAGE_ROOT="${PORTAGE_ROOT:-/}"
453 # Update the incremental variables using /etc/profile.env, /etc/ld.so.conf,
454 # portage, and the environment
456 # Read the incremental variables from environment and portage
457 # Until such time as portage supports these variables as incrementals
458 # The value will be what is in /etc/make.conf
459 SEARCH_DIRS+=" "$(unset SEARCH_DIRS; portageq envvar SEARCH_DIRS)
460 SEARCH_DIRS_MASK+=" "$(unset SEARCH_DIRS_MASK; portageq envvar SEARCH_DIRS_MASK)
461 LD_LIBRARY_MASK+=" "$(unset LD_LIBRARY_MASK; portageq envvar LD_LIBRARY_MASK)
464 if [[ -d /etc/revdep-rebuild ]]; then
465 for e in /etc/revdep-rebuild/*; do
466 SEARCH_DIRS+=" "$(. $e; echo $SEARCH_DIRS)
467 SEARCH_DIRS_MASK+=" "$(. $e; echo $SEARCH_DIRS_MASK)
468 LD_LIBRARY_MASK+=" "$(. $e; echo $LD_LIBRARY_MASK)
472 SEARCH_DIRS+=" /bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*"
473 SEARCH_DIRS_MASK+=" /opt/OpenOffice /usr/lib/openoffice"
474 LD_LIBRARY_MASK+=" libodbcinst.so libodbc.so libjava.so libjvm.so"
477 # Get the ROOTPATH and PATH from /etc/profile.env
478 if [[ -r "/etc/profile.env" && -s "/etc/profile.env" ]]; then
479 SEARCH_DIRS+=" "$(. /etc/profile.env; /usr/bin/tr ':' ' ' <<< "$ROOTPATH $PATH")
482 # Get the directories from /etc/ld.so.conf
483 if [[ -r /etc/ld.so.conf && -s /etc/ld.so.conf ]]; then
484 SEARCH_DIRS+=" "$(sed '/^#/d;s/#.*$//' /etc/ld.so.conf)
487 # Set the final variables
488 SEARCH_DIRS=$(clean_var <<< "$SEARCH_DIRS")
489 SEARCH_DIRS_MASK=$(clean_var <<< "$SEARCH_DIRS_MASK")
490 LD_LIBRARY_MASK=$(clean_var <<< "$LD_LIBRARY_MASK")
491 # Filter masked paths from SEARCH_DIRS
493 for sdir in ${SEARCH_DIRS} ; do
495 for mdir in ${SEARCH_DIRS_MASK} ; do
496 [[ ${sdir} == ${mdir}/* ]] \
497 && skip_me=1 && break
499 [[ -n ${skip_me} ]] || filter_SEARCH_DIRS+=" ${sdir}"
501 SEARCH_DIRS=$(clean_var <<< "${filter_SEARCH_DIRS}")
502 unset sdir mdir skip_me filter_SEARCH_DIRS
503 [[ $SEARCH_DIRS ]] || die 1 "No search defined -- this is a bug."
506 # Clean up temporary files and exit
510 die 1 " ...terminated. Removing incomplete $@."
515 trap "cleanup_and_die $*" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
519 # Returns 0 if the first arg is found in the remaining args, 1 otherwise
520 # (Returns 2 if given less than 2 arguments)
522 (( $# > 1 )) || return 2
523 local IFS=$'\a' target="$1"
525 [[ $'\a'"$*"$'\a' = *$'\a'$target$'\a'* ]]
530 if builtin cd -P "$@"; then
531 if [[ $1 != $PWD ]]; then
532 # Some symlink malfeasance is going on
533 die 1 "Working directory expected to be $1, but it is $PWD"
536 die 1 "Unable to change working directory to '$@'"
543 # Anything in the FILES array in tmpdir is fair game for removal
546 [[ $APP_NAME ]] || die 1 '$APP_NAME is not defined! (This is a bug.)'
548 */*|*-r*|*-R*) die 1 "Oops, I'm not allowed to delete that. ($@)";;
551 # Don't delete files that are not listed in the array
552 # Allow no slashes or recursive deletes at all.
554 */*|-*r*|-*R*) :;; # Not OK
557 has "$i" "${FILES[@]}" && continue
558 die 1 "Oops, I'm not allowed to delete that. ($@)"
562 # delete this setup function so it's harmless to re-run
566 # Make our temporary files directory
569 die 1 'Temporary file path is unset! (This is a bug.)'
570 elif [[ -d $1 ]]; then
571 # HACK: I hate using find this way
572 if [[ $(find "$1" -type d ! \( -user $2 -group portage -perm -0700 \) ) ]]; then
573 eerror "Incorrect permissions on $1"
574 eerror "or at least one file in $1."
575 die 1 "Please make sure it's not a symlink and then remove it."
578 elif mkdir -m 0700 "$1" && chown :portage "$1"; then
581 die 1 "Unable to find or create a satisfactory location for temporary files"
583 [[ $VERBOSE ]] && einfo "Temporary files are located in $PWD"
589 local uid=$(python -c 'import os; import pwd; print pwd.getpwuid(os.getuid())[0]')
590 # Find a place to put temporary files
591 # Use "${TMPDIR}/revdep-rebuild" or /tmp/revdep-rebuild
592 local tmp_target="${TMPDIR:=/tmp}/${APP_NAME}-${uid}"
594 # From here on all work is done inside the temporary directory
595 setup_tmpdir "$tmp_target" "$uid"
597 if [[ $SEARCH_BROKEN ]]; then
598 SONAME_SEARCH="$SONAME"
599 HEAD_TEXT="broken by a package update"
600 OK_TEXT="Dynamic linking on your system is consistent"
601 WORKING_TEXT="consistency"
603 # first case is needed to test against /path/to/foo.so
604 if [[ $SONAME = /* ]]; then
605 # Set to "<space>$SONAME<space>"
606 SONAME_SEARCH=" $SONAME "
607 # Escape the "/" characters
608 SONAME_SEARCH="${SONAME_SEARCH//\//\\/}"
610 # Set to "<tab>$SONAME<space>"
611 SONAME_SEARCH=$'\t'"$SONAME "
613 local uuid="${SONAME##*/}"
614 uuid="${uuid//[[:space:]]}"
616 HEAD_TEXT="using $SONAME"
617 OK_TEXT="There are no dynamic links to $SONAME"
622 # If any of our temporary files are older than 1 day, remove them all
623 if [[ ! $KEEP_TEMP ]]; then
627 done < <(find -L . -maxdepth 1 -type f -name '*.rr' -mmin +1440 -print 2>/dev/null)
630 # Compare old and new environments
631 # Don't use our previous files if environment doesn't match
633 # We do not care if these emerge options change
634 EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--pretend/})
635 EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--fetchonly/})
636 EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--verbose/})
638 SEARCH_DIRS="$SEARCH_DIRS"
639 SEARCH_DIRS_MASK="$SEARCH_DIRS_MASK"
640 LD_LIBRARY_MASK="$LD_LIBRARY_MASK"
641 PORTAGE_ROOT="$PORTAGE_ROOT"
642 EMERGE_OPTIONS="${EMERGE_OPTIONS[@]}"
643 ORDER_PKGS="$ORDER_PKGS"
644 FULL_LD_PATH="$FULL_LD_PATH"
647 if [[ -r "$ENV_FILE" && -s "$ENV_FILE" ]]; then
648 old_env=$(<"$ENV_FILE")
649 if [[ $old_env != $new_env ]]; then
650 ewarn 'Environment mismatch from previous run, deleting temporary files...'
654 # No env file found, silently delete any other tempfiles that may exist
658 # If we should remove old tempfiles, do so
659 if [[ $RM_OLD_TEMPFILES ]]; then
662 for file in "${FILES[@]}"; do
663 chown ${uid}:portage "$file"
668 # Save the environment in a file for next time
669 echo "$new_env" > "$ENV_FILE"
671 [[ $VERBOSE ]] && echo $'\n'"$APP_NAME environment:"$'\n'"$new_env"
674 einfo "Checking reverse dependencies"
675 einfo "Packages containing binaries and libraries $HEAD_TEXT"
676 einfo "will be emerged."
679 einfo "Collecting system binaries and libraries"
680 if [[ -r "$FILES_FILE" && -s "$FILES_FILE" ]]; then
681 einfo "Found existing $FILES_FILE"
683 # Be safe and remove any extraneous temporary files
684 rm -f "${FILES[@]:1}"
686 clean_trap "$FILES_FILE"
688 if [[ $SEARCH_DIRS_MASK ]]; then
689 findMask=($SEARCH_DIRS_MASK)
690 findMask="${findMask[@]/#/-o -path }"
691 findMask="( ${findMask#-o } ) -prune -o"
694 find ${SEARCH_DIRS[@]} $findMask -type f \( -executable -o \
695 -name '*.so' -o -name '*.so.*' -o -name '*.la' \) -print 2> /dev/null |
696 sort -u > "$FILES_FILE" ||
697 die $? "find failed to list binary files (This is a bug.)"
698 einfo "Generated new $FILES_FILE"
702 local COMPLETE_LD_LIBRARY_PATH
703 [[ $SEARCH_BROKEN && $FULL_LD_PATH ]] || return
704 einfo 'Collecting complete LD_LIBRARY_PATH'
705 if [[ -r "$LDPATH_FILE" && -s "$LDPATH_FILE" ]]; then
706 einfo "Found existing $LDPATH_FILE."
708 clean_trap "$LDPATH_FILE"
709 # Ensure that the "trusted" lib directories are at the start of the path
710 COMPLETE_LD_LIBRARY_PATH=(
713 $(sed '/^#/d;s/#.*$//' < /etc/ld.so.conf)
714 $(sed 's:/[^/]*$::' < "$FILES_FILE" | sort -ru)
717 COMPLETE_LD_LIBRARY_PATH="${COMPLETE_LD_LIBRARY_PATH[*]}"
719 echo "$COMPLETE_LD_LIBRARY_PATH" > "$LDPATH_FILE"
720 einfo "Generated new $LDPATH_FILE"
730 local COMPLETE_LD_LIBRARY_PATH
731 if [[ $SEARCH_BROKEN && $FULL_LD_PATH ]]; then
732 [[ -r "$LDPATH_FILE" && -s "$LDPATH_FILE" ]] ||
733 die 1 "Unable to find $LDPATH_FILE"
734 COMPLETE_LD_LIBRARY_PATH=$(<"$LDPATH_FILE")
736 einfo "Checking dynamic linking $WORKING_TEXT"
737 if [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]]; then
738 einfo "Found existing $BROKEN_FILE."
740 clean_trap "$BROKEN_FILE" "$ERRORS_FILE"
741 files=($(<"$FILES_FILE"))
742 numFiles="${#files[@]}"
743 for target_file in "${files[@]}"; do
744 if [[ $target_file != *.la ]]; then
745 # Note: double checking seems to be faster than single with complete path
746 # (special add ons are rare).
747 ldd_output=$(ldd "$target_file" 2>> "$ERRORS_FILE" | sort -u)
748 ldd_status=$? # TODO: Check this for problems with sort
749 # HACK: if LD_LIBRARY_MASK is null or undefined grep -vF doesn't work
750 if grep -vF "${LD_LIBRARY_MASK:=$'\a'}" <<< "$ldd_output" |
751 grep -q "$SONAME_SEARCH"; then
752 if [[ $SEARCH_BROKEN && $FULL_LD_PATH ]]; then
753 if LD_LIBRARY_PATH="$COMPLETE_LD_LIBRARY_PATH" ldd "$target_file" 2>/dev/null |
754 grep -vF "$LD_LIBRARY_MASK" | grep -q "$SONAME_SEARCH"; then
755 # FIXME: I hate duplicating code
756 # Only build missing direct dependencies
758 expr='s/[[:space:]]*\([^[:space:]]*\) => not found/\1/p'
759 sed -n "$expr" <<< "$ldd_output"
762 expr='s/^[[:space:]]*NEEDED[[:space:]]*\([^[:space:]]*\).*/\1/p';
763 objdump -x "$target_file" | grep NEEDED | sed "$expr" | sort -u
765 MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS")
766 if [[ $MISSING_LIBS ]]; then
767 echo "obj $target_file" >> "$BROKEN_FILE"
768 echo_v " broken $target_file (requires $MISSING_LIBS)"
772 # FIXME: I hate duplicating code
773 # Only rebuild for direct dependencies
775 expr="/$SONAME_SEARCH/s/^[[:space:]]*\([^[:space:]]*\).*$/\1/p"
776 sort -u <<< "$ldd_output" | sed -n "$expr"
779 expr='s/^[[:space:]]*NEEDED[[:space:]]*\([^[:space:]]*\).*/\1/p';
780 objdump -x "$target_file" | grep NEEDED | sed "$expr" | sort -u
782 MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS")
783 if [[ $MISSING_LIBS ]]; then
784 echo "obj $target_file" >> "$BROKEN_FILE"
785 if [[ $SEARCH_BROKEN ]]; then
786 echo_v " broken $target_file (requires $MISSING_LIBS)"
788 echo_v " found $target_file"
793 elif [[ $SEARCH_BROKEN ]]; then
794 # Look for broken .la files
796 awk -F"[=']" '/^dependency_libs/{
797 gsub("^-[^[:space:]]*", "", $3);
798 gsub("[[:space:]]-[^[:space:]]*", "", $3);
802 if [[ $depend = /* && ! -e $depend ]]; then
803 echo "obj $target_file" >> "$BROKEN_FILE"
804 echo_v " broken $target_file (requires $depend)"
809 progress $((++i)) $numFiles $target_file ||
810 progress $((++i)) $numFiles
812 if [[ $SEARCH_BROKEN ]]; then
813 # Look for missing version
814 while read target_file; do
815 echo "obj $target_file" >> "$BROKEN_FILE"
816 echo_v " broken $target_file (no version information available)"
818 # Regexify LD_LIBRARY_MASK. Exclude it from the search.
819 LD_LIBRARY_MASK="${LD_LIBRARY_MASK//$'\n'/|}"
820 awk -v ldmask="(${LD_LIBRARY_MASK//./\\\.})" '
821 /no version information available/ && $0 !~ ldmask {
822 gsub(/[()]/, "", $NF)
823 if (seen[$NF]++) next
828 [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]] || clean_exit
829 einfo "Generated new $BROKEN_FILE"
837 einfo 'Assigning files to packages'
838 if [[ -r "$RAW_FILE" && -s "$RAW_FILE" ]]; then
839 einfo "Found existing $RAW_FILE"
841 clean_trap "$RAW_FILE" "$OWNERS_FILE"
842 while read obj target_file; do
843 EXACT_PKG=$(get_file_owner $target_file)
844 if [[ $EXACT_PKG ]]; then
845 # Strip version information
846 PKG="${EXACT_PKG%%-r[[:digit:]]*}"
848 echo "$EXACT_PKG" >> "$RAW_FILE"
849 echo "$target_file -> $EXACT_PKG" >> "$OWNERS_FILE"
850 echo_v " $target_file -> $PKG"
852 ewarn " !!! $target_file not owned by any package is broken !!!"
853 echo "$target_file -> (none)" >> "$OWNERS_FILE"
854 echo_v " $target_file -> (none)"
856 done < "$BROKEN_FILE"
857 einfo "Generated new $RAW_FILE and $OWNERS_FILE"
859 # if we find '(none)' on every line, exit out
860 if ! grep -qvF '(none)' "$OWNERS_FILE"; then
861 ewarn "Found some broken files, but none of them were associated with known packages"
862 ewarn "Unable to proceed with automatic repairs."
863 ewarn "The broken files are listed in $OWNERS_FILE"
864 if [[ $VERBOSE ]]; then
865 ewarn "The broken files are:"
866 while read filename junk; do
868 done < "$OWNERS_FILE"
870 exit 0 # FIXME: Should we exit 1 here?
874 einfo 'Cleaning list of packages to rebuild'
875 if [[ -r "$PKGS_FILE" && -s "$PKGS_FILE" ]]; then
876 einfo "Found existing $PKGS_FILE"
878 sort -u "$RAW_FILE" > "$PKGS_FILE"
879 einfo "Generated new $PKGS_FILE"
882 assign_packages_to_ebuilds() {
886 einfo 'Assigning packages to ebuilds'
887 if [[ -r "$EBUILDS_FILE" && -s "$EBUILDS_FILE" ]]; then
888 einfo "Found existing $EBUILDS_FILE"
889 elif [[ -r "$PKGS_FILE" && -s "$PKGS_FILE" ]]; then
890 clean_trap "$EBUILDS_FILE"
891 while read EXACT_PKG; do
893 PKG="${EXACT_PKG%%-r[[:digit:]]*}"
895 SLOT=$(</var/db/pkg/$EXACT_PKG/SLOT)
897 done < "$PKGS_FILE" > "$EBUILDS_FILE"
898 einfo "Generated new $EBUILDS_FILE"
900 einfo 'Nothing to rebuild.'
901 die 1 '(The program should have already quit, so this is a minor bug.)'
904 get_exact_ebuilds() {
905 einfo 'Assigning files to ebuilds'
906 if [[ -r "$EBUILDS_FILE" && -s "$EBUILDS_FILE" ]]; then
907 einfo "Found existing $EBUILDS_FILE"
908 elif [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]]; then
909 rebuildList=" $(<"$BROKEN_FILE") "
910 rebuildList=(${rebuildList//[[:space:]]obj[[:space:]]/ })
911 get_file_owner "${rebuildList[@]}" | sed 's/^/=/' > "$EBUILDS_FILE"
912 einfo "Generated new $EBUILDS_FILE"
914 einfo 'Nothing to rebuild.'
915 die 1 '(The program should have already quit, so this is a minor bug.)'
918 list_skipped_packages() {
920 ewarn 'Portage could not find any version of the following packages it could build:'
921 ewarn "${SKIP_LIST[@]}"
923 ewarn '(Perhaps they are masked, blocked, or removed from portage.)'
924 ewarn 'Try to emerge them manually.'
928 local -r OLD_EMERGE_DEFAULT_OPTS="$EMERGE_DEFAULT_OPTS"
929 local RAW_REBUILD_LIST
932 if [[ ! $ORDER_PKGS ]]; then
933 einfo 'Skipping package ordering'
936 einfo 'Evaluating package order'
937 if [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" ]]; then
938 einfo "Found existing $ORDER_FILE"
940 clean_trap "$ORDER_FILE"
941 RAW_REBUILD_LIST=$(<"$EBUILDS_FILE")
942 if [[ $RAW_REBUILD_LIST ]]; then
943 export EMERGE_DEFAULT_OPTS="--nospinner --pretend --oneshot --quiet"
944 RAW_REBUILD_LIST=($RAW_REBUILD_LIST) # convert into array
945 # If PACKAGE_NAMES is defined we're using slots, not versions
946 if [[ $PACKAGE_NAMES ]]; then
947 # Eliminate atoms that can't be built
948 for i in "${!RAW_REBUILD_LIST[@]}"; do
949 if [[ "${RAW_REBUILD_LIST[i]}" = *[A-Za-z]* ]]; then
950 portageq best_visible "$PORTAGE_ROOT" "${RAW_REBUILD_LIST[i]}" >/dev/null && continue
951 SKIP_LIST+=("${RAW_REBUILD_LIST[i]}")
953 unset RAW_REBUILD_LIST[i]
955 # If RAW_REBUILD_LIST is empty, then we have nothing to build.
956 if (( ${#RAW_REBUILD_LIST[@]} == 0 )); then
957 if (( ${#SKIP_LIST[@]} == 0 )); then
958 ewarn "The list of packages to skip is empty, but there are no"
959 ewarn "packages listed to rebuild either. This is a bug."
961 list_skipped_packages
963 die 1 'Warning: Portage cannot rebuild any of the necessary packages.'
966 RAW_REBUILD_LIST=("${RAW_REBUILD_LIST[@]/#/=}")
968 RAW_REBUILD_LIST="${RAW_REBUILD_LIST[@]}"
969 REBUILD_GREP=$(emerge --nodeps $RAW_REBUILD_LIST | sed 's/\[[^]]*\]//g')
970 if (( ${PIPESTATUS[0]} == 0 )); then
971 emerge --deep $RAW_REBUILD_LIST |
972 sed 's/\[[^]]*\]//g' |
973 grep -F "$REBUILD_GREP" > "$ORDER_FILE"
976 # Here we use the PIPESTATUS from the second emerge, the --deep one.
977 if (( ${PIPESTATUS[0]} != 0 )); then
979 eerror 'Warning: Failed to resolve package order.'
980 eerror 'Will merge in arbitrary order'
984 - An ebuild is no longer in the portage tree.
985 - An ebuild is masked, use /etc/portage/packages.keyword
986 and/or /etc/portage/package.unmask to unmask it
991 export EMERGE_DEFAULT_OPTS="$OLD_EMERGE_DEFAULT_OPTS"
993 einfo 'Nothing to rebuild.'
994 die 1 '(The program should have already quit, so this is a minor bug.)'
997 [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" ]] && einfo "Generated new $ORDER_FILE"
1008 if [[ $PACKAGE_NAMES ]]; then
1013 assign_packages_to_ebuilds
1021 # Clean up no longer needed environment variables
1022 unset SEARCH_DIRS SEARCH_DIRS_MASK LD_LIBRARY_MASK PORTAGE_ROOT
1024 if [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" ]]; then
1025 REBUILD_LIST=( $(<"$ORDER_FILE") )
1026 REBUILD_LIST="${REBUILD_LIST[@]/#/=}"
1028 REBUILD_LIST=$(sort -u "$EBUILDS_FILE")
1031 trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
1033 einfo 'All prepared. Starting rebuild'
1034 echo "emerge --oneshot ${EMERGE_OPTIONS[@]} $REBUILD_LIST"
1036 is_real_merge && countdown 10
1038 # Link file descriptor #6 with stdin so --ask will work
1041 # Run in background to correctly handle Ctrl-C
1043 EMERGE_DEFAULT_OPTS="--oneshot ${EMERGE_OPTIONS[@]}" emerge $REBUILD_LIST <&6
1044 echo $? > "$STATUS_FILE"
1048 # Now restore stdin from fd #6, where it had been saved, and close fd #6 ( 6<&- ) to free it for other processes to use.
1051 show_unowned_files() {
1052 if grep -qF '(none)' "$OWNERS_FILE"; then
1053 ewarn "Found some broken files that weren't associated with known packages"
1054 ewarn "The broken files are:"
1055 while read filename junk; do
1056 [[ $junk = *none* ]] && ewarn " $filename"
1057 done < "$OWNERS_FILE" | awk '!s[$0]++' # (omit dupes)
1061 if (( $(<"$STATUS_FILE") != 0 )); then
1063 ewarn "$APP_NAME failed to emerge all packages."
1064 ewarn 'you have the following choices:'
1065 einfo "- If emerge failed during the build, fix the problems and re-run $APP_NAME."
1066 einfo '- Use /etc/portage/package.keywords to unmask a newer version of the package.'
1067 einfo " (and remove $ORDER_FILE to be evaluated again)"
1068 einfo '- Modify the above emerge command and run it manually.'
1069 einfo '- Compile or unmerge unsatisfied packages manually,'
1070 einfo ' remove temporary files, and try again.'
1071 einfo ' (you can edit package/ebuild list first)'
1073 einfo 'To remove temporary files, please run:'
1074 einfo "rm ${TMPDIR}/$APP_NAME/*.rr"
1077 elif is_real_merge; then
1079 eerror "terminated. Please remove the temporary files manually:"
1080 eerror "rm ${TMPDIR}/$APP_NAME/*.rr"
1083 (( "${#SKIP_LIST[@]}" != 0 )) && list_skipped_packages
1084 trap trap_cmd SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
1085 einfo 'Build finished correctly. Removing temporary files...'
1087 einfo 'You can re-run revdep-rebuild to verify that all libraries and binaries'
1088 einfo 'are fixed. If some inconsistency remains, it can be orphaned file, deep'
1089 einfo 'dependency, binary package or specially evaluated library.'
1090 if [[ -r "$OWNERS_FILE" && -s "$OWNERS_FILE" ]]; then
1093 [[ $KEEP_TEMP ]] || rm "${FILES[@]}"
1095 einfo 'Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.'