commit:     9a9adbf228320fdc135ad1457bb8bf586c71279c
Author:     Mike Frysinger <vapier <AT> chromium <DOT> org>
AuthorDate: Thu Mar 26 18:32:57 2020 +0000
Commit:     Mike Frysinger <vapier <AT> gentoo <DOT> org>
CommitDate: Thu Apr 15 23:10:24 2021 +0000
URL:        https://gitweb.gentoo.org/proj/pax-utils.git/commit/?id=9a9adbf2

pylintrc: adjust python code to 4 space indent

This aligns with the latest Google/PEP standards.
This doesn't add any pylint warnings as we've been disabling long
lines in here for a long time.  We don't do any other reformatting
to try and cut down on git log/diff noise.

Looking at this with --word-diff=color shows only whitespace changes.

Signed-off-by: Mike Frysinger <vapier <AT> gentoo.org>

 .pylintrc  |    2 +-
 lddtree.py | 1270 ++++++++++++++++++++++++++++++------------------------------
 pylint     |   46 +--
 3 files changed, 659 insertions(+), 659 deletions(-)

diff --git a/.pylintrc b/.pylintrc
index cf1379d..577641f 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -36,7 +36,7 @@ score=no
 
 [FORMAT]
 max-line-length=80
-indent-string='  '
+indent-string = '    '
 
 [BASIC]
 bad-functions=

diff --git a/lddtree.py b/lddtree.py
index 141195b..cdb3f1c 100755
--- a/lddtree.py
+++ b/lddtree.py
@@ -55,107 +55,107 @@ from elftools.common import exceptions
 
 
 def warn(msg, prefix='warning'):
-  """Write |msg| to stderr with a |prefix| before it"""
-  print('%s: %s: %s' % (os.path.basename(sys.argv[0]), prefix, msg), 
file=sys.stderr)
+    """Write |msg| to stderr with a |prefix| before it"""
+    print('%s: %s: %s' % (os.path.basename(sys.argv[0]), prefix, msg), 
file=sys.stderr)
 
 
 def err(msg, status=1):
-  """Write |msg| to stderr and exit with |status|"""
-  warn(msg, prefix='error')
-  sys.exit(status)
+    """Write |msg| to stderr and exit with |status|"""
+    warn(msg, prefix='error')
+    sys.exit(status)
 
 
 def dbg(debug, *args, **kwargs):
-  """Pass |args| and |kwargs| to print() when |debug| is True"""
-  if debug:
-    print(*args, **kwargs)
+    """Pass |args| and |kwargs| to print() when |debug| is True"""
+    if debug:
+        print(*args, **kwargs)
 
 
 def bstr(buf):
-  """Decode the byte string into a string"""
-  if isinstance(buf, str):
-    return buf
-  return buf.decode('utf-8')
+    """Decode the byte string into a string"""
+    if isinstance(buf, str):
+        return buf
+    return buf.decode('utf-8')
 
 
 def normpath(path):
-  """Normalize a path
+    """Normalize a path
 
-  Python's os.path.normpath() doesn't handle some cases:
-    // -> //
-    //..// -> //
-    //..//..// -> ///
-  """
-  return os.path.normpath(path).replace('//', '/')
+    Python's os.path.normpath() doesn't handle some cases:
+      // -> //
+      //..// -> //
+      //..//..// -> ///
+    """
+    return os.path.normpath(path).replace('//', '/')
 
 
 def readlink(path, root, prefixed=False):
-  """Like os.readlink(), but relative to a |root|
+    """Like os.readlink(), but relative to a |root|
 
-  This does not currently handle the pathological case:
-    /lib/foo.so -> ../../../../../../../foo.so
-  This relies on the .. entries in / to point to itself.
+    This does not currently handle the pathological case:
+      /lib/foo.so -> ../../../../../../../foo.so
+    This relies on the .. entries in / to point to itself.
 
-  Args:
-    path: The symlink to read
-    root: The path to use for resolving absolute symlinks
-    prefixed: When False, the |path| must not have |root| prefixed to it, nor
-              will the return value have |root| prefixed.  When True, |path|
-              must have |root| prefixed, and the return value will have |root|
-              added.
+    Args:
+      path: The symlink to read
+      root: The path to use for resolving absolute symlinks
+      prefixed: When False, the |path| must not have |root| prefixed to it, nor
+          will the return value have |root| prefixed.  When True, |path|
+          must have |root| prefixed, and the return value will have |root|
+          added.
 
-  Returns:
-    A fully resolved symlink path
-  """
-  root = root.rstrip('/')
-  if prefixed:
-    path = path[len(root):]
+    Returns:
+      A fully resolved symlink path
+    """
+    root = root.rstrip('/')
+    if prefixed:
+        path = path[len(root):]
 
-  while os.path.islink(root + path):
-    path = os.path.join(os.path.dirname(path), os.readlink(root + path))
+    while os.path.islink(root + path):
+        path = os.path.join(os.path.dirname(path), os.readlink(root + path))
 
-  return normpath((root + path) if prefixed else path)
+    return normpath((root + path) if prefixed else path)
 
 
 def makedirs(path):
-  """Like os.makedirs(), but ignore EEXIST errors"""
-  try:
-    os.makedirs(path)
-  except OSError as e:
-    if e.errno != errno.EEXIST:
-      raise
+    """Like os.makedirs(), but ignore EEXIST errors"""
+    try:
+        os.makedirs(path)
+    except OSError as e:
+        if e.errno != errno.EEXIST:
+            raise
 
 
 def dedupe(items):
-  """Remove all duplicates from |items| (keeping order)"""
-  seen = {}
-  return [seen.setdefault(x, x) for x in items if x not in seen]
+    """Remove all duplicates from |items| (keeping order)"""
+    seen = {}
+    return [seen.setdefault(x, x) for x in items if x not in seen]
 
 
 def GenerateLdsoWrapper(root, path, interp, libpaths=()):
-  """Generate a shell script wrapper which uses local ldso to run the ELF
-
-  Since we cannot rely on the host glibc (or other libraries), we need to
-  execute the local packaged ldso directly and tell it where to find our
-  copies of libraries.
-
-  Args:
-    root: The root tree to generate scripts inside of
-    path: The full path (inside |root|) to the program to wrap
-    interp: The ldso interpreter that we need to execute
-    libpaths: Extra lib paths to search for libraries
-  """
-  basedir = os.path.dirname(path)
-  interp_dir, interp_name = os.path.split(interp)
-  # Add ldso interpreter dir to end of libpaths as a fallback library path.
-  libpaths = dedupe(list(libpaths) + [interp_dir])
-  replacements = {
-      'interp': os.path.join(os.path.relpath(interp_dir, basedir),
-                             interp_name),
-      'libpaths': ':'.join(['${basedir}/' + os.path.relpath(p, basedir)
-                            for p in libpaths]),
-  }
-  wrapper = """#!/bin/sh
+    """Generate a shell script wrapper which uses local ldso to run the ELF
+
+    Since we cannot rely on the host glibc (or other libraries), we need to
+    execute the local packaged ldso directly and tell it where to find our
+    copies of libraries.
+
+    Args:
+      root: The root tree to generate scripts inside of
+      path: The full path (inside |root|) to the program to wrap
+      interp: The ldso interpreter that we need to execute
+      libpaths: Extra lib paths to search for libraries
+    """
+    basedir = os.path.dirname(path)
+    interp_dir, interp_name = os.path.split(interp)
+    # Add ldso interpreter dir to end of libpaths as a fallback library path.
+    libpaths = dedupe(list(libpaths) + [interp_dir])
+    replacements = {
+        'interp': os.path.join(os.path.relpath(interp_dir, basedir),
+                               interp_name),
+        'libpaths': ':'.join(['${basedir}/' + os.path.relpath(p, basedir)
+                              for p in libpaths]),
+    }
+    wrapper = """#!/bin/sh
 if ! base=$(realpath "$0" 2>/dev/null); then
   case $0 in
   /*) base=$0;;
@@ -171,635 +171,635 @@ exec \
   "${base}.elf" \
   "$@"
 """
-  wrappath = root + path
-  os.rename(wrappath, wrappath + '.elf')
-  with open(wrappath, 'w') as f:
-    f.write(wrapper % replacements)
-  os.chmod(wrappath, 0o0755)
+    wrappath = root + path
+    os.rename(wrappath, wrappath + '.elf')
+    with open(wrappath, 'w') as f:
+        f.write(wrapper % replacements)
+    os.chmod(wrappath, 0o0755)
 
 
 def ParseLdPaths(str_ldpaths, root='', path=None):
-  """Parse the colon-delimited list of paths and apply ldso rules to each
-
-  Note the special handling as dictated by the ldso:
-   - Empty paths are equivalent to $PWD
-   - $ORIGIN is expanded to the path of the given file
-   - (TODO) $LIB and friends
-
-  Args:
-    str_ldpaths: A colon-delimited string of paths
-    root: The path to prepend to all paths found
-    path: The object actively being parsed (used for $ORIGIN)
-
-  Returns:
-    list of processed paths
-  """
-  ldpaths = []
-  for ldpath in str_ldpaths.split(':'):
-    if not ldpath:
-      # The ldso treats "" paths as $PWD.
-      ldpath = os.getcwd()
-    elif '$ORIGIN' in ldpath:
-      ldpath = ldpath.replace('$ORIGIN', os.path.dirname(path))
-    else:
-      ldpath = root + ldpath
-    ldpaths.append(normpath(ldpath))
-  return dedupe(ldpaths)
+    """Parse the colon-delimited list of paths and apply ldso rules to each
+
+    Note the special handling as dictated by the ldso:
+     - Empty paths are equivalent to $PWD
+     - $ORIGIN is expanded to the path of the given file
+     - (TODO) $LIB and friends
+
+    Args:
+      str_ldpaths: A colon-delimited string of paths
+      root: The path to prepend to all paths found
+      path: The object actively being parsed (used for $ORIGIN)
+
+    Returns:
+      list of processed paths
+    """
+    ldpaths = []
+    for ldpath in str_ldpaths.split(':'):
+        if not ldpath:
+            # The ldso treats "" paths as $PWD.
+            ldpath = os.getcwd()
+        elif '$ORIGIN' in ldpath:
+            ldpath = ldpath.replace('$ORIGIN', os.path.dirname(path))
+        else:
+            ldpath = root + ldpath
+        ldpaths.append(normpath(ldpath))
+    return dedupe(ldpaths)
 
 
 def ParseLdSoConf(ldso_conf, root='/', debug=False, _first=True):
-  """Load all the paths from a given ldso config file
-
-  This should handle comments, whitespace, and "include" statements.
-
-  Args:
-    ldso_conf: The file to scan
-    root: The path to prepend to all paths found
-    debug: Enable debug output
-    _first: Recursive use only; is this the first ELF ?
-
-  Returns:
-    list of paths found
-  """
-  paths = []
-
-  dbg_pfx = '' if _first else '  '
-  try:
-    dbg(debug, '%sParseLdSoConf(%s)' % (dbg_pfx, ldso_conf))
-    with open(ldso_conf) as f:
-      for line in f.readlines():
-        line = line.split('#', 1)[0].strip()
-        if not line:
-          continue
-        if line.startswith('include '):
-          line = line[8:]
-          if line[0] == '/':
-            line = root + line.lstrip('/')
-          else:
-            line = os.path.dirname(ldso_conf) + '/' + line
-          dbg(debug, '%s  glob: %s' % (dbg_pfx, line))
-          # ldconfig in glibc uses glob() which returns entries sorted 
according
-          # to LC_COLLATE.  Further, ldconfig does not reset that but respects
-          # the active env settings (which might be a mistake).  Python does 
not
-          # sort its results by default though, so do it ourselves.
-          for path in sorted(glob.glob(line)):
-            paths += ParseLdSoConf(path, root=root, debug=debug, _first=False)
-        else:
-          paths += [normpath(root + line)]
-  except IOError as e:
-    if e.errno != errno.ENOENT:
-      warn(e)
+    """Load all the paths from a given ldso config file
+
+    This should handle comments, whitespace, and "include" statements.
 
-  if _first:
-    # XXX: Load paths from ldso itself.
-    # Remove duplicate entries to speed things up.
-    paths = dedupe(paths)
+    Args:
+      ldso_conf: The file to scan
+      root: The path to prepend to all paths found
+      debug: Enable debug output
+      _first: Recursive use only; is this the first ELF ?
 
-  return paths
+    Returns:
+      list of paths found
+    """
+    paths = []
+
+    dbg_pfx = '' if _first else '  '
+    try:
+        dbg(debug, '%sParseLdSoConf(%s)' % (dbg_pfx, ldso_conf))
+        with open(ldso_conf) as f:
+            for line in f.readlines():
+                line = line.split('#', 1)[0].strip()
+                if not line:
+                    continue
+                if line.startswith('include '):
+                    line = line[8:]
+                    if line[0] == '/':
+                        line = root + line.lstrip('/')
+                    else:
+                        line = os.path.dirname(ldso_conf) + '/' + line
+                    dbg(debug, '%s  glob: %s' % (dbg_pfx, line))
+                    # ldconfig in glibc uses glob() which returns entries 
sorted according
+                    # to LC_COLLATE.  Further, ldconfig does not reset that 
but respects
+                    # the active env settings (which might be a mistake).  
Python does not
+                    # sort its results by default though, so do it ourselves.
+                    for path in sorted(glob.glob(line)):
+                        paths += ParseLdSoConf(path, root=root, debug=debug, 
_first=False)
+                else:
+                    paths += [normpath(root + line)]
+    except IOError as e:
+        if e.errno != errno.ENOENT:
+            warn(e)
+
+    if _first:
+        # XXX: Load paths from ldso itself.
+        # Remove duplicate entries to speed things up.
+        paths = dedupe(paths)
+
+    return paths
 
 
 def LoadLdpaths(root='/', prefix='', debug=False):
-  """Load linker paths from common locations
-
-  This parses the ld.so.conf and LD_LIBRARY_PATH env var.
-
-  Args:
-    root: The root tree to prepend to paths
-    prefix: The path under |root| to search
-    debug: Enable debug output
-
-  Returns:
-    dict containing library paths to search
-  """
-  ldpaths = {
-      'conf': [],
-      'env': [],
-      'interp': [],
-  }
-
-  # Load up $LD_LIBRARY_PATH.
-  ldpaths['env'] = []
-  env_ldpath = os.environ.get('LD_LIBRARY_PATH')
-  if not env_ldpath is None:
-    if root != '/':
-      warn('ignoring LD_LIBRARY_PATH due to ROOT usage')
-    else:
-      # XXX: If this contains $ORIGIN, we probably have to parse this
-      # on a per-ELF basis so it can get turned into the right thing.
-      ldpaths['env'] = ParseLdPaths(env_ldpath, path='')
+    """Load linker paths from common locations
+
+    This parses the ld.so.conf and LD_LIBRARY_PATH env var.
+
+    Args:
+      root: The root tree to prepend to paths
+      prefix: The path under |root| to search
+      debug: Enable debug output
+
+    Returns:
+      dict containing library paths to search
+    """
+    ldpaths = {
+        'conf': [],
+        'env': [],
+        'interp': [],
+    }
 
-  # Load up /etc/ld.so.conf.
-  ldpaths['conf'] = ParseLdSoConf(root + prefix + '/etc/ld.so.conf', root=root,
-                                  debug=debug)
+    # Load up $LD_LIBRARY_PATH.
+    ldpaths['env'] = []
+    env_ldpath = os.environ.get('LD_LIBRARY_PATH')
+    if not env_ldpath is None:
+        if root != '/':
+            warn('ignoring LD_LIBRARY_PATH due to ROOT usage')
+        else:
+            # XXX: If this contains $ORIGIN, we probably have to parse this
+            # on a per-ELF basis so it can get turned into the right thing.
+            ldpaths['env'] = ParseLdPaths(env_ldpath, path='')
+
+    # Load up /etc/ld.so.conf.
+    ldpaths['conf'] = ParseLdSoConf(root + prefix + '/etc/ld.so.conf', 
root=root,
+                                    debug=debug)
 
-  return ldpaths
+    return ldpaths
 
 
 def CompatibleELFs(elf1, elf2):
-  """See if two ELFs are compatible
+    """See if two ELFs are compatible
 
-  This compares the aspects of the ELF to see if they're compatible:
-  bit size, endianness, machine type, and operating system.
+    This compares the aspects of the ELF to see if they're compatible:
+    bit size, endianness, machine type, and operating system.
 
-  Args:
-    elf1: an ELFFile object
-    elf2: an ELFFile object
+    Args:
+      elf1: an ELFFile object
+      elf2: an ELFFile object
 
-  Returns:
-    True if compatible, False otherwise
-  """
-  osabis = frozenset([e.header['e_ident']['EI_OSABI'] for e in (elf1, elf2)])
-  compat_sets = (
-      frozenset('ELFOSABI_%s' % x for x in ('NONE', 'SYSV', 'GNU', 'LINUX',)),
-  )
-  return ((len(osabis) == 1 or any(osabis.issubset(x) for x in compat_sets)) 
and
-          elf1.elfclass == elf2.elfclass and
-          elf1.little_endian == elf2.little_endian and
-          elf1.header['e_machine'] == elf2.header['e_machine'])
+    Returns:
+      True if compatible, False otherwise
+    """
+    osabis = frozenset([e.header['e_ident']['EI_OSABI'] for e in (elf1, elf2)])
+    compat_sets = (
+        frozenset('ELFOSABI_%s' % x for x in ('NONE', 'SYSV', 'GNU', 
'LINUX',)),
+    )
+    return ((len(osabis) == 1 or any(osabis.issubset(x) for x in compat_sets)) 
and
+            elf1.elfclass == elf2.elfclass and
+            elf1.little_endian == elf2.little_endian and
+            elf1.header['e_machine'] == elf2.header['e_machine'])
 
 
 def FindLib(elf, lib, ldpaths, root='/', debug=False):
-  """Try to locate a |lib| that is compatible to |elf| in the given |ldpaths|
-
-  Args:
-    elf: The elf which the library should be compatible with (ELF wise)
-    lib: The library (basename) to search for
-    ldpaths: A list of paths to search
-    root: The root path to resolve symlinks
-    debug: Enable debug output
-
-  Returns:
-    Tuple of the full path to the desired library and the real path to it
-  """
-  dbg(debug, '  FindLib(%s)' % lib)
-
-  for ldpath in ldpaths:
-    path = os.path.join(ldpath, lib)
-    target = readlink(path, root, prefixed=True)
-    if path != target:
-      dbg(debug, '    checking: %s -> %s' % (path, target))
-    else:
-      dbg(debug, '    checking:', path)
+    """Try to locate a |lib| that is compatible to |elf| in the given |ldpaths|
+
+    Args:
+      elf: The elf which the library should be compatible with (ELF wise)
+      lib: The library (basename) to search for
+      ldpaths: A list of paths to search
+      root: The root path to resolve symlinks
+      debug: Enable debug output
+
+    Returns:
+      Tuple of the full path to the desired library and the real path to it
+    """
+    dbg(debug, '  FindLib(%s)' % lib)
+
+    for ldpath in ldpaths:
+        path = os.path.join(ldpath, lib)
+        target = readlink(path, root, prefixed=True)
+        if path != target:
+            dbg(debug, '    checking: %s -> %s' % (path, target))
+        else:
+            dbg(debug, '    checking:', path)
 
-    if os.path.exists(target):
-      with open(target, 'rb') as f:
-        try:
-          libelf = ELFFile(f)
-          if CompatibleELFs(elf, libelf):
-            return (target, path)
-        except exceptions.ELFError as e:
-          warn('%s: %s' % (target, e))
+        if os.path.exists(target):
+            with open(target, 'rb') as f:
+                try:
+                    libelf = ELFFile(f)
+                    if CompatibleELFs(elf, libelf):
+                        return (target, path)
+                except exceptions.ELFError as e:
+                    warn('%s: %s' % (target, e))
 
-  return (None, None)
+    return (None, None)
 
 
 # We abuse the _all_libs state.  We probably shouldn't, but we do currently.
 # pylint: disable=dangerous-default-value
 def ParseELF(path, root='/', prefix='', ldpaths={'conf':[], 'env':[], 
'interp':[]},
              display=None, debug=False, _first=True, _all_libs={}):
-  """Parse the ELF dependency tree of the specified file
+    """Parse the ELF dependency tree of the specified file
 
-  Args:
-    path: The ELF to scan
-    root: The root tree to prepend to paths; this applies to interp and rpaths
+    Args:
+      path: The ELF to scan
+      root: The root tree to prepend to paths; this applies to interp and 
rpaths
           only as |path| and |ldpaths| are expected to be prefixed already
-    prefix: The path under |root| to search
-    ldpaths: dict containing library paths to search; should have the keys:
-             conf, env, interp
-    display: The path to show rather than |path|
-    debug: Enable debug output
-    _first: Recursive use only; is this the first ELF ?
-    _all_libs: Recursive use only; dict of all libs we've seen
-
-  Returns:
-    a dict containing information about all the ELFs; e.g.
-    {
-      'interp': '/lib64/ld-linux.so.2',
-      'needed': ['libc.so.6', 'libcurl.so.4',],
-      'libs': {
-        'libc.so.6': {
-          'path': '/lib64/libc.so.6',
-          'needed': [],
-        },
-        'libcurl.so.4': {
-          'path': '/usr/lib64/libcurl.so.4',
-          'needed': ['libc.so.6', 'librt.so.1',],
+      prefix: The path under |root| to search
+      ldpaths: dict containing library paths to search; should have the keys:
+          conf, env, interp
+      display: The path to show rather than |path|
+      debug: Enable debug output
+      _first: Recursive use only; is this the first ELF ?
+      _all_libs: Recursive use only; dict of all libs we've seen
+
+    Returns:
+      a dict containing information about all the ELFs; e.g.
+      {
+        'interp': '/lib64/ld-linux.so.2',
+        'needed': ['libc.so.6', 'libcurl.so.4',],
+        'libs': {
+          'libc.so.6': {
+            'path': '/lib64/libc.so.6',
+            'needed': [],
+          },
+          'libcurl.so.4': {
+            'path': '/usr/lib64/libcurl.so.4',
+            'needed': ['libc.so.6', 'librt.so.1',],
+          },
         },
-      },
-    }
-  """
-  if _first:
-    _all_libs = {}
-    ldpaths = ldpaths.copy()
-  ret = {
-      'interp': None,
-      'path': path if display is None else display,
-      'realpath': path,
-      'needed': [],
-      'rpath': [],
-      'runpath': [],
-      'libs': _all_libs,
-  }
-
-  dbg(debug, 'ParseELF(%s)' % path)
-
-  with open(path, 'rb') as f:
-    elf = ELFFile(f)
-
-    # If this is the first ELF, extract the interpreter.
+      }
+    """
     if _first:
-      for segment in elf.iter_segments():
-        if segment.header.p_type != 'PT_INTERP':
-          continue
-
-        interp = bstr(segment.get_interp_name())
-        dbg(debug, '  interp           =', interp)
-        ret['interp'] = normpath(root + interp)
-        real_interp = readlink(ret['interp'], root, prefixed=True)
-        ret['libs'][os.path.basename(interp)] = {
-            'path': ret['interp'],
-            'realpath': real_interp,
-            'needed': [],
-        }
-        # XXX: Could read it and scan for /lib paths.
-        # If the interp is a symlink, lets follow it on the assumption that it
-        # is in this path purely for ABI reasons, and the distro is using a
-        # different (probably more correct) path.  This can come up in some
-        # multilib situations like s390x where /lib64/ contains all the native
-        # libraries, but /lib/ld64.so.1 is the interp hardcoded in gcc, so the
-        # ld64.so.1 is really a symlink to ../lib64/ld64.so.1.  In the 
multiarch
-        # setup, it'll be /lib/ld64.so.1 -> /lib/s390x-linux-gnu/ld64.so.1.
-        # That is why we use |real_interp| here instead of |interp|.
-        ldpaths['interp'] = [
-            os.path.dirname(real_interp),
-            normpath(root + prefix + '/usr/' + os.path.dirname(
-                real_interp)[len(root) + len(prefix):]),
-        ]
-        dbg(debug, '  ldpaths[interp]  =', ldpaths['interp'])
-        break
-
-    # Parse the ELF's dynamic tags.
-    libs = []
-    rpaths = []
-    runpaths = []
-    for segment in elf.iter_segments():
-      if segment.header.p_type != 'PT_DYNAMIC':
-        continue
-
-      for t in segment.iter_tags():
-        if t.entry.d_tag == 'DT_RPATH':
-          rpaths = ParseLdPaths(bstr(t.rpath), root=root, path=path)
-        elif t.entry.d_tag == 'DT_RUNPATH':
-          runpaths = ParseLdPaths(bstr(t.runpath), root=root, path=path)
-        elif t.entry.d_tag == 'DT_NEEDED':
-          libs.append(bstr(t.needed))
-      if runpaths:
-        # If both RPATH and RUNPATH are set, only the latter is used.
-        rpaths = []
+        _all_libs = {}
+        ldpaths = ldpaths.copy()
+    ret = {
+        'interp': None,
+        'path': path if display is None else display,
+        'realpath': path,
+        'needed': [],
+        'rpath': [],
+        'runpath': [],
+        'libs': _all_libs,
+    }
 
-      # XXX: We assume there is only one PT_DYNAMIC.  This is
-      # probably fine since the runtime ldso does the same.
-      break
-    if _first:
-      # Propagate the rpaths used by the main ELF since those will be
-      # used at runtime to locate things.
-      ldpaths['rpath'] = rpaths
-      ldpaths['runpath'] = runpaths
-      dbg(debug, '  ldpaths[rpath]   =', rpaths)
-      dbg(debug, '  ldpaths[runpath] =', runpaths)
-    ret['rpath'] = rpaths
-    ret['runpath'] = runpaths
-    ret['needed'] = libs
-
-    # Search for the libs this ELF uses.
-    all_ldpaths = None
-    for lib in libs:
-      if lib in _all_libs:
-        continue
-      if all_ldpaths is None:
-        all_ldpaths = rpaths + ldpaths['rpath'] + ldpaths['env'] + runpaths + 
ldpaths['runpath'] + ldpaths['conf'] + ldpaths['interp']
-      realpath, fullpath = FindLib(elf, lib, all_ldpaths, root, debug=debug)
-      _all_libs[lib] = {
-          'realpath': realpath,
-          'path': fullpath,
-          'needed': [],
-      }
-      if fullpath:
-        try:
-          lret = ParseELF(realpath, root, prefix, ldpaths, display=fullpath,
-                          debug=debug, _first=False, _all_libs=_all_libs)
-        except exceptions.ELFError as e:
-          warn('%s: %s' % (realpath, e))
-        _all_libs[lib]['needed'] = lret['needed']
+    dbg(debug, 'ParseELF(%s)' % path)
+
+    with open(path, 'rb') as f:
+        elf = ELFFile(f)
+
+        # If this is the first ELF, extract the interpreter.
+        if _first:
+            for segment in elf.iter_segments():
+                if segment.header.p_type != 'PT_INTERP':
+                    continue
+
+                interp = bstr(segment.get_interp_name())
+                dbg(debug, '  interp           =', interp)
+                ret['interp'] = normpath(root + interp)
+                real_interp = readlink(ret['interp'], root, prefixed=True)
+                ret['libs'][os.path.basename(interp)] = {
+                    'path': ret['interp'],
+                    'realpath': real_interp,
+                    'needed': [],
+                }
+                # XXX: Could read it and scan for /lib paths.
+                # If the interp is a symlink, lets follow it on the assumption 
that it
+                # is in this path purely for ABI reasons, and the distro is 
using a
+                # different (probably more correct) path.  This can come up in 
some
+                # multilib situations like s390x where /lib64/ contains all 
the native
+                # libraries, but /lib/ld64.so.1 is the interp hardcoded in 
gcc, so the
+                # ld64.so.1 is really a symlink to ../lib64/ld64.so.1.  In the 
multiarch
+                # setup, it'll be /lib/ld64.so.1 -> 
/lib/s390x-linux-gnu/ld64.so.1.
+                # That is why we use |real_interp| here instead of |interp|.
+                ldpaths['interp'] = [
+                    os.path.dirname(real_interp),
+                    normpath(root + prefix + '/usr/' + os.path.dirname(
+                        real_interp)[len(root) + len(prefix):]),
+                ]
+                dbg(debug, '  ldpaths[interp]  =', ldpaths['interp'])
+                break
+
+        # Parse the ELF's dynamic tags.
+        libs = []
+        rpaths = []
+        runpaths = []
+        for segment in elf.iter_segments():
+            if segment.header.p_type != 'PT_DYNAMIC':
+                continue
+
+            for t in segment.iter_tags():
+                if t.entry.d_tag == 'DT_RPATH':
+                    rpaths = ParseLdPaths(bstr(t.rpath), root=root, path=path)
+                elif t.entry.d_tag == 'DT_RUNPATH':
+                    runpaths = ParseLdPaths(bstr(t.runpath), root=root, 
path=path)
+                elif t.entry.d_tag == 'DT_NEEDED':
+                    libs.append(bstr(t.needed))
+            if runpaths:
+                # If both RPATH and RUNPATH are set, only the latter is used.
+                rpaths = []
+
+            # XXX: We assume there is only one PT_DYNAMIC.  This is
+            # probably fine since the runtime ldso does the same.
+            break
+        if _first:
+            # Propagate the rpaths used by the main ELF since those will be
+            # used at runtime to locate things.
+            ldpaths['rpath'] = rpaths
+            ldpaths['runpath'] = runpaths
+            dbg(debug, '  ldpaths[rpath]   =', rpaths)
+            dbg(debug, '  ldpaths[runpath] =', runpaths)
+        ret['rpath'] = rpaths
+        ret['runpath'] = runpaths
+        ret['needed'] = libs
+
+        # Search for the libs this ELF uses.
+        all_ldpaths = None
+        for lib in libs:
+            if lib in _all_libs:
+                continue
+            if all_ldpaths is None:
+                all_ldpaths = rpaths + ldpaths['rpath'] + ldpaths['env'] + 
runpaths + ldpaths['runpath'] + ldpaths['conf'] + ldpaths['interp']
+            realpath, fullpath = FindLib(elf, lib, all_ldpaths, root, 
debug=debug)
+            _all_libs[lib] = {
+                'realpath': realpath,
+                'path': fullpath,
+                'needed': [],
+            }
+            if fullpath:
+                try:
+                    lret = ParseELF(realpath, root, prefix, ldpaths, 
display=fullpath,
+                                    debug=debug, _first=False, 
_all_libs=_all_libs)
+                except exceptions.ELFError as e:
+                    warn('%s: %s' % (realpath, e))
+                _all_libs[lib]['needed'] = lret['needed']
 
-    del elf
+        del elf
 
-  return ret
+    return ret
 # pylint: enable=dangerous-default-value
 
 
 class _NormalizePathAction(argparse.Action):
-  def __call__(self, parser, namespace, values, option_string=None):
-    setattr(namespace, self.dest, normpath(values))
+    def __call__(self, parser, namespace, values, option_string=None):
+        setattr(namespace, self.dest, normpath(values))
 
 
 def _ActionShow(options, elf):
-  """Show the dependency tree for this ELF"""
-  def _show(lib, depth):
-    chain_libs.append(lib)
-    fullpath = elf['libs'][lib]['path']
+    """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'])
+    new_libs = elf['needed'][:]
+    chain_libs = []
+    interp = elf['interp']
+    if interp:
+        lib = os.path.basename(interp)
+        shown_libs.add(lib)
+        # If we are in non-list mode, then we want to show the "duplicate" 
interp
+        # lines -- first the header (interp=>xxx), and then the DT_NEEDED line 
to
+        # show that the ELF is directly linked against the interp.
+        # If we're in list mode though, we only want to show the interp once.
+        # Unless of course we have the --all flag active, then we show 
everything.
+        if not options.all and options.list and lib in new_libs:
+            new_libs.remove(lib)
     if options.list:
-      print(fullpath or lib)
+        print(elf['path'])
+        if not interp is None:
+            print(interp)
     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)
-
+        print('%s (interpreter => %s)' % (elf['path'], interp))
     for lib in new_libs:
-      _show(lib, depth + 1)
-    chain_libs.pop()
-
-  shown_libs = set(elf['needed'])
-  new_libs = elf['needed'][:]
-  chain_libs = []
-  interp = elf['interp']
-  if interp:
-    lib = os.path.basename(interp)
-    shown_libs.add(lib)
-    # If we are in non-list mode, then we want to show the "duplicate" interp
-    # lines -- first the header (interp=>xxx), and then the DT_NEEDED line to
-    # show that the ELF is directly linked against the interp.
-    # If we're in list mode though, we only want to show the interp once.
-    # Unless of course we have the --all flag active, then we show everything.
-    if not options.all and options.list and lib in new_libs:
-      new_libs.remove(lib)
-  if options.list:
-    print(elf['path'])
-    if not interp is None:
-      print(interp)
-  else:
-    print('%s (interpreter => %s)' % (elf['path'], interp))
-  for lib in new_libs:
-    _show(lib, 1)
+        _show(lib, 1)
 
 
 def _ActionCopy(options, elf):
-  """Copy the ELF and its dependencies to a destination tree"""
-  def _StripRoot(path):
-    return path[len(options.root) - 1:]
-
-  def _copy(realsrc, src, striproot=True, wrapit=False, libpaths=(),
-            outdir=None):
-    if realsrc is None:
-      return
+    """Copy the ELF and its dependencies to a destination tree"""
+    def _StripRoot(path):
+        return path[len(options.root) - 1:]
 
-    if wrapit:
-      # Static ELFs don't need to be wrapped.
-      if not elf['interp']:
-        wrapit = False
+    def _copy(realsrc, src, striproot=True, wrapit=False, libpaths=(),
+              outdir=None):
+        if realsrc is None:
+            return
 
-    striproot = _StripRoot if striproot else lambda x: x
+        if wrapit:
+            # Static ELFs don't need to be wrapped.
+            if not elf['interp']:
+                wrapit = False
 
-    if outdir:
-      subdst = os.path.join(outdir, os.path.basename(src))
-    else:
-      subdst = striproot(src)
-    dst = options.dest + subdst
+        striproot = _StripRoot if striproot else lambda x: x
 
-    try:
-      # See if they're the same file.
-      nstat = os.stat(dst + ('.elf' if wrapit else ''))
-      ostat = os.stat(realsrc)
-      for field in ('mode', 'mtime', 'size'):
-        if getattr(ostat, 'st_' + field) != \
-           getattr(nstat, 'st_' + field):
-          break
-      else:
-        return
-    except OSError as e:
-      if e.errno != errno.ENOENT:
-        raise
+        if outdir:
+            subdst = os.path.join(outdir, os.path.basename(src))
+        else:
+            subdst = striproot(src)
+        dst = options.dest + subdst
 
-    if options.verbose:
-      print('%s -> %s' % (src, dst))
+        try:
+            # See if they're the same file.
+            nstat = os.stat(dst + ('.elf' if wrapit else ''))
+            ostat = os.stat(realsrc)
+            for field in ('mode', 'mtime', 'size'):
+                if getattr(ostat, 'st_' + field) != \
+                   getattr(nstat, 'st_' + field):
+                    break
+            else:
+                return
+        except OSError as e:
+            if e.errno != errno.ENOENT:
+                raise
+
+        if options.verbose:
+            print('%s -> %s' % (src, dst))
+
+        makedirs(os.path.dirname(dst))
+        try:
+            shutil.copy2(realsrc, dst)
+        except IOError:
+            os.unlink(dst)
+            shutil.copy2(realsrc, dst)
+
+        if wrapit:
+            if options.verbose:
+                print('generate wrapper %s' % (dst,))
+
+            if options.libdir:
+                interp = os.path.join(options.libdir, 
os.path.basename(elf['interp']))
+            else:
+                interp = _StripRoot(elf['interp'])
+            GenerateLdsoWrapper(options.dest, subdst, interp, libpaths)
+
+    # XXX: We should automatically import libgcc_s.so whenever libpthread.so
+    # is copied over (since we know it can be dlopen-ed by NPTL at runtime).
+    # Similarly, we should provide an option for automatically copying over
+    # the libnsl.so and libnss_*.so libraries, as well as an open ended list
+    # for known libs that get loaded (e.g. curl will dlopen(libresolv)).
+    uniq_libpaths = set()
+    for lib in elf['libs']:
+        libdata = elf['libs'][lib]
+        path = libdata['realpath']
+        if path is None:
+            warn('could not locate library: %s' % lib)
+            continue
+        if not options.libdir:
+            uniq_libpaths.add(_StripRoot(os.path.dirname(path)))
+        _copy(path, libdata['path'], outdir=options.libdir)
 
-    makedirs(os.path.dirname(dst))
-    try:
-      shutil.copy2(realsrc, dst)
-    except IOError:
-      os.unlink(dst)
-      shutil.copy2(realsrc, dst)
-
-    if wrapit:
-      if options.verbose:
-        print('generate wrapper %s' % (dst,))
-
-      if options.libdir:
-        interp = os.path.join(options.libdir, os.path.basename(elf['interp']))
-      else:
-        interp = _StripRoot(elf['interp'])
-      GenerateLdsoWrapper(options.dest, subdst, interp, libpaths)
-
-  # XXX: We should automatically import libgcc_s.so whenever libpthread.so
-  # is copied over (since we know it can be dlopen-ed by NPTL at runtime).
-  # Similarly, we should provide an option for automatically copying over
-  # the libnsl.so and libnss_*.so libraries, as well as an open ended list
-  # for known libs that get loaded (e.g. curl will dlopen(libresolv)).
-  uniq_libpaths = set()
-  for lib in elf['libs']:
-    libdata = elf['libs'][lib]
-    path = libdata['realpath']
-    if path is None:
-      warn('could not locate library: %s' % lib)
-      continue
     if not options.libdir:
-      uniq_libpaths.add(_StripRoot(os.path.dirname(path)))
-    _copy(path, libdata['path'], outdir=options.libdir)
-
-  if not options.libdir:
-    libpaths = list(uniq_libpaths)
-    if elf['runpath']:
-      libpaths = elf['runpath'] + libpaths
+        libpaths = list(uniq_libpaths)
+        if elf['runpath']:
+            libpaths = elf['runpath'] + libpaths
+        else:
+            libpaths = elf['rpath'] + libpaths
     else:
-      libpaths = elf['rpath'] + libpaths
-  else:
-    uniq_libpaths.add(options.libdir)
-    libpaths = list(uniq_libpaths)
+        uniq_libpaths.add(options.libdir)
+        libpaths = list(uniq_libpaths)
 
-  # We don't bother to copy this as ParseElf adds the interp to the 'libs',
-  # so it was already copied in the libs loop above.
-  #_copy(elf['interp'], outdir=options.libdir)
-  _copy(elf['realpath'], elf['path'], striproot=options.auto_root,
-        wrapit=options.generate_wrappers, libpaths=libpaths,
-        outdir=options.bindir)
+    # We don't bother to copy this as ParseElf adds the interp to the 'libs',
+    # so it was already copied in the libs loop above.
+    #_copy(elf['interp'], outdir=options.libdir)
+    _copy(elf['realpath'], elf['path'], striproot=options.auto_root,
+          wrapit=options.generate_wrappers, libpaths=libpaths,
+          outdir=options.bindir)
 
 
 def GetParser():
-  """Get a CLI parser."""
-  parser = argparse.ArgumentParser(
-      description=__doc__,
-      formatter_class=argparse.RawDescriptionHelpFormatter)
-  parser.add_argument('-a', '--all',
-                      action='store_true', default=False,
-                      help='Show all duplicated dependencies')
-  parser.add_argument('-R', '--root',
-                      default=os.environ.get('ROOT', ''), type=str,
-                      action=_NormalizePathAction,
-                      help='Search for all files/dependencies in ROOT')
-  parser.add_argument('-P', '--prefix',
-                      default=os.environ.get(
-                          'EPREFIX', '@GENTOO_PORTAGE_EPREFIX@'), type=str,
-                      action=_NormalizePathAction,
-                      help='Specify EPREFIX for binaries (for Gentoo Prefix)')
-  parser.add_argument('--no-auto-root',
-                      dest='auto_root', action='store_false', default=True,
-                      help='Do not automatically prefix input ELFs with ROOT')
-  parser.add_argument('-l', '--list',
-                      action='store_true', default=False,
-                      help='Display output in a simple list (easy for 
copying)')
-  parser.add_argument('-x', '--debug',
-                      action='store_true', default=False,
-                      help='Run with debugging')
-  parser.add_argument('-v', '--verbose',
-                      action='store_true', default=False,
-                      help='Be verbose')
-  parser.add_argument('--skip-non-elfs',
-                      action='store_true', default=False,
-                      help='Skip plain (non-ELF) files instead of warning')
-  parser.add_argument('-V', '--version',
-                      action='version',
-                      version='lddtree by Mike Frysinger <[email protected]>',
-                      help='Show version information')
-  parser.add_argument('path', nargs='+')
-
-  group = parser.add_argument_group('Copying options')
-  group.add_argument('--copy-to-tree',
-                     dest='dest', default=None, type=str,
-                     action=_NormalizePathAction,
-                     help='Copy all files to the specified tree')
-  group.add_argument('--bindir',
-                     default=None, type=str,
-                     action=_NormalizePathAction,
-                     help='Dir to store all ELFs specified on the command 
line')
-  group.add_argument('--libdir',
-                     default=None, type=str,
-                     action=_NormalizePathAction,
-                     help='Dir to store all ELF libs')
-  group.add_argument('--generate-wrappers',
-                     action='store_true', default=False,
-                     help='Wrap executable ELFs with scripts for local ldso')
-  group.add_argument('--copy-non-elfs',
-                     action='store_true', default=False,
-                     help='Copy over plain (non-ELF) files instead of 
warn+ignore')
-
-  return parser
+    """Get a CLI parser."""
+    parser = argparse.ArgumentParser(
+        description=__doc__,
+        formatter_class=argparse.RawDescriptionHelpFormatter)
+    parser.add_argument('-a', '--all',
+                        action='store_true', default=False,
+                        help='Show all duplicated dependencies')
+    parser.add_argument('-R', '--root',
+                        default=os.environ.get('ROOT', ''), type=str,
+                        action=_NormalizePathAction,
+                        help='Search for all files/dependencies in ROOT')
+    parser.add_argument('-P', '--prefix',
+                        default=os.environ.get(
+                            'EPREFIX', '@GENTOO_PORTAGE_EPREFIX@'), type=str,
+                        action=_NormalizePathAction,
+                        help='Specify EPREFIX for binaries (for Gentoo 
Prefix)')
+    parser.add_argument('--no-auto-root',
+                        dest='auto_root', action='store_false', default=True,
+                        help='Do not automatically prefix input ELFs with 
ROOT')
+    parser.add_argument('-l', '--list',
+                        action='store_true', default=False,
+                        help='Display output in a simple list (easy for 
copying)')
+    parser.add_argument('-x', '--debug',
+                        action='store_true', default=False,
+                        help='Run with debugging')
+    parser.add_argument('-v', '--verbose',
+                        action='store_true', default=False,
+                        help='Be verbose')
+    parser.add_argument('--skip-non-elfs',
+                        action='store_true', default=False,
+                        help='Skip plain (non-ELF) files instead of warning')
+    parser.add_argument('-V', '--version',
+                        action='version',
+                        version='lddtree by Mike Frysinger 
<[email protected]>',
+                        help='Show version information')
+    parser.add_argument('path', nargs='+')
+
+    group = parser.add_argument_group('Copying options')
+    group.add_argument('--copy-to-tree',
+                       dest='dest', default=None, type=str,
+                       action=_NormalizePathAction,
+                       help='Copy all files to the specified tree')
+    group.add_argument('--bindir',
+                       default=None, type=str,
+                       action=_NormalizePathAction,
+                       help='Dir to store all ELFs specified on the command 
line')
+    group.add_argument('--libdir',
+                       default=None, type=str,
+                       action=_NormalizePathAction,
+                       help='Dir to store all ELF libs')
+    group.add_argument('--generate-wrappers',
+                       action='store_true', default=False,
+                       help='Wrap executable ELFs with scripts for local ldso')
+    group.add_argument('--copy-non-elfs',
+                       action='store_true', default=False,
+                       help='Copy over plain (non-ELF) files instead of 
warn+ignore')
+
+    return parser
 
 
 def main(argv):
-  """The main entry point!"""
-  parser = GetParser()
-  options = parser.parse_args(argv)
-  paths = options.path
-
-  if options.root != '/':
-    options.root += '/'
-  if options.prefix == '@''GENTOO_PORTAGE_EPREFIX''@':
-    options.prefix = ''
-
-  if options.bindir and options.bindir[0] != '/':
-    parser.error('--bindir accepts absolute paths only')
-  if options.libdir and options.libdir[0] != '/':
-    parser.error('--libdir accepts absolute paths only')
-
-  if options.skip_non_elfs and options.copy_non_elfs:
-    parser.error('pick one handler for non-ELFs: skip or copy')
-
-  dbg(options.debug, 'root =', options.root)
-  if options.dest:
-    dbg(options.debug, 'dest =', options.dest)
-  if not paths:
-    err('missing ELF files to scan')
-
-  ldpaths = LoadLdpaths(options.root, options.prefix, debug=options.debug)
-  dbg(options.debug, 'ldpaths[conf] =', ldpaths['conf'])
-  dbg(options.debug, 'ldpaths[env]  =', ldpaths['env'])
-
-  # Process all the files specified.
-  ret = 0
-  for path in paths:
-    dbg(options.debug, 'argv[x]       =', path)
-    # Only auto-prefix the path if the ELF is absolute.
-    # If it's a relative path, the user most likely wants
-    # the local path.
-    if options.auto_root and path.startswith('/'):
-      path = options.root + path.lstrip('/')
-      dbg(options.debug, '  +auto-root  =', path)
-
-    matched = False
-    for p in glob.iglob(path):
-      # Once we've processed the globs, resolve the symlink.  This way you can
-      # operate on a path that is an absolute symlink itself.  e.g.:
-      #   $ ln -sf /bin/bash $PWD/root/bin/sh
-      #   $ lddtree --root $PWD/root /bin/sh
-      # First we'd turn /bin/sh into $PWD/root/bin/sh, then we want to resolve
-      # the symlink to $PWD/root/bin/bash rather than a plain /bin/bash.
-      dbg(options.debug, '  globbed     =', p)
-      if not path.startswith('/'):
-        realpath = os.path.realpath(path)
-      elif options.auto_root:
-        realpath = readlink(p, options.root, prefixed=True)
-      else:
-        realpath = path
-      if path != realpath:
-        dbg(options.debug, '  resolved    =', realpath)
-
-      matched = True
-      try:
-        elf = ParseELF(realpath, options.root, options.prefix, ldpaths,
-                       display=p, debug=options.debug)
-      except exceptions.ELFError as e:
-        if options.skip_non_elfs:
-          continue
-        # XXX: Ugly.  Should unify with _Action* somehow.
-        if options.dest is not None and options.copy_non_elfs:
-          if os.path.exists(p):
-            elf = {
-                'interp': None,
-                'libs': [],
-                'runpath': [],
-                'rpath': [],
-                'path': p,
-                'realpath': realpath,
-            }
-            _ActionCopy(options, elf)
-            continue
-        ret = 1
-        warn('%s: %s' % (p, e))
-        continue
-      except IOError as e:
-        ret = 1
-        warn('%s: %s' % (p, e))
-        continue
-
-      if options.dest is None:
-        _ActionShow(options, elf)
-      else:
-        _ActionCopy(options, elf)
-
-    if not matched:
-      ret = 1
-      warn('%s: did not match any paths' % (path,))
-
-  return ret
+    """The main entry point!"""
+    parser = GetParser()
+    options = parser.parse_args(argv)
+    paths = options.path
+
+    if options.root != '/':
+        options.root += '/'
+    if options.prefix == '@''GENTOO_PORTAGE_EPREFIX''@':
+        options.prefix = ''
+
+    if options.bindir and options.bindir[0] != '/':
+        parser.error('--bindir accepts absolute paths only')
+    if options.libdir and options.libdir[0] != '/':
+        parser.error('--libdir accepts absolute paths only')
+
+    if options.skip_non_elfs and options.copy_non_elfs:
+        parser.error('pick one handler for non-ELFs: skip or copy')
+
+    dbg(options.debug, 'root =', options.root)
+    if options.dest:
+        dbg(options.debug, 'dest =', options.dest)
+    if not paths:
+        err('missing ELF files to scan')
+
+    ldpaths = LoadLdpaths(options.root, options.prefix, debug=options.debug)
+    dbg(options.debug, 'ldpaths[conf] =', ldpaths['conf'])
+    dbg(options.debug, 'ldpaths[env]  =', ldpaths['env'])
+
+    # Process all the files specified.
+    ret = 0
+    for path in paths:
+        dbg(options.debug, 'argv[x]       =', path)
+        # Only auto-prefix the path if the ELF is absolute.
+        # If it's a relative path, the user most likely wants
+        # the local path.
+        if options.auto_root and path.startswith('/'):
+            path = options.root + path.lstrip('/')
+            dbg(options.debug, '  +auto-root  =', path)
+
+        matched = False
+        for p in glob.iglob(path):
+            # Once we've processed the globs, resolve the symlink.  This way 
you can
+            # operate on a path that is an absolute symlink itself.  e.g.:
+            #   $ ln -sf /bin/bash $PWD/root/bin/sh
+            #   $ lddtree --root $PWD/root /bin/sh
+            # First we'd turn /bin/sh into $PWD/root/bin/sh, then we want to 
resolve
+            # the symlink to $PWD/root/bin/bash rather than a plain /bin/bash.
+            dbg(options.debug, '  globbed     =', p)
+            if not path.startswith('/'):
+                realpath = os.path.realpath(path)
+            elif options.auto_root:
+                realpath = readlink(p, options.root, prefixed=True)
+            else:
+                realpath = path
+            if path != realpath:
+                dbg(options.debug, '  resolved    =', realpath)
+
+            matched = True
+            try:
+                elf = ParseELF(realpath, options.root, options.prefix, ldpaths,
+                               display=p, debug=options.debug)
+            except exceptions.ELFError as e:
+                if options.skip_non_elfs:
+                    continue
+                # XXX: Ugly.  Should unify with _Action* somehow.
+                if options.dest is not None and options.copy_non_elfs:
+                    if os.path.exists(p):
+                        elf = {
+                            'interp': None,
+                            'libs': [],
+                            'runpath': [],
+                            'rpath': [],
+                            'path': p,
+                            'realpath': realpath,
+                        }
+                        _ActionCopy(options, elf)
+                        continue
+                ret = 1
+                warn('%s: %s' % (p, e))
+                continue
+            except IOError as e:
+                ret = 1
+                warn('%s: %s' % (p, e))
+                continue
+
+            if options.dest is None:
+                _ActionShow(options, elf)
+            else:
+                _ActionCopy(options, elf)
+
+        if not matched:
+            ret = 1
+            warn('%s: did not match any paths' % (path,))
+
+    return ret
 
 
 if __name__ == '__main__':
-  sys.exit(main(sys.argv[1:]))
+    sys.exit(main(sys.argv[1:]))

diff --git a/pylint b/pylint
index 965537d..38d77a2 100755
--- a/pylint
+++ b/pylint
@@ -12,38 +12,38 @@ import sys
 
 
 def find_all_modules(source_root):
-  """Locate all python modules in the tree for scanning"""
-  ret = []
+    """Locate all python modules in the tree for scanning"""
+    ret = []
 
-  for root, _dirs, files in os.walk(source_root, topdown=False):
-    # Add all of the .py modules in the tree.
-    ret += [os.path.join(root, x) for x in files if x.endswith('.py')]
+    for root, _dirs, files in os.walk(source_root, topdown=False):
+        # Add all of the .py modules in the tree.
+        ret += [os.path.join(root, x) for x in files if x.endswith('.py')]
 
-  # Add the main scripts that don't end in .py.
-  ret += [os.path.join(source_root, x) for x in ('pylint',)]
+    # Add the main scripts that don't end in .py.
+    ret += [os.path.join(source_root, x) for x in ('pylint',)]
 
-  return ret
+    return ret
 
 
 def main(argv):
-  """The main entry point"""
-  source_root = os.path.dirname(os.path.realpath(__file__))
+    """The main entry point"""
+    source_root = os.path.dirname(os.path.realpath(__file__))
 
-  if not argv:
-    argv = find_all_modules(source_root)
+    if not argv:
+        argv = find_all_modules(source_root)
 
-  pympath = source_root
-  pythonpath = os.environ.get('PYTHONPATH')
-  if pythonpath is None:
-    pythonpath = pympath
-  else:
-    pythonpath = pympath + ':' + pythonpath
-  os.environ['PYTHONPATH'] = pythonpath
+    pympath = source_root
+    pythonpath = os.environ.get('PYTHONPATH')
+    if pythonpath is None:
+        pythonpath = pympath
+    else:
+        pythonpath = pympath + ':' + pythonpath
+    os.environ['PYTHONPATH'] = pythonpath
 
-  pylintrc = os.path.join(source_root, '.pylintrc')
-  cmd = ['pylint', '--rcfile', pylintrc]
-  os.execvp(cmd[0], cmd + argv)
+    pylintrc = os.path.join(source_root, '.pylintrc')
+    cmd = ['pylint', '--rcfile', pylintrc]
+    os.execvp(cmd[0], cmd + argv)
 
 
 if __name__ == '__main__':
-  sys.exit(main(sys.argv[1:]))
+    sys.exit(main(sys.argv[1:]))

Reply via email to