#!/usr/bin/env python import sys import getopt import os import subprocess import re import pax def get_ldd_linkings(elf): try: #When subprocess.DEVNULL makes it to python, change this: http://bugs.python.org/issue5870 ldd_output = subprocess.check_output(['/usr/bin/ldd', elf], stderr=subprocess.PIPE) except: # We should record these elfs which are probably static return [] ldd_lines = ldd_output.split('\n') linkings = [] mappings = {} for m in range(0,len(ldd_lines)): if not re.search('=>', ldd_lines[m]): continue ldd_lines[m] = ldd_lines[m].strip() mapp = re.split('=>', ldd_lines[m] ) soname = mapp[0].strip() soname = os.path.basename(soname) # This is for ./libSDL-1.2.so.0 filename = re.sub('\(.*$', '', mapp[1]).strip() if filename == '': continue filename = os.path.realpath(filename) linkings.append(soname) mappings[soname] = filename return ( linkings, mappings ) def get_forward_linkings(): # I'm still not sure we wan to use /var/db/pkg vs some path of binaries var_db_pkg = '/var/db/pkg' forward_linkings = {} so2filename_mappings = {} for cat in os.listdir(var_db_pkg): catdir = '%s/%s' % (var_db_pkg, cat) for pkg in os.listdir(catdir): pkgdir = '%s/%s' % (catdir, pkg) need = '%s/%s' % (pkgdir, 'NEEDED') try: g = open(need, 'r') needs = g.readlines() for line in needs: line = line.strip() link = re.split('\s', line) elf = link[0] ( linkings, mappings ) = get_ldd_linkings(elf) forward_linkings[elf] = linkings so2filename_mappings.update(mappings) except: continue return ( forward_linkings, so2filename_mappings ) def invert_linkings( forward_linkings ): reverse_linkings = {} for elf in forward_linkings: for elf_dep in forward_linkings[elf]: reverse_linkings[elf_dep] = [] for elf in forward_linkings: for elf_dep in forward_linkings[elf]: reverse_linkings[elf_dep].append(elf) return reverse_linkings def print_forward_linkings( forward_linkings, so2filename_mappings ): missing_elfs = [] missing_links = [] for elf in forward_linkings: try: print elf, '(', pax.getflags(elf), ')' except: missing_elfs.append(elf) continue for elf_dep in forward_linkings[elf]: try: filename = so2filename_mappings[elf_dep] flags = pax.getflags(filename) print '\t', elf_dep, '\t', filename, '(', flags, ')' except: missing_links.append(elf_dep) missing_elfs = set(missing_elfs) print '\n\n' print '**** Missing elfs ****' for m in missing_elfs: print m missing_links = set(missing_links) print '\n\n' print '**** Missing forward linkings ****' for m in missing_links: print m print '\n\n' def print_reverse_linkings( reverse_linkings, so2filename_mappings ): missing_elfs = [] missing_links = [] for elf in reverse_linkings: try: filename = so2filename_mappings[elf] flags = pax.getflags(filename) print elf, '\t', filename, '(', flags, ')' except: missing_elfs.append(elf) for elf_dep in reverse_linkings[elf]: try: flags = pax.getflags(elf_dep) print '\t', elf_dep, '(', flags, ')' except: missing_links.append(elf_dep) missing_elfs = set(missing_elfs) print '\n\n' print '**** Missing elfs ****' for m in missing_elfs: print m missing_links = set(missing_links) print '\n\n' print '**** Missing reverse linkings ****' for m in missing_links: print m print '\n\n' def usage(): print 'Package Name : elfix\n' print 'Bug Reports : http://bugs.gentoo.org/' print 'Program Name : revdep-pax\n' print 'Description : Get or set pax flags on an ELF object\n\n' print 'Usage : revdep-pax [-fv] | [-rv] | -v [-b BINARY] | -v [-s SONAME] | -h\n\n' print 'Options : -f print out all the forward mappings for all system binaries\n' print ' : -r print out all the reverse mappints for all system sonames\n' print ' : -b BINARY print all the forward mappings only for BINARY\n' print ' : -s SONAME print all the reverse mappings only for SONAME\n' print ' : -v verbose, otherwise just print mismatched pax flags \n' print ' : -h print out this help\n\n' def run_forward(): ( forward_linkings, so2filename_mappings ) = get_forward_linkings() print_forward_linkings( forward_linkings, so2filename_mappings ) def run_reverse(): ( forward_linkings, so2filename_mappings ) = get_forward_linkings() reverse_linkings = invert_linkings( forward_linkings ) print_reverse_linkings( reverse_linkings, so2filename_mappings ) def run_binary(binary, verbose): ( linkings, mappings ) = get_ldd_linkings(binary) binary_flags = pax.getflags(binary) print binary, '(', binary_flags, ')' count = 0 for soname in linkings: try: filename = mappings[soname] soname_flags = pax.getflags(filename) if verbose: print '\t', soname, '\t', filename, '(', soname_flags, ')' else: if binary_flags != soname_flags: print '\t', soname, '\t',filename, '(', soname_flags, ')' count = count + 1 except: print "file for soname %s not found" % soname if count == 0: print '\nNo mismatches' def run_soname(soname, verbose): ( forward_linkings, so2filename_mappings ) = get_forward_linkings() reverse_linkings = invert_linkings( forward_linkings ) linkings = reverse_linkings[soname] library = so2filename_mappings[soname] flags = pax.getflags(library) if verbose: print soname, '\t', library, '(', flags, ')' for binary in linkings: try: flags = pax.getflags(binary) if verbose: print '\t', binary, '(', flags, ')' except: print "cannot obtain pax flags for %s" % binary def main(): try: opts, args = getopt.getopt(sys.argv[1:], 'hfrb:s:v') except getopt.GetoptError, err: print str(err) # will print something like 'option -a not recognized' usage() sys.exit(1) if len(opts) == 0: usage() sys.exit(1) do_usage = False do_forward = False do_reverse = False binary = None soname = None verbose = False for o, a in opts: if o == '-h': do_usage = True elif o == '-f': do_forward = True elif o == '-r': do_reverse = True elif o == '-b': binary = a elif o == '-s': soname = a elif o == '-v': verbose = True else: print 'Option included in getopt but not handled here!' print 'Please file a bug' sys.exit(1) if do_usage: run_usage() if do_forward: run_forward() if do_reverse: run_reverse() if binary != None: run_binary(binary, verbose) if soname !=None: run_soname(soname) if __name__ == '__main__': main()