Fix revdep-rebuild issues exposed by expat upgrade. Bugs 128085, 128174)
[gentoolkit.git] / trunk / src / revdep-rebuild / revdep-rebuild
1 #! /bin/bash 
2 # Copyright 1999-2005 Gentoo Foundation
3 # $Header$
4
5 # revdep-rebuild: Reverse dependency rebuilder.
6 # Original Author: Stanislav Brabec
7 # Current Maintainer: Paul Varner <fuzzyray@gentoo.org>
8
9 # Known problems:
10 #
11 # In exact ebuild mode revdep-rebuild can fail to properly order packages,
12 # which are not up to date.
13 # http://bugs.gentoo.org/show_bug.cgi?id=23018
14 #
15 # Rebuilding using --package-names mode should be default, but emerge has no
16 # feature to update to latest version of defined SLOT.
17 # http://bugs.gentoo.org/show_bug.cgi?id=4698
18
19 # Customizable variables:
20 #
21 # LD_LIBRARY_MASK - Mask of specially evaluated libraries
22 # SEARCH_DIRS - List of directories to search for executables and libraries
23 # SEARCH_DIRS_MASK - List of directories to not search
24 #
25 # These variables can be prepended to either by setting the variable in 
26 # your environment prior to execution, or by placing an entry in
27 # /etc/make.conf.
28 #
29 # An entry of "-*" means to clear the variable from that point forward.
30 # Example: env SEARCH_DIRS="/usr/bin -*" revdep-rebuild will set SEARCH_DIRS
31 # to contain only /usr/bin
32
33 if [ "$1" = "-h" -o "$1" = "--help" ]
34 then
35         echo "Usage: $0 [OPTIONS] [--] [EMERGE_OPTIONS]"
36         echo
37         echo "Broken reverse dependency rebuilder."
38         echo
39         echo "  -X, --package-names  Emerge based on package names, not exact versions"
40         echo "      --library NAME   Emerge existing packages that use the library with NAME"
41         echo "      --library=NAME   NAME can be a full path to the library or a basic"
42         echo "                       regular expression (man grep)"
43         echo " -nc, --no-color       Turn off colored output"
44         echo "  -i, --ignore         Ignore temporary files from previous runs"
45         echo "  -q, --quiet          Be less verbose (also passed to emerge command)"
46         echo " -vv, --extra-verbose  Be extra verbose"
47         echo
48         echo "Calls emerge, all other options are used for it (e. g. -p, --pretend)."
49         echo
50         echo "Report bugs to <http://bugs.gentoo.org>"
51         exit 0
52 fi
53
54 echo "Configuring search environment for revdep-rebuild"
55
56 # Obey PORTAGE_NICENESS
57 PORTAGE_NICENESS=$(portageq envvar PORTAGE_NICENESS)
58 if [ ! -z "$PORTAGE_NICENESS" ]
59 then
60         renice $PORTAGE_NICENESS $$ > /dev/null
61         # Since we have already set our nice value for our processes,
62         # reset PORTAGE_NICENESS to zero to avoid having emerge renice again.
63         export PORTAGE_NICENESS="0"
64 fi
65
66 PORTAGE_ROOT=$(portageq envvar ROOT)
67 [ -z "$PORTAGE_ROOT" ] && PORTAGE_ROOT="/"
68
69 # Update the incremental variables using /etc/profile.env, /etc/ld.so.conf,
70 # portage, and the environment
71
72 # Read the incremental variables from environment and portage
73 # Until such time as portage supports these variables as incrementals
74 # The value will be what is in /etc/make.conf
75 PRELIMINARY_SEARCH_DIRS="$SEARCH_DIRS $(unset SEARCH_DIRS; portageq envvar SEARCH_DIRS)"
76 PRELIMINARY_SEARCH_DIRS_MASK="$SEARCH_DIRS_MASK $(unset SEARCH_DIRS_MASK; portageq envvar SEARCH_DIRS_MASK)"
77 PRELIMINARY_LD_LIBRARY_MASK="$LD_LIBRARY_MASK $(unset LD_LIBRARY_MASK; portageq envvar LD_LIBRARY_MASK)"
78
79 # Add the defaults
80 if [ -d /etc/revdep-rebuild ]
81 then
82         for file in $(ls /etc/revdep-rebuild)
83         do
84                 PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS $(. /etc/revdep-rebuild/${file}; echo $SEARCH_DIRS)"
85                 PRELIMINARY_SEARCH_DIRS_MASK="$PRELIMINARY_SEARCH_DIRS_MASK $(. /etc/revdep-rebuild/${file}; echo $SEARCH_DIRS_MASK)"
86                 PRELIMINARY_LD_LIBRARY_MASK="$PRELIMINARY_LD_LIBRARY_MASK $(. /etc/revdep-rebuild/${file}; echo $LD_LIBRARY_MASK)"
87         done
88 else
89         PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS /bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*"
90         PRELIMINARY_SEARCH_DIRS_MASK="$PRELIMINARY_SEARCH_DIRS_MASK /opt/OpenOffice /usr/lib/openoffice"
91         PRELIMINARY_LD_LIBRARY_MASK="$PRELIMINARY_LD_LIBRARY_MASK libodbcinst.so libodbc.so libjava.so libjvm.so"
92 fi
93
94 # Get the ROOTPATH and PATH from /etc/profile.env
95 if [ -e "/etc/profile.env" ]
96 then
97         PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS $((. /etc/profile.env; echo ${ROOTPATH}:${PATH}) | tr ':' ' ')"
98 fi
99
100 # Get the directories from /etc/ld.so.conf
101 if [ -e /etc/ld.so.conf ]
102 then
103         PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS $(grep -v "^#" /etc/ld.so.conf | tr '\n' ' ')"
104 fi      
105
106 # Set the final variables
107 # Note: Using $(echo $variable) removes extraneous spaces from variable assignment
108 unset SEARCH_DIRS
109 for i in $(echo $PRELIMINARY_SEARCH_DIRS)
110 do
111         [ "$i" = "-*" ] && break
112         # Append a / at the end so that links and directories are treated the same by find
113         # Remove any existing trailing slashes to prevent double-slashes
114         SEARCH_DIRS="$(echo $SEARCH_DIRS ${i/%\//}/)"
115 done
116
117 unset SEARCH_DIRS_MASK
118 for i in $(echo $PRELIMINARY_SEARCH_DIRS_MASK)
119 do
120         [ "$i" = "-*" ] && break
121         SEARCH_DIRS_MASK="$(echo $SEARCH_DIRS_MASK $i)"
122 done
123
124 unset LD_LIBRARY_MASK
125 for i in $(echo $PRELIMINARY_LD_LIBRARY_MASK)
126 do
127         [ "$i" = "-*" ] && break
128         LD_LIBRARY_MASK="$(echo $LD_LIBRARY_MASK $i)"
129 done
130
131 # Use the color preference from portage
132 NOCOLOR=$(portageq envvar NOCOLOR)
133
134 # Base of temporary files names.
135 LIST=~/.revdep-rebuild
136
137 shopt -s nullglob
138 shopt -s expand_aliases
139 unalias -a
140
141 # Color Definitions
142 NO="\x1b[0m"
143 BR="\x1b[0;01m"
144 CY="\x1b[36;01m"
145 GR="\x1b[32;01m"
146 RD="\x1b[31;01m"
147 YL="\x1b[33;01m"
148 BL="\x1b[34;01m"
149
150 alias echo_v=echo
151
152 PACKAGE_NAMES=false
153 SONAME="not found"
154 SONAME_GREP=grep
155 SEARCH_BROKEN=true
156 EXTRA_VERBOSE=false
157 KEEP_TEMP=false
158
159 EMERGE_OPTIONS=""
160 PRELIMINARY_CALLED_OPTIONS=""
161 while [ ! -z "$1" ] ; do
162         case "$1" in
163         -X | --package-names )
164                 PACKAGE_NAMES=true
165                 PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --package_names"
166                 shift
167                 ;;
168         -q | --quiet )
169                 alias echo_v=:
170                 EMERGE_OPTIONS="${EMERGE_OPTIONS} $1"
171                 shift
172                 ;;
173         --library=* | --soname=* | --soname-regexp=* )
174                 SONAME="${1#*=}"
175                 SEARCH_BROKEN=false
176                 PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --library=${SONAME}"
177                 shift
178                 ;;
179         --library | --soname | --soname-regexp )
180                 SONAME="$2"
181                 SEARCH_BROKEN=false
182                 PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --library=${SONAME}"
183                 shift 2
184                 ;;
185         -nc | --no-color )
186                 NOCOLOR=true
187                 shift
188                 ;;
189         -i | --ignore )
190                 rm -f ${LIST}*
191                 shift
192                 ;;
193         --keep-temp )
194                 KEEPTEMP=true
195                 shift
196                 ;;
197         -vv | --extra-verbose )
198                 EXTRA_VERBOSE=true
199                 shift
200                 ;;
201         -- )
202                 shift
203                 ;;
204         * )
205                 EMERGE_OPTIONS="${EMERGE_OPTIONS} $1"
206                 shift
207                 ;;
208         esac
209 done
210
211 EMERGE_OPTIONS=$(echo $EMERGE_OPTIONS | sed 's/^ //')
212
213 if [ -z "$PRELIMINARY_CALLED_OPTIONS" ]
214 then
215         CALLED_OPTIONS=""
216 else
217         for i in $(echo $PRELIMINARY_CALLED_OPTIONS | tr ' ' '\n'| sort)
218         do
219                 CALLED_OPTIONS="$(echo $CALLED_OPTIONS $i)"
220         done
221 fi
222
223 if [ "$NOCOLOR" = "yes" -o "$NOCOLOR" = "true" ]
224 then
225         NOCOLOR=true
226 else
227         NOCOLOR=false
228 fi
229
230 # Make the NOCOLOR variable visible to emerge
231 export NOCOLOR
232
233 if $NOCOLOR
234 then
235         NO=""
236         BR=""
237         CY=""
238         GR=""
239         RD=""
240         YL=""
241         BL=""
242 fi
243
244 function set_trap () {
245         trap "rm_temp $1" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
246 }
247
248 function rm_temp () {
249         echo " terminated."
250         echo "Removing incomplete $1."
251         rm $1
252         echo
253         exit 1
254 }
255
256 if $SEARCH_BROKEN ; then
257         SONAME_SEARCH="$SONAME"
258         LLIST=$LIST
259         HEAD_TEXT="broken by a package update"
260         OK_TEXT="Dynamic linking on your system is consistent"
261         WORKING_TEXT=" consistency"
262 else
263         # first case is needed to test against /path/to/foo.so
264         if [ ${SONAME:0:1} == '/' ] ; then 
265                 # Set to "<space>$SONAME<space>"
266                 SONAME_SEARCH=" $SONAME "
267         else
268                 # Set to "<tab>$SONAME<space>"
269                 SONAME_SEARCH=" $SONAME "
270         fi
271         LLIST=${LIST}_$(echo "$SONAME_SEARCH$SONAME" | md5sum | head -c 8)
272         HEAD_TEXT="using $SONAME"
273         OK_TEXT="There are no dynamic links to $SONAME"
274         WORKING_TEXT=""
275 fi
276
277 # If any of our temporary files are older than 1 day, remove them all
278 [ "$(find "${LIST%/*}/." ! -name . -prune -name "${LIST##*/}*" -type f -mmin +1440)" != "" ] && rm -f ${LIST}*
279
280 # Don't use our previous files if environment doesn't match
281 if [ -f $LIST.0_env ]
282 then
283         PREVIOUS_SEARCH_DIRS=$(. ${LIST}.0_env; echo "$SEARCH_DIRS")
284         PREVIOUS_SEARCH_DIRS_MASK=$(. ${LIST}.0_env; echo "$SEARCH_DIRS_MASK")
285         PREVIOUS_LD_LIBRARY_MASK=$(. ${LIST}.0_env; echo "$LD_LIBRARY_MASK")
286         PREVIOUS_PORTAGE_ROOT=$(. ${LIST}.0_env; echo "$PORTAGE_ROOT")
287         PREVIOUS_OPTIONS=$(. ${LIST}.0_env; echo "$CALLED_OPTIONS")
288         if [ "$PREVIOUS_SEARCH_DIRS" != "$SEARCH_DIRS" ] || \
289            [ "$PREVIOUS_SEARCH_DIRS_MASK" != "$SEARCH_DIRS_MASK" ] || \
290            [ "$PREVIOUS_LD_LIBRARY_MASK" != "$LD_LIBRARY_MASK" ] || \
291            [ "$PREVIOUS_PORTAGE_ROOT" != "$PORTAGE_ROOT" ] || \
292            [ "$PREVIOUS_OPTIONS" != "$CALLED_OPTIONS" ] 
293         then
294                 echo
295                 echo "Environment mismatch from previous run, deleting temporary files..."
296                 rm -f ${LIST}*
297         fi
298 fi
299
300 # Log our environment
301 echo "SEARCH_DIRS=\"$SEARCH_DIRS\"" > $LIST.0_env
302 echo "SEARCH_DIRS_MASK=\"$SEARCH_DIRS_MASK\"" >> $LIST.0_env
303 echo "LD_LIBRARY_MASK=\"$LD_LIBRARY_MASK\"" >> $LIST.0_env
304 echo "PORTAGE_ROOT=\"$PORTAGE_ROOT\"" >> $LIST.0_env
305 echo "CALLED_OPTIONS=\"$CALLED_OPTIONS\"" >> $LIST.0_env
306 echo "EMERGE_OPTIONS=\"$EMERGE_OPTIONS\"" >> $LIST.0_env
307
308 if $EXTRA_VERBOSE
309 then
310         echo
311         echo "revdep-rebuild environment:"
312         cat $LIST.0_env
313 fi
314
315 echo
316 echo "Checking reverse dependencies..."
317 echo
318 echo "Packages containing binaries and libraries $HEAD_TEXT"
319 echo "will be emerged."
320
321 echo
322 echo -n -e "${GR}Collecting system binaries and libraries...${NO}"
323
324 if [ -f $LIST.1_files ]
325 then
326         echo " using existing $LIST.1_files."
327 else
328         # Be safe and remove any extraneous temporary files
329         rm -f ${LIST}.[1-9]_*
330
331         set_trap "$LIST.1_*"
332
333         # Hack for the different versions of find.
334         find_results=$(find /usr/bin/revdep-rebuild -type f -perm /u+x 2>/dev/null)
335         if [ -z $find_results ]
336         then
337                 find_results=$(find /usr/bin/revdep-rebuild -type f -perm +u+x 2>/dev/null)
338                 if [ -z $find_results ]
339                 then
340                         echo -e "\n"
341                         echo -e "${RD}Unable to determine how to use find to locate executable files${NO}"
342                         echo -e "${RD}Open a bug at http://bugs.gentoo.org${NO}"
343                         echo
344                         exit 1
345                 else
346                         # using -perm +u+x for find command
347                         find $SEARCH_DIRS -type f \( -perm +u+x -o -name '*.so' -o -name '*.so.*' -o -name '*.la' \) 2>/dev/null | sort | uniq >$LIST.0_files
348                 fi
349         else
350                 # using -perm /u+x for find command
351                 find $SEARCH_DIRS -type f \( -perm /u+x -o -name '*.so' -o -name '*.so.*' -o -name '*.la' \) 2>/dev/null | sort | uniq >$LIST.0_files
352         fi
353
354         # Remove files that match SEARCH_DIR_MASK
355         for dir in $SEARCH_DIRS_MASK
356         do
357                 grep -v "^$dir" $LIST.0_files > $LIST.1_files
358                 mv $LIST.1_files $LIST.0_files
359         done
360         
361         mv $LIST.0_files $LIST.1_files
362         echo -e " done.\n  ($LIST.1_files)"
363 fi
364
365 if $SEARCH_BROKEN ; then
366         echo
367         echo -n -e "${GR}Collecting complete LD_LIBRARY_PATH...${NO}"
368         if [ -f $LIST.2_ldpath ] ; then
369                 echo " using existing $LIST.2_ldpath."
370         else
371                 set_trap "$LIST.2_ldpath"
372                 # Ensure that the "trusted" lib directories are at the start of the path
373                 (
374                         echo /lib* /usr/lib* | sed 's/ /:/g'
375                         sed '/^#/d;s/#.*$//' </etc/ld.so.conf
376                         sed 's:/[^/]*$::' <$LIST.1_files | sort -ru
377                 ) | tr '\n' : | tr -d '\r' | sed 's/:$//' >$LIST.2_ldpath
378                 echo -e " done.\n  ($LIST.2_ldpath)"
379         fi
380         export COMPLETE_LD_LIBRARY_PATH="$(cat $LIST.2_ldpath)"
381 fi
382
383 echo
384 echo -n -e "${GR}Checking dynamic linking$WORKING_TEXT...${NO}"
385 if [ -f $LLIST.3_rebuild ] ; then
386         echo " using existing $LLIST.3_rebuild."
387 else
388         echo_v
389         set_trap "$LLIST.3_rebuild"
390         LD_MASK="\\(    $(echo "$LD_LIBRARY_MASK" | sed 's/\./\\./g;s/ / \\|    /g') \\)"
391         echo -n >$LLIST.3_rebuild
392         cat $LIST.1_files | egrep -v '*\.la$' | while read FILE ; do
393         # Note: double checking seems to be faster than single
394         # with complete path (special add ons are rare).
395         if ldd "$FILE" 2>/dev/null | grep -v "$LD_MASK" | $SONAME_GREP -q "$SONAME_SEARCH" ; then
396                 if $SEARCH_BROKEN ; then
397                         if LD_LIBRARY_PATH="$COMPLETE_LD_LIBRARY_PATH" ldd "$FILE" 2>/dev/null | grep -v "$LD_MASK" | $SONAME_GREP -q "$SONAME_SEARCH" ; then
398                                 # FIX: I hate duplicating code
399                                 # Only build missing direct dependencies
400                                 ALL_MISSING_LIBS=$(ldd "$FILE" 2>/dev/null | sort -u | sed -n 's/       \(.*\) => not found/\1/p' | tr '\n' ' ' | sed 's/ $//' )
401                                 REQUIRED_LIBS=$(objdump -x $FILE | grep NEEDED | awk '{print $2}' | tr '\n' ' ' | sed 's/ $//')
402                                 MISSING_LIBS=""
403                                 for lib in $ALL_MISSING_LIBS
404                                 do
405                                         if echo $REQUIRED_LIBS | grep -q $lib
406                                         then
407                                                 MISSING_LIBS="$MISSING_LIBS $lib"
408                                         fi
409                                 done
410                                 if [ "$MISSING_LIBS" != "" ]
411                                 then
412                                         echo "$FILE" >>$LLIST.3_rebuild
413                                         echo_v "  broken $FILE (requires ${MISSING_LIBS})"
414                                 fi
415                         fi
416                 else
417                         # FIX: I hate duplicating code
418                         # Only rebuild for direct dependencies
419                         ALL_MISSING_LIBS=$(ldd "$FILE" 2>/dev/null | sort -u | $SONAME_GREP "$SONAME_SEARCH" | awk '{print $1}' | tr '\n' ' ' | sed 's/ $//' )
420                         REQUIRED_LIBS=$(objdump -x $FILE | grep NEEDED | awk '{print $2}' | tr '\n' ' ' | sed 's/ $//')
421                         MISSING_LIBS=""
422                         for lib in $ALL_MISSING_LIBS
423                         do
424                                 if echo $REQUIRED_LIBS | grep -q $lib
425                                 then
426                                         MISSING_LIBS="$MISSING_LIBS $lib"
427                                 fi
428                         done
429                         if [ "$MISSING_LIBS" != "" ]
430                         then
431                                 echo "$FILE" >>$LLIST.3_rebuild
432                                 echo_v "  found $FILE"
433                         fi
434                 fi
435         fi
436         done
437         if $SEARCH_BROKEN ; then
438                 cat $LIST.1_files | egrep '*\.la$' | while read FILE ; do
439                         for depend in $(grep '^dependency_libs' $FILE | awk -F'=' '{print $2}' | sed "s/'//g") ; do
440                                 [ ${depend:0:1} != '/' ] && continue
441                                 if [ ! -e $depend ] ; then
442                                         echo "$FILE" >>$LLIST.3_rebuild
443                                         echo_v "  broken $FILE (requires ${depend})"
444                                 fi
445                         done
446                 done
447         fi
448         echo -e " done.\n  ($LLIST.3_rebuild)"
449 fi
450
451 if $PACKAGE_NAMES ; then
452         EXACT_EBUILDS=false
453
454         echo
455         echo -n -e "${GR}Assigning files to packages...${NO}"
456         if [ -f $LLIST.4_packages_raw ] ; then
457                 echo " using existing $LLIST.4_packages_raw."
458         else
459                 set_trap "$LLIST.4_packages*"
460                 echo -n >$LLIST.4_packages_raw
461                 echo -n >$LLIST.4_package_owners
462                 cat $LLIST.3_rebuild | while read FILE ; do
463                         EXACT_PKG="$(echo $FILE | sed 's/^/obj /' | (cd /var/db/pkg; grep -l -f - */*/CONTENTS) | sed s:/CONTENTS:: )"
464                         # Ugly sed hack to strip version information
465                         PKG="$(echo $EXACT_PKG | sed 's/-r[0-9].*$//;s/\(^.*\/*\)-.*$/\1/')"
466                         if [ -z "$PKG" ] ; then
467                                 echo -n -e "\n  ${RD}*** $FILE not owned by any package is broken! ***${NO}"
468                                 echo "$FILE -> (none)" >> $LLIST.4_package_owners
469                                 echo_v -n -e "\n  $FILE -> (none)"
470                         else
471                                 echo "$EXACT_PKG" >> $LLIST.4_packages_raw
472                                 echo "$FILE -> $EXACT_PKG" >> $LLIST.4_package_owners
473                                 echo_v -n -e "\n  $FILE -> $PKG"
474                         fi
475                 done
476                 echo_v
477                 echo -e " done.\n  ($LLIST.4_packages_raw, $LLIST.4_package_owners)"
478         fi
479
480         echo
481         echo -n -e "${GR}Cleaning list of packages to rebuild...${NO}"
482         if [ -f $LLIST.4_packages ] ; then
483                 echo " using existing $LLIST.4_packages."
484         else
485                 sort -u $LLIST.4_packages_raw >$LLIST.4_packages
486                 echo -e " done.\n  ($LLIST.4_packages)"
487         fi
488
489         echo
490         echo -n -e "${GR}Assigning packages to ebuilds...${NO}"
491         if [ -f $LLIST.4_ebuilds ] ; then
492                 echo " using existing $LLIST.4_ebuilds."
493         else
494                 if [ -s "$LLIST.4_packages" ]
495                 then
496                         set_trap "$LLIST.4_ebuilds"
497                         cat $LLIST.4_packages | while read EXACT_PKG
498                         do
499                                 # Get the slot
500                                 PKG="$(echo $EXACT_PKG | sed 's/-r[0-9].*$//;s/\(^.*\/*\)-.*$/\1/')"
501                                 SLOT=$(cat /var/db/pkg/${EXACT_PKG}/SLOT)
502                                 # If SLOT is equal to 0, then just see what portage says is latest version
503                                 if [ "$SLOT" = "0" ]
504                                 then
505                                         best_visible=$(portageq best_visible $PORTAGE_ROOT $PKG)
506                                         [ "x" != "x$best_visible" ] && echo $best_visible
507                                         continue
508                                 fi
509                                 # Otherwise mask the other SLOTTED versions and check for latest
510                                 OTHER_VERSIONS=$(/usr/lib/gentoolkit/bin/find_pkgs.py $PKG | grep -v "($SLOT)" | awk '{print $2}')
511                                 if [ -f /etc/portage/package.mask ]
512                                 then
513                                         mv -f /etc/portage/package.mask /etc/portage/package.mask.revdep-rebuild.backup
514                                 else
515                                         # Make sure that /etc/portage/package.mask exists
516                                         mkdir -p /etc/portage
517                                         touch /etc/portage/package.mask
518                                 fi
519                                 for pkg_version in $(echo $OTHER_VERSIONS | tr '\n' ' ') 
520                                 do
521                                         echo "=${PKG}-${pkg_version}" >> /etc/portage/package.mask
522                                 done
523                                 best_visible=$(portageq best_visible $PORTAGE_ROOT $PKG)
524                                 [ "x" != "x$best_visible" ] && echo $best_visible
525                                 if [ -f /etc/portage/package.mask.revdep-rebuild.backup ]
526                                 then
527                                         mv -f /etc/portage/package.mask.revdep-rebuild.backup /etc/portage/package.mask
528                                 else
529                                         rm -f /etc/portage/package.mask
530                                 fi
531                         done > $LLIST.4_ebuilds
532                         echo -e " done.\n  ($LLIST.4_ebuilds)"
533                 else
534                         echo " Nothing to rebuild"
535                         echo -n > $LLIST.4_ebuilds
536                 fi
537         fi
538 else
539         EXACT_EBUILDS=true
540
541         echo
542         echo -n -e "${GR}Assigning files to ebuilds...${NO}"
543         if [ -f $LLIST.4_ebuilds ] ; then
544                 echo " using existing $LLIST.4_ebuilds."
545         else
546                 if [ -s "$LLIST.3_rebuild" ] ; then
547                         set_trap "$LLIST.4_ebuilds"
548                         cat $LLIST.3_rebuild | sed 's/^/obj /;s/$/ /' |
549                         (
550                                 cd /var/db/pkg
551                                 fgrep -l -f - */*/CONTENTS
552                         ) | sed s:/CONTENTS:: > $LLIST.4_ebuilds
553                         echo -e " done.\n  ($LLIST.4_ebuilds)"
554                 else
555                         echo " Nothing to rebuild"
556                         echo -n > $LLIST.4_ebuilds
557                 fi
558         fi
559
560 fi
561
562 echo
563 echo -n -e "${GR}Evaluating package order...${NO}"
564 if [ -f $LLIST.5_order ] ; then
565         echo " using existing $LLIST.5_order."
566 else
567         RAW_REBUILD_LIST="$(cat $LLIST.4_ebuilds | sed s/^/=/ | tr '\n' ' ')"
568         if [ ! -z "$RAW_REBUILD_LIST" ] ; then
569                 REBUILD_GREP="^\\($( (EMERGE_DEFAULT_OPTS="" emerge --nospinner --pretend --oneshot --nodeps --quiet $RAW_REBUILD_LIST ; echo $? >$LLIST.5a_status ) | sed -n 's/\./\\&/g;s/ //g;s/$/\\/;s/\[[^]]*\]//gp' | tr '\n' '|' | sed 's/|$//'))\$"
570                 if [ $(cat $LLIST.5a_status) -gt 0 ] ; then
571                         echo ""
572                         echo -e "${RD}Warning: Failed to resolve package order."
573                         echo -e "Will merge in \"random\" order!${NO}"
574                         echo "Possible reasons:"
575                         echo "- An ebuild is no longer in the portage tree."
576                         echo "- An ebuild is masked, use /etc/portage/packages.keyword"
577                         echo "  and/or /etc/portage/package.unmask to unmask it"
578                         for i in . . . . . ; do
579                                 echo -n -e '\a.'
580                                 sleep 1
581                         done
582                         ln -f $LLIST.4_ebuilds $LLIST.5_order
583                 else
584                         (EMERGE_DEFAULT_OPTS="" emerge --nospinner --pretend --oneshot --emptytree --quiet $RAW_REBUILD_LIST ; echo $? >$LLIST.5b_status ) | sed -n 's/ //g;s/^.*\]//p' | grep "$REBUILD_GREP" >$LLIST.5_order
585                         if [ $(cat $LLIST.5b_status) -gt 0 ] ; then
586                                 echo ""
587                                 echo -e "${RD}Warning: Failed to resolve package order."
588                                 echo -e "Will merge in \"random\" order!${NO}"
589                                 echo "Possible reasons:"
590                                 echo "- An ebuild is no longer in the portage tree."
591                                 echo "- An ebuild is masked, use /etc/portage/packages.keyword"
592                                 echo "  and/or /etc/portage/package.unmask to unmask it"
593                                 for i in . . . . . ; do
594                                         echo -n -e '\a.'
595                                         sleep 1
596                                 done
597                                 rm -f $LLIST.5_order
598                                 ln -f $LLIST.4_ebuilds $LLIST.5_order
599                         fi
600                 fi
601         else
602                 echo -n "" >$LLIST.5_order
603         fi
604         echo -e " done.\n  ($LLIST.5_order)"
605 fi
606
607 REBUILD_LIST="$(cat $LLIST.5_order | sed s/^/=/ | tr '\n' ' ')"
608
609 trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
610
611 if [ -z "$REBUILD_LIST" ] ; then
612         echo -e "\n${GR}$OK_TEXT... All done.${NO} "
613         if [ ! $KEEPTEMP ]
614         then
615                 rm $LIST.[0-2]_*
616                 rm $LLIST.[3-9]_*
617         fi
618         exit 0
619 fi
620
621 IS_REAL_MERGE=true
622 echo " $EMERGE_OPTIONS " | grep -q '\( -p \| --pretend \| -f \| --fetchonly \)' && IS_REAL_MERGE=false
623
624 echo
625 echo -e "${GR}All prepared. Starting rebuild...${NO}"
626
627 echo "emerge --oneshot $EMERGE_OPTIONS $REBUILD_LIST"
628
629 if $IS_REAL_MERGE ; then
630         for i in . . . . . . . . . . ; do
631                 echo -n -e '\a.'
632                 sleep 1
633         done
634         echo
635 fi
636
637 #if $EXACT_EBUILDS ; then
638 # Uncomment following, if you want to recompile masked ebuilds.
639 ## FIXME: Check for PORTDIR_OVERLAY
640 #       echo -e "${GR}Temporarilly disabling package mask...${NO}"
641 #       trap "mv -i /usr/portage/profiles/package.mask.hidden /usr/portage/profiles/package.mask ; echo -e "\\n\\nTerminated." ; exit 1" \
642 #       SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
643 #       mv -i /usr/portage/profiles/package.mask /usr/portage/profiles/package.mask.hidden
644 #fi
645
646 # Run in background to correctly handle Ctrl-C
647 (
648         EMERGE_DEFAULT_OPTS="" emerge --oneshot $EMERGE_OPTIONS $REBUILD_LIST
649         echo $? >$LLIST.6_status
650 ) &
651 wait
652
653 #if $EXACT_EBUILDS ; then
654 #       mv -i /usr/portage/profiles/package.mask.hidden /usr/portage/profiles/package.mask
655 #       trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
656 #fi
657
658 if [ "$(cat $LLIST.6_status)" -gt 0 ] ; then
659         echo
660         echo -e "${RD}revdep-rebuild failed to emerge all packages${NO}"
661         echo -e "${RD}you have the following choices:${NO}"
662         echo
663         echo "- if emerge failed during the build, fix the problems and re-run revdep-rebuild"
664         echo "    or"
665         echo "- use -X or --package-names as first argument (trys to rebuild package, not exact"
666         echo "  ebuild)"
667         echo "    or"
668         echo "- set ACCEPT_KEYWORDS=\"~<your platform>\" and/or /etc/portage/package.unmask"
669         echo "  (and remove $LLIST.5_order to be evaluated again)"
670         echo "    or"
671         echo "- modify the above emerge command and run it manually"
672         echo "    or"
673         echo "- compile or unmerge unsatisfied packages manually, remove temporary files and"
674         echo "  try again (you can edit package/ebuild list first)"
675         echo
676         echo -e "${GR}To remove temporary files, please run:${NO}"
677         echo "rm $LIST*.?_*"
678         exit $(cat $LLIST.6_status)
679 else
680         if $IS_REAL_MERGE ; then
681                 trap "echo -e \" terminated. Please remove them manually:\nrm $LIST*.?_*\" ; exit 1" \
682                         SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
683                 echo -n -e "${GR}Build finished correctly. Removing temporary files...${NO} "
684                 echo
685                 rm $LIST.[0-2]_*
686                 rm $LLIST.[3-9]_*
687                 echo "You can re-run revdep-rebuild to verify that all libraries and binaries"
688                 echo "are fixed. If some inconsistency remains, it can be orphaned file, deep"
689                 echo "dependency, binary package or specially evaluated library."
690         else
691                 echo -e "${GR}Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.${NO}"
692         fi
693 fi
694 exit 0