From 783118944874d559e30eea1600352e3feb5263a7 Mon Sep 17 00:00:00 2001 From: Andreas Wacknitz <A.Wacknitz@gmx.de> Date: Sun, 31 Mar 2024 09:35:05 +0200 Subject: [PATCH] libcares: update to 1.28.0 --- tools/userland-mangler | 448 +++++++++++++++++++++++++++++++++++++------------------- 1 files changed, 296 insertions(+), 152 deletions(-) diff --git a/tools/userland-mangler b/tools/userland-mangler index 825cd37..8cdbbe3 100755 --- a/tools/userland-mangler +++ b/tools/userland-mangler @@ -1,4 +1,4 @@ -#!/usr/bin/python2.6 +#!/usr/bin/python3.9 # # CDDL HEADER START # @@ -7,7 +7,7 @@ # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE -# or http://www.opensolaris.org/os/licensing. +# or http://www.illumos.org/license/CDDL. # See the License for the specific language governing permissions # and limitations under the License. # @@ -19,7 +19,7 @@ # # CDDL HEADER END # -# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. # # # userland-mangler - a file mangling utility @@ -31,11 +31,18 @@ import os import sys import re +import subprocess +import shutil +import stat + import pkg.fmri import pkg.manifest import pkg.actions import pkg.elf as elf + +attribute_oracle_table_header = """ +.\\\" Oracle has added the ARC stability level to this manual page""" attribute_table_header = """ .SH ATTRIBUTES @@ -58,22 +65,29 @@ Stability %s""" attribute_table_footer = """ -.TE +.TE .PP """ -def write_attributes_section(ofp, availability, stability): - # is there anything to do? - if availability is None and stability is None: - return +def attributes_section_text(availability, stability, modified_date): + result = '' - # append the ATTRIBUTES section - ofp.write(attribute_table_header) - if availability is not None: - ofp.write(attribute_table_availability % availability) - if stability is not None: - ofp.write(attribute_table_stability % stability.capitalize()) - ofp.write(attribute_table_footer) + # is there anything to do? + if availability is not None or stability is not None: + result = attribute_oracle_table_header + if modified_date is not None: + result += ("\n.\\\" on %s" % modified_date) + result += attribute_table_header + if availability is not None: + result += (attribute_table_availability % availability) + if stability is not None: + result += (attribute_table_stability % stability.capitalize()) + result += attribute_table_footer + + return result + +notes_oracle_comment = """ +.\\\" Oracle has added source availability information to this manual page""" notes_header = """ .SH NOTES @@ -83,194 +97,324 @@ Further information about this software can be found on the open source community website at %s. """ notes_source = """ -This software was built from source available at http://opensolaris.org/. The original community source was downloaded from %s +This software was built from source available at https://openindiana.org/. The original community source was downloaded from %s """ -def write_notes_section(ofp, header_seen, community, source): - # is there anything to do? - if community is None and source is None: - return +def notes_section_text(header_seen, community, source, modified_date): + result = '' - # append the NOTES section - if header_seen == False: - ofp.write(notes_header) - if source is not None: - ofp.write(notes_source % source) - if community is not None: - ofp.write(notes_community % community) + # is there anything to do? + if community is not None or source is not None: + if header_seen == False: + result += notes_header + result += notes_oracle_comment + if modified_date is not None: + result += ("\n.\\\" on %s" % modified_date) + if source is not None: + result += (notes_source % source) + if community is not None: + result += (notes_community % community) + return result +so_re = re.compile('^\.so.+$', re.MULTILINE) section_re = re.compile('\.SH "?([^"]+).*$', re.IGNORECASE) +TH_re = re.compile('\.TH\s+(?:"[^"]+"|\S+)\s+(\S+)', re.IGNORECASE) # # mangler.man.stability = (mangler.man.stability) +# mangler.man.modified_date = (mangler.man.modified-date) # mangler.man.availability = (pkg.fmri) -# mangler.man.source_url = (pkg.source_url) -# mangler.man.upstream_url = (pkg.upstream_url) +# mangler.man.source-url = (pkg.source-url) +# mangler.man.upstream-url = (pkg.upstream-url) # -def mangle_manpage(manifest, action, src, dest): - # manpages must have a taxonomy defined - stability = action.attrs.pop('mangler.man.stability', None) - if stability is None: - sys.stderr.write("ERROR: manpage action missing mangler.man.stability: %s" % action) - sys.exit(1) +def mangle_manpage(manifest, action, text): + # manpages must have a taxonomy defined + stability = action.attrs.pop('mangler.man.stability', None) + if stability is None: + sys.stderr.write("ERROR: manpage action missing mangler.man.stability: %s" % action) + sys.exit(1) - attributes_written = False - notes_seen = False + # manpages may have a 'modified date' + modified_date = action.attrs.pop('mangler.man.modified-date', None) - if 'pkg.fmri' in manifest.attributes: - fmri = pkg.fmri.PkgFmri(manifest.attributes['pkg.fmri']) - availability = fmri.pkg_name + # Rewrite the section in the .TH line to match the section in which + # we're delivering it. + rewrite_sect = action.attrs.pop('mangler.man.rewrite-section', 'true') - community = None - if 'info.upstream_url' in manifest.attributes: - community = manifest.attributes['info.upstream_url'] + attributes_written = False + notes_seen = False - source = None - if 'info.source_url' in manifest.attributes: - source = manifest.attributes['info.source_url'] - elif 'info.repository_url' in manifest.attributes: - source = manifest.attributes['info.repository_url'] + if 'pkg.fmri' in manifest.attributes: + fmri = pkg.fmri.PkgFmri(manifest.attributes['pkg.fmri']) + availability = fmri.pkg_name - # create a directory to write to - destdir = os.path.dirname(dest) - if not os.path.exists(destdir): - os.makedirs(destdir) + community = None + if 'info.upstream-url' in manifest.attributes: + community = manifest.attributes['info.upstream-url'] - # read the source document - ifp = open(src, "r") - lines = ifp.readlines() - ifp.close() + source = None + if 'info.source-url' in manifest.attributes: + source = manifest.attributes['info.source-url'] + elif 'info.repository-url' in manifest.attributes: + source = manifest.attributes['info.repository-url'] - # skip reference only pages - if lines[0].startswith(".so "): - return + # skip reference only pages + if so_re.match(text) is not None: + return text - # open a destination - ofp = open(dest, "w+") + # tell man that we want tables (and eqn) + result = "'\\\" te\n" - # tell man that we want tables (and eqn) - ofp.write("'\\\" te\n") + # write the orginal data + for line in text.split('\n'): + match = section_re.match(line) + if match is not None: + section = match.group(1) + if section in ['SEE ALSO', 'NOTES']: + if attributes_written == False: + result += attributes_section_text( + availability, + stability, + modified_date) + attributes_written = True + if section == 'NOTES': + notes_seen = True + match = TH_re.match(line) + if match and rewrite_sect.lower() == "true": + # Use the section defined by the filename, rather than + # the directory in which it sits. + sect = os.path.splitext(action.attrs["path"])[1][1:] + line = line[:match.span(1)[0]] + sect + \ + line[match.span(1)[1]:] - # write the orginal data - for line in lines: - match = section_re.match(line) - if match is not None: - section = match.group(1) - if section in ['SEE ALSO', 'NOTES']: - if attributes_written == False: - write_attributes_section(ofp, - availability, - stability) - attributes_written = True - if section == 'NOTES': - notes_seen = True - ofp.write(line) + result += ("%s\n" % line) - if attributes_written == False: - write_attributes_section(ofp, availability, stability) + if attributes_written == False: + result += attributes_section_text(availability, stability, + modified_date) - write_notes_section(ofp, notes_seen, community, source) + result += notes_section_text(notes_seen, community, source, + modified_date) - ofp.close() - + 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 == 'false': + return + + # + # Strip any runtime linker default search path elements from the file + # and replace relative paths with absolute paths + # + 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, + universal_newlines=True) + 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: + if dir.startswith('$ORIGIN'): + path = action.attrs['path'] + dirname = os.path.dirname(path) + if dirname[0] != '/': + dirname = '/' + dirname + corrected_dir = dir.replace('$ORIGIN', dirname) + corrected_dir = os.path.realpath(corrected_dir) + matched_dirs.append(dir) + keep_dirs.append(corrected_dir) + else: + 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("Stripping %s from %s in %s" % (":".join(matched_dirs), element, src), file=sys.stderr) + + # 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 + # Earlier the code would check that the destination file does not exist + # yet, however internal library versioning can be different while the + # filename remains the same. + # When publishing from a non-clean prototype directory older libraries + # which may be ABI incompatible would then be republished in the new + # package instead of the new version. + shutil.copy2(src, dest) + + # Make sure we do have write permission before we try to modify the file + os.chmod(dest, os.stat(dest).st_mode | stat.S_IWUSR) + + # 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 = # -def mangle_script(manifest, action, src, dest): - pass +def mangle_script(manifest, action, text): + return text -def mangle_path(manifest, action, src, dest): - if 'facet.doc.man' in action.attrs: - mangle_manpage(manifest, action, src, dest) - elif 'mode' in action.attrs and int(action.attrs['mode'], 8) & 0111 != 0: - if elf.is_elf_object(src): - mangle_elf(manifest, action, src, dest) - else: - mangle_script(manifest, action, src, dest) +# +# mangler.strip_cddl = false +# +def mangle_cddl(manifest, action, text): + strip_cddl = action.attrs.pop('mangler.strip_cddl', 'false') + if strip_cddl == 'false': + return text + cddl_re = re.compile('^[^\n]*CDDL HEADER START.+CDDL HEADER END[^\n]*$', + re.MULTILINE|re.DOTALL) + return cddl_re.sub('', text) + +def do_ctfconvert(converter, file): + args = [converter, '-i', '-m', '-k', file] + print(*args, file=sys.stderr) + subprocess.call(args) + +def mangle_path(manifest, action, src, dest, ctfconvert): + if elf.is_elf_object(src): + if ctfconvert is not None: + do_ctfconvert(ctfconvert, src) + mangle_elf(manifest, action, src, dest) + else: + # a 'text' document (script, man page, config file, ... + # We treat all documents as latin-1 text to avoid + # reencoding them and loosing data + ifp = open(src, 'r', encoding='latin-1') + text = ifp.read() + ifp.close() + + # remove the CDDL from files + result = mangle_cddl(manifest, action, text) + + if 'facet.doc.man' in action.attrs: + result = mangle_manpage(manifest, action, result) + elif 'mode' in action.attrs and int(action.attrs['mode'], 8) & 0o111 != 0: + result = mangle_script(manifest, action, result) + + if text != result: + destdir = os.path.dirname(dest) + if not os.path.exists(destdir): + os.makedirs(destdir) + with open(dest, 'w', encoding='latin-1') as ofp: + ofp.write(result) # # mangler.bypass = (true|false) # -def mangle_paths(manifest, search_paths, destination): - for action in manifest.gen_actions_by_type("file"): - bypass = action.attrs.pop('mangler.bypass', 'false').lower() - if bypass == 'true': - continue +def mangle_paths(manifest, search_paths, destination, ctfconvert): + for action in manifest.gen_actions_by_type("file"): + bypass = action.attrs.pop('mangler.bypass', 'false').lower() + if bypass == 'true': + continue - path = None - if 'path' in action.attrs: - path = action.attrs['path'] - if action.hash and action.hash != 'NOHASH': - path = action.hash - if not path: - continue + path = None + if 'path' in action.attrs: + path = action.attrs['path'] + if action.hash and action.hash != 'NOHASH': + path = action.hash + if not path: + continue - dest = os.path.join(destination, path) - for directory in search_paths: - if directory != destination: - src = os.path.join(directory, path) - if os.path.exists(src): - mangle_path(manifest, action, src, dest) - break + if not os.path.exists(destination): + os.makedirs(destination) + + dest = os.path.join(destination, path) + for directory in search_paths: + if directory != destination: + src = os.path.join(directory, path) + if os.path.isfile(src): + mangle_path(manifest, action, + src, dest, ctfconvert) + break def load_manifest(manifest_file): - manifest = pkg.manifest.Manifest() - manifest.set_content(pathname=manifest_file) + manifest = pkg.manifest.Manifest() + manifest.set_content(pathname=manifest_file) - return manifest + return manifest def usage(): - print "Usage: %s [-m|--manifest (file)] [-d|--search-directory (dir)] [-D|--destination (dir)] " % (sys.argv[0].split('/')[-1]) - sys.exit(1) + print("Usage: %s [-m|--manifest (file)] [-d|--search-directory (dir)] [-D|--destination (dir)] " % (sys.argv[0].split('/')[-1])) + sys.exit(1) def main(): - import getopt + import getopt - # FLUSH STDOUT - sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) + sys.stdout.flush() - search_paths = [] - destination = None - manifests = [] + search_paths = [] + destination = None + manifests = [] + ctfconvert = None - try: - opts, args = getopt.getopt(sys.argv[1:], "D:d:m:", - ["destination=", "search-directory=", "manifest="]) - except getopt.GetoptError, err: - print str(err) - usage() + try: + opts, args = getopt.getopt(sys.argv[1:], "c:D:d:m:", + ["ctf=", "destination=", "search-directory=", "manifest="]) + except getopt.GetoptError as err: + print(str(err)) + usage() - for opt, arg in opts: - if opt in [ "-D", "--destination" ]: - destination = arg - elif opt in [ "-d", "--search-directory" ]: - search_paths.append(arg) - elif opt in [ "-m", "--manifest" ]: - try: - manifest = load_manifest(arg) - except IOError, err: - print "oops, %s: %s" % (arg, str(err)) - usage() - else: - manifests.append(manifest) - else: - usage() + for opt, arg in opts: + if opt in [ "-D", "--destination" ]: + destination = arg + elif opt in [ "-d", "--search-directory" ]: + search_paths.append(arg) + elif opt in [ "-m", "--manifest" ]: + try: + manifest = load_manifest(arg) + except IOError as err: + print("oops, %s: %s" % (arg, str(err))) + usage() + else: + manifests.append(manifest) + elif opt in [ "-c", "--ctf" ]: + ctfconvert = arg + else: + usage() - if destination == None: - usage() + if destination == None: + usage() - for manifest in manifests: - mangle_paths(manifest, search_paths, destination) - print manifest + for manifest in manifests: + mangle_paths(manifest, search_paths, destination, ctfconvert) + print(manifest) - sys.exit(0) + sys.exit(0) if __name__ == "__main__": - main() + main() -- Gitblit v1.9.3