diff options
-rw-r--r-- | abs/extra/findbrokenpkgs/PKGBUILD | 18 | ||||
-rw-r--r-- | abs/extra/findbrokenpkgs/findbrokenpkgs-1.1.sh | 326 |
2 files changed, 344 insertions, 0 deletions
diff --git a/abs/extra/findbrokenpkgs/PKGBUILD b/abs/extra/findbrokenpkgs/PKGBUILD new file mode 100644 index 0000000..32d7a38 --- /dev/null +++ b/abs/extra/findbrokenpkgs/PKGBUILD @@ -0,0 +1,18 @@ +# Maintaine: Jaroslav Lichtblau <dragonlord@aur.archlinux.org> +# Contributor: Stefan Husmann <stefan-husmann@t-online.de> +# Contributor: Paul Bredbury <brebs@sent.com> + +pkgname=findbrokenpkgs +pkgver=1.1 +pkgrel=1 +pkgdesc="Broken package identifier for Arch Linux, based on Gentoo's revdep-rebuild" +arch=('any') +url="http://bbs.archlinux.org/viewtopic.php?id=13882" +license=('GPL') +depends=('binutils' 'pacman') +source=($pkgname-$pkgver.sh) +md5sums=('ee683c467e4881736ed60a15ebbcc7a5') + +package() { + install -Dm755 $pkgname-$pkgver.sh "${pkgdir}"/usr/bin/$pkgname +} diff --git a/abs/extra/findbrokenpkgs/findbrokenpkgs-1.1.sh b/abs/extra/findbrokenpkgs/findbrokenpkgs-1.1.sh new file mode 100644 index 0000000..ee59628 --- /dev/null +++ b/abs/extra/findbrokenpkgs/findbrokenpkgs-1.1.sh @@ -0,0 +1,326 @@ +#! /bin/bash +# Distributed under the terms of the GNU General Public License v2 + +# Shamelessly copied mostly from Gentoo's revdep-rebuild utility. +# http://sources.gentoo.org/viewcvs.py/gentoo-x86/app-portage/gentoolkit/ +# $ equery belongs /usr/bin/revdep-rebuild +# app-portage/gentoolkit-0.2.3-r1 +# $ cat /usr/portage/app-portage/gentoolkit/gentoolkit-0.2.3-r1.ebuild | grep LICENSE +# LICENSE="GPL-2" + +# findbrokenpkgs for Arch Linux. +# Converted to use pacman instead of emerge by Paul Bredbury <brebs@sent.com> +# +# v1.1 - files now in $HOME/.findbrokenpkgs/ directory - based on changes from +# Stefan Husmann, repackaged by Jaroslav Lichtblau + +# 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 by setting the variable in +# your environment prior to execution. +# +# An entry of "-*" means to clear the variable from that point forward. +# Example: env SEARCH_DIRS="/usr/bin -*" findbrokenpkgs will set SEARCH_DIRS +# to contain only /usr/bin + +if [ "$1" = "-h" -o "$1" = "-help" -o "$1" = "--help" ] ; then + echo "Broken package identifier, version 1.0" + echo "Checks dynamic library linking." + echo + echo "Usage: $0 [OPTIONS]" + echo + echo " -nc, --no-color Turn off colored output" + echo " -nw, --no-warning Disable newbie-friendly warning" + echo " -q, --quiet Be less verbose" + echo + echo "Report bugs to http://bbs.archlinux.org/viewtopic.php?id=13882" + exit 0 +fi + +# Update the incremental variables using /etc/profile.env, /etc/ld.so.conf, +# and the environment. + +# Read the incremental variables from environment +PRELIMINARY_SEARCH_DIRS="$SEARCH_DIRS" +PRELIMINARY_SEARCH_DIRS_MASK="$SEARCH_DIRS_MASK" +PRELIMINARY_LD_LIBRARY_MASK="$LD_LIBRARY_MASK" +SONAME_SEARCH="not found" +SONAME_GREP=grep + +# Add the defaults +if [ -d /etc/findbrokenpkgs ] ; then + for file in $(ls /etc/findbrokenpkgs) ; do + PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS $(. /etc/findbrokenpkgs/${file}; echo $SEARCH_DIRS)" + PRELIMINARY_SEARCH_DIRS_MASK="$PRELIMINARY_SEARCH_DIRS_MASK $(. /etc/findbrokenpkgs/${file}; echo $SEARCH_DIRS_MASK)" + PRELIMINARY_LD_LIBRARY_MASK="$PRELIMINARY_LD_LIBRARY_MASK $(. /etc/findbrokenpkgs/${file}; echo $LD_LIBRARY_MASK)" + done +else + PRELIMINARY_SEARCH_DIRS="$PRELIMINARY_SEARCH_DIRS /bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*" + # openoffice is a binary, and we don't want to check that monster + PRELIMINARY_SEARCH_DIRS_MASK="$PRELIMINARY_SEARCH_DIRS_MASK /opt/openoffice" + # Binary libraries + 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 + +# Base of temporary files names. +[ -d ${HOME}/.findbrokenpkgs ] || mkdir ${HOME}/.findbrokenpkgs +touch ${HOME}/.findbrokenpkgs/findbrokenpkgs_0.test 2>/dev/null +if [ $? -eq 0 ] ; then + LIST="${HOME}/.findbrokenpkgs/findbrokenpkgs" + rm ~/.findbrokenpkgs/findbrokenpkgs_0.test +else + # Try to use /var/tmp since $HOME is not available + touch /var/tmp/.findbrokenpkgs/findbrokenpkgs_0.test 2>/dev/null + if [ $? -eq 0 ] ; then + LIST="/var/tmp/.findbrokenpkgs/findbrokenpkgs" + rm /var/tmp/.findbrokenpkgs/findbrokenpkgs_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 +alias echo_v=echo + +while [ ! -z "$1" ] ; do + case "$1" in + -q | --quiet ) + alias echo_v=: + shift + ;; + -nc | --no-color ) + NOCOLOR=true + shift + ;; + -nw | --no-warning ) + NOWARNING=true + shift + ;; + * ) + echo "Unknown option: $1" + exit 1 + ;; + esac +done + +# Color Definitions +if [ "$NOCOLOR" = "yes" -o "$NOCOLOR" = "true" ] ; then + NO="" + BR="" + CY="" + GR="" + RD="" + YL="" + BL="" +else + 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" +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 +} + +# Want program results (especially from pacman) in English +export LC_ALL=C + +# Always delete the temporary files from a previous run +rm -f ${LIST}.[0-9]_* + +# Clean up no longer needed environment variables +unset PREVIOUS_SEARCH_DIRS PREVIOUS_SEARCH_DIRS_MASK PREVIOUS_LD_LIBRARY_MASK PREVIOUS_PREVIOUS_OPTIONS +unset PRELIMINARY_SEARCH_DIRS PRELIMINARY_SEARCH_DIRS_MASK PRELIMINARY_LD_LIBRARY_MASK + +# 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_v +echo_v "Checking reverse dependencies..." +echo_v +echo_v -n -e "${GR}Collecting system binaries and libraries...${NO}" + +set_trap "$LIST.1_*" + +# Be extra paranoid and pipe results through sed to remove multiple slashes +# 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 + +# 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_v -e " ${GR}done.${NO}\n ($LIST.1_files)" + +echo_v +echo_v -n -e "${GR}Collecting complete LD_LIBRARY_PATH...${NO}" +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_v -e " ${GR}done.${NO}\n ($LIST.2_ldpath)" +COMPLETE_LD_LIBRARY_PATH="$(cat $LIST.2_ldpath)" + +echo_v +echo_v -e "${GR}Checking dynamic linking consistency...${NO}" +set_trap "$LIST.3_rebuild" +LD_MASK="\\( $(echo "$LD_LIBRARY_MASK" | sed 's/\./\\./g;s/ / \\| /g') \\)" +echo -n > $LIST.3_rebuild +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>/dev/null | grep -v "$LD_MASK" | $SONAME_GREP -q "$SONAME_SEARCH" ; then + if LD_LIBRARY_PATH="$COMPLETE_LD_LIBRARY_PATH" ldd "$FILE" 2>/dev/null | grep -v "$LD_MASK" | $SONAME_GREP -q "$SONAME_SEARCH" ; then + # 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 "$FILE" >> $LIST.3_rebuild + # MISSING_LIBS already starts with a space + echo_v -e " $FILE ${RD}needs missing${NO}${MISSING_LIBS}" + fi + fi + fi +done +# Not sure if *.la files should even be checked +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 "$FILE" >> $LIST.3_rebuild + echo_v -e " $FILE ${RD}needs missing${NO} ${depend}" + fi + done +done +echo_v -e " ${GR}done${NO}.\n ($LIST.3_rebuild)" + +echo_v +echo_v -n -e "${GR}Assigning files to packages...${NO}" +set_trap "$LIST.4_*" +echo -n > $LIST.4_package_owners +echo -n > $LIST.4_packages_raw +echo -n > $LIST.4_orphans + +cat $LIST.3_rebuild | while read FILE ; do + EXACT_PKG=$(pacman -Qo $FILE | awk '{print $5 " " $6}') + PKG=$(echo $EXACT_PKG | awk '{print $1}') + if [ -z "$PKG" ] ; then + echo_v -n -e "\n ${RD}*** $FILE is orphan & broken! ***${NO}" + echo "$FILE -> (none)" >> $LIST.4_package_owners + echo "$FILE" >> $LIST.4_orphans + echo_v -n -e "\n $FILE ${RD}-> (none)${NO}" + else + echo "$PKG" >> $LIST.4_packages_raw + echo "$FILE -> $EXACT_PKG" >> $LIST.4_package_owners + echo_v -n -e "\n $FILE ${CY}->${NO} ${BR}$PKG${NO}" + fi +done +echo_v +echo_v -e " ${GR}done.${NO}\n ($LIST.4_*)" + +echo_v +echo_v -n -e "${GR}Cleaning list of packages to rebuild...${NO}" +set_trap "$LIST.5_packages" +sort -u $LIST.4_packages_raw >$LIST.5_packages +echo_v -e " ${GR}done.${NO}\n ($LIST.5_packages)" + +REBUILD_LIST="$(cat $LIST.5_packages | tr '\n' ' ')" +ORPHAN_LIST="$(cat $LIST.4_orphans)" + +# Clean up no longer needed environment variables +unset COMPLETE_LD_LIBRARY_PATH SEARCH_DIRS SEARCH_DIRS_MASK LD_LIBRARY_MASK + +trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM + +if [ -z "$REBUILD_LIST" ] && [ -z "$ORPHAN_LIST" ] ; then + echo_v -e "\n${GR}Dynamic linking on your system is consistent.${NO}" + # All OK, so delete temporary files + rm -f ${LIST}.[0-9]_* +else + # Show broken files & packages + if [ -n "$ORPHAN_LIST" ] ; then + echo -e "\n${RD}Orphaned broken files:${NO}" + echo "$ORPHAN_LIST" + echo_v -e "\n${GR}This list of orphaned broken files is in $LIST.4_orphans${NO}" + fi + if [ -n "$REBUILD_LIST" ] ; then + echo -e "\n${RD}Recompile these packages:${NO}" + echo -e "${BR}$REBUILD_LIST${NO}" + if ! [ "$NOWARNING" = "yes" -o "$NOWARNING" = "true" ] ; then + echo_v -e "\nSome/all breakages may be ${GR}OK${NO} - this program cannot distinguish between ${RD}required${NO}" + echo_v -e "and ${GR}optional${NO} dependencies. See http://bbs.archlinux.org/viewtopic.php?id=13882" + fi + fi + # The temporary files are deliberately not deleted, as a source of info +fi + +exit 0 |