summaryrefslogtreecommitdiff
path: root/bin/portseal
diff options
context:
space:
mode:
authorJustus Winter <4winter@informatik.uni-hamburg.de>2014-03-30 19:20:05 +0200
committerJustus Winter <4winter@informatik.uni-hamburg.de>2014-03-30 19:20:05 +0200
commit04fc869149c3ae10d3835049738818e68174d05d (patch)
treea65edd7f02ab50028d5d8de659620ded21ac8df3 /bin/portseal
parentbdc34d0383ffd80bc76b24619b26df29307243e0 (diff)
Add portseal
Diffstat (limited to 'bin/portseal')
-rwxr-xr-xbin/portseal247
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))