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