diff options
author | Justus Winter <4winter@informatik.uni-hamburg.de> | 2014-03-30 19:20:05 +0200 |
---|---|---|
committer | Justus Winter <4winter@informatik.uni-hamburg.de> | 2014-03-30 19:20:05 +0200 |
commit | 04fc869149c3ae10d3835049738818e68174d05d (patch) | |
tree | a65edd7f02ab50028d5d8de659620ded21ac8df3 /bin/portseal | |
parent | bdc34d0383ffd80bc76b24619b26df29307243e0 (diff) |
Add portseal
Diffstat (limited to 'bin/portseal')
-rwxr-xr-x | bin/portseal | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/bin/portseal b/bin/portseal new file mode 100755 index 0000000..bcb39b8 --- /dev/null +++ b/bin/portseal @@ -0,0 +1,247 @@ +#!/usr/bin/env python +from __future__ import print_function + +# Copyright (c) 2014 Justus Winter <4winter@informatik.uni-hamburg.de> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +import difflib +import logging as log +import os +import re +import subprocess +import string +import sys + +log.basicConfig(format='%(levelname)s:%(message)s', level=log.DEBUG) + +base_path = os.path.dirname (os.path.dirname (os.path.abspath (sys.argv[0]))) +template_path = os.path.join (base_path, "share", "portseal") +state_path = os.path.abspath (".portseal") +portseal_h = os.path.join (base_path, "libportseal", "portseal.h") +portseal_L = os.path.join (base_path, "libportseal") + +def pkg_config (pkg, what): + return subprocess.check_output (["pkg-config", "--"+what, pkg]).strip () + +ldflags = "-L{0} -Wl,-rpath={0} -lportseal -ldl {1} {2} {3}".format ( + portseal_L, + pkg_config ("liburcu", "libs"), + pkg_config ("liburcu-cds", "libs"), + pkg_config ("liburcu-mb", "libs"), +) + +def template (x): + return os.path.join (template_path, x) + +def state (x): + return os.path.join (state_path, x) + +def make_state_dir (): + if not os.path.exists (state_path): + os.mkdir (state_path) + +def is_patched (): + return os.path.exists (state ("portseal.patch")) + +def template_apply (name, mapping, sink=None, **overlay): + log.debug ("applying template {0}".format (name)) + with open (template (name)) as source: + t = source.read () + + m = mapping.copy () + m.update (overlay) + for key, value in sorted (m.items (), + cmp=lambda a, b: cmp (len (a[0]), len (b[0])), + reverse=True): + t = t.replace (key, value) + + if sink: + sink.write (t) + else: + with open (state (name), "w") as sink: + sink.write (t) + +def spatch (cocci): + includes = list () + for i in (args.I or ["/usr/include"]): + includes.extend (("-I", i)) + + c = ["spatch", + "--no-loops", + "--no-gotos", + "--smpl-spacing", + "--include-headers", + "--sp-file", cocci, + "-dir", ".", + ] + includes + log.debug ("executing {0}".format (c)) + + return subprocess.check_output (c) + +def do_wrap_hack(s, r = False): + wraphack = 'PORTSEAL_WRAP_HACK' + if r: + wraphack += '_R' + + def walk (s, i, direction, p): + while p != 0: + if s[i] == "(": + p += 1 + elif s[i] == ")": + p -= 1 + i += direction + return i + + def skip_ws (s, i, direction): + while 0 < i < len (s) - 1: + if string.strip (s[i]): + break + i += direction + return i + + def skip_nws (s, i, direction): + while 0 < i < len (s) - 1: + if not string.strip (s[i]): + break + i += direction + return i + + while wraphack in s: + i = s.index(wraphack) + start = skip_nws (s, skip_ws (s, walk (s, i, -1, -1), -1), -1) + id_start = skip_ws (s, i + len (wraphack), 1) + id_end = walk (s, id_start + 1, 1, 1) + ident = s[id_start:id_end] + end = walk (s, id_end, 1, 1) + s = "{0} PORTSEAL_WRAP{1}({2}{3}, {4}){5}".format ( + s[:start], + "_R" if r else "", + s[start:i], + s[id_start:end], + ident, + s[end:]) + + return s + +def patch (args): + if is_patched (): + return + + make_state_dir () + + mapping = dict () + with open (state ("portseal.cocci"), "w") as sink: + template_apply ("portseal.cocci", mapping, sink) + + cocci_patch = spatch (state ("portseal.cocci")) + + patches = list () + patches.append (cocci_patch) + + # add include to every file the cocci patch touched + for l in cocci_patch.split ("\n"): + if not l.startswith ("--- a/"): + continue + patches.append (make_patch ( + l[6:], + lambda a: "#include \"{0}\"\n#line 1\n{1}".format (portseal_h, a))) + + ldflags_re = re.compile (r"^(\s*LDFLAGS\s*=.*)(\\?)$", re.M) + for dirpath, dirs, files in os.walk("."): + if dirpath.endswith (".portseal"): + continue + for f in filter (lambda f: "Make" in f, files): + patches.append ( + make_patch ( + os.path.join (dirpath, f), + lambda m: + ldflags_re.sub (r"\1 {0} \2".format (ldflags), m, 0))) + + with open(state ("portseal.patch"), "w") as h: + h.write ("\n".join (patches)) + + subprocess.check_call ( + ["patch", "-p1"], + stdin=open (state ("portseal.patch")), + ) + + # wraphack + wraphack_patches = list () + for dirpath, dirs, files in os.walk("."): + if dirpath.endswith (".portseal"): + continue + + #continue + + for f in filter (lambda f: f[-2:] in ('.c', '.h'), files): + try: + wraphack_patches.append ( + make_patch ( + os.path.join (dirpath, f), + lambda m: do_wrap_hack (do_wrap_hack (m, True)))) + except IOError: + pass + + with open(state ("wraphack.patch"), "w") as h: + h.write ("\n".join (wraphack_patches)) + + subprocess.check_call ( + ["patch", "-p1"], + stdin=open (state ("wraphack.patch")), + ) + + +def make_patch (filename, mutator): + a = open (filename).read () + b = mutator (a) + p = os.path.join ("a", filename) + def split(x): + return [l+"\n" for l in x.split ("\n")] + return "".join (difflib.unified_diff (split (a), + split (b), + fromfile=p, + tofile=p)) +def unpatch (args): + if not is_patched (): + return + + subprocess.check_call ( + ["patch", "-p1", "-R"], + stdin=open (state ("wraphack.patch")), + ) + + subprocess.check_call ( + ["patch", "-p1", "-R"], + stdin=open (state ("portseal.patch")), + ) + + os.remove (state ("portseal.patch")) + +import argparse + +parser = argparse.ArgumentParser() +subparsers = parser.add_subparsers(title='subcommands', + description='valid subcommands', + help='additional help') + +parser_patch = subparsers.add_parser('patch') +parser_patch.set_defaults(func=patch) +parser_patch.add_argument('-I', metavar='DIR', action="append", + help='add include directory') + +parser_unpatch = subparsers.add_parser('unpatch') +parser_unpatch.set_defaults(func=unpatch) + +args = parser.parse_args() +sys.exit(args.func(args)) |