aboutsummaryrefslogtreecommitdiff
blob: 52d6d1947dae4f4c55d3ba15ce9ce84637f6b179 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
#!/bin/bash 
# Copyright 1999-2007 Gentoo Foundation
# $Header$

# revdep-rebuild: Reverse dependency rebuilder.
# Original Author: Stanislav Brabec
# Current Maintainer: Paul Varner <fuzzyray@gentoo.org>

# Known problems:
#
# In exact ebuild mode revdep-rebuild can fail to properly order packages,
# which are not up to date.
# http://bugs.gentoo.org/show_bug.cgi?id=23018
#
# Rebuilding using --package-names mode should be default, but emerge has no
# feature to update to latest version of defined SLOT.
# http://bugs.gentoo.org/show_bug.cgi?id=4698

# Customizable variables:
#
# LD_LIBRARY_MASK - Mask of specially evaluated libraries
# SEARCH_DIRS - List of directories to search for executables and libraries
# SEARCH_DIRS_MASK - List of directories to not search
#
# These variables can be prepended to either by setting the variable in 
# your environment prior to execution, or by placing an entry in
# /etc/make.conf.
#
# An entry of "-*" means to clear the variable from that point forward.
# Example: env SEARCH_DIRS="/usr/bin -*" revdep-rebuild will set SEARCH_DIRS
# to contain only /usr/bin

if [ "$1" = "-h" -o "$1" = "--help" ]
then
	echo "Usage: $0 [OPTIONS] [--] [EMERGE_OPTIONS]"
	echo
	echo "Broken reverse dependency rebuilder."
	echo
	echo "  -X, --package-names  Emerge based on package names, not exact versions"
	echo "      --library NAME   Emerge existing packages that use the library with NAME"
	echo "      --library=NAME   NAME can be a full path to the library or a basic"
	echo "                       regular expression (man grep)"
	echo " -np, --no-ld-path     Do not set LD_LIBRARY_PATH"
	echo " -nc, --nocolor        Turn off colored output"
	echo "  -i, --ignore         Ignore temporary files from previous runs"
	echo "  -q, --quiet          Be less verbose (also passed to emerge command)"
	echo " -vv, --extra-verbose  Be extra verbose"
	echo
	echo "Calls emerge, all other options are used for it (e. g. -p, --pretend)."
	echo
	echo "Report bugs to <http://bugs.gentoo.org>"
	exit 0
fi

echo "Configuring search environment for revdep-rebuild"

# Obey PORTAGE_NICENESS
PORTAGE_NICENESS=$(portageq envvar PORTAGE_NICENESS)
if [ ! -z "$PORTAGE_NICENESS" ]
then
	renice $PORTAGE_NICENESS $$ > /dev/null
	# Since we have already set our nice value for our processes,
	# reset PORTAGE_NICENESS to zero to avoid having emerge renice again.
	export PORTAGE_NICENESS="0"
fi

PORTAGE_ROOT=$(portageq envvar ROOT)
[ -z "$PORTAGE_ROOT" ] && PORTAGE_ROOT="/"

# Update the incremental variables using /etc/profile.env, /etc/ld.so.conf,
# portage, and the environment

# Read the incremental variables from environment and portage
# Until such time as portage supports these variables as incrementals
# The value will be what is in /etc/make.conf
PRELIMINARY_SEARCH_DIRS="$SEARCH_DIRS $(unset SEARCH_DIRS; portageq envvar SEARCH_DIRS)"
PRELIMINARY_SEARCH_DIRS_MASK="$SEARCH_DIRS_MASK $(unset SEARCH_DIRS_MASK; portageq envvar SEARCH_DIRS_MASK)"
PRELIMINARY_LD_LIBRARY_MASK="$LD_LIBRARY_MASK $(unset LD_LIBRARY_MASK; portageq envvar LD_LIBRARY_MASK)"

# Add the defaults
if [ -d /etc/revdep-rebuild ]
then
	for file in $(ls /etc/revdep-rebuild)
	do
		PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS $(. /etc/revdep-rebuild/${file}; echo $SEARCH_DIRS)"
		PRELIMINARY_SEARCH_DIRS_MASK="$PRELIMINARY_SEARCH_DIRS_MASK $(. /etc/revdep-rebuild/${file}; echo $SEARCH_DIRS_MASK)"
		PRELIMINARY_LD_LIBRARY_MASK="$PRELIMINARY_LD_LIBRARY_MASK $(. /etc/revdep-rebuild/${file}; echo $LD_LIBRARY_MASK)"
	done
else
	PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS /bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*"
	PRELIMINARY_SEARCH_DIRS_MASK="$PRELIMINARY_SEARCH_DIRS_MASK /opt/OpenOffice /usr/lib/openoffice"
	PRELIMINARY_LD_LIBRARY_MASK="$PRELIMINARY_LD_LIBRARY_MASK libodbcinst.so libodbc.so libjava.so libjvm.so"
fi

# Get the ROOTPATH and PATH from /etc/profile.env
if [ -e "/etc/profile.env" ]
then
	PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS $((. /etc/profile.env; echo ${ROOTPATH}:${PATH}) | tr ':' ' ')"
fi

# Get the directories from /etc/ld.so.conf
if [ -e /etc/ld.so.conf ]
then
	PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS $(grep -v "^#" /etc/ld.so.conf | tr '\n' ' ')"
fi	

# Set the final variables
# Note: Using $(echo $variable) removes extraneous spaces from variable assignment
unset SEARCH_DIRS
for i in $(echo $PRELIMINARY_SEARCH_DIRS)
do
	[ "$i" = "-*" ] && break
	# Append a / at the end so that links and directories are treated the same by find
	# Remove any existing trailing slashes to prevent double-slashes
	SEARCH_DIRS="$(echo $SEARCH_DIRS ${i/%\//}/)"
done
# Remove any double-slashes from the path
SEARCH_DIRS="$(echo $SEARCH_DIRS | sed 's:/\+:/:g')"

unset SEARCH_DIRS_MASK
for i in $(echo $PRELIMINARY_SEARCH_DIRS_MASK)
do
	[ "$i" = "-*" ] && break
	SEARCH_DIRS_MASK="$(echo $SEARCH_DIRS_MASK $i)"
done

unset LD_LIBRARY_MASK
for i in $(echo $PRELIMINARY_LD_LIBRARY_MASK)
do
	[ "$i" = "-*" ] && break
	LD_LIBRARY_MASK="$(echo $LD_LIBRARY_MASK $i)"
done

# Use the color preference from portage
NOCOLOR=$(portageq envvar NOCOLOR)

# Base of temporary files names.
touch ${HOME}/.revdep-rebuild_0.test 2>/dev/null
if [ $? -eq 0 ]
then
	LIST="${HOME}/.revdep-rebuild"
	rm ~/.revdep-rebuild_0.test
else
	# Try to use /var/tmp since $HOME is not available
	touch /var/tmp/.revdep-rebuild_0.test 2>/dev/null
	if [ $? -eq 0 ]
	then
		LIST="/var/tmp/.revdep-rebuild"
		rm /var/tmp/.revdep-rebuild_0.test
	else
		echo
		echo "!!! Unable to write temporary files to either $HOME or /var/tmp !!!"
		echo
		exit 1
	fi
fi

shopt -s nullglob
shopt -s expand_aliases
unalias -a

# Color Definitions
NO="\x1b[0m"
BR="\x1b[0;01m"
CY="\x1b[36;01m"
GR="\x1b[32;01m"
RD="\x1b[31;01m"
YL="\x1b[33;01m"
BL="\x1b[34;01m"

# Check if portage-utils are installed
portageq has_version $PORTAGE_ROOT  portage-utils
if [ "$?" -eq 0 ]
then
	PORTAGE_UTILS=true
else
	PORTAGE_UTILS=false
fi

alias echo_v=echo

PACKAGE_NAMES=false
SONAME="not found"
SONAME_GREP=grep
SEARCH_BROKEN=true
EXTRA_VERBOSE=false
KEEP_TEMP=false
FULL_LD_PATH=true

EMERGE_OPTIONS=""
PRELIMINARY_CALLED_OPTIONS=""
while [ ! -z "$1" ] ; do
	case "$1" in
	-X | --package-names )
		PACKAGE_NAMES=true
		PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --package_names"
		shift
		;;
	-q | --quiet )
		alias echo_v=:
		EMERGE_OPTIONS="${EMERGE_OPTIONS} $1"
		shift
		;;
	--library=* | --soname=* | --soname-regexp=* )
		SONAME="${1#*=}"
		SEARCH_BROKEN=false
		PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --library=${SONAME}"
		shift
		;;
	--library | --soname | --soname-regexp )
		SONAME="$2"
		SEARCH_BROKEN=false
		PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --library=${SONAME}"
		shift 2
		;;
	-nc | --no-color | --nocolor )
		NOCOLOR=true
		shift
		;;
	-np | --no-ld-path )
		FULL_LD_PATH=false
		PRELIMINARY_CALLED_OPTIONS="${PRELIMINARY_CALLED_OPTIONS} --no-ld-path"
		shift
		;;
	-i | --ignore )
		rm -f ${LIST}*
		shift
		;;
	--keep-temp )
		KEEPTEMP=true
		shift
		;;
	-vv | --extra-verbose )
		EXTRA_VERBOSE=true
		shift
		;;
	-- )
		shift
		;;
	* )
		EMERGE_OPTIONS="${EMERGE_OPTIONS} $1"
		shift
		;;
	esac
done

EMERGE_OPTIONS=$(echo $EMERGE_OPTIONS | sed 's/^ //')

if [ -z "$PRELIMINARY_CALLED_OPTIONS" ]
then
	CALLED_OPTIONS=""
else
	for i in $(echo $PRELIMINARY_CALLED_OPTIONS | tr ' ' '\n'| sort)
	do
		CALLED_OPTIONS="$(echo $CALLED_OPTIONS $i)"
	done
fi

if [ "$NOCOLOR" = "yes" -o "$NOCOLOR" = "true" ]
then
	NOCOLOR=true
else
	NOCOLOR=false
fi

# Make the NOCOLOR variable visible to emerge
export NOCOLOR

if $NOCOLOR
then
	NO=""
	BR=""
	CY=""
	GR=""
	RD=""
	YL=""
	BL=""
fi

function set_trap () {
	trap "rm_temp $1" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
}

function rm_temp () {
	echo " terminated."
	echo "Removing incomplete $1."
	rm $1
	echo
	exit 1
}

if $SEARCH_BROKEN ; then
	SONAME_SEARCH="$SONAME"
	LLIST=$LIST
	HEAD_TEXT="broken by a package update"
	OK_TEXT="Dynamic linking on your system is consistent"
	WORKING_TEXT=" consistency"
else
	# first case is needed to test against /path/to/foo.so
	if [ ${SONAME:0:1} == '/' ] ; then 
		# Set to "<space>$SONAME<space>"
		SONAME_SEARCH=" $SONAME "
	else
		# Set to "<tab>$SONAME<space>"
		SONAME_SEARCH="	$SONAME "
	fi
	LLIST=${LIST}_$(echo "$SONAME_SEARCH$SONAME" | md5sum | head -c 8)
	HEAD_TEXT="using $SONAME"
	OK_TEXT="There are no dynamic links to $SONAME"
	WORKING_TEXT=""
fi

# If any of our temporary files are older than 1 day, remove them all
[ "$(find "${LIST%/*}/." ! -name . -prune -name "${LIST##*/}*" -type f -mmin +1440)" != "" ] && rm -f ${LIST}*

# Don't use our previous files if environment doesn't match
if [ -f $LIST.0_env ]
then
	PREVIOUS_SEARCH_DIRS=$(. ${LIST}.0_env; echo "$SEARCH_DIRS")
	PREVIOUS_SEARCH_DIRS_MASK=$(. ${LIST}.0_env; echo "$SEARCH_DIRS_MASK")
	PREVIOUS_LD_LIBRARY_MASK=$(. ${LIST}.0_env; echo "$LD_LIBRARY_MASK")
	PREVIOUS_PORTAGE_ROOT=$(. ${LIST}.0_env; echo "$PORTAGE_ROOT")
	PREVIOUS_OPTIONS=$(. ${LIST}.0_env; echo "$CALLED_OPTIONS")
	if [ "$PREVIOUS_SEARCH_DIRS" != "$SEARCH_DIRS" ] || \
	   [ "$PREVIOUS_SEARCH_DIRS_MASK" != "$SEARCH_DIRS_MASK" ] || \
	   [ "$PREVIOUS_LD_LIBRARY_MASK" != "$LD_LIBRARY_MASK" ] || \
	   [ "$PREVIOUS_PORTAGE_ROOT" != "$PORTAGE_ROOT" ] || \
	   [ "$PREVIOUS_OPTIONS" != "$CALLED_OPTIONS" ] 
	then
		echo
		echo "Environment mismatch from previous run, deleting temporary files..."
		rm -f ${LIST}*
	fi
fi

# Clean up no longer needed environment variables
unset PREVIOUS_SEARCH_DIRS PREVIOUS_SEARCH_DIRS_MASK PREVIOUS_LD_LIBRARY_MASK PREVIOUS_PORTAGE_ROOT PREVIOUS_OPTIONS
unset PRELIMINARY_SEARCH_DIRS PRELIMINARY_SEARCH_DIRS_MASK PRELIMINARY_LD_LIBRARY_MASK PRELIMINARY_CALLED_OPTIONS

# Log our environment
echo "SEARCH_DIRS=\"$SEARCH_DIRS\"" > $LIST.0_env
echo "SEARCH_DIRS_MASK=\"$SEARCH_DIRS_MASK\"" >> $LIST.0_env
echo "LD_LIBRARY_MASK=\"$LD_LIBRARY_MASK\"" >> $LIST.0_env
echo "PORTAGE_ROOT=\"$PORTAGE_ROOT\"" >> $LIST.0_env
echo "CALLED_OPTIONS=\"$CALLED_OPTIONS\"" >> $LIST.0_env
echo "EMERGE_OPTIONS=\"$EMERGE_OPTIONS\"" >> $LIST.0_env

if $EXTRA_VERBOSE
then
	echo
	echo "revdep-rebuild environment:"
	cat $LIST.0_env
fi

echo
echo "Checking reverse dependencies..."
echo
echo "Packages containing binaries and libraries $HEAD_TEXT"
echo "will be emerged."

echo
echo -n -e "${GR}Collecting system binaries and libraries...${NO}"

if [ -f $LIST.1_files ]
then
	echo " using existing $LIST.1_files."
else
	# Be safe and remove any extraneous temporary files
	rm -f ${LIST}.[1-9]_*

	set_trap "$LIST.1_*"

	# Hack for the different versions of find.
	# Be extra paranoid and pipe results through sed to remove multiple slashes
	find_results=$(find /usr/bin/revdep-rebuild -type f -perm /u+x 2>/dev/null)
	if [ -z $find_results ]
	then
		find_results=$(find /usr/bin/revdep-rebuild -type f -perm +u+x 2>/dev/null)
		if [ -z $find_results ]
		then
			echo -e "\n"
			echo -e "${RD}Unable to determine how to use find to locate executable files${NO}"
			echo -e "${RD}Open a bug at http://bugs.gentoo.org${NO}"
			echo
			exit 1
		else
			# using -perm +u+x for find command
			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
		fi
	else
		# using -perm /u+x for find command
		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
	fi

	# Remove files that match SEARCH_DIR_MASK
	for dir in $SEARCH_DIRS_MASK
	do
		grep -v "^$dir" $LIST.0_files > $LIST.1_files
		mv $LIST.1_files $LIST.0_files
	done
	
	mv $LIST.0_files $LIST.1_files
	echo -e " done.\n  ($LIST.1_files)"
fi

if $SEARCH_BROKEN && $FULL_LD_PATH ; then
	echo
	echo -n -e "${GR}Collecting complete LD_LIBRARY_PATH...${NO}"
	if [ -f $LIST.2_ldpath ] ; then
		echo " using existing $LIST.2_ldpath."
	else
		set_trap "$LIST.2_ldpath"
		# Ensure that the "trusted" lib directories are at the start of the path
		(
			echo /lib* /usr/lib* | sed 's/ /:/g'
			sed '/^#/d;s/#.*$//' </etc/ld.so.conf
			sed 's:/[^/]*$::' <$LIST.1_files | sort -ru
		) | tr '\n' : | tr -d '\r' | sed 's/:$//' >$LIST.2_ldpath
		echo -e " done.\n  ($LIST.2_ldpath)"
	fi
	COMPLETE_LD_LIBRARY_PATH="$(cat $LIST.2_ldpath)"
fi

echo
echo -n -e "${GR}Checking dynamic linking$WORKING_TEXT...${NO}"
if [ -f $LLIST.3_rebuild ] ; then
	echo " using existing $LLIST.3_rebuild."
else
	echo_v
	set_trap "$LLIST.3_rebuild"
	LD_MASK="\\(	$(echo "$LD_LIBRARY_MASK" | sed 's/\./\\./g;s/ / \\|	/g') \\)"
	echo -n >$LLIST.3_rebuild
	echo -n >$LLIST.3_ldd_errors
	cat $LIST.1_files | egrep -v '*\.la$' | while read FILE ; do
	# Note: double checking seems to be faster than single
	# with complete path (special add ons are rare).
	if ldd "$FILE" 2>>$LLIST.3_ldd_errors | grep -v "$LD_MASK" | $SONAME_GREP -q "$SONAME_SEARCH" ; then
		if $SEARCH_BROKEN && $FULL_LD_PATH ; then
			if LD_LIBRARY_PATH="$COMPLETE_LD_LIBRARY_PATH" ldd "$FILE" 2>/dev/null | grep -v "$LD_MASK" | $SONAME_GREP -q "$SONAME_SEARCH" ; then
				# FIX: I hate duplicating code
				# Only build missing direct dependencies
				ALL_MISSING_LIBS=$(ldd "$FILE" 2>/dev/null | sort -u | sed -n 's/	\(.*\) => not found/\1/p' | tr '\n' ' ' | sed 's/ $//' )
				REQUIRED_LIBS=$(objdump -x $FILE | grep NEEDED | awk '{print $2}' | tr '\n' ' ' | sed 's/ $//')
				MISSING_LIBS=""
				for lib in $ALL_MISSING_LIBS
				do
					if echo $REQUIRED_LIBS | grep -q $lib
					then
						MISSING_LIBS="$MISSING_LIBS $lib"
					fi
				done
				if [ "$MISSING_LIBS" != "" ]
				then
					echo "obj $FILE" >>$LLIST.3_rebuild
					echo_v "  broken $FILE (requires ${MISSING_LIBS})"
				fi
			fi
		else
			# FIX: I hate duplicating code
			# Only rebuild for direct dependencies
			ALL_MISSING_LIBS=$(ldd "$FILE" 2>/dev/null | sort -u | $SONAME_GREP "$SONAME_SEARCH" | awk '{print $1}' | tr '\n' ' ' | sed 's/ $//' )
			REQUIRED_LIBS=$(objdump -x $FILE | grep NEEDED | awk '{print $2}' | tr '\n' ' ' | sed 's/ $//')
			MISSING_LIBS=""
			for lib in $ALL_MISSING_LIBS
			do
				if echo $REQUIRED_LIBS | grep -q $lib
				then
					MISSING_LIBS="$MISSING_LIBS $lib"
				fi
			done
			if [ "$MISSING_LIBS" != "" ]
			then
				echo "obj $FILE" >>$LLIST.3_rebuild
				if $SEARCH_BROKEN ; then
					echo_v "  broken $FILE (requires ${MISSING_LIBS})"
				else
					echo_v "  found $FILE"
				fi
			fi
		fi
	fi
	done
	if $SEARCH_BROKEN ; then
		# Look for missing version
		for FILE in $(grep "no version information available" $LLIST.3_ldd_errors | awk '{print $NF}' | sed 's/[()]//g' | sort -u) ; do
			echo "obj $FILE" >>$LLIST.3_rebuild
			echo_v "  broken $FILE (no version information available)"
		done
		# Look for broken .la files
		cat $LIST.1_files | egrep '*\.la$' | while read FILE ; do
			for depend in $(grep '^dependency_libs' $FILE | awk -F'=' '{print $2}' | sed "s/'//g") ; do
				[ ${depend:0:1} != '/' ] && continue
				if [ ! -e $depend ] ; then
					echo "obj $FILE" >>$LLIST.3_rebuild
					echo_v "  broken $FILE (requires ${depend})"
				fi
			done
		done
	fi
	echo -e " done.\n  ($LLIST.3_rebuild)"
fi

if $PACKAGE_NAMES ; then
	EXACT_EBUILDS=false

	echo
	echo -n -e "${GR}Assigning files to packages...${NO}"
	if [ -f $LLIST.4_packages_raw ] ; then
		echo " using existing $LLIST.4_packages_raw."
	else
		set_trap "$LLIST.4_packages*"
		echo -n >$LLIST.4_packages_raw
		echo -n >$LLIST.4_package_owners
		cat $LLIST.3_rebuild | while read obj FILE ; do
			if $PORTAGE_UTILS ; then
				EXACT_PKG="$(qfile -qvC ${FILE} )"
			else
				EXACT_PKG=$(find /var/db/pkg -name CONTENTS | xargs fgrep -l "obj $FILE " | sed -e 's:/var/db/pkg/\(.*\)/CONTENTS:\1:g')
			fi
			# Ugly sed hack to strip version information
			PKG="$(echo $EXACT_PKG | sed 's/-r[0-9].*$//;s/\(^.*\/*\)-.*$/\1/')"
			if [ -z "$PKG" ] ; then
				echo -n -e "\n  ${RD}*** $FILE not owned by any package is broken! ***${NO}"
				echo "$FILE -> (none)" >> $LLIST.4_package_owners
				echo_v -n -e "\n  $FILE -> (none)"
			else
				echo "$EXACT_PKG" >> $LLIST.4_packages_raw
				echo "$FILE -> $EXACT_PKG" >> $LLIST.4_package_owners
				echo_v -n -e "\n  $FILE -> $PKG"
			fi
		done
		echo_v
		echo -e " done.\n  ($LLIST.4_packages_raw, $LLIST.4_package_owners)"
	fi

	echo
	echo -n -e "${GR}Cleaning list of packages to rebuild...${NO}"
	if [ -f $LLIST.4_packages ] ; then
		echo " using existing $LLIST.4_packages."
	else
		sort -u $LLIST.4_packages_raw >$LLIST.4_packages
		echo -e " done.\n  ($LLIST.4_packages)"
	fi

	echo
	echo -n -e "${GR}Assigning packages to ebuilds...${NO}"
	if [ -f $LLIST.4_ebuilds ] ; then
		echo " using existing $LLIST.4_ebuilds."
	else
		if [ -s "$LLIST.4_packages" ]
		then
			set_trap "$LLIST.4_ebuilds"
			cat $LLIST.4_packages | while read EXACT_PKG
			do
				PKG="$(echo $EXACT_PKG | sed 's/-r[0-9].*$//;s/\(^.*\/*\)-.*$/\1/')"
				SLOT=$(cat /var/db/pkg/${EXACT_PKG}/SLOT)
				best_visible=$(portageq best_visible $PORTAGE_ROOT ${PKG}:${SLOT})
				[ "x" != "x$best_visible" ] && echo $best_visible
			done > $LLIST.4_ebuilds
			echo -e " done.\n  ($LLIST.4_ebuilds)"
		else
			echo " Nothing to rebuild"
			echo -n > $LLIST.4_ebuilds
		fi
	fi
else
	EXACT_EBUILDS=true

	echo
	echo -n -e "${GR}Assigning files to ebuilds...${NO}"
	if [ -f $LLIST.4_ebuilds ] ; then
		echo " using existing $LLIST.4_ebuilds."
	else
		if [ -s "$LLIST.3_rebuild" ] ; then
			set_trap "$LLIST.4_ebuilds"
			find /var/db/pkg -name CONTENTS | xargs fgrep -l -f $LLIST.3_rebuild |
			sed 's:/var/db/pkg/\(.*\)/CONTENTS:\1:' > $LLIST.4_ebuilds
			echo -e " done.\n  ($LLIST.4_ebuilds)"
		else
			echo " Nothing to rebuild"
			echo -n > $LLIST.4_ebuilds
		fi
	fi

fi

echo
echo -n -e "${GR}Evaluating package order...${NO}"
if [ -f $LLIST.5_order ] ; then
	echo " using existing $LLIST.5_order."
else
	set_trap "$LLIST.5_order"
	RAW_REBUILD_LIST="$(cat $LLIST.4_ebuilds | sed s/^/=/ | tr '\n' ' ')"
	if [ ! -z "$RAW_REBUILD_LIST" ] ; then
		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/|$//'))\$"
		if [ $(cat $LLIST.5a_status) -gt 0 ] ; then
			echo ""
			echo -e "${RD}Warning: Failed to resolve package order."
			echo -e "Will merge in \"random\" order!${NO}"
			echo "Possible reasons:"
			echo "- An ebuild is no longer in the portage tree."
			echo "- An ebuild is masked, use /etc/portage/packages.keyword"
			echo "  and/or /etc/portage/package.unmask to unmask it"
			for i in . . . . . ; do
				echo -n -e '\a.'
				sleep 1
			done
			ln -f $LLIST.4_ebuilds $LLIST.5_order
		else
			(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
			if [ $(cat $LLIST.5b_status) -gt 0 ] ; then
				echo ""
				echo -e "${RD}Warning: Failed to resolve package order."
				echo -e "Will merge in \"random\" order!${NO}"
				echo "Possible reasons:"
				echo "- An ebuild is no longer in the portage tree."
				echo "- An ebuild is masked, use /etc/portage/packages.keyword"
				echo "  and/or /etc/portage/package.unmask to unmask it"
				for i in . . . . . ; do
					echo -n -e '\a.'
					sleep 1
				done
				rm -f $LLIST.5_order
				ln -f $LLIST.4_ebuilds $LLIST.5_order
			fi
		fi
	else
		echo -n "" >$LLIST.5_order
	fi
	echo -e " done.\n  ($LLIST.5_order)"
fi

# Clean up no longer needed environment variables
unset COMPLETE_LD_LIBRARY_PATH SEARCH_DIRS SEARCH_DIRS_MASK LD_LIBRARY_MASK PORTAGE_ROOT CALLED_OPTIONS

REBUILD_LIST="$(cat $LLIST.5_order | sed s/^/=/ | tr '\n' ' ')"

trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM

if [ -z "$REBUILD_LIST" ] ; then
	echo -e "\n${GR}$OK_TEXT... All done.${NO} "
	if [ ! $KEEPTEMP ]
	then
		rm $LIST.[0-2]_*
		rm $LLIST.[3-9]_*
	fi
	exit 0
fi

IS_REAL_MERGE=true
echo " $EMERGE_OPTIONS " | grep -q '\( -p \| --pretend \| -f \| --fetchonly \)' && IS_REAL_MERGE=false

echo
echo -e "${GR}All prepared. Starting rebuild...${NO}"

echo "emerge --oneshot $EMERGE_OPTIONS $REBUILD_LIST"

if $IS_REAL_MERGE ; then
	for i in . . . . . . . . . . ; do
		echo -n -e '\a.'
		sleep 1
	done
	echo
fi

# Link file descriptor #6 with stdin
exec 6<&0

# Run in background to correctly handle Ctrl-C
(
	EMERGE_DEFAULT_OPTS="" emerge --oneshot $EMERGE_OPTIONS $REBUILD_LIST <&6
	echo $? >$LLIST.6_status
) &
wait

# Now restore stdin from fd #6, where it had been saved, and close fd #6 ( 6<&- ) to free it for other processes to use.
exec 0<&6 6<&-

#if $EXACT_EBUILDS ; then
#	mv -i /usr/portage/profiles/package.mask.hidden /usr/portage/profiles/package.mask
#	trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
#fi

if [ "$(cat $LLIST.6_status)" -gt 0 ] ; then
	echo
	echo -e "${RD}revdep-rebuild failed to emerge all packages${NO}"
	echo -e "${RD}you have the following choices:${NO}"
	echo
	echo "- if emerge failed during the build, fix the problems and re-run revdep-rebuild"
	echo "    or"
	echo "- use -X or --package-names as first argument (trys to rebuild package, not exact"
	echo "  ebuild)"
	echo "    or"
	echo "- set ACCEPT_KEYWORDS=\"~<your platform>\" and/or /etc/portage/package.unmask"
	echo "  (and remove $LLIST.5_order to be evaluated again)"
	echo "    or"
	echo "- modify the above emerge command and run it manually"
	echo "    or"
	echo "- compile or unmerge unsatisfied packages manually, remove temporary files and"
	echo "  try again (you can edit package/ebuild list first)"
	echo
	echo -e "${GR}To remove temporary files, please run:${NO}"
	echo "rm $LIST*.?_*"
	exit $(cat $LLIST.6_status)
else
	if $IS_REAL_MERGE ; then
		trap "echo -e \" terminated. Please remove them manually:\nrm $LIST*.?_*\" ; exit 1" \
			SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
		echo -n -e "${GR}Build finished correctly. Removing temporary files...${NO} "
		echo
		rm $LIST.[0-2]_*
		rm $LLIST.[3-9]_*
		echo "You can re-run revdep-rebuild to verify that all libraries and binaries"
		echo "are fixed. If some inconsistency remains, it can be orphaned file, deep"
		echo "dependency, binary package or specially evaluated library."
	else
		echo -e "${GR}Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.${NO}"
	fi
fi
exit 0