commit:     29ece55c0c90b5bbe8ab21ddd6e0363ea9bd053a
Author:     Michael Palimaka <kensington <AT> gentoo <DOT> org>
AuthorDate: Sun Jun  8 16:23:26 2014 +0000
Commit:     Michael Palimaka <kensington <AT> gentoo <DOT> org>
CommitDate: Sun Jun  8 16:23:26 2014 +0000
URL:        
http://git.overlays.gentoo.org/gitweb/?p=proj/qa-scripts.git;a=commit;h=29ece55c

depcheck: add script for checking binary runtime dependencies.

---
 depcheck | 258 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 258 insertions(+)

diff --git a/depcheck b/depcheck
new file mode 100755
index 0000000..15e171e
--- /dev/null
+++ b/depcheck
@@ -0,0 +1,258 @@
+#!/bin/bash
+#
+# Copyright (c) 2014 Michael Palimaka <[email protected]>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+# A tool to report both undeclared and potentially-unused runtime dependencies.
+#
+# Depends on app-misc/pax-utils, app-portage/portage-utils and
+# sys-apps/gentoo-functions.
+
+DEBUG=FALSE
+IGNORE_DEPS=( "sys-libs/glibc" "sys-devel/gcc" )
+IGNORE_LINKS=( "/lib64/libgcc_s.so.1" )
+PKG_DIR="/var/db/pkg/"
+
+. /lib/gentoo/functions.sh
+
+bold() {
+       echo $@
+       return
+       local bold=$(tput bold)
+       local normal=$(tput sgr0)
+       echo "${bold}${@}${normal}"
+}
+
+debug() {
+       if [ $DEBUG = TRUE ]; then
+               # write to stderr so as not to interfere with function returns
+               echo "$@" 1>&2
+       fi
+}
+
+# app-foo/bar-1.2.3-r1 -> app-foo/bar
+remove_atom_version() {
+       local atom=`qatom "${1}" | cut -d " " -f 1-2 | tr " " /`
+       echo $atom
+}
+
+check_atom() {
+
+       local errors=0
+       local atom=$1
+       local checked=()
+       local rdepends=()
+
+       local objects=`qlist -qo ${atom}`
+
+       if [ ! "${objects}" ]; then
+               einfo ${atom} does not have any objects installed, skipping...
+               echo
+               return
+       fi
+
+       einfo Checking ${atom} for undeclared dependencies
+       eindent
+
+       local obj
+       for obj in $objects
+       do
+               debug "Checking ${obj}"
+
+               readelf -h ${obj} > /dev/null 2>&1
+
+               # can it have stuff linked to it?
+               if [ $? -ne 0 ]; then
+                       debug "It can't have links, skipping"
+                       continue
+               fi
+
+               local elf=`scanelf --format "#f%n" --nobanner --use-ldpath 
${obj} 2>&1`
+               local links=`echo ${elf} | tr "," " "`
+
+               # get a list of everything that it's linked to
+               local link
+               for link in $links
+               do
+                       local ignore
+                       for ignore in "${IGNORE_LINKS[@]}"; do
+                               if [ "${ignore}" = "${link}" ]; then
+                                       debug "Ignoring ${link} due to 
blacklist"
+                                       continue 2
+                               fi
+                       done
+
+                       # only check a library once per atom for performance 
reasons
+                       local check
+                       for check in "${checked[@]}"; do
+                               if [ "${check}" = "${link}" ]; then
+                                       debug "Already checked ${link} for this 
atom, skipping"
+                                       continue 2
+                               fi
+                       done
+
+                       checked=( "${checked[@]}" "${link}" )
+
+                       debug "Found ${link}"
+
+                       local libowner=`qfile -vqC ${link} | uniq`
+
+                       if [ ! "${libowner}" ]; then
+                               ewarn "No package claims ${link} (${obj})"
+                               continue
+                       fi
+
+                       debug "Owning package for ${link} is ${libowner}"
+
+                       local libowner_pn=$(remove_atom_version ${libowner})
+                       local my_pn=$(remove_atom_version ${atom})
+
+                       rdepends+=( "${libowner_pn}" )
+
+                       if [ "${libowner_pn}" = "${my_pn}" ]; then
+                               debug "Owning package is self, ignoring"
+                               continue
+                       fi
+
+                       local ignorelib
+                       for ignorelib in "${IGNORE_DEPS[@]}"
+                       do
+                               if [ "${libowner_pn}" = "${ignorelib}" ]; then
+                                       debug "Ignoring objects belonging to 
${ignorelib}"
+                                       continue 2
+                               fi
+                       done
+
+                       debug "Checking if ${libowner_pn} is in the RDEPEND 
list of ${atom}"
+
+                       local isdep
+                       isdep=`qdepends -r ${atom} | grep ${libowner_pn}`
+
+                       if [ $? -ne 0 ]; then
+                               eerror "${obj} links to ${link}"
+                               eindent
+                               eerror Missing dependency on $(bold 
${libowner_pn})
+                               eoutdent
+                               errors=1
+                       fi
+
+
+               done
+
+       done
+
+       local ebuild_rdepends=()
+       for rdepend in $(qdepends --nocolor --quiet --rdepend ${atom} | sed -e 
"s/\[[^]]*\]//g" | cut -d : -f 2-)
+       do
+               ebuild_rdepends+=( $(remove_atom_version $rdepend) )
+       done
+
+       debug "Ebuild RDEPENDS: ${ebuild_rdepends[@]}"
+       debug "Linked RDEPENDS: ${rdepends[@]}"
+
+       local suspect_rdepends=$(comm -13 <(echo ${rdepends[@]} | sed 's/ 
/\n/g' | sort -u) <(echo ${ebuild_rdepends[@]} | sed 's/ /\n/g' | sort -u))
+       if [ "${suspect_rdepends}" ]; then
+               ewarn "Suspect RDEPEND: $(bold ${suspect_rdepends})"
+       fi
+
+       echo
+       eoutdent
+
+       return $errors
+
+}
+
+check_package() {
+
+       local package=$1
+       local atoms=`qlist -IcCS ${package} | tr ' ' '-' | cut -d : -f1`
+
+       debug Package ${package} own atoms: ${atoms}
+
+       if [ ! "${atoms}" ]; then
+               eerror ERROR: ${package} is not a valid atom
+               exit 1
+       fi
+
+       for atom in ${atoms}; do
+               check_atom ${atom}
+       done
+
+}
+
+check_category() {
+
+       local errors=0
+       
+       for package in `ls "${PKG_DIR}/${1}"`; do
+       
+               check_package "${1}/${package}"
+               
+               if [ $? -ne 0 ]; then
+                       errors=1
+               fi
+               
+       done;
+       
+       return $errors
+       
+}
+
+BINNAME=`basename ${0}`
+if [ -z $1 ]; then
+       echo "Checks emerged package(s) for undeclared depedencies"
+       echo
+        echo "Usage: ${BINNAME} [ atom | -c category | -a ]"
+       echo
+        echo "Examples:"
+       echo "Check a single package: ${BINNAME} app-foo/bar-1.2.3"
+       echo "Check a category: ${BINNAME} -c app-foo"
+       echo "Check everything: ${BINNAME} -a"
+       exit 1
+fi
+
+# check a particular category
+if [ "$1" = "-c" ]; then
+
+       CAT=$2
+
+       if [ ! -d "${PKG_DIR}/${CAT}" ]; then
+               eerror ERROR: No packages from the category ${CAT} have been 
emerged yet
+               exit 1
+       fi
+
+       check_category $CAT
+
+# check everything
+elif [ "$1" = "-a" ]; then
+
+       for category in `ls ${PKG_DIR}`; do
+               check_category $category
+       done;
+
+else
+       check_package $1
+fi
+
+if [ $? -eq 0 ]; then
+       einfo Checking complete, no errors found
+else
+       eerror Checking complete, errors found
+fi

Reply via email to