From 0054b3cac50dfa3b1bfd693c32411382c79f8045 Mon Sep 17 00:00:00 2001 From: Wolfgang Frisch Date: Tue, 10 Jan 2017 03:36:04 +0100 Subject: [PATCH 1/2] Improve OpenSSL library version detection PyBitmessage depends on OpenSSL 1.0 but some GNU/Linux systems have multiple versions installed. Try to locate the correct version. --- INSTALL.md | 2 +- src/depends.py | 6 +-- src/pyelliptic/find_library_version.py | 73 ++++++++++++++++++++++++++ src/pyelliptic/openssl.py | 6 +-- 4 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 src/pyelliptic/find_library_version.py diff --git a/INSTALL.md b/INSTALL.md index 823608fe..052d528b 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -13,7 +13,7 @@ installed on your system. Here's a list of dependencies needed for PyBitmessage - python2.7 - python2-qt4 (python-qt4 on Debian/Ubuntu) -- openssl +- openssl 1.0 - (Fedora & Redhat only) openssl-compat-bitcoin-libs ##Running PyBitmessage diff --git a/src/depends.py b/src/depends.py index 294c6a22..bc855b16 100755 --- a/src/depends.py +++ b/src/depends.py @@ -99,10 +99,10 @@ def check_openssl(): import re if re.match(r'linux|darwin|freebsd', sys.platform): try: - import ctypes.util - path = ctypes.util.find_library('ssl') + from pyelliptic.find_library_version import find_library_version + path = find_library_version('ssl', '1.0') if path not in paths: - paths.append(path) + paths.insert(0, path) except: pass diff --git a/src/pyelliptic/find_library_version.py b/src/pyelliptic/find_library_version.py new file mode 100644 index 00000000..e0197a60 --- /dev/null +++ b/src/pyelliptic/find_library_version.py @@ -0,0 +1,73 @@ +#!/usr/bin/python2.7 +# This function mimicks ctypes.util.find_library() +# but allows you to specify a desired library version. +# (c) 2017 Wolfgang Frisch +# based on https://github.com/python/cpython/blob/2.7/Lib/ctypes/util.py + +import ctypes.util +import os +import re +import subprocess +import sys + + +def find_library_version(name, version=None): + """ + Try to find the desired version of a library, and return a pathname. + Fall back to ctypes.util.find_library() on platforms other than POSIX. + :param name: The library name without any prefix like lib, + suffix like .so, .dylib or version number. + :param version: The library version. + :return: Returns the filename or, if no library can be found, None. + """ + def _num_version(libname): + # "libxyz.so.MAJOR.MINOR" => [ MAJOR, MINOR ] + parts = libname.split(b".") + nums = [] + try: + while parts: + nums.insert(0, int(parts.pop())) + except ValueError: + pass + return nums or [sys.maxint] + + if "linux" in sys.platform: + ename = re.escape(name) + expr = r'lib%s\.so[.0-9]*.*? => \S*/(lib%s\.so[.0-9]*)' % (ename, ename) + + null = open(os.devnull, 'wb') + try: + with null: + proc = subprocess.Popen(('/sbin/ldconfig', '-p'), + stdout=subprocess.PIPE, + stderr=null) + except OSError: # E.g. command not found + data = b'' + else: + [data, _] = proc.communicate() + + res = re.findall(expr, data) + if not res: + return None + + res.sort(key=_num_version) + if version: + lst = filter(lambda x: x.split("so.")[-1].startswith(version), res) + if len(lst): + return lst[-1] + return res[-1] + else: + # fallback (unversioned) + return ctypes.util.find_library(name) + + +if __name__ == "__main__": + if len(sys.argv) < 2: + print("example: %s crypto 1.0" % sys.argv[0]) + else: + name = sys.argv[1] + version = sys.argv[2] if len(sys.argv) == 3 else None + print(find_library_version(name, version)) + + +# vim:set expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap: diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index be2f2afc..9d71f040 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -430,7 +430,7 @@ class _OpenSSL: def loadOpenSSL(): global OpenSSL from os import path, environ - from ctypes.util import find_library + from find_library_version import find_library_version libdir = [] if getattr(sys,'frozen', None): @@ -456,7 +456,7 @@ def loadOpenSSL(): libdir.append('libcrypto.so') libdir.append('libssl.so') if 'linux' in sys.platform or 'darwin' in sys.platform or 'freebsd' in sys.platform: - libdir.append(find_library('ssl')) + libdir.append(find_library_version('ssl', '1.0')) elif 'win32' in sys.platform or 'win64' in sys.platform: libdir.append(find_library('libeay32')) for library in libdir: @@ -467,4 +467,4 @@ def loadOpenSSL(): pass raise Exception("Couldn't find and load the OpenSSL library. You must install it.") -loadOpenSSL() \ No newline at end of file +loadOpenSSL() -- 2.45.1 From 777168b47fbd4d621cc9ed3e41c5e12480796767 Mon Sep 17 00:00:00 2001 From: Wolfgang Frisch Date: Wed, 11 Jan 2017 02:40:12 +0100 Subject: [PATCH 2/2] Fix regression in pyelliptic/loadOpenSSL() introduced by 0054b3cac50dfa3b1bfd693c32411382c79f8045 --- src/pyelliptic/openssl.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index 9d71f040..d281e7d5 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -430,6 +430,7 @@ class _OpenSSL: def loadOpenSSL(): global OpenSSL from os import path, environ + from ctypes.util import find_library from find_library_version import find_library_version libdir = [] -- 2.45.1