mirror of
https://github.com/flatcar/scripts.git
synced 2025-08-08 13:36:58 +02:00
The path passed to _ReadLdSoConf must start with a '/' which wasn't happening since relpath returns a relative path.
192 lines
5.2 KiB
Python
Executable File
192 lines
5.2 KiB
Python
Executable File
#!/usr/bin/python
|
|
|
|
# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
import os
|
|
import re
|
|
import sys
|
|
import glob
|
|
|
|
_SHARED_RE = re.compile(r"Shared library: \[([^\]]+)\]")
|
|
_RPATH_RE = re.compile(r"Library r(?:un)?path: \[([^\]]+)\]")
|
|
|
|
|
|
class CheckDependencies(object):
|
|
"""Check that dependencies for binaries can be found in the specified dir."""
|
|
|
|
def _ReadLdSoConf(self, path):
|
|
"""Parse ld.so.conf files.
|
|
|
|
Starting with the file at PATH (searched relative to self._root), return
|
|
all the valid libdirs found. Include directives are handled recursively.
|
|
|
|
Args:
|
|
path: the path to the ld.so.conf file (inside of the root).
|
|
|
|
Returns:
|
|
A list of valid libdirs.
|
|
"""
|
|
|
|
libdirs = []
|
|
|
|
ld_so_conf = self._root + path
|
|
if os.path.exists(ld_so_conf):
|
|
f = file(ld_so_conf)
|
|
|
|
for line in f:
|
|
line = line.rstrip()
|
|
|
|
if line.startswith("/"):
|
|
libpath = self._root + line
|
|
if os.path.exists(libpath):
|
|
libdirs.append(libpath)
|
|
|
|
elif line.startswith("include "):
|
|
# Includes are absolute or relative to the file itself.
|
|
line = os.path.join(os.path.dirname(path), line[8:])
|
|
for p in glob.glob(self._root + line):
|
|
rel_p = "/%s" % os.path.relpath(p, self._root)
|
|
libdirs.extend(self._ReadLdSoConf(rel_p))
|
|
|
|
f.close()
|
|
|
|
return libdirs
|
|
|
|
def __init__(self, root, verbose=False):
|
|
"""Initializer.
|
|
|
|
Args:
|
|
root: The sysroot (e.g. "/")
|
|
verbose: Print helpful messages.
|
|
"""
|
|
|
|
self._root = root
|
|
self._libcache = set()
|
|
self._verbose = verbose
|
|
|
|
libdirs = []
|
|
|
|
# Add the native paths. Get the ELF interpreter from a known file
|
|
# and assume that the path it is in is our native libdir. So here
|
|
# we would get something like "/lib64/ld-linux-x86-64.so.2".
|
|
elf = "/bin/sh"
|
|
f = os.popen("scanelf -qF'%%i#p' %s/%s" % (root, elf))
|
|
native_libdir = os.path.dirname(f.readline().rstrip())
|
|
f.close()
|
|
if len(native_libdir) == 0:
|
|
print >>sys.stderr, "Problem with %s: can't find ELF interp" % elf
|
|
sys.exit(1)
|
|
elif native_libdir != "/lib":
|
|
libdirs.extend([
|
|
"%s/%s" % (root, native_libdir),
|
|
"%s/usr%s" % (root, native_libdir)
|
|
])
|
|
|
|
# Insert some default directories into our library cache.
|
|
libdirs.extend([
|
|
"%s/lib" % root,
|
|
"%s/usr/lib" % root,
|
|
"%s/opt/google/o3d/lib" % root,
|
|
"%s/usr/lib/opengl/xorg-x11/lib" % root,
|
|
"%s/usr/local/lib/icedtea6/jre/lib/i386/client" % root,
|
|
"%s/usr/local/lib/icedtea6/jre/lib/i386/headless" % root
|
|
])
|
|
|
|
# Read more directories from ld.so.conf.
|
|
libdirs.extend(self._ReadLdSoConf("/etc/ld.so.conf"))
|
|
|
|
self._ReadLibs(libdirs, self._libcache)
|
|
|
|
def _ReadLibs(self, paths, libcache):
|
|
for path in paths:
|
|
if os.path.exists(path):
|
|
for lib in os.listdir(path):
|
|
libcache.add(lib)
|
|
|
|
def _ReadDependencies(self, binary):
|
|
"""Run readelf -d on BINARY, returning (deps, rpaths)."""
|
|
|
|
deps = set()
|
|
rpaths = set()
|
|
|
|
# Read list of dynamic libraries, ignoring error messages that occur
|
|
# when we look at files that aren't actually libraries
|
|
f = os.popen("readelf -d '%s' 2>/dev/null" % binary)
|
|
for line in f:
|
|
|
|
# Grab dependencies
|
|
m = _SHARED_RE.search(line)
|
|
if m:
|
|
deps.add(m.group(1))
|
|
|
|
# Add RPATHs in our search path
|
|
m = _RPATH_RE.search(line)
|
|
if m:
|
|
for path in m.group(1).split(":"):
|
|
if path.startswith("$ORIGIN"):
|
|
rpaths.add(path.replace("$ORIGIN", os.path.dirname(binary)))
|
|
else:
|
|
rpaths.add(os.path.join(self._root, path[1:]))
|
|
f.close()
|
|
|
|
return (deps, rpaths)
|
|
|
|
def CheckDependencies(self, binary):
|
|
"""Check whether the libs for BINARY can be found in our sysroot."""
|
|
|
|
good = True
|
|
|
|
deps, rpaths = self._ReadDependencies(binary)
|
|
|
|
if self._verbose:
|
|
for lib in self._libcache & deps:
|
|
print "Found %s" % lib
|
|
|
|
for lib in deps - self._libcache:
|
|
if lib[0] != "/":
|
|
for path in rpaths:
|
|
if os.path.exists(os.path.join(path, lib)):
|
|
if self._verbose:
|
|
print "Found %s" % lib
|
|
break
|
|
else:
|
|
print >>sys.stderr, "Problem with %s: Can't find %s" % (binary, lib)
|
|
good = False
|
|
else:
|
|
full_path = os.path.join(self._root, lib[1:])
|
|
if os.path.exists(full_path):
|
|
if self._verbose: print "Found %s" % lib
|
|
else:
|
|
print >>sys.stderr, "Problem with %s: Can't find %s" % (binary, lib)
|
|
good = False
|
|
|
|
return good
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) < 3:
|
|
print "Usage: %s [-v] sysroot binary [ binary ... ]" % sys.argv[0]
|
|
sys.exit(1)
|
|
|
|
verbose = False
|
|
if sys.argv[1] == "-v":
|
|
verbose = True
|
|
sys.argv = sys.argv[0:1] + sys.argv[2:]
|
|
|
|
checker = CheckDependencies(sys.argv[1], verbose)
|
|
errors = False
|
|
for binary in sys.argv[2:]:
|
|
if verbose: print "Checking %s" % binary
|
|
if not checker.CheckDependencies(binary):
|
|
errors = True
|
|
|
|
if errors:
|
|
sys.exit(1)
|
|
else:
|
|
sys.exit(0)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|