25cbe638a86c5ab42b1c95ee7cc4b4c8b7924678
[gentoolkit.git] / trunk / src / revdep-rebuild / revdep-rebuild
1 #!/bin/bash
2 # Copyright 1999-2008 Gentoo Foundation
3
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>
8
9 # TODO:
10 # - Use more /etc/init.d/functions.sh
11 # - Try to reduce the number of global vars
12
13 ##
14 # Global Variables:
15
16 # Must-be-blank variables:
17 unset GREP_OPTIONS
18
19 # Readonly 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
34 declare -ra FILES=(
35         "$ENV_FILE"
36         "$FILES_FILE"
37         "$LDPATH_FILE"
38         "$BROKEN_FILE"
39         "$ERRORS_FILE"
40         "$RAW_FILE"
41         "$OWNERS_FILE"
42         "$PKGS_FILE"
43         "$EBUILDS_FILE"
44         "$ORDER_FILE"
45         "$STATUS_FILE"
46 )
47
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
57
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
63
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
67 # /etc/make.conf.
68 #
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
75
76 # Other globals:
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
88
89 ##
90 # Refuse to delete anything before we cd to our tmpdir
91 # (See mkdir_and_cd_to_tmpdir()
92 rm() {
93         eerror "I was instructed to rm '$@'"
94         die 1 "Refusing to delete anything before changing to temporary directory."
95 }
96 # Somewhat more portable find -executable
97 # FIXME/UNTESTED (I don't have access to all of the different versions of 
98 # find.)
99 # Usage: find PATH ARGS -- use find like normal, except use -executable instead 
100 # of various versions of -perm /+ blah blah and hacks
101 find() {
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
108                 find() {
109                         a=(${@//-executable/-perm \/u+x})
110                         a=(${a[@]//-writable/-perm \/u+w})
111                         a=(${a[@]//-readable/-perm \/r+w})
112                         command find "${a[@]}"
113                 }
114         elif [[ $(command find "$testsubject" -perm +u+x 2> /dev/null) ]]; then
115                 find() {
116                         a=(${@//-executable/-perm +u+x})
117                         a=(${a[@]//-writable/-perm +u+w})
118                         a=(${a[@]//-readable/-perm +r+w})
119                         command find "${a[@]}"
120                 }
121         else # Last resort
122                 find() {
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[@]}"
127                 }
128         fi
129         find "$@"
130 }
131 print_usage() {
132 cat << EOF
133 Usage: $APP_NAME [OPTIONS] [--] [EMERGE_OPTIONS]
134
135 Broken reverse dependency rebuilder.
136
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.
157
158 Calls emerge, options after -- are ignored by $APP_NAME
159 and passed directly to emerge.
160
161 Report bugs to <http://bugs.gentoo.org>
162 EOF
163 }
164 # Usage: progress i n
165 #        i: current item
166 #        n: total number of items to process
167 progress() {
168         if [[ -t 1 ]]; then
169                 progress() {
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"
175                 }
176                 progress $@
177         else # STDOUT is not a tty. Disable progress meter.
178                 progress() { :; }
179         fi
180 }
181 # Usage: countdown n
182 #        n: number of seconds to count
183 countdown() {
184         local i
185         for ((i=1; i<$1; i++)); do
186                 echo -ne '\a.'
187                 ((i<$1)) && sleep 1
188         done
189         echo -e '\a.'
190 }
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.)
196 clean_var() {
197         awk 'BEGIN         {RS="[[:space:]]"}
198              /-\*/         {exit}
199              /[^[:space:]]/ {gsub(/\/\/+/, "/"); print}' | sort -u
200 }
201 # Exit and optionally output to sterr
202 die() {
203         local status=$1
204         shift
205         eerror "$@"
206         exit $status
207 }
208 # What to do when dynamic linking is consistent
209 clean_exit() {
210         [[ $KEEP_TEMP ]] || rm -f "${FILES[@]}"
211         echo
212         einfo "$OK_TEXT... All done. "
213         exit 0
214 }
215
216 ##
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 $@; }
228         else
229                 get_file_owner() {
230                         local IFS=$'\n'
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:'
236                 }
237         fi
238 }
239
240 ##
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})
247 }
248
249 ##
250 # Use the color preference from portage
251 setup_color() {
252         # This should still work if NOCOLOR is set by the -C flag or in the user's
253         # environment.
254         export NOCOLOR=$(portageq envvar NOCOLOR)
255         [[ $NOCOLOR = yes || $NOCOLOR = true ]] && export RC_NOCOLOR=yes # HACK! (grr)
256         . /etc/init.d/functions.sh
257 }
258
259 ##
260 # Die if an argument is missing.
261 die_if_missing_arg() {
262         [[ ! $2 || $2 = -* ]] && die 1 "Missing expected argument to $1"
263 }
264
265 ##
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 
269         # is sourced
270         print_usage
271         echo
272         echo  "Encountered unrecognized option $1." >&2
273         echo
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."
276         echo
277         exit 1
278 }
279
280 ##
281 # Warn about deprecated options.
282 warn_deprecated_opt() {
283         # We cannot use eerror and einfo because this gets called before function.sh 
284         # is sourced
285         echo
286         echo "Encountered deprecated option $1." >&2
287         [[ $2 ]] && echo "Please use $2 instead." >&2
288 }
289
290 ##
291 # Get whole-word commandline options preceded by two dashes.
292 get_longopts() {
293         case $1 in
294                                                --nocolor) export NOCOLOR="yes";;
295                                               --no-color) warn_deprecated_opt "$1" "--nocolor"
296                                                           export NOCOLOR="yes";;
297                                                  --debug) set -xv;;
298                                                  --exact) unset PACKAGE_NAMES;;
299                                                   --help) print_usage
300                                                           exit 0;;
301                                                 --ignore) RM_OLD_TEMPFILES=1;;
302                                              --keep-temp) KEEP_TEMP=1;;
303                                              --library=*) # TODO: check for invalid values
304                                                           SONAME="${1#*=}"
305                                                           unset SEARCH_BROKEN;;
306                             --soname=*|--soname-regexp=*) # TODO: check for invalid values
307                                                           warn_deprecated_opt "${1%=*}" "--library"
308                                                           SONAME="${1#*=}"
309                                                           unset SEARCH_BROKEN;;
310                                                --library) # TODO: check for invalid values
311                                                           die_if_missing_arg $1 $2
312                                                           shift
313                                                           SONAME="$1"
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
318                                                           shift
319                                                           SONAME="$1"
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() { :; }
326                                                           progress() { :; }
327                                                           quiet=1
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
333                                                           shift
334                                                           avoid_utils="$1";;
335                                                --verbose) VERBOSE=1
336                                                           EMERGE_OPTIONS+=("--verbose");;
337                                          --extra-verbose) warn_deprecated_opt "$1" "--verbose"
338                                                           VERBOSE=1
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"
344                                                           PACKAGE_NAMES=1;;
345                                                        *) die_invalid_option $1;;
346         esac
347 }
348
349 ##
350 # Get single-letter commandline options preceded by a single dash.
351 get_shortopts() {
352         local OPT OPTSTRING OPTARG OPTIND
353         while getopts ":CdehikL:loPpqu:vX" OPT; do
354                 case "$OPT" in
355                         C) # TODO: Match syntax with the rest of gentoolkit
356                            export NOCOLOR="yes";;
357                         d) set -xv;;
358                         e) unset PACKAGE_NAMES;;
359                         h) print_usage
360                            exit 0;;
361                         i) RM_OLD_TEMPFILES=1;;
362                         k) KEEP_TEMP=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");;
370                         q) echo_v() { :; }
371                            progress() { :; }
372                            quiet=1
373                            EMERGE_OPTIONS+=("--quiet");;
374                         u) avoid_utils="$1";; # TODO: Check for invalid values
375                         v) VERBOSE=1
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"
380                            PACKAGE_NAMES=1;;
381                         *) die_invalid_option "-$OPTARG";;
382                 esac
383         done
384 }
385
386 ##
387 # Get command-line options.
388 get_opts() {
389         local avoid_utils
390         local -a args
391         echo_v() { ewarn "$@"; }
392         unset VERBOSE KEEP_TEMP EMERGE_OPTIONS RM_OLD_TEMPFILES
393         ORDER_PKGS=1
394         PACKAGE_NAMES=1
395         SONAME="not found"
396         SEARCH_BROKEN=1
397         FULL_LD_PATH=1
398         while [[ $1 ]]; do
399                 case $1 in
400                         --) shift
401                             EMERGE_OPTIONS+=("$@")
402                             break;;
403                         -*) while true; do
404                               args+=("$1")
405                               shift
406                               [[ ${1:--} = -* ]] && break
407                             done
408                             if [[ ${args[0]} = --* ]]; then
409                               get_longopts  "${args[@]}"
410                             else
411                               get_shortopts "${args[@]}"
412                             fi;;
413                          *) die_invalid_option "$1";;
414                 esac
415                 unset args
416         done
417
418         setup_get_file_owner
419         setup_color
420         normalize_emerge_opts
421
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)
426         fi
427 }
428
429 is_real_merge() {
430         [[ ${EMERGE_OPTIONS[@]} != *--pretend* &&
431            ${EMERGE_OPTIONS[@]} != *--fetchonly* ]]
432 }
433
434 get_opts "$@"
435
436 einfo "Configuring search environment for $APP_NAME"
437
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"
445 fi
446
447 PORTAGE_ROOT=$(portageq envvar ROOT)
448 PORTAGE_ROOT="${PORTAGE_ROOT:-/}"
449
450 # Update the incremental variables using /etc/profile.env, /etc/ld.so.conf,
451 # portage, and the environment
452
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)
459
460 # Add the defaults
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)
466         done
467         unset e # HACK
468 else
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"
472 fi
473
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")
477 fi
478
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)
482 fi
483
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
489 filter_SEARCH_DIRS=
490 for sdir in ${SEARCH_DIRS} ; do
491         unset skip_me
492         for mdir in ${SEARCH_DIRS_MASK} ; do
493                 [[ ${sdir} == ${mdir}/* ]] \
494                         && skip_me=1 && break
495         done
496         [[ -n ${skip_me} ]] || filter_SEARCH_DIRS+=" ${sdir}"
497 done
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."
501
502 ##
503 # Clean up temporary files and exit
504 cleanup_and_die() {
505         rm -f "$@"
506         die 1 "  ...terminated. Removing incomplete $@."
507 }
508 ##
509 # Clean trap
510 clean_trap() {
511         trap "cleanup_and_die $*" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
512         rm -f "$@"
513 }
514 ##
515 # Returns 0 if the first arg is found in the remaining args, 1 otherwise
516 # (Returns 2 if given less than 2 arguments)
517 has() {
518         (( $# > 1 )) || return 2
519         local IFS=$'\a' target="$1"
520         shift
521         [[ $'\a'"$*"$'\a' = *$'\a'$target$'\a'* ]]
522 }
523 ##
524 # Special custom cd
525 cd() {
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"
530                 fi
531         else
532                 die 1 "Unable to change working directory to '$@'"
533         fi
534 }
535 ##
536 # Special custom rm
537 setup_rm() {
538         ##
539         # Anything in the FILES array in tmpdir is fair game for removal
540         rm() {
541                 local i IFS=$'\a'
542                 [[ $APP_NAME ]] || die 1 '$APP_NAME is not defined! (This is a bug.)'
543                 case $@ in
544                         */*|*-r*|*-R*) die 1 "Oops, I'm not allowed to delete that. ($@)";;
545                 esac
546                 for i; do
547                         # Don't delete files that are not listed in the array
548                         # Allow no slashes or recursive deletes at all.
549                         case $i in
550                                 */*|-*r*|-*R*) :;;        # Not OK
551                                            -*) continue;; # OK
552                         esac
553                         has "$i" "${FILES[@]}" && continue
554                         die 1 "Oops, I'm not allowed to delete that. ($@)"
555                 done
556                 command rm "$@"
557         }
558         # delete this setup function so it's harmless to re-run
559         setup_rm() { :; }
560 }
561 ##
562 # Make our temporary files directory
563 setup_tmpdir() {
564         if [[ ! $1 ]]; then
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."
572                 fi
573                 cd "$1"
574         elif mkdir -m 02700 "$1" && chown :portage "$1" && chmod 02770 "$1"; then
575                 cd "$1"
576         else
577                 die 1 "Unable to find or create a satisfactory location for temporary files"
578         fi
579         [[ $VERBOSE ]] && einfo "Temporary files are located in $PWD"
580         setup_rm
581 }
582 get_search_env() {
583         local new_env
584         local old_env
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"
588
589         # From here on all work is done inside the temporary directory
590         setup_tmpdir "$tmp_target"
591
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"
597         else
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//\//\\/}"
604                 else
605                         # Set to "<tab>$SONAME<space>"
606                         SONAME_SEARCH=$'\t'"$SONAME "
607                 fi
608                 local uuid="${SONAME##*/}"
609                 uuid="${uuid//[[:space:]]}"
610                 uuid="${uuid//\*}"
611                 HEAD_TEXT="using $SONAME"
612                 OK_TEXT="There are no dynamic links to $SONAME"
613                 unset WORKING_TEXT
614                 setup_tmpdir "$uuid"
615         fi
616
617         # If any of our temporary files are older than 1 day, remove them all
618         if [[ ! $KEEP_TEMP ]]; then
619                 while read; do
620                         RM_OLD_TEMPFILES=1
621                         break
622                 done < <(find -L . -maxdepth 1 -type f -name '*.rr' -mmin +1440 -print 2>/dev/null)
623         fi
624
625         # Compare old and new environments
626         # Don't use our previous files if environment doesn't match
627         new_env=$(
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/})
632                 cat <<- EOF
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"
640                 EOF
641         )
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...'
646                         RM_OLD_TEMPFILES=1
647                 fi
648         else
649                 # No env file found, silently delete any other tempfiles that may exist
650                 RM_OLD_TEMPFILES=1
651         fi
652
653         # If we should remove old tempfiles, do so
654         if [[ $RM_OLD_TEMPFILES ]]; then
655                 rm -f "${FILES[@]}"
656         else
657                 for file in "${FILES[@]}"; do
658                         chown root:portage "$file"
659                         chmod 02770 "$file"
660                 done
661         fi
662
663         # Save the environment in a file for next time
664         echo "$new_env" > "$ENV_FILE"
665
666         [[ $VERBOSE ]] && echo $'\n'"$APP_NAME environment:"$'\n'"$new_env"
667
668         echo
669         einfo "Checking reverse dependencies"
670         einfo "Packages containing binaries and libraries $HEAD_TEXT"
671         einfo "will be emerged."
672 }
673 get_files() {
674         einfo "Collecting system binaries and libraries"
675         if [[ -r "$FILES_FILE" && -s "$FILES_FILE" ]]; then
676                 einfo "Found existing $FILES_FILE"
677         else
678                 # Be safe and remove any extraneous temporary files
679                 rm -f "${FILES[@]}"
680
681                 clean_trap "$FILES_FILE"
682
683                 if [[ $SEARCH_DIRS_MASK ]]; then
684                         findMask=($SEARCH_DIRS_MASK)
685                         findMask="${findMask[@]/#/-o -path }"
686                         findMask="( ${findMask#-o } ) -prune -o"
687                 fi
688                 # TODO: Check this
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"
694         fi
695 }
696 get_ldpath() {
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."
702         else
703                 clean_trap "$LDPATH_FILE"
704                 # Ensure that the "trusted" lib directories are at the start of the path
705                 COMPLETE_LD_LIBRARY_PATH=(
706                         /lib*
707                         /usr/lib*
708                         $(sed '/^#/d;s/#.*$//' < /etc/ld.so.conf)
709                         $(sed 's:/[^/]*$::' < "$FILES_FILE" | sort -ru)
710                 )
711                 IFS=':'
712                 COMPLETE_LD_LIBRARY_PATH="${COMPLETE_LD_LIBRARY_PATH[*]}"
713                 IFS="$OIFS"
714                 echo "$COMPLETE_LD_LIBRARY_PATH" > "$LDPATH_FILE"
715                 einfo "Generated new $LDPATH_FILE"
716         fi
717 }
718 main_checks() {
719         local target_file
720         local -a files
721         local i=0
722         local ldd_output
723         local ldd_status
724         local numFiles
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")
730         fi
731         einfo "Checking dynamic linking $WORKING_TEXT"
732         if [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]]; then
733                 einfo "Found existing $BROKEN_FILE."
734         else
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
752                                                         MISSING_LIBS=$(
753                                                                 expr='s/[[:space:]]*\([^[:space:]]*\) => not found/\1/p'
754                                                                 sed -n "$expr" <<< "$ldd_output"
755                                                         )
756                                                         REQUIRED_LIBS=$(
757                                                                 expr='s/^[[:space:]]*NEEDED[[:space:]]*\([^[:space:]]*\).*/\1/p';
758                                                                 objdump -x "$target_file" | grep NEEDED | sed "$expr" | sort -u
759                                                         )
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)"
764                                                         fi
765                                                 fi
766                                         else
767                                                 # FIXME: I hate duplicating code
768                                                 # Only rebuild for direct dependencies
769                                                 MISSING_LIBS=$(
770                                                         expr="/$SONAME_SEARCH/s/^[[:space:]]*\([^[:space:]]*\).*$/\1/p"
771                                                         sort -u <<< "$ldd_output" | sed -n "$expr"
772                                                 )
773                                                 REQUIRED_LIBS=$(
774                                                         expr='s/^[[:space:]]*NEEDED[[:space:]]*\([^[:space:]]*\).*/\1/p';
775                                                         objdump -x "$target_file" | grep NEEDED | sed "$expr" | sort -u
776                                                 )
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)"
782                                                         else
783                                                                 echo_v "  found $target_file"
784                                                         fi
785                                                 fi
786                                         fi
787                                 fi
788                         elif [[ $SEARCH_BROKEN ]]; then
789                                 # Look for broken .la files
790                                 for depend in $(
791                                         awk -F"[=']" '/^dependency_libs/{
792                                                 gsub("^-[^[:space:]]*", "", $3);
793                                                 gsub("[[:space:]]-[^[:space:]]*", "", $3);
794                                                 print $3
795                                         }' "$target_file"
796                                 ); do
797                                         if [[ $depend = /* && ! -e $depend ]]; then
798                                                 echo "obj $target_file" >> "$BROKEN_FILE"
799                                                 echo_v "  broken $target_file (requires $depend)"
800                                         fi
801                                 done
802                         fi
803                         [[ $VERBOSE ]] &&
804                                 progress $((++i)) $numFiles $target_file ||
805                                 progress $((++i)) $numFiles
806                 done
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)"
812                         done < <(
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
819                                                 print $NF
820                                         }' "$ERRORS_FILE"
821                         )
822                 fi
823                 [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]] || clean_exit
824                 einfo "Generated new $BROKEN_FILE"
825         fi
826 }
827 get_packages() {
828         local target_file
829         local EXACT_PKG
830         local PKG
831         local obj
832         einfo 'Assigning files to packages'
833         if [[ -r "$RAW_FILE" && -s "$RAW_FILE" ]]; then
834                 einfo "Found existing $RAW_FILE"
835         else
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:]]*}"
842                                 PKG="${PKG%-*}"
843                                 echo "$EXACT_PKG" >> "$RAW_FILE"
844                                 echo "$target_file -> $EXACT_PKG" >> "$OWNERS_FILE"
845                                 echo_v "  $target_file -> $PKG"
846                         else
847                                 ewarn " !!! $target_file not owned by any package is broken !!!"
848                                 echo "$target_file -> (none)" >> "$OWNERS_FILE"
849                                 echo_v "  $target_file -> (none)"
850                         fi
851                 done < "$BROKEN_FILE"
852                 einfo "Generated new $RAW_FILE and $OWNERS_FILE"
853         fi
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
862                                 ewarn "  $filename"
863                         done < "$OWNERS_FILE"
864                 fi
865                 exit 0 # FIXME: Should we exit 1 here?
866         fi
867 }
868 clean_packages() {
869         einfo 'Cleaning list of packages to rebuild'
870         if [[ -r "$PKGS_FILE" && -s "$PKGS_FILE" ]]; then
871                 einfo "Found existing $PKGS_FILE"
872         else
873                 sort -u "$RAW_FILE" > "$PKGS_FILE"
874                 einfo "Generated new $PKGS_FILE"
875         fi
876 }
877 assign_packages_to_ebuilds() {
878         local EXACT_PKG
879         local PKG
880         local SLOT
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
887                                 # Get the slot
888                                 PKG="${EXACT_PKG%%-r[[:digit:]]*}"
889                                 PKG="${PKG%-*}"
890                                 SLOT=$(</var/db/pkg/$EXACT_PKG/SLOT)
891                                 echo "$PKG:$SLOT"
892                         done < "$PKGS_FILE" > "$EBUILDS_FILE"
893                         einfo "Generated new $EBUILDS_FILE"
894         else
895                 einfo 'Nothing to rebuild.'
896                 die 1 '(The program should have already quit, so this is a minor bug.)'
897         fi
898 }
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"
908         else
909                 einfo 'Nothing to rebuild.'
910                 die 1 '(The program should have already quit, so this is a minor bug.)'
911         fi
912 }
913 list_skipped_packages() {
914         ewarn
915         ewarn 'Portage could not find any version of the following packages it could build:'
916         ewarn "${SKIP_LIST[@]}"
917         ewarn
918         ewarn '(Perhaps they are masked, blocked, or removed from portage.)'
919         ewarn 'Try to emerge them manually.'
920         ewarn
921 }
922 get_build_order() {
923         local -r OLD_EMERGE_DEFAULT_OPTS="$EMERGE_DEFAULT_OPTS"
924         local RAW_REBUILD_LIST
925         local REBUILD_GREP
926         local i
927         if [[ ! $ORDER_PKGS ]]; then
928                 einfo 'Skipping package ordering'
929                 return
930         fi
931         einfo 'Evaluating package order'
932         if [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" ]]; then
933                 einfo "Found existing $ORDER_FILE"
934         else
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]}")
947                                         fi
948                                         unset RAW_REBUILD_LIST[i]
949                                 done
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."
955                                         else
956                                                 list_skipped_packages
957                                         fi
958                                         die 1 'Warning: Portage cannot rebuild any of the necessary packages.'
959                                 fi
960                         else
961                                 RAW_REBUILD_LIST=("${RAW_REBUILD_LIST[@]/#/=}")
962                         fi
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"
969                         fi
970
971                         # Here we use the PIPESTATUS from the second emerge, the --deep one.
972                         if (( ${PIPESTATUS[0]} != 0 )); then
973                                         eerror
974                                         eerror 'Warning: Failed to resolve package order.'
975                                         eerror 'Will merge in arbitrary order'
976                                         eerror
977                                         cat <<- EOF
978                                                 Possible reasons:
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
982                                         EOF
983                                         countdown 5
984                                         rm -f "$ORDER_FILE"
985                         fi
986                         export EMERGE_DEFAULT_OPTS="$OLD_EMERGE_DEFAULT_OPTS"
987                 else
988                         einfo 'Nothing to rebuild.'
989                         die 1 '(The program should have already quit, so this is a minor bug.)'
990                 fi
991         fi
992         [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" ]] && einfo "Generated new $ORDER_FILE"
993 }
994
995 get_search_env
996 echo
997 get_files
998 echo
999 get_ldpath
1000 echo
1001 main_checks
1002 echo
1003 if [[ $PACKAGE_NAMES ]]; then
1004         get_packages
1005         echo
1006         clean_packages
1007         echo
1008         assign_packages_to_ebuilds
1009 else
1010         get_exact_ebuilds
1011 fi
1012 echo
1013 get_build_order
1014 echo
1015
1016 # Clean up no longer needed environment variables
1017 unset SEARCH_DIRS SEARCH_DIRS_MASK LD_LIBRARY_MASK PORTAGE_ROOT
1018
1019 if [[ -r $ORDER_FILE && -s $ORDER_FILE ]]; then
1020         REBUILD_LIST=( $(<"$ORDER_FILE") )
1021         REBUILD_LIST="${REBUILD_LIST[@]/#/=}"
1022 else
1023         REBUILD_LIST=$(sort -u "$EBUILDS_FILE")
1024 fi
1025
1026 trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
1027
1028 einfo 'All prepared. Starting rebuild'
1029 echo "emerge --oneshot ${EMERGE_OPTIONS[@]} $REBUILD_LIST"
1030
1031 is_real_merge && countdown 10
1032
1033 # Link file descriptor #6 with stdin so --ask will work
1034 exec 6<&0
1035
1036 # Run in background to correctly handle Ctrl-C
1037 {
1038         EMERGE_DEFAULT_OPTS="--oneshot ${EMERGE_OPTIONS[@]}" emerge $REBUILD_LIST <&6
1039         echo $? > "$STATUS_FILE"
1040 } &
1041 wait
1042
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.
1044 exec 0<&6 6<&-
1045
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)
1053         fi
1054 }
1055
1056 if (( $(<"$STATUS_FILE") != 0 )); then
1057         ewarn
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)'
1067         einfo
1068         einfo 'To remove temporary files, please run:'
1069         einfo "rm ${TMPDIR}/$APP_NAME/*.rr"
1070         show_unowned_files
1071         exit $EMERGE_STATUS
1072 elif is_real_merge; then
1073         trap_cmd() {
1074                 eerror "terminated. Please remove the temporary files manually:"
1075                 eerror "rm ${TMPDIR}/$APP_NAME/*.rr"
1076                 exit 1
1077         }
1078         (( "${#SKIP_LIST[@]}" != 0 )) && list_skipped_packages
1079         trap trap_cmd SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
1080         einfo 'Build finished correctly. Removing temporary files...'
1081         einfo
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
1086         show_unowned_files
1087         fi
1088         [[ $KEEP_TEMP ]] || rm "${FILES[@]}"
1089 else
1090         einfo 'Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.'
1091 fi
1092