Norm Jacobs
2018-01-29 df98988a54b3cf2cc02eff2eecf98b0781d4e40d
userland-mangler: strip runtime linker default directories from R*PATH
1 files modified
67 ■■■■■ changed files
tools/userland-mangler 67 ●●●●● patch | view | raw | blame | history
tools/userland-mangler
@@ -31,6 +31,9 @@
import os
import sys
import re
import subprocess
import shutil
import pkg.fmri
import pkg.manifest
@@ -194,12 +197,70 @@
    return result
#
# mangler.elf.strip = (true|false)
# mangler.elf.strip_runpath = (true|false)
#
def mangle_elf(manifest, action, src, dest):
    pass
    strip_elf_runpath = action.attrs.pop('mangler.elf.strip_runpath', 'true')
    if strip_elf_runpath is 'false':
        return
    #
    # Strip any runtime linker default search path elements from the file
    #
    ELFEDIT = '/usr/bin/elfedit'
    # runtime linker default search path elements + /64 link
    rtld_default_dirs = [ '/lib', '/usr/lib',
                  '/lib/64', '/usr/lib/64',
                  '/lib/amd64', '/usr/lib/amd64',
                  '/lib/sparcv9', '/usr/lib/sparcv9' ]
    runpath_re = re.compile('.+\s(RPATH|RUNPATH)\s+\S+\s+(\S+)')
    # Retreive the search path from the object file.  Use elfedit(1) because pkg.elf only
    # retrieves the RUNPATH.  Note that dyn:rpath and dyn:runpath return both values.
    # Both RPATH and RUNPATH are expected to be the same, but in an overabundand of caution,
    # process each element found separately.
    result = subprocess.Popen([ELFEDIT, '-re', 'dyn:runpath', src ],
                  stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        result.wait()
    if result.returncode != 0:    # no RUNPATH or RPATH to potentially strip
        return
    for line in result.stdout:
        result = runpath_re.match(line)
        if result != None:
            element = result.group(1)
            original_dirs = result.group(2).split(":")
            keep_dirs = []
            matched_dirs = []
            for dir in original_dirs:
                if dir not in rtld_default_dirs:
                    keep_dirs.append(dir)
                else:
                    matched_dirs.append(dir)
            if len(matched_dirs) != 0:
                # Emit an "Error" message in case someone wants to look at the build log
                # and fix the component build so that this is a NOP.
                print >>sys.stderr, "Stripping %s from %s in %s" % (":".join(matched_dirs), element, src)
                # Make sure that there is a destdir to copy the file into for mangling.
                destdir = os.path.dirname(dest)
                if not os.path.exists(destdir):
                    os.makedirs(destdir)
                # Create a copy to mangle if it doesn't exist yet.
                if os.path.isfile(dest) == False:
                    shutil.copy2(src, dest)
                # Mangle the copy by deleting the tag if there is nothing left to keep
                # or replacing the value if there is something left.
                elfcmd = "dyn:delete %s" % element.lower()
                if len(keep_dirs) > 0:
                    elfcmd = "dyn:%s '%s'" % (element.lower(), ":".join(keep_dirs))
                subprocess.call([ELFEDIT, '-e', elfcmd, dest])
#
# mangler.script.file-magic =