2 # Distributed under the terms of the GNU General Public License v2
4 # Shamelessly copied mostly from Gentoo's revdep-rebuild utility.
5 # http://sources.gentoo.org/viewcvs.py/gentoo-x86/app-portage/gentoolkit/
6 # $ equery belongs /usr/bin/revdep-rebuild
7 # app-portage/gentoolkit-0.2.3-r1
8 # $ cat /usr/portage/app-portage/gentoolkit/gentoolkit-0.2.3-r1.ebuild | grep LICENSE
11 # findbrokenpkgs for Arch Linux.
12 # Converted to use pacman instead of emerge by Paul Bredbury <brebs@sent.com>
14 # v1.1 - files now in $HOME/.findbrokenpkgs/ directory - based on changes from
15 # Stefan Husmann, repackaged by Jaroslav Lichtblau
17 # Customizable variables:
19 # LD_LIBRARY_MASK - Mask of specially evaluated libraries
20 # SEARCH_DIRS - List of directories to search for executables and libraries
21 # SEARCH_DIRS_MASK - List of directories to not search
23 # These variables can be prepended to by setting the variable in
24 # your environment prior to execution.
26 # An entry of "-*" means to clear the variable from that point forward.
27 # Example: env SEARCH_DIRS="/usr/bin -*" findbrokenpkgs will set SEARCH_DIRS
28 # to contain only /usr/bin
30 if [ "$1" = "-h" -o "$1" = "-help" -o "$1" = "--help" ] ; then
31 echo "Broken package identifier, version 1.0"
32 echo "Checks dynamic library linking."
34 echo "Usage: $0 [OPTIONS]"
36 echo " -nc, --no-color Turn off colored output"
37 echo " -nw, --no-warning Disable newbie-friendly warning"
38 echo " -q, --quiet Be less verbose"
40 echo "Report bugs to http://bbs.archlinux.org/viewtopic.php?id=13882"
44 # Update the incremental variables using /etc/profile.env, /etc/ld.so.conf,
45 # and the environment.
47 # Read the incremental variables from environment
48 PRELIMINARY_SEARCH_DIRS
="$SEARCH_DIRS"
49 PRELIMINARY_SEARCH_DIRS_MASK
="$SEARCH_DIRS_MASK"
50 PRELIMINARY_LD_LIBRARY_MASK
="$LD_LIBRARY_MASK"
51 SONAME_SEARCH
="not found"
55 if [ -d /etc
/findbrokenpkgs
] ; then
56 for file in $
(ls /etc
/findbrokenpkgs
) ; do
57 PRELIMINARY_SEARCH_DIRS
="$PRELIMINARY_SEARCH_DIRS $(. /etc/findbrokenpkgs/${file}; echo $SEARCH_DIRS)"
58 PRELIMINARY_SEARCH_DIRS_MASK
="$PRELIMINARY_SEARCH_DIRS_MASK $(. /etc/findbrokenpkgs/${file}; echo $SEARCH_DIRS_MASK)"
59 PRELIMINARY_LD_LIBRARY_MASK
="$PRELIMINARY_LD_LIBRARY_MASK $(. /etc/findbrokenpkgs/${file}; echo $LD_LIBRARY_MASK)"
62 PRELIMINARY_SEARCH_DIRS
="$PRELIMINARY_SEARCH_DIRS /bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*"
63 # openoffice is a binary, and we don't want to check that monster
64 PRELIMINARY_SEARCH_DIRS_MASK
="$PRELIMINARY_SEARCH_DIRS_MASK /opt/openoffice"
66 PRELIMINARY_LD_LIBRARY_MASK
="$PRELIMINARY_LD_LIBRARY_MASK libodbcinst.so libodbc.so libjava.so libjvm.so"
69 # Get the ROOTPATH and PATH from /etc/profile.env
70 if [ -e "/etc/profile.env" ] ; then
71 PRELIMINARY_SEARCH_DIRS
="$PRELIMINARY_SEARCH_DIRS $((. /etc/profile.env; echo ${ROOTPATH}:${PATH}) | tr ':' ' ')"
74 # Get the directories from /etc/ld.so.conf
75 if [ -e /etc
/ld.so.conf
] ; then
76 PRELIMINARY_SEARCH_DIRS
="$PRELIMINARY_SEARCH_DIRS $(grep -v "^
#" /etc/ld.so.conf | tr '\n' ' ')"
79 # Set the final variables
80 # Note: Using $(echo $variable) removes extraneous spaces from variable assignment
82 for i
in $
(echo $PRELIMINARY_SEARCH_DIRS) ; do
83 [ "$i" = "-*" ] && break
84 # Append a / at the end so that links and directories are treated the same by find
85 # Remove any existing trailing slashes to prevent double-slashes
86 SEARCH_DIRS
="$(echo $SEARCH_DIRS ${i/%\//}/)"
88 # Remove any double-slashes from the path
89 SEARCH_DIRS
="$(echo $SEARCH_DIRS | sed 's:/\+:/:g')"
91 unset SEARCH_DIRS_MASK
92 for i
in $
(echo $PRELIMINARY_SEARCH_DIRS_MASK) ; do
93 [ "$i" = "-*" ] && break
94 SEARCH_DIRS_MASK
="$(echo $SEARCH_DIRS_MASK $i)"
98 for i
in $
(echo $PRELIMINARY_LD_LIBRARY_MASK) ; do
99 [ "$i" = "-*" ] && break
100 LD_LIBRARY_MASK
="$(echo $LD_LIBRARY_MASK $i)"
103 # Base of temporary files names.
104 [ -d ${HOME}/.findbrokenpkgs
] || mkdir
${HOME}/.findbrokenpkgs
105 touch ${HOME}/.findbrokenpkgs
/findbrokenpkgs_0.
test 2>/dev
/null
106 if [ $?
-eq 0 ] ; then
107 LIST
="${HOME}/.findbrokenpkgs/findbrokenpkgs"
108 rm ~
/.findbrokenpkgs
/findbrokenpkgs_0.
test
110 # Try to use /var/tmp since $HOME is not available
111 touch /var
/tmp
/.findbrokenpkgs
/findbrokenpkgs_0.
test 2>/dev
/null
112 if [ $?
-eq 0 ] ; then
113 LIST
="/var/tmp/.findbrokenpkgs/findbrokenpkgs"
114 rm /var
/tmp
/.findbrokenpkgs
/findbrokenpkgs_0.
test
117 echo "!!! Unable to write temporary files to either $HOME or /var/tmp !!!"
124 shopt -s expand_aliases
128 while [ ! -z "$1" ] ; do
143 echo "Unknown option: $1"
150 if [ "$NOCOLOR" = "yes" -o "$NOCOLOR" = "true" ] ; then
168 function set_trap
() {
169 trap "rm_temp $1" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
172 function rm_temp
() {
174 echo "Removing incomplete $1."
180 # Want program results (especially from pacman) in English
183 # Always delete the temporary files from a previous run
184 rm -f ${LIST}.
[0-9]_
*
186 # Clean up no longer needed environment variables
187 unset PREVIOUS_SEARCH_DIRS PREVIOUS_SEARCH_DIRS_MASK PREVIOUS_LD_LIBRARY_MASK PREVIOUS_PREVIOUS_OPTIONS
188 unset PRELIMINARY_SEARCH_DIRS PRELIMINARY_SEARCH_DIRS_MASK PRELIMINARY_LD_LIBRARY_MASK
190 # Log our environment
191 echo "SEARCH_DIRS=\"$SEARCH_DIRS\"" > $LIST.0_env
192 echo "SEARCH_DIRS_MASK=\"$SEARCH_DIRS_MASK\"" >> $LIST.0_env
193 echo "LD_LIBRARY_MASK=\"$LD_LIBRARY_MASK\"" >> $LIST.0_env
196 echo_v
"Checking reverse dependencies..."
198 echo_v
-n -e "${GR}Collecting system binaries and libraries...${NO}"
202 # Be extra paranoid and pipe results through sed to remove multiple slashes
203 # using -perm /u+x for find command
204 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
206 # Remove files that match SEARCH_DIR_MASK
207 for dir
in $SEARCH_DIRS_MASK ; do
208 grep -v "^$dir" $LIST.0_files
> $LIST.1_files
209 mv $LIST.1_files
$LIST.0_files
212 mv $LIST.0_files
$LIST.1_files
213 echo_v
-e " ${GR}done.${NO}\n ($LIST.1_files)"
216 echo_v
-n -e "${GR}Collecting complete LD_LIBRARY_PATH...${NO}"
217 set_trap
"$LIST.2_ldpath"
218 # Ensure that the "trusted" lib directories are at the start of the path
220 echo /lib
* /usr
/lib
* |
sed 's/ /:/g'
221 sed '/^#/d;s/#.*$//' </etc
/ld.so.conf
222 sed 's:/[^/]*$::' <$LIST.1_files |
sort -ru
223 ) |
tr '\n' : |
tr -d '\r' |
sed 's/:$//' >$LIST.2_ldpath
224 echo_v
-e " ${GR}done.${NO}\n ($LIST.2_ldpath)"
225 COMPLETE_LD_LIBRARY_PATH
="$(cat $LIST.2_ldpath)"
228 echo_v
-e "${GR}Checking dynamic linking consistency...${NO}"
229 set_trap
"$LIST.3_rebuild"
230 LD_MASK
="\\( $(echo "$LD_LIBRARY_MASK" | sed 's/\./\\./g;s/ / \\| /g') \\)"
231 echo -n > $LIST.3_rebuild
232 cat $LIST.1_files |
egrep -v '*\.la$' |
while read FILE
; do
233 # Note: double checking seems to be faster than single
234 # with complete path (special add-ons are rare).
235 if ldd
"$FILE" 2>/dev
/null |
grep -v "$LD_MASK" |
$SONAME_GREP -q "$SONAME_SEARCH" ; then
236 if LD_LIBRARY_PATH
="$COMPLETE_LD_LIBRARY_PATH" ldd
"$FILE" 2>/dev
/null |
grep -v "$LD_MASK" |
$SONAME_GREP -q "$SONAME_SEARCH" ; then
237 # Only build missing direct dependencies
238 ALL_MISSING_LIBS
=$
(ldd
"$FILE" 2>/dev
/null |
sort -u |
sed -n 's/ \(.*\) => not found/\1/p' |
tr '\n' ' ' |
sed 's/ $//' )
239 REQUIRED_LIBS
=$
(objdump
-x $FILE |
grep NEEDED |
awk '{print $2}' |
tr '\n' ' ' |
sed 's/ $//')
241 for lib
in $ALL_MISSING_LIBS ; do
242 if echo $REQUIRED_LIBS |
grep -q $lib ; then
243 MISSING_LIBS
="$MISSING_LIBS $lib"
246 if [ "$MISSING_LIBS" != "" ] ; then
247 echo "$FILE" >> $LIST.3_rebuild
248 # MISSING_LIBS already starts with a space
249 echo_v
-e " $FILE ${RD}needs missing${NO}${MISSING_LIBS}"
254 # Not sure if *.la files should even be checked
255 cat $LIST.1_files |
egrep '*\.la$' |
while read FILE
; do
256 for depend
in $
(grep '^dependency_libs' $FILE |
awk -F'=' '{print $2}' |
sed "s/'//g") ; do
257 [ ${depend:0:1} != '/' ] && continue
258 if [ ! -e $depend ] ; then
259 echo "$FILE" >> $LIST.3_rebuild
260 echo_v
-e " $FILE ${RD}needs missing${NO} ${depend}"
264 echo_v
-e " ${GR}done${NO}.\n ($LIST.3_rebuild)"
267 echo_v
-n -e "${GR}Assigning files to packages...${NO}"
269 echo -n > $LIST.4_package_owners
270 echo -n > $LIST.4_packages_raw
271 echo -n > $LIST.4_orphans
273 cat $LIST.3_rebuild |
while read FILE
; do
274 EXACT_PKG
=$
(pacman
-Qo $FILE |
awk '{print $5 " " $6}')
275 PKG
=$
(echo $EXACT_PKG |
awk '{print $1}')
276 if [ -z "$PKG" ] ; then
277 echo_v
-n -e "\n ${RD}*** $FILE is orphan & broken! ***${NO}"
278 echo "$FILE -> (none)" >> $LIST.4_package_owners
279 echo "$FILE" >> $LIST.4_orphans
280 echo_v
-n -e "\n $FILE ${RD}-> (none)${NO}"
282 echo "$PKG" >> $LIST.4_packages_raw
283 echo "$FILE -> $EXACT_PKG" >> $LIST.4_package_owners
284 echo_v
-n -e "\n $FILE ${CY}->${NO} ${BR}$PKG${NO}"
288 echo_v
-e " ${GR}done.${NO}\n ($LIST.4_*)"
291 echo_v
-n -e "${GR}Cleaning list of packages to rebuild...${NO}"
292 set_trap
"$LIST.5_packages"
293 sort -u $LIST.4_packages_raw
>$LIST.5_packages
294 echo_v
-e " ${GR}done.${NO}\n ($LIST.5_packages)"
296 REBUILD_LIST
="$(cat $LIST.5_packages | tr '\n' ' ')"
297 ORPHAN_LIST
="$(cat $LIST.4_orphans)"
299 # Clean up no longer needed environment variables
300 unset COMPLETE_LD_LIBRARY_PATH SEARCH_DIRS SEARCH_DIRS_MASK LD_LIBRARY_MASK
302 trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
304 if [ -z "$REBUILD_LIST" ] && [ -z "$ORPHAN_LIST" ] ; then
305 echo_v
-e "\n${GR}Dynamic linking on your system is consistent.${NO}"
306 # All OK, so delete temporary files
307 rm -f ${LIST}.
[0-9]_
*
309 # Show broken files & packages
310 if [ -n "$ORPHAN_LIST" ] ; then
311 echo -e "\n${RD}Orphaned broken files:${NO}"
313 echo_v
-e "\n${GR}This list of orphaned broken files is in $LIST.4_orphans${NO}"
315 if [ -n "$REBUILD_LIST" ] ; then
316 echo -e "\n${RD}Recompile these packages:${NO}"
317 echo -e "${BR}$REBUILD_LIST${NO}"
318 if ! [ "$NOWARNING" = "yes" -o "$NOWARNING" = "true" ] ; then
319 echo_v
-e "\nSome/all breakages may be ${GR}OK${NO} - this program cannot distinguish between ${RD}required${NO}"
320 echo_v
-e "and ${GR}optional${NO} dependencies. See http://bbs.archlinux.org/viewtopic.php?id=13882"
323 # The temporary files are deliberately not deleted, as a source of info