010c20ae7b0959c38fc5fd24c859a991deaee43b
[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         echo
271         echo  "Encountered unrecognized option $1." >&2
272         echo
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."
275         echo
276         echo  "For example, $APP_NAME -v -- --ask"
277         echo
278         echo  "See the man page or $APP_NAME -h for more detail."
279         echo
280         exit 1
281 }
282
283 ##
284 # Warn about deprecated options.
285 warn_deprecated_opt() {
286         # We cannot use eerror and einfo because this gets called before function.sh 
287         # is sourced
288         echo
289         echo "Encountered deprecated option $1." >&2
290         [[ $2 ]] && echo "Please use $2 instead." >&2
291 }
292
293 ##
294 # Get whole-word commandline options preceded by two dashes.
295 get_longopts() {
296         case $1 in
297                                                --nocolor) export NOCOLOR="yes";;
298                                               --no-color) warn_deprecated_opt "$1" "--nocolor"
299                                                           export NOCOLOR="yes";;
300                                                  --debug) set -xv;;
301                                                  --exact) unset PACKAGE_NAMES;;
302                                                   --help) print_usage
303                                                           exit 0;;
304                                                 --ignore) RM_OLD_TEMPFILES=1;;
305                                              --keep-temp) KEEP_TEMP=1;;
306                                              --library=*) # TODO: check for invalid values
307                                                           SONAME="${1#*=}"
308                                                           unset SEARCH_BROKEN;;
309                             --soname=*|--soname-regexp=*) # TODO: check for invalid values
310                                                           warn_deprecated_opt "${1%=*}" "--library"
311                                                           SONAME="${1#*=}"
312                                                           unset SEARCH_BROKEN;;
313                                                --library) # TODO: check for invalid values
314                                                           die_if_missing_arg $1 $2
315                                                           shift
316                                                           SONAME="$1"
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
321                                                           shift
322                                                           SONAME="$1"
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() { :; }
329                                                           progress() { :; }
330                                                           quiet=1
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
336                                                           shift
337                                                           avoid_utils="$1";;
338                                                --verbose) VERBOSE=1
339                                                           EMERGE_OPTIONS+=("--verbose");;
340                                          --extra-verbose) warn_deprecated_opt "$1" "--verbose"
341                                                           VERBOSE=1
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"
347                                                           PACKAGE_NAMES=1;;
348                                                        *) die_invalid_option $1;;
349         esac
350 }
351
352 ##
353 # Get single-letter commandline options preceded by a single dash.
354 get_shortopts() {
355         local OPT OPTSTRING OPTARG OPTIND
356         while getopts ":CdehikL:loPpqu:vX" OPT; do
357                 case "$OPT" in
358                         C) # TODO: Match syntax with the rest of gentoolkit
359                            export NOCOLOR="yes";;
360                         d) set -xv;;
361                         e) unset PACKAGE_NAMES;;
362                         h) print_usage
363                            exit 0;;
364                         i) RM_OLD_TEMPFILES=1;;
365                         k) KEEP_TEMP=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");;
373                         q) echo_v() { :; }
374                            progress() { :; }
375                            quiet=1
376                            EMERGE_OPTIONS+=("--quiet");;
377                         u) avoid_utils="$1";; # TODO: Check for invalid values
378                         v) VERBOSE=1
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"
383                            PACKAGE_NAMES=1;;
384                         *) die_invalid_option "-$OPTARG";;
385                 esac
386         done
387 }
388
389 ##
390 # Get command-line options.
391 get_opts() {
392         local avoid_utils
393         local -a args
394         echo_v() { ewarn "$@"; }
395         unset VERBOSE KEEP_TEMP EMERGE_OPTIONS RM_OLD_TEMPFILES
396         ORDER_PKGS=1
397         PACKAGE_NAMES=1
398         SONAME="not found"
399         SEARCH_BROKEN=1
400         FULL_LD_PATH=1
401         while [[ $1 ]]; do
402                 case $1 in
403                         --) shift
404                             EMERGE_OPTIONS+=("$@")
405                             break;;
406                         -*) while true; do
407                               args+=("$1")
408                               shift
409                               [[ ${1:--} = -* ]] && break
410                             done
411                             if [[ ${args[0]} = --* ]]; then
412                               get_longopts  "${args[@]}"
413                             else
414                               get_shortopts "${args[@]}"
415                             fi;;
416                          *) die_invalid_option "$1";;
417                 esac
418                 unset args
419         done
420
421         setup_get_file_owner
422         setup_color
423         normalize_emerge_opts
424
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)
429         fi
430 }
431
432 is_real_merge() {
433         [[ ${EMERGE_OPTIONS[@]} != *--pretend* &&
434            ${EMERGE_OPTIONS[@]} != *--fetchonly* ]]
435 }
436
437 get_opts "$@"
438
439 einfo "Configuring search environment for $APP_NAME"
440
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"
448 fi
449
450 PORTAGE_ROOT=$(portageq envvar ROOT)
451 PORTAGE_ROOT="${PORTAGE_ROOT:-/}"
452
453 # Update the incremental variables using /etc/profile.env, /etc/ld.so.conf,
454 # portage, and the environment
455
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)
462
463 # Add the defaults
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)
469         done
470         unset e # HACK
471 else
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"
475 fi
476
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")
480 fi
481
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)
485 fi
486
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
492 filter_SEARCH_DIRS=
493 for sdir in ${SEARCH_DIRS} ; do
494         unset skip_me
495         for mdir in ${SEARCH_DIRS_MASK} ; do
496                 [[ ${sdir} == ${mdir}/* ]] \
497                         && skip_me=1 && break
498         done
499         [[ -n ${skip_me} ]] || filter_SEARCH_DIRS+=" ${sdir}"
500 done
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."
504
505 ##
506 # Clean up temporary files and exit
507 cleanup_and_die() {
508         set -x
509         rm -f "$@"
510         die 1 "  ...terminated. Removing incomplete $@."
511 }
512 ##
513 # Clean trap
514 clean_trap() {
515         trap "cleanup_and_die $*" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
516         rm -f "$@"
517 }
518 ##
519 # Returns 0 if the first arg is found in the remaining args, 1 otherwise
520 # (Returns 2 if given less than 2 arguments)
521 has() {
522         (( $# > 1 )) || return 2
523         local IFS=$'\a' target="$1"
524         shift
525         [[ $'\a'"$*"$'\a' = *$'\a'$target$'\a'* ]]
526 }
527 ##
528 # Special custom cd
529 cd() {
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"
534                 fi
535         else
536                 die 1 "Unable to change working directory to '$@'"
537         fi
538 }
539 ##
540 # Special custom rm
541 setup_rm() {
542         ##
543         # Anything in the FILES array in tmpdir is fair game for removal
544         rm() {
545                 local i IFS=$'\a'
546                 [[ $APP_NAME ]] || die 1 '$APP_NAME is not defined! (This is a bug.)'
547                 case $@ in
548                         */*|*-r*|*-R*) die 1 "Oops, I'm not allowed to delete that. ($@)";;
549                 esac
550                 for i; do
551                         # Don't delete files that are not listed in the array
552                         # Allow no slashes or recursive deletes at all.
553                         case $i in
554                                 */*|-*r*|-*R*) :;;        # Not OK
555                                            -*) continue;; # OK
556                         esac
557                         has "$i" "${FILES[@]}" && continue
558                         die 1 "Oops, I'm not allowed to delete that. ($@)"
559                 done
560                 command rm "$@"
561         }
562         # delete this setup function so it's harmless to re-run
563         setup_rm() { :; }
564 }
565 ##
566 # Make our temporary files directory
567 setup_tmpdir() {
568         if [[ ! $1 ]]; then
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."
576                 fi
577                 cd "$1"
578         elif mkdir -m 0700 "$1" && chown :portage "$1"; then
579                 cd "$1"
580         else
581                 die 1 "Unable to find or create a satisfactory location for temporary files"
582         fi
583         [[ $VERBOSE ]] && einfo "Temporary files are located in $PWD"
584         setup_rm
585 }
586 get_search_env() {
587         local new_env
588         local old_env
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}"
593
594         # From here on all work is done inside the temporary directory
595         setup_tmpdir "$tmp_target" "$uid"
596
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"
602         else
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//\//\\/}"
609                 else
610                         # Set to "<tab>$SONAME<space>"
611                         SONAME_SEARCH=$'\t'"$SONAME "
612                 fi
613                 local uuid="${SONAME##*/}"
614                 uuid="${uuid//[[:space:]]}"
615                 uuid="${uuid//\*}"
616                 HEAD_TEXT="using $SONAME"
617                 OK_TEXT="There are no dynamic links to $SONAME"
618                 unset WORKING_TEXT
619                 setup_tmpdir "$uuid"
620         fi
621
622         # If any of our temporary files are older than 1 day, remove them all
623         if [[ ! $KEEP_TEMP ]]; then
624                 while read; do
625                         RM_OLD_TEMPFILES=1
626                         break
627                 done < <(find -L . -maxdepth 1 -type f -name '*.rr' -mmin +1440 -print 2>/dev/null)
628         fi
629
630         # Compare old and new environments
631         # Don't use our previous files if environment doesn't match
632         new_env=$(
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/})
637                 cat <<- EOF
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"
645                 EOF
646         )
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...'
651                         RM_OLD_TEMPFILES=1
652                 fi
653         else
654                 # No env file found, silently delete any other tempfiles that may exist
655                 RM_OLD_TEMPFILES=1
656         fi
657
658         # If we should remove old tempfiles, do so
659         if [[ $RM_OLD_TEMPFILES ]]; then
660                 rm -f "${FILES[@]}"
661         else
662                 for file in "${FILES[@]}"; do
663                         chown ${uid}:portage "$file"
664                         chmod 700 "$file"
665                 done
666         fi
667
668         # Save the environment in a file for next time
669         echo "$new_env" > "$ENV_FILE"
670
671         [[ $VERBOSE ]] && echo $'\n'"$APP_NAME environment:"$'\n'"$new_env"
672
673         echo
674         einfo "Checking reverse dependencies"
675         einfo "Packages containing binaries and libraries $HEAD_TEXT"
676         einfo "will be emerged."
677 }
678 get_files() {
679         einfo "Collecting system binaries and libraries"
680         if [[ -r "$FILES_FILE" && -s "$FILES_FILE" ]]; then
681                 einfo "Found existing $FILES_FILE"
682         else
683                 # Be safe and remove any extraneous temporary files
684                 rm -f "${FILES[@]:1}"
685
686                 clean_trap "$FILES_FILE"
687
688                 if [[ $SEARCH_DIRS_MASK ]]; then
689                         findMask=($SEARCH_DIRS_MASK)
690                         findMask="${findMask[@]/#/-o -path }"
691                         findMask="( ${findMask#-o } ) -prune -o"
692                 fi
693                 # TODO: Check this
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"
699         fi
700 }
701 get_ldpath() {
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."
707         else
708                 clean_trap "$LDPATH_FILE"
709                 # Ensure that the "trusted" lib directories are at the start of the path
710                 COMPLETE_LD_LIBRARY_PATH=(
711                         /lib*
712                         /usr/lib*
713                         $(sed '/^#/d;s/#.*$//' < /etc/ld.so.conf)
714                         $(sed 's:/[^/]*$::' < "$FILES_FILE" | sort -ru)
715                 )
716                 IFS=':'
717                 COMPLETE_LD_LIBRARY_PATH="${COMPLETE_LD_LIBRARY_PATH[*]}"
718                 IFS="$OIFS"
719                 echo "$COMPLETE_LD_LIBRARY_PATH" > "$LDPATH_FILE"
720                 einfo "Generated new $LDPATH_FILE"
721         fi
722 }
723 main_checks() {
724         local target_file
725         local -a files
726         local i=0
727         local ldd_output
728         local ldd_status
729         local numFiles
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")
735         fi
736         einfo "Checking dynamic linking $WORKING_TEXT"
737         if [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]]; then
738                 einfo "Found existing $BROKEN_FILE."
739         else
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
757                                                         MISSING_LIBS=$(
758                                                                 expr='s/[[:space:]]*\([^[:space:]]*\) => not found/\1/p'
759                                                                 sed -n "$expr" <<< "$ldd_output"
760                                                         )
761                                                         REQUIRED_LIBS=$(
762                                                                 expr='s/^[[:space:]]*NEEDED[[:space:]]*\([^[:space:]]*\).*/\1/p';
763                                                                 objdump -x "$target_file" | grep NEEDED | sed "$expr" | sort -u
764                                                         )
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)"
769                                                         fi
770                                                 fi
771                                         else
772                                                 # FIXME: I hate duplicating code
773                                                 # Only rebuild for direct dependencies
774                                                 MISSING_LIBS=$(
775                                                         expr="/$SONAME_SEARCH/s/^[[:space:]]*\([^[:space:]]*\).*$/\1/p"
776                                                         sort -u <<< "$ldd_output" | sed -n "$expr"
777                                                 )
778                                                 REQUIRED_LIBS=$(
779                                                         expr='s/^[[:space:]]*NEEDED[[:space:]]*\([^[:space:]]*\).*/\1/p';
780                                                         objdump -x "$target_file" | grep NEEDED | sed "$expr" | sort -u
781                                                 )
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)"
787                                                         else
788                                                                 echo_v "  found $target_file"
789                                                         fi
790                                                 fi
791                                         fi
792                                 fi
793                         elif [[ $SEARCH_BROKEN ]]; then
794                                 # Look for broken .la files
795                                 for depend in $(
796                                         awk -F"[=']" '/^dependency_libs/{
797                                                 gsub("^-[^[:space:]]*", "", $3);
798                                                 gsub("[[:space:]]-[^[:space:]]*", "", $3);
799                                                 print $3
800                                         }' "$target_file"
801                                 ); do
802                                         if [[ $depend = /* && ! -e $depend ]]; then
803                                                 echo "obj $target_file" >> "$BROKEN_FILE"
804                                                 echo_v "  broken $target_file (requires $depend)"
805                                         fi
806                                 done
807                         fi
808                         [[ $VERBOSE ]] &&
809                                 progress $((++i)) $numFiles $target_file ||
810                                 progress $((++i)) $numFiles
811                 done
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)"
817                         done < <(
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
824                                                 print $NF
825                                         }' "$ERRORS_FILE"
826                         )
827                 fi
828                 [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]] || clean_exit
829                 einfo "Generated new $BROKEN_FILE"
830         fi
831 }
832 get_packages() {
833         local target_file
834         local EXACT_PKG
835         local PKG
836         local obj
837         einfo 'Assigning files to packages'
838         if [[ -r "$RAW_FILE" && -s "$RAW_FILE" ]]; then
839                 einfo "Found existing $RAW_FILE"
840         else
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:]]*}"
847                                 PKG="${PKG%-*}"
848                                 echo "$EXACT_PKG" >> "$RAW_FILE"
849                                 echo "$target_file -> $EXACT_PKG" >> "$OWNERS_FILE"
850                                 echo_v "  $target_file -> $PKG"
851                         else
852                                 ewarn " !!! $target_file not owned by any package is broken !!!"
853                                 echo "$target_file -> (none)" >> "$OWNERS_FILE"
854                                 echo_v "  $target_file -> (none)"
855                         fi
856                 done < "$BROKEN_FILE"
857                 einfo "Generated new $RAW_FILE and $OWNERS_FILE"
858         fi
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
867                                 ewarn "  $filename"
868                         done < "$OWNERS_FILE"
869                 fi
870                 exit 0 # FIXME: Should we exit 1 here?
871         fi
872 }
873 clean_packages() {
874         einfo 'Cleaning list of packages to rebuild'
875         if [[ -r "$PKGS_FILE" && -s "$PKGS_FILE" ]]; then
876                 einfo "Found existing $PKGS_FILE"
877         else
878                 sort -u "$RAW_FILE" > "$PKGS_FILE"
879                 einfo "Generated new $PKGS_FILE"
880         fi
881 }
882 assign_packages_to_ebuilds() {
883         local EXACT_PKG
884         local PKG
885         local SLOT
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
892                                 # Get the slot
893                                 PKG="${EXACT_PKG%%-r[[:digit:]]*}"
894                                 PKG="${PKG%-*}"
895                                 SLOT=$(</var/db/pkg/$EXACT_PKG/SLOT)
896                                 echo "$PKG:$SLOT"
897                         done < "$PKGS_FILE" > "$EBUILDS_FILE"
898                         einfo "Generated new $EBUILDS_FILE"
899         else
900                 einfo 'Nothing to rebuild.'
901                 die 1 '(The program should have already quit, so this is a minor bug.)'
902         fi
903 }
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"
913         else
914                 einfo 'Nothing to rebuild.'
915                 die 1 '(The program should have already quit, so this is a minor bug.)'
916         fi
917 }
918 list_skipped_packages() {
919         ewarn
920         ewarn 'Portage could not find any version of the following packages it could build:'
921         ewarn "${SKIP_LIST[@]}"
922         ewarn
923         ewarn '(Perhaps they are masked, blocked, or removed from portage.)'
924         ewarn 'Try to emerge them manually.'
925         ewarn
926 }
927 get_build_order() {
928         local -r OLD_EMERGE_DEFAULT_OPTS="$EMERGE_DEFAULT_OPTS"
929         local RAW_REBUILD_LIST
930         local REBUILD_GREP
931         local i
932         if [[ ! $ORDER_PKGS ]]; then
933                 einfo 'Skipping package ordering'
934                 return
935         fi
936         einfo 'Evaluating package order'
937         if [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" ]]; then
938                 einfo "Found existing $ORDER_FILE"
939         else
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]}")
952                                         fi
953                                         unset RAW_REBUILD_LIST[i]
954                                 done
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."
960                                         else
961                                                 list_skipped_packages
962                                         fi
963                                         die 1 'Warning: Portage cannot rebuild any of the necessary packages.'
964                                 fi
965                         else
966                                 RAW_REBUILD_LIST=("${RAW_REBUILD_LIST[@]/#/=}")
967                         fi
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"
974                         fi
975
976                         # Here we use the PIPESTATUS from the second emerge, the --deep one.
977                         if (( ${PIPESTATUS[0]} != 0 )); then
978                                         eerror
979                                         eerror 'Warning: Failed to resolve package order.'
980                                         eerror 'Will merge in arbitrary order'
981                                         eerror
982                                         cat <<- EOF
983                                                 Possible reasons:
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
987                                         EOF
988                                         countdown 5
989                                         rm -f "$ORDER_FILE"
990                         fi
991                         export EMERGE_DEFAULT_OPTS="$OLD_EMERGE_DEFAULT_OPTS"
992                 else
993                         einfo 'Nothing to rebuild.'
994                         die 1 '(The program should have already quit, so this is a minor bug.)'
995                 fi
996         fi
997         [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" ]] && einfo "Generated new $ORDER_FILE"
998 }
999
1000 get_search_env
1001 echo
1002 get_files
1003 echo
1004 get_ldpath
1005 echo
1006 main_checks
1007 echo
1008 if [[ $PACKAGE_NAMES ]]; then
1009         get_packages
1010         echo
1011         clean_packages
1012         echo
1013         assign_packages_to_ebuilds
1014 else
1015         get_exact_ebuilds
1016 fi
1017 echo
1018 get_build_order
1019 echo
1020
1021 # Clean up no longer needed environment variables
1022 unset SEARCH_DIRS SEARCH_DIRS_MASK LD_LIBRARY_MASK PORTAGE_ROOT
1023
1024 if [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" ]]; then
1025         REBUILD_LIST=( $(<"$ORDER_FILE") )
1026         REBUILD_LIST="${REBUILD_LIST[@]/#/=}"
1027 else
1028         REBUILD_LIST=$(sort -u "$EBUILDS_FILE")
1029 fi
1030
1031 trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
1032
1033 einfo 'All prepared. Starting rebuild'
1034 echo "emerge --oneshot ${EMERGE_OPTIONS[@]} $REBUILD_LIST"
1035
1036 is_real_merge && countdown 10
1037
1038 # Link file descriptor #6 with stdin so --ask will work
1039 exec 6<&0
1040
1041 # Run in background to correctly handle Ctrl-C
1042 {
1043         EMERGE_DEFAULT_OPTS="--oneshot ${EMERGE_OPTIONS[@]}" emerge $REBUILD_LIST <&6
1044         echo $? > "$STATUS_FILE"
1045 } &
1046 wait
1047
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.
1049 exec 0<&6 6<&-
1050
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)
1058         fi
1059 }
1060
1061 if (( $(<"$STATUS_FILE") != 0 )); then
1062         ewarn
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)'
1072         einfo
1073         einfo 'To remove temporary files, please run:'
1074         einfo "rm ${TMPDIR}/$APP_NAME/*.rr"
1075         show_unowned_files
1076         exit $EMERGE_STATUS
1077 elif is_real_merge; then
1078         trap_cmd() {
1079                 eerror "terminated. Please remove the temporary files manually:"
1080                 eerror "rm ${TMPDIR}/$APP_NAME/*.rr"
1081                 exit 1
1082         }
1083         (( "${#SKIP_LIST[@]}" != 0 )) && list_skipped_packages
1084         trap trap_cmd SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
1085         einfo 'Build finished correctly. Removing temporary files...'
1086         einfo
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
1091         show_unowned_files
1092         fi
1093         [[ $KEEP_TEMP ]] || rm "${FILES[@]}"
1094 else
1095         einfo 'Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.'
1096 fi
1097