#!/usr/bin/env python # # Copyright (c) 2004 Benjamin Lutz. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote # products derived from this software without specific prior written # permission. # # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # --------------------------------------------------------------------------- # # This script will work on FreeBSD only. # # This script returns a list of packages that use the libraries in badlibs. # It was written after the release of FreeBSD-5.3-BETA7 as a tool to figure # out which packages needed to be rebuilt as a result of the library bump. # # Changelog: # # 2004-09-04: Check libraries too # # 2004-09-03: Initial Version badlibs = ['libm.so.2', 'libreadline.so.4', 'libhistory.so.4', 'libopie.so.2', 'libpcap.so.2'] binsearchpath = ['/usr/local/bin', '/usr/local/sbin', '/usr/X11R6/bin', '/usr/X11R6/sbin'] libsearchpath = ['/usr/local/lib', '/usr/X11R6/lib'] depthlimit = 1 binfilematch = ['ELF 32-bit LSB executable', 'FreeBSD', 'dynamically linked'] libfilematch = ['ELF 32-bit LSB shared object', 'FreeBSD'] badfiles = [] badpackages = [] orphanedbadfiles = [] import os import os.path import re import sys def main(): sys.stderr.write("Finding affected files... ") numberofdirs = len(binsearchpath) + len(libsearchpath) for i in range(len(binsearchpath)): percentage = int(i * 100 / numberofdirs) sys.stderr.write('%c%c%c%c%3i%%' % (8, 8, 8, 8, percentage)) checkdir(binsearchpath[i], binfilematch) for i in range(len(libsearchpath)): percentage = int((i + len(binsearchpath)) * 100 / numberofdirs) sys.stderr.write('%c%c%c%c%3i%%' % (8, 8, 8, 8, percentage)) checkdir(libsearchpath[i], libfilematch) sys.stderr.write("%c%c%c%c100%% (found: %i)\n" % (8, 8, 8, 8, len(badfiles))) if os.path.isfile('/usr/local/sbin/pkg_which'): sys.stderr.write("Finding affected packages... ") for i in range(len(badfiles)): percentage = int(i * 100 / len(badfiles)) sys.stderr.write('%c%c%c%c%3i%%' % (8, 8, 8, 8, percentage)) package = os.popen('/usr/local/sbin/pkg_which %s' % badfiles[i]).read().strip() if package == '?': orphanedbadfiles.append(badfiles[i]) continue if package not in badpackages: badpackages.append(package) else: sys.stderr.write("Warning: pkg_which not found, I will use pkg_info, which is much slower, instead.\n") sys.stderr.write(" pkg_which is part of portupgrade (/usr/ports/sysutils/portupgrade).\n") sys.stderr.write("Finding affected packages... ") for i in range(len(badfiles)): percentage = int(i * 100 / len(badfiles)) sys.stderr.write('%c%c%c%c%3i%%' % (8, 8, 8, 8, percentage)) output = os.popen('/usr/sbin/pkg_info -W %s' % badfiles[i]).read().strip() try: package = re.search('installed by package (.+)$', output).group(1) if package not in badpackages: badpackages.append(package) except: orphanedbadfile.append(badfiles[i]) sys.stderr.write("%c%c%c%c100%% (found: %i)\n" % (8, 8, 8, 8, len(badpackages))) if (len(badpackages)): badpackages.sort() print "Affected Packages:" for package in badpackages: print " %s" % package if (len(orphanedbadfiles)): orphanedbadfiles.sort() print "Affected Orphaned Files:" for orphanedfile in orphanedbadfiles: print " %s" % orphanedfile def checkdir(directory, fileteststrings, depth = 0): """This function calls itself recursively up until depth reaches maxdepth. It searches through directory (and subdirectories), and returns a list of files that use the badlibs libraries in the badfiles array""" if depth > depthlimit: return for f in os.listdir(directory): f = "%s/%s" % (directory, f) if os.path.islink(f): continue if os.path.isdir(f): checkdir(f, fileteststrings, depth + 1) elif os.path.isfile(f): output = os.popen('/usr/bin/file %s' % f).read().strip() libfile = True for teststring in fileteststrings: if output.find(teststring) == -1: libfile = False; continue if not libfile: continue output = os.popen('/usr/bin/readelf -d %s' % f).read().strip() usesbadlib = False for lib in badlibs: if output.find('Shared library: [%s]' % lib) != -1: usesbadlib = True continue if not usesbadlib: continue badfiles.append(f) if __name__ == '__main__': main()