From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) by finch.gentoo.org (Postfix) with ESMTP id 6AFC71381F3 for ; Tue, 13 Nov 2012 05:10:49 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id C08F5E049A; Tue, 13 Nov 2012 05:10:40 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) (using TLSv1 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 2A294E049A for ; Tue, 13 Nov 2012 05:10:40 +0000 (UTC) Received: from flycatcher.gentoo.org (flycatcher.gentoo.org [81.93.255.6]) (using TLSv1 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 0D00E33D9D4 for ; Tue, 13 Nov 2012 05:10:39 +0000 (UTC) Received: by flycatcher.gentoo.org (Postfix, from userid 559) id CAF5B20C65; Tue, 13 Nov 2012 05:10:37 +0000 (UTC) From: "Mike Frysinger (vapier)" To: gentoo-commits@lists.gentoo.org Reply-To: gentoo-dev@lists.gentoo.org, vapier@gentoo.org Subject: [gentoo-commits] gentoo-projects commit in pax-utils: lddtree.py X-VCS-Repository: gentoo-projects X-VCS-Files: lddtree.py X-VCS-Directories: pax-utils X-VCS-Committer: vapier X-VCS-Committer-Name: Mike Frysinger Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Message-Id: <20121113051037.CAF5B20C65@flycatcher.gentoo.org> Date: Tue, 13 Nov 2012 05:10:37 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Archives-Salt: 3866826d-94eb-467f-9aa9-5c2994a8da47 X-Archives-Hash: ed23f06812d447405735f280f738a3ea vapier 12/11/13 05:10:37 Modified: lddtree.py Log: lddtree.py: add a --copy-to-tree option so people can quickly copy ELFs and their dependencies to a different location (useful for initramfs and such) Revision Changes Path 1.5 pax-utils/lddtree.py file : http://sources.gentoo.org/viewvc.cgi/gentoo-projects/pax-utils/lddtree.py?rev=1.5&view=markup plain: http://sources.gentoo.org/viewvc.cgi/gentoo-projects/pax-utils/lddtree.py?rev=1.5&content-type=text/plain diff : http://sources.gentoo.org/viewvc.cgi/gentoo-projects/pax-utils/lddtree.py?r1=1.4&r2=1.5 Index: lddtree.py =================================================================== RCS file: /var/cvsroot/gentoo-projects/pax-utils/lddtree.py,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- lddtree.py 13 Nov 2012 02:33:01 -0000 1.4 +++ lddtree.py 13 Nov 2012 05:10:37 -0000 1.5 @@ -2,7 +2,7 @@ # Copyright 2012 Gentoo Foundation # Copyright 2012 Mike Frysinger # Distributed under the terms of the GNU General Public License v2 -# $Header: /var/cvsroot/gentoo-projects/pax-utils/lddtree.py,v 1.4 2012/11/13 02:33:01 vapier Exp $ +# $Header: /var/cvsroot/gentoo-projects/pax-utils/lddtree.py,v 1.5 2012/11/13 05:10:37 vapier Exp $ """Read the ELF dependency tree and show it @@ -15,6 +15,7 @@ import glob import optparse import os +import shutil import sys from elftools.elf.elffile import ELFFile @@ -193,6 +194,7 @@ """ ret = { 'interp': None, + 'path': file, 'needed': [], 'libs': _all_libs, } @@ -261,18 +263,94 @@ return ret -def _NormalizeRoot(_option, _opt, value, parser): - parser.values.root = normpath(value) - if parser.values.root == '/': - parser.values.root = '' +def _NormalizePath(option, _opt, value, parser): + setattr(parser.values, option.dest, normpath(value)) def _ShowVersion(_option, _opt, _value, _parser): - id = '$Id: lddtree.py,v 1.4 2012/11/13 02:33:01 vapier Exp $'.split() + id = '$Id: lddtree.py,v 1.5 2012/11/13 05:10:37 vapier Exp $'.split() print('%s-%s %s %s' % (id[1].split('.')[0], id[2], id[3], id[4])) sys.exit(0) +def _ActionShow(options, elf): + """Show the dependency tree for this ELF""" + def _show(lib, depth): + chain_libs.append(lib) + fullpath = elf['libs'][lib]['path'] + if options.list: + print(fullpath or lib) + else: + print('%s%s => %s' % (' ' * depth, lib, fullpath)) + + new_libs = [] + for lib in elf['libs'][lib]['needed']: + if lib in chain_libs: + if not options.list: + print('%s%s => !!! circular loop !!!' % (' ' * depth, lib)) + continue + if options.all or not lib in shown_libs: + shown_libs.add(lib) + new_libs.append(lib) + + for lib in new_libs: + _show(lib, depth + 1) + chain_libs.pop() + + shown_libs = set(elf['needed']) + chain_libs = [] + interp = elf['interp'] + if interp: + shown_libs.add(os.path.basename(interp)) + if options.list: + print(elf['path']) + if not interp is None: + print(interp) + else: + print('%s (interpreter => %s)' % (elf['path'], interp)) + for lib in elf['needed']: + _show(lib, 1) + + +def _ActionCopy(options, elf): + """Copy the ELF and its dependencies to a destination tree""" + def _copy(file): + if file is None: + return + + dest = options.dest + file + if os.path.exists(dest): + # See if they're the same file. + ostat = os.stat(file) + nstat = os.stat(dest) + for field in ('mode', 'mtime', 'size'): + if getattr(ostat, 'st_' + field) != \ + getattr(nstat, 'st_' + field): + break + else: + return + + if options.verbose: + print('%s -> %s' % (file, dest)) + + try: + os.makedirs(os.path.dirname(dest)) + except OSError as e: + if e.errno != os.errno.EEXIST: + raise + try: + shutil.copy2(file, dest) + return + except IOError: + os.unlink(dest) + shutil.copy2(file, dest) + + _copy(elf['path']) + _copy(elf['interp']) + for lib in elf['libs']: + _copy(elf['libs'][lib]['path']) + + def main(argv): parser = optparse.OptionParser("""%prog [options] @@ -282,24 +360,34 @@ help=('Show all duplicated dependencies')) parser.add_option('-R', '--root', dest='root', default=os.environ.get('ROOT', ''), type='string', - action='callback', callback=_NormalizeRoot, + action='callback', callback=_NormalizePath, help=('Show all duplicated dependencies')) + parser.add_option('--copy-to-tree', + dest='dest', default=None, type='string', + action='callback', callback=_NormalizePath, + help=('Copy all files to the specified tree')) parser.add_option('-l', '--list', action='store_true', default=False, help=('Display output in a simple list (easy for copying)')) parser.add_option('-x', '--debug', action='store_true', default=False, help=('Run with debugging')) + parser.add_option('-v', '--verbose', + action='store_true', default=False, + help=('Be verbose')) parser.add_option('-V', '--version', action='callback', callback=_ShowVersion, help=('Show version information')) (options, files) = parser.parse_args(argv) files.pop(0) - options.root += '/' + if options.root != '/': + options.root += '/' if options.debug: print('root =', options.root) + if options.dest: + print('dest =', options.dest) if not files: err('missing ELF files to scan') @@ -325,29 +413,7 @@ print('ldpaths[conf] =', ldpaths['conf']) print('ldpaths[env] =', ldpaths['env']) - # Now show the tree for each specified ELF. - def _show(lib, depth): - chain_libs.append(lib) - fullpath = elf['libs'][lib]['path'] - if options.list: - print(fullpath or lib) - else: - print('%s%s => %s' % (' ' * depth, lib, fullpath)) - - new_libs = [] - for lib in elf['libs'][lib]['needed']: - if lib in chain_libs: - if not options.list: - print('%s%s => !!! circular loop !!!' % (' ' * depth, lib)) - continue - if options.all or not lib in shown_libs: - shown_libs.add(lib) - new_libs.append(lib) - - for lib in new_libs: - _show(lib, depth + 1) - chain_libs.pop() - + # Process all the files specified. ret = 0 for file in files: try: @@ -356,19 +422,10 @@ ret = 1 warn('%s: %s' % (file, e)) continue - shown_libs = set(elf['needed']) - chain_libs = [] - interp = elf['interp'] - if interp: - shown_libs.add(os.path.basename(interp)) - if options.list: - print(file) - if not interp is None: - print(interp) + if options.dest is None: + _ActionShow(options, elf) else: - print('%s (interpreter => %s)' % (file, interp)) - for lib in elf['needed']: - _show(lib, 1) + _ActionCopy(options, elf) return ret