summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJelmer Vernooij <jelmer@debian.org>2015-09-19 02:56:39 +0000
committerJelmer Vernooij <jelmer@debian.org>2015-09-19 02:56:39 +0000
commit72c40d6046e26a0ea8d1463d8cfadcd5f8c0a022 (patch)
treeab5a7212cc05abeeca83b45339ad401f6c091e73
parent7d7a23bf2a1f1820101d9eec51f16bb2fd78d1a0 (diff)
parent94f15f4ac5cc4986d7be05c6d428c3cb2e824381 (diff)
Merge tag 'upstream/1.3.7'
Upstream version 1.3.7 # gpg: Signature made Sat 19 Sep 2015 02:56:37 UTC using RSA key ID 5E63D2DA # gpg: Good signature from "Jelmer Vernooij <jelmer@jelmer.uk>" # gpg: aka "Jelmer Vernooij <jelmer@samba.org>" # gpg: aka "Jelmer Vernooij <jelmer@apache.org>" # gpg: aka "Jelmer Vernooij <jelmer@debian.org>" # gpg: aka "Jelmer Vernooij <jelmer@ubuntu.com>" # gpg: aka "Jelmer Vernooij <jelmer@vernstok.nl>" # gpg: aka "Jelmer Vernooij <jelmer@jelmer.co.uk>" # gpg: aka "Jelmer Vernooij <jelmer@openchange.org>" # gpg: aka "Jelmer Vernooij <jrvernooij@tigris.org>"
-rw-r--r--ABI/tdb-1.3.6.sigs69
-rw-r--r--ABI/tdb-1.3.7.sigs69
-rw-r--r--_tdb_text.py138
-rwxr-xr-xbuildtools/examples/run_on_target.py148
-rw-r--r--buildtools/wafsamba/samba_autoconf.py13
-rw-r--r--buildtools/wafsamba/samba_bundled.py2
-rw-r--r--buildtools/wafsamba/samba_cross.py75
-rw-r--r--buildtools/wafsamba/samba_deps.py3
-rw-r--r--buildtools/wafsamba/samba_dist.py6
-rw-r--r--buildtools/wafsamba/samba_git.py57
-rw-r--r--buildtools/wafsamba/samba_install.py161
-rw-r--r--buildtools/wafsamba/samba_patterns.py6
-rw-r--r--buildtools/wafsamba/samba_python.py84
-rw-r--r--buildtools/wafsamba/samba_utils.py16
-rw-r--r--buildtools/wafsamba/samba_version.py64
-rw-r--r--buildtools/wafsamba/wafsamba.py9
-rwxr-xr-xbuildtools/wafsamba/wscript8
-rw-r--r--common/traverse.c14
-rw-r--r--lib/replace/replace.c8
-rw-r--r--lib/replace/system/threads.h9
-rw-r--r--lib/replace/test/testsuite.c4
-rw-r--r--lib/replace/wscript15
-rw-r--r--pytdb.c234
-rw-r--r--python/tests/simple.py240
-rw-r--r--test/run-allrecord-traverse-deadlock.c203
-rw-r--r--tools/tdbrestore.c2
-rw-r--r--wscript31
27 files changed, 1357 insertions, 331 deletions
diff --git a/ABI/tdb-1.3.6.sigs b/ABI/tdb-1.3.6.sigs
new file mode 100644
index 0000000..2545c99
--- /dev/null
+++ b/ABI/tdb-1.3.6.sigs
@@ -0,0 +1,69 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/ABI/tdb-1.3.7.sigs b/ABI/tdb-1.3.7.sigs
new file mode 100644
index 0000000..2545c99
--- /dev/null
+++ b/ABI/tdb-1.3.7.sigs
@@ -0,0 +1,69 @@
+tdb_add_flags: void (struct tdb_context *, unsigned int)
+tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA)
+tdb_chainlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_read_nonblock: int (struct tdb_context *, TDB_DATA)
+tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock: int (struct tdb_context *, TDB_DATA)
+tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA)
+tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_close: int (struct tdb_context *)
+tdb_delete: int (struct tdb_context *, TDB_DATA)
+tdb_dump_all: void (struct tdb_context *)
+tdb_enable_seqnum: void (struct tdb_context *)
+tdb_error: enum TDB_ERROR (struct tdb_context *)
+tdb_errorstr: const char *(struct tdb_context *)
+tdb_exists: int (struct tdb_context *, TDB_DATA)
+tdb_fd: int (struct tdb_context *)
+tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_firstkey: TDB_DATA (struct tdb_context *)
+tdb_freelist_size: int (struct tdb_context *)
+tdb_get_flags: int (struct tdb_context *)
+tdb_get_logging_private: void *(struct tdb_context *)
+tdb_get_seqnum: int (struct tdb_context *)
+tdb_hash_size: int (struct tdb_context *)
+tdb_increment_seqnum_nonblock: void (struct tdb_context *)
+tdb_jenkins_hash: unsigned int (TDB_DATA *)
+tdb_lock_nonblock: int (struct tdb_context *, int, int)
+tdb_lockall: int (struct tdb_context *)
+tdb_lockall_mark: int (struct tdb_context *)
+tdb_lockall_nonblock: int (struct tdb_context *)
+tdb_lockall_read: int (struct tdb_context *)
+tdb_lockall_read_nonblock: int (struct tdb_context *)
+tdb_lockall_unmark: int (struct tdb_context *)
+tdb_log_fn: tdb_log_func (struct tdb_context *)
+tdb_map_size: size_t (struct tdb_context *)
+tdb_name: const char *(struct tdb_context *)
+tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA)
+tdb_null: dptr = 0xXXXX, dsize = 0
+tdb_open: struct tdb_context *(const char *, int, int, int, mode_t)
+tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func)
+tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_printfreelist: int (struct tdb_context *)
+tdb_remove_flags: void (struct tdb_context *, unsigned int)
+tdb_reopen: int (struct tdb_context *)
+tdb_reopen_all: int (int)
+tdb_repack: int (struct tdb_context *)
+tdb_rescue: int (struct tdb_context *, void (*)(TDB_DATA, TDB_DATA, void *), void *)
+tdb_runtime_check_for_robust_mutexes: bool (void)
+tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *)
+tdb_set_max_dead: void (struct tdb_context *, int)
+tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *)
+tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int)
+tdb_summary: char *(struct tdb_context *)
+tdb_transaction_cancel: int (struct tdb_context *)
+tdb_transaction_commit: int (struct tdb_context *)
+tdb_transaction_prepare_commit: int (struct tdb_context *)
+tdb_transaction_start: int (struct tdb_context *)
+tdb_transaction_start_nonblock: int (struct tdb_context *)
+tdb_transaction_write_lock_mark: int (struct tdb_context *)
+tdb_transaction_write_lock_unmark: int (struct tdb_context *)
+tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *)
+tdb_unlock: int (struct tdb_context *, int, int)
+tdb_unlockall: int (struct tdb_context *)
+tdb_unlockall_read: int (struct tdb_context *)
+tdb_validate_freelist: int (struct tdb_context *, int *)
+tdb_wipe_all: int (struct tdb_context *)
diff --git a/_tdb_text.py b/_tdb_text.py
new file mode 100644
index 0000000..c823bf8
--- /dev/null
+++ b/_tdb_text.py
@@ -0,0 +1,138 @@
+# Text wrapper for tdb bindings
+#
+# Copyright (C) 2015 Petr Viktorin <pviktori@redhat.com>
+# Published under the GNU LGPLv3 or later
+
+import sys
+import functools
+
+import tdb
+
+
+class TdbTextWrapper(object):
+ """Text interface for a TDB file"""
+
+ def __init__(self, tdb):
+ self._tdb = tdb
+
+ @property
+ def raw(self):
+ return self._tdb
+
+ def get(self, key):
+ key = key.encode('utf-8')
+ result = self._tdb.get(key)
+ if result is not None:
+ return result.decode('utf-8')
+
+ def append(self, key, value):
+ key = key.encode('utf-8')
+ value = value.encode('utf-8')
+ self._tdb.append(key, value)
+
+ def firstkey(self):
+ result = self._tdb.firstkey()
+ if result:
+ return result.decode('utf-8')
+
+ def nextkey(self, key):
+ key = key.encode('utf-8')
+ result = self._tdb.nextkey(key)
+ if result is not None:
+ return result.decode('utf-8')
+
+ def delete(self, key):
+ key = key.encode('utf-8')
+ self._tdb.delete(key)
+
+ def store(self, key, value):
+ key = key.encode('utf-8')
+ value = value.encode('utf-8')
+ self._tdb.store(key, value)
+
+ def __iter__(self):
+ for key in iter(self._tdb):
+ yield key.decode('utf-8')
+
+ def __getitem__(self, key):
+ key = key.encode('utf-8')
+ result = self._tdb[key]
+ return result.decode('utf-8')
+
+ def __contains__(self, key):
+ key = key.encode('utf-8')
+ return key in self._tdb
+
+ def __repr__(self):
+ return '<TdbTextWrapper for %r>' % self._tdb
+
+ def __setitem__(self, key, value):
+ key = key.encode('utf-8')
+ value = value.encode('utf-8')
+ self._tdb[key] = value
+
+ def __delitem__(self, key):
+ key = key.encode('utf-8')
+ del self._tdb[key]
+
+ if sys.version_info > (3, 0):
+ keys = __iter__
+ else:
+ iterkeys = __iter__
+ has_key = __contains__
+
+
+## Add wrappers for functions and getters that don't deal with text
+
+def _add_wrapper(name):
+ orig = getattr(tdb.Tdb, name)
+
+ def wrapper(self, *args, **kwargs):
+ return orig(self._tdb, *args, **kwargs)
+ wrapper.__name__ = orig.__name__
+ wrapper.__doc__ = orig.__doc__
+
+ setattr(TdbTextWrapper, name, wrapper)
+
+for name in ("transaction_cancel",
+ "transaction_commit",
+ "transaction_prepare_commit",
+ "transaction_start",
+ "reopen",
+ "lock_all",
+ "unlock_all",
+ "read_lock_all",
+ "read_unlock_all",
+ "close",
+ "add_flags",
+ "remove_flags",
+ "clear",
+ "repack",
+ "enable_seqnum",
+ "increment_seqnum_nonblock",
+ ):
+ _add_wrapper(name)
+
+
+def _add_getter(name):
+ orig = getattr(tdb.Tdb, name)
+ doc = orig.__doc__
+
+ def getter(self):
+ return getattr(self._tdb, name)
+
+ def setter(self, value):
+ return setattr(self._tdb, name, value)
+
+ setattr(TdbTextWrapper, name, property(getter, setter, doc=doc))
+
+for name in ("hash_size",
+ "map_size",
+ "freelist_size",
+ "flags",
+ "max_dead",
+ "filename",
+ "seqnum",
+ "text",
+ ):
+ _add_getter(name)
diff --git a/buildtools/examples/run_on_target.py b/buildtools/examples/run_on_target.py
new file mode 100755
index 0000000..8322759
--- /dev/null
+++ b/buildtools/examples/run_on_target.py
@@ -0,0 +1,148 @@
+#!/usr/bin/env python
+
+#
+# Sample run-on-target script
+# This is a script that can be used as cross-execute parameter to samba
+# configuration process, running the command on a remote target for which
+# the cross-compiled configure test was compiled.
+#
+# To use:
+# ./configure \
+# --cross-compile \
+# '--cross-execute=./buildtools/example/run_on_target.py --host=<host>'
+#
+# A more elaborate example:
+# ./configure \
+# --cross-compile \
+# '--cross-execute=./buildtools/example/run_on_target.py --host=<host> --user=<user> "--ssh=ssh -i <some key file>" --destdir=/path/to/dir'
+#
+# Typically this is to be used also with --cross-answers, so that the
+# cross answers file gets built and further builds can be made without
+# the help of a remote target.
+#
+# The following assumptions are made:
+# 1. rsync is available on build machine and target machine
+# 2. A running ssh service on target machine with password-less shell login
+# 3. A directory writable by the password-less login user
+# 4. The tests on the target can run and provide reliable results
+# from the login account's home directory. This is significant
+# for example in locking tests which
+# create files in the current directory. As a workaround to this
+# assumption, the TESTDIR environment variable can be set on the target
+# (using ssh command line or server config) and the tests shall
+# chdir to that directory.
+#
+
+import sys
+import os
+import subprocess
+from optparse import OptionParser
+
+# those are defaults, but can be overidden using command line
+SSH = 'ssh'
+USER = None
+HOST = 'localhost'
+
+
+def xfer_files(ssh, srcdir, host, user, targ_destdir):
+ """Transfer executable files to target
+
+ Use rsync to copy the directory containing program to run
+ INTO a destination directory on the target. An exact copy
+ of the source directory is created on the target machine,
+ possibly deleting files on the target machine which do not
+ exist on the source directory.
+
+ The idea is that the test may include files in addition to
+ the compiled binary, and all of those files reside alongside
+ the binary in a source directory.
+
+ For example, if the test to run is /foo/bar/test and the
+ destination directory on the target is /tbaz, then /tbaz/bar
+ on the target shall be an exact copy of /foo/bar on the source,
+ including deletion of files inside /tbaz/bar which do not exist
+ on the source.
+ """
+
+ userhost = host
+ if user:
+ userhost = '%s@%s' % (user, host)
+
+ cmd = 'rsync --verbose -rl --ignore-times --delete -e "%s" %s %s:%s/' % \
+ (ssh, srcdir, userhost, targ_destdir)
+ p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ (out, err) = p.communicate()
+ if p.returncode != 0:
+ raise Exception('failed syncing files\n stdout:\n%s\nstderr:%s\n'
+ % (out, err))
+
+
+def exec_remote(ssh, host, user, destdir, targdir, prog, args):
+ """Run a test on the target
+
+ Using password-less ssh, run the compiled binary on the target.
+
+ An assumption is that there's no need to cd into the target dir,
+ same as there's no need to do it on a native build.
+ """
+ userhost = host
+ if user:
+ userhost = '%s@%s' % (user, host)
+
+ cmd = '%s %s %s/%s/%s' % (ssh, userhost, destdir, targdir, prog)
+ if args:
+ cmd = cmd + ' ' + ' '.join(args)
+ p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ (out, err) = p.communicate()
+ return (p.returncode, out)
+
+
+def main(argv):
+ usage = "usage: %prog [options] <prog> [args]"
+ parser = OptionParser(usage)
+
+ parser.add_option('--ssh', help="SSH client and additional flags",
+ default=SSH)
+ parser.add_option('--host', help="target host name or IP address",
+ default=HOST)
+ parser.add_option('--user', help="login user on target",
+ default=USER)
+ parser.add_option('--destdir', help="work directory on target",
+ default='~')
+
+ (options, args) = parser.parse_args(argv)
+ if len(args) < 1:
+ parser.error("please supply test program to run")
+
+ progpath = args[0]
+
+ # assume that a test that was not compiled fails (e.g. getconf)
+ if progpath[0] != '/':
+ return (1, "")
+
+ progdir = os.path.dirname(progpath)
+ prog = os.path.basename(progpath)
+ targ_progdir = os.path.basename(progdir)
+
+ xfer_files(
+ options.ssh,
+ progdir,
+ options.host,
+ options.user,
+ options.destdir)
+
+ (rc, out) = exec_remote(options.ssh,
+ options.host,
+ options.user,
+ options.destdir,
+ targ_progdir,
+ prog, args[1:])
+ return (rc, out)
+
+
+if __name__ == '__main__':
+ (rc, out) = main(sys.argv[1:])
+ sys.stdout.write(out)
+ sys.exit(rc)
diff --git a/buildtools/wafsamba/samba_autoconf.py b/buildtools/wafsamba/samba_autoconf.py
index 4f646fd..c5f132c 100644
--- a/buildtools/wafsamba/samba_autoconf.py
+++ b/buildtools/wafsamba/samba_autoconf.py
@@ -229,7 +229,18 @@ def CHECK_DECLS(conf, vars, reverse=False, headers=None, always=False):
headers=headers,
msg='Checking for declaration of %s' % v,
always=always):
- ret = False
+ if not CHECK_CODE(conf,
+ '''
+ return (int)%s;
+ ''' % (v),
+ execute=False,
+ link=False,
+ msg='Checking for declaration of %s (as enum)' % v,
+ local_include=False,
+ headers=headers,
+ define=define,
+ always=always):
+ ret = False
return ret
diff --git a/buildtools/wafsamba/samba_bundled.py b/buildtools/wafsamba/samba_bundled.py
index 515590f..c8bfcd2 100644
--- a/buildtools/wafsamba/samba_bundled.py
+++ b/buildtools/wafsamba/samba_bundled.py
@@ -190,7 +190,7 @@ def CHECK_BUNDLED_SYSTEM(conf, libname, minversion='0.0.0',
pkg = libname
# try pkgconfig first
- if (conf.check_cfg(package=pkg,
+ if (conf.CHECK_CFG(package=pkg,
args='"%s >= %s" --cflags --libs' % (pkg, minversion),
msg=msg, uselib_store=uselib_store) and
check_functions_headers_code()):
diff --git a/buildtools/wafsamba/samba_cross.py b/buildtools/wafsamba/samba_cross.py
index 3838e34..ed3af1e 100644
--- a/buildtools/wafsamba/samba_cross.py
+++ b/buildtools/wafsamba/samba_cross.py
@@ -2,11 +2,12 @@
import Utils, Logs, sys, os, Options, re
from Configure import conf
+import shlex
real_Popen = None
ANSWER_UNKNOWN = (254, "")
-ANSWER_FAIL = (255, "")
+ANSWER_NO = (1, "")
ANSWER_OK = (0, "")
cross_answers_incomplete = False
@@ -19,15 +20,27 @@ def add_answer(ca_file, msg, answer):
except:
Logs.error("Unable to open cross-answers file %s" % ca_file)
sys.exit(1)
+ (retcode, retstring) = answer
+ # if retstring is more than one line then we probably
+ # don't care about its actual content (the tests should
+ # yield one-line output in order to comply with the cross-answer
+ # format)
+ retstring = retstring.strip()
+ if len(retstring.split('\n')) > 1:
+ retstring = ''
+ answer = (retcode, retstring)
+
if answer == ANSWER_OK:
f.write('%s: OK\n' % msg)
elif answer == ANSWER_UNKNOWN:
f.write('%s: UNKNOWN\n' % msg)
- elif answer == ANSWER_FAIL:
- f.write('%s: FAIL\n' % msg)
+ elif answer == ANSWER_NO:
+ f.write('%s: NO\n' % msg)
else:
- (retcode, retstring) = answer
- f.write('%s: (%d, "%s")' % (msg, retcode, retstring))
+ if retcode == 0:
+ f.write('%s: "%s"\n' % (msg, retstring))
+ else:
+ f.write('%s: (%d, "%s")\n' % (msg, retcode, retstring))
f.close()
@@ -36,14 +49,13 @@ def cross_answer(ca_file, msg):
try:
f = open(ca_file, 'r')
except:
- add_answer(ca_file, msg, ANSWER_UNKNOWN)
return ANSWER_UNKNOWN
for line in f:
line = line.strip()
if line == '' or line[0] == '#':
continue
if line.find(':') != -1:
- a = line.split(':')
+ a = line.split(':', 1)
thismsg = a[0].strip()
if thismsg != msg:
continue
@@ -56,10 +68,12 @@ def cross_answer(ca_file, msg):
return ANSWER_UNKNOWN
elif ans == "FAIL" or ans == "NO":
f.close()
- return ANSWER_FAIL
+ return ANSWER_NO
elif ans[0] == '"':
+ f.close()
return (0, ans.strip('"'))
elif ans[0] == "'":
+ f.close()
return (0, ans.strip("'"))
else:
m = re.match('\(\s*(-?\d+)\s*,\s*\"(.*)\"\s*\)', ans)
@@ -69,7 +83,6 @@ def cross_answer(ca_file, msg):
else:
raise Utils.WafError("Bad answer format '%s' in %s" % (line, ca_file))
f.close()
- add_answer(ca_file, msg, ANSWER_UNKNOWN)
return ANSWER_UNKNOWN
@@ -77,24 +90,47 @@ class cross_Popen(Utils.pproc.Popen):
'''cross-compilation wrapper for Popen'''
def __init__(*k, **kw):
(obj, args) = k
-
- if '--cross-execute' in args:
- # when --cross-execute is set, then change the arguments
- # to use the cross emulator
- i = args.index('--cross-execute')
- newargs = args[i+1].split()
- newargs.extend(args[0:i])
- args = newargs
- elif '--cross-answers' in args:
+ use_answers = False
+ ans = ANSWER_UNKNOWN
+
+ # Three possibilities:
+ # 1. Only cross-answers - try the cross-answers file, and if
+ # there's no corresponding answer, add to the file and mark
+ # the configure process as unfinished.
+ # 2. Only cross-execute - get the answer from cross-execute
+ # 3. Both - try the cross-answers file, and if there is no
+ # corresponding answer - use cross-execute to get an answer,
+ # and add that answer to the file.
+ if '--cross-answers' in args:
# when --cross-answers is set, then change the arguments
# to use the cross answers if available
+ use_answers = True
i = args.index('--cross-answers')
ca_file = args[i+1]
msg = args[i+2]
ans = cross_answer(ca_file, msg)
+
+ if '--cross-execute' in args and ans == ANSWER_UNKNOWN:
+ # when --cross-execute is set, then change the arguments
+ # to use the cross emulator
+ i = args.index('--cross-execute')
+ newargs = shlex.split(args[i+1])
+ newargs.extend(args[0:i])
+ if use_answers:
+ p = real_Popen(newargs,
+ stdout=Utils.pproc.PIPE,
+ stderr=Utils.pproc.PIPE)
+ ce_out, ce_err = p.communicate()
+ ans = (p.returncode, ce_out)
+ add_answer(ca_file, msg, ans)
+ else:
+ args = newargs
+
+ if use_answers:
if ans == ANSWER_UNKNOWN:
global cross_answers_incomplete
cross_answers_incomplete = True
+ add_answer(ca_file, msg, ans)
(retcode, retstring) = ans
args = ['/bin/sh', '-c', "echo -n '%s'; exit %d" % (retstring, retcode)]
real_Popen.__init__(*(obj, args), **kw)
@@ -115,7 +151,8 @@ def SAMBA_CROSS_ARGS(conf, msg=None):
if conf.env.CROSS_EXECUTE:
ret.extend(['--cross-execute', conf.env.CROSS_EXECUTE])
- elif conf.env.CROSS_ANSWERS:
+
+ if conf.env.CROSS_ANSWERS:
if msg is None:
raise Utils.WafError("Cannot have NULL msg in cross-answers")
ret.extend(['--cross-answers', os.path.join(Options.launch_dir, conf.env.CROSS_ANSWERS), msg])
diff --git a/buildtools/wafsamba/samba_deps.py b/buildtools/wafsamba/samba_deps.py
index 3be9956..d252dc4 100644
--- a/buildtools/wafsamba/samba_deps.py
+++ b/buildtools/wafsamba/samba_deps.py
@@ -964,7 +964,8 @@ savedeps_version = 3
savedeps_inputs = ['samba_deps', 'samba_includes', 'local_include', 'local_include_first', 'samba_cflags',
'source', 'grouping_library', 'samba_ldflags', 'allow_undefined_symbols',
'use_global_deps', 'global_include' ]
-savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes', 'ccflags', 'ldflags', 'samba_deps_extended']
+savedeps_outputs = ['uselib', 'uselib_local', 'add_objects', 'includes',
+ 'ccflags', 'ldflags', 'samba_deps_extended', 'final_libs']
savedeps_outenv = ['INC_PATHS']
savedeps_envvars = ['NONSHARED_BINARIES', 'GLOBAL_DEPENDENCIES', 'EXTRA_CFLAGS', 'EXTRA_LDFLAGS', 'EXTRA_INCLUDES' ]
savedeps_caches = ['GLOBAL_DEPENDENCIES', 'TARGET_TYPE', 'INIT_FUNCTIONS', 'SYSLIB_DEPS']
diff --git a/buildtools/wafsamba/samba_dist.py b/buildtools/wafsamba/samba_dist.py
index aecacb7..654a168 100644
--- a/buildtools/wafsamba/samba_dist.py
+++ b/buildtools/wafsamba/samba_dist.py
@@ -86,12 +86,6 @@ def vcs_dir_contents(path):
env = dict(os.environ)
env["GIT_DIR"] = os.path.join(repo, ".git")
break
- elif os.path.isdir(os.path.join(repo, ".bzr")):
- ls_files_cmd = [ 'bzr', 'ls', '--recursive', '--versioned',
- os_path_relpath(path, repo)]
- cwd = repo
- env = None
- break
repo = os.path.dirname(repo)
if repo == "/":
raise Exception("unsupported or no vcs for %s" % path)
diff --git a/buildtools/wafsamba/samba_git.py b/buildtools/wafsamba/samba_git.py
new file mode 100644
index 0000000..c58a579
--- /dev/null
+++ b/buildtools/wafsamba/samba_git.py
@@ -0,0 +1,57 @@
+import os
+import subprocess
+
+def find_git(env=None):
+ """Find the git binary."""
+ if env is not None and 'GIT' in env:
+ return env['GIT']
+
+ # Get version from GIT
+ if os.path.exists("/usr/bin/git"):
+ # this is useful when doing make dist without configuring
+ return "/usr/bin/git"
+
+ return None
+
+
+def has_submodules(path):
+ """Check whether a source directory is git-versioned and has submodules.
+
+ :param path: Path to Samba source directory
+ """
+ return (os.path.isdir(os.path.join(path, ".git")) and
+ os.path.isfile(os.path.join(path, ".gitmodules")))
+
+
+def read_submodule_status(path, env=None):
+ """Check status of submodules.
+
+ :param path: Path to git directory
+ :param env: Optional waf environment
+ :return: Yields tuples with submodule relpath and status
+ (one of: 'out-of-date', 'not-checked-out', 'up-to-date')
+ :raise RuntimeError: raised when parsing of 'git submodule status' output
+ fails.
+ """
+ if not has_submodules(path):
+ # No point in running git.
+ return
+ git = find_git(env)
+ if git is None:
+ return
+ p = subprocess.Popen([git, "submodule", "status"], stdout=subprocess.PIPE,
+ cwd=path)
+ (stdout, stderr) = p.communicate(None)
+ for l in stdout.splitlines():
+ l = l.rstrip()
+ status = l[0]
+ l = l[1:]
+ parts = l.split(" ")
+ if len(parts) > 2 and status in ("-", "+"):
+ yield (parts[1], "out-of-date")
+ elif len(parts) == 2 and status == "-":
+ yield (parts[1], "not-checked-out")
+ elif len(parts) > 2 and status == " ":
+ yield (parts[1], "up-to-date")
+ else:
+ raise RuntimeError("Unable to parse submodule status: %r, %r" % (status, parts))
diff --git a/buildtools/wafsamba/samba_install.py b/buildtools/wafsamba/samba_install.py
index aa7f143..3d0c23a 100644
--- a/buildtools/wafsamba/samba_install.py
+++ b/buildtools/wafsamba/samba_install.py
@@ -59,90 +59,97 @@ def install_library(self):
bld = self.bld
- install_ldflags = install_rpath(self)
- build_ldflags = build_rpath(bld)
-
- if not Options.is_install or not getattr(self, 'samba_install', True):
- # just need to set the build rpath if we are not installing
- self.env.RPATH = build_ldflags
- return
-
- # setup the install path, expanding variables
- install_path = getattr(self, 'samba_inst_path', None)
- if install_path is None:
- if getattr(self, 'private_library', False):
- install_path = '${PRIVATELIBDIR}'
- else:
- install_path = '${LIBDIR}'
- install_path = bld.EXPAND_VARIABLES(install_path)
-
- target_name = self.target
-
- if install_ldflags != build_ldflags:
- # we will be creating a new target name, and using that for the
- # install link. That stops us from overwriting the existing build
- # target, which has different ldflags
- self.done_install_library = True
- t = self.clone('default')
- t.posted = False
- t.target += '.inst'
- self.env.RPATH = build_ldflags
- else:
- t = self
-
- t.env.RPATH = install_ldflags
+ default_env = bld.all_envs['default']
+ try:
+ if self.env['IS_EXTRA_PYTHON']:
+ bld.all_envs['default'] = bld.all_envs['extrapython']
- dev_link = None
+ install_ldflags = install_rpath(self)
+ build_ldflags = build_rpath(bld)
- # in the following the names are:
- # - inst_name is the name with .inst. in it, in the build
- # directory
- # - install_name is the name in the install directory
- # - install_link is a symlink in the install directory, to install_name
+ if not Options.is_install or not getattr(self, 'samba_install', True):
+ # just need to set the build rpath if we are not installing
+ self.env.RPATH = build_ldflags
+ return
- if getattr(self, 'samba_realname', None):
- install_name = self.samba_realname
- install_link = None
- if getattr(self, 'soname', ''):
- install_link = self.soname
- if getattr(self, 'samba_type', None) == 'PYTHON':
- inst_name = bld.make_libname(t.target, nolibprefix=True, python=True)
+ # setup the install path, expanding variables
+ install_path = getattr(self, 'samba_inst_path', None)
+ if install_path is None:
+ if getattr(self, 'private_library', False):
+ install_path = '${PRIVATELIBDIR}'
+ else:
+ install_path = '${LIBDIR}'
+ install_path = bld.EXPAND_VARIABLES(install_path)
+
+ target_name = self.target
+
+ if install_ldflags != build_ldflags:
+ # we will be creating a new target name, and using that for the
+ # install link. That stops us from overwriting the existing build
+ # target, which has different ldflags
+ self.done_install_library = True
+ t = self.clone(self.env)
+ t.posted = False
+ t.target += '.inst'
+ self.env.RPATH = build_ldflags
else:
+ t = self
+
+ t.env.RPATH = install_ldflags
+
+ dev_link = None
+
+ # in the following the names are:
+ # - inst_name is the name with .inst. in it, in the build
+ # directory
+ # - install_name is the name in the install directory
+ # - install_link is a symlink in the install directory, to install_name
+
+ if getattr(self, 'samba_realname', None):
+ install_name = self.samba_realname
+ install_link = None
+ if getattr(self, 'soname', ''):
+ install_link = self.soname
+ if getattr(self, 'samba_type', None) == 'PYTHON':
+ inst_name = bld.make_libname(t.target, nolibprefix=True, python=True)
+ else:
+ inst_name = bld.make_libname(t.target)
+ elif self.vnum:
+ vnum_base = self.vnum.split('.')[0]
+ install_name = bld.make_libname(target_name, version=self.vnum)
+ install_link = bld.make_libname(target_name, version=vnum_base)
+ inst_name = bld.make_libname(t.target)
+ if not self.private_library:
+ # only generate the dev link for non-bundled libs
+ dev_link = bld.make_libname(target_name)
+ elif getattr(self, 'soname', ''):
+ install_name = bld.make_libname(target_name)
+ install_link = self.soname
inst_name = bld.make_libname(t.target)
- elif self.vnum:
- vnum_base = self.vnum.split('.')[0]
- install_name = bld.make_libname(target_name, version=self.vnum)
- install_link = bld.make_libname(target_name, version=vnum_base)
- inst_name = bld.make_libname(t.target)
- if not self.private_library:
- # only generate the dev link for non-bundled libs
- dev_link = bld.make_libname(target_name)
- elif getattr(self, 'soname', ''):
- install_name = bld.make_libname(target_name)
- install_link = self.soname
- inst_name = bld.make_libname(t.target)
- else:
- install_name = bld.make_libname(target_name)
- install_link = None
- inst_name = bld.make_libname(t.target)
-
- if t.env.SONAME_ST:
- # ensure we get the right names in the library
- if install_link:
- t.env.append_value('LINKFLAGS', t.env.SONAME_ST % install_link)
else:
- t.env.append_value('LINKFLAGS', t.env.SONAME_ST % install_name)
- t.env.SONAME_ST = ''
+ install_name = bld.make_libname(target_name)
+ install_link = None
+ inst_name = bld.make_libname(t.target)
- # tell waf to install the library
- bld.install_as(os.path.join(install_path, install_name),
- os.path.join(self.path.abspath(bld.env), inst_name),
- chmod=MODE_755)
- if install_link and install_link != install_name:
- # and the symlink if needed
- bld.symlink_as(os.path.join(install_path, install_link), os.path.basename(install_name))
- if dev_link:
- bld.symlink_as(os.path.join(install_path, dev_link), os.path.basename(install_name))
+ if t.env.SONAME_ST:
+ # ensure we get the right names in the library
+ if install_link:
+ t.env.append_value('LINKFLAGS', t.env.SONAME_ST % install_link)
+ else:
+ t.env.append_value('LINKFLAGS', t.env.SONAME_ST % install_name)
+ t.env.SONAME_ST = ''
+
+ # tell waf to install the library
+ bld.install_as(os.path.join(install_path, install_name),
+ os.path.join(self.path.abspath(bld.env), inst_name),
+ chmod=MODE_755)
+ if install_link and install_link != install_name:
+ # and the symlink if needed
+ bld.symlink_as(os.path.join(install_path, install_link), os.path.basename(install_name))
+ if dev_link:
+ bld.symlink_as(os.path.join(install_path, dev_link), os.path.basename(install_name))
+ finally:
+ bld.all_envs['default'] = default_env
@feature('cshlib')
diff --git a/buildtools/wafsamba/samba_patterns.py b/buildtools/wafsamba/samba_patterns.py
index b4427d3..0469992 100644
--- a/buildtools/wafsamba/samba_patterns.py
+++ b/buildtools/wafsamba/samba_patterns.py
@@ -140,9 +140,9 @@ def write_build_options_footer(fp):
fp.write(" output(screen, \" sizeof(int): %lu\\n\",(unsigned long)sizeof(int));\n")
fp.write(" output(screen, \" sizeof(long): %lu\\n\",(unsigned long)sizeof(long));\n")
fp.write(" output(screen, \" sizeof(long long): %lu\\n\",(unsigned long)sizeof(long long));\n")
- fp.write(" output(screen, \" sizeof(uint8): %lu\\n\",(unsigned long)sizeof(uint8));\n")
- fp.write(" output(screen, \" sizeof(uint16): %lu\\n\",(unsigned long)sizeof(uint16));\n")
- fp.write(" output(screen, \" sizeof(uint32): %lu\\n\",(unsigned long)sizeof(uint32));\n")
+ fp.write(" output(screen, \" sizeof(uint8_t): %lu\\n\",(unsigned long)sizeof(uint8_t));\n")
+ fp.write(" output(screen, \" sizeof(uint16_t): %lu\\n\",(unsigned long)sizeof(uint16_t));\n")
+ fp.write(" output(screen, \" sizeof(uint32_t): %lu\\n\",(unsigned long)sizeof(uint32_t));\n")
fp.write(" output(screen, \" sizeof(short): %lu\\n\",(unsigned long)sizeof(short));\n")
fp.write(" output(screen, \" sizeof(void*): %lu\\n\",(unsigned long)sizeof(void*));\n")
fp.write(" output(screen, \" sizeof(size_t): %lu\\n\",(unsigned long)sizeof(size_t));\n")
diff --git a/buildtools/wafsamba/samba_python.py b/buildtools/wafsamba/samba_python.py
index a371b43..a8f780f 100644
--- a/buildtools/wafsamba/samba_python.py
+++ b/buildtools/wafsamba/samba_python.py
@@ -9,20 +9,70 @@ from Configure import conf
@conf
def SAMBA_CHECK_PYTHON(conf, mandatory=True, version=(2,4,2)):
# enable tool to build python extensions
+ if conf.env.HAVE_PYTHON_H:
+ conf.check_python_version(version)
+ return
+
+ interpreters = []
+
+ if conf.env['EXTRA_PYTHON']:
+ conf.all_envs['extrapython'] = conf.env.copy()
+ conf.setenv('extrapython')
+ conf.env['PYTHON'] = conf.env['EXTRA_PYTHON']
+ conf.env['IS_EXTRA_PYTHON'] = 'yes'
+ conf.find_program('python', var='PYTHON', mandatory=True)
+ conf.check_tool('python')
+ try:
+ conf.check_python_version((3, 3, 0))
+ except Exception:
+ Logs.warn('extra-python needs to be Python 3.3 or later')
+ raise
+ interpreters.append(conf.env['PYTHON'])
+ conf.setenv('default')
+
conf.find_program('python', var='PYTHON', mandatory=mandatory)
conf.check_tool('python')
path_python = conf.find_program('python')
conf.env.PYTHON_SPECIFIED = (conf.env.PYTHON != path_python)
conf.check_python_version(version)
+ interpreters.append(conf.env['PYTHON'])
+ conf.env.python_interpreters = interpreters
+
+
@conf
def SAMBA_CHECK_PYTHON_HEADERS(conf, mandatory=True):
if conf.env["python_headers_checked"] == []:
- conf.check_python_headers(mandatory)
+ if conf.env['EXTRA_PYTHON']:
+ conf.setenv('extrapython')
+ _check_python_headers(conf, mandatory=True)
+ conf.setenv('default')
+
+ _check_python_headers(conf, mandatory)
conf.env["python_headers_checked"] = "yes"
+
+ if conf.env['EXTRA_PYTHON']:
+ extraversion = conf.all_envs['extrapython']['PYTHON_VERSION']
+ if extraversion == conf.env['PYTHON_VERSION']:
+ raise Utils.WafError("extrapython %s is same as main python %s" % (
+ extraversion, conf.env['PYTHON_VERSION']))
else:
conf.msg("python headers", "using cache")
+ # we don't want PYTHONDIR in config.h, as otherwise changing
+ # --prefix causes a complete rebuild
+ del(conf.env.defines['PYTHONDIR'])
+ del(conf.env.defines['PYTHONARCHDIR'])
+
+def _check_python_headers(conf, mandatory):
+ conf.check_python_headers(mandatory=mandatory)
+
+ if conf.env['PYTHON_VERSION'] > '3':
+ abi_pattern = os.path.splitext(conf.env['pyext_PATTERN'])[0]
+ conf.env['PYTHON_SO_ABI_FLAG'] = abi_pattern % ''
+ else:
+ conf.env['PYTHON_SO_ABI_FLAG'] = ''
+
def SAMBA_PYTHON(bld, name,
source='',
@@ -38,6 +88,9 @@ def SAMBA_PYTHON(bld, name,
enabled=True):
'''build a python extension for Samba'''
+ if bld.env['IS_EXTRA_PYTHON']:
+ name = 'extra-' + name
+
# when we support static python modules we'll need to gather
# the list from all the SAMBA_PYTHON() targets
if init_function_sentinel is not None:
@@ -64,8 +117,35 @@ def SAMBA_PYTHON(bld, name,
target_type='PYTHON',
install_path='${PYTHONARCHDIR}',
allow_undefined_symbols=True,
- allow_warnings=True,
install=install,
enabled=enabled)
Build.BuildContext.SAMBA_PYTHON = SAMBA_PYTHON
+
+
+def pyembed_libname(bld, name, extrapython=False):
+ return name + bld.env['PYTHON_SO_ABI_FLAG']
+
+Build.BuildContext.pyembed_libname = pyembed_libname
+
+
+def gen_python_environments(bld, extra_env_vars=()):
+ """Generate all Python environments
+
+ To be used in a for loop. Normally, the loop body will be executed once.
+
+ When --extra-python is used, the body will additionaly be executed
+ with the extra-python environment active.
+ """
+ yield
+
+ if bld.env['EXTRA_PYTHON']:
+ copied = ('GLOBAL_DEPENDENCIES', 'TARGET_TYPE') + tuple(extra_env_vars)
+ for name in copied:
+ bld.all_envs['extrapython'][name] = bld.all_envs['default'][name]
+ default_env = bld.all_envs['default']
+ bld.all_envs['default'] = bld.all_envs['extrapython']
+ yield
+ bld.all_envs['default'] = default_env
+
+Build.BuildContext.gen_python_environments = gen_python_environments
diff --git a/buildtools/wafsamba/samba_utils.py b/buildtools/wafsamba/samba_utils.py
index e8bc0f3..540fe44 100644
--- a/buildtools/wafsamba/samba_utils.py
+++ b/buildtools/wafsamba/samba_utils.py
@@ -386,6 +386,22 @@ def RUN_COMMAND(cmd,
return -1
+def RUN_PYTHON_TESTS(testfiles, pythonpath=None):
+ env = LOAD_ENVIRONMENT()
+ if pythonpath is None:
+ pythonpath = os.path.join(Utils.g_module.blddir, 'python')
+ result = 0
+ for interp in env.python_interpreters:
+ for testfile in testfiles:
+ cmd = "PYTHONPATH=%s %s %s" % (pythonpath, interp, testfile)
+ print('Running Python test with %s: %s' % (interp, testfile))
+ ret = RUN_COMMAND(cmd)
+ if ret:
+ print('Python test failed: %s' % cmd)
+ result = ret
+ return result
+
+
# make sure we have md5. some systems don't have it
try:
from hashlib import md5
diff --git a/buildtools/wafsamba/samba_version.py b/buildtools/wafsamba/samba_version.py
index 67ff232..bb0be96 100644
--- a/buildtools/wafsamba/samba_version.py
+++ b/buildtools/wafsamba/samba_version.py
@@ -1,68 +1,16 @@
import os
import Utils
import samba_utils
-import sys
-
-def bzr_version_summary(path):
- try:
- import bzrlib
- except ImportError:
- return ("BZR-UNKNOWN", {})
-
- import bzrlib.ui
- bzrlib.ui.ui_factory = bzrlib.ui.make_ui_for_terminal(
- sys.stdin, sys.stdout, sys.stderr)
- from bzrlib import branch, osutils, workingtree
- from bzrlib.plugin import load_plugins
- load_plugins()
-
- b = branch.Branch.open(path)
- (revno, revid) = b.last_revision_info()
- rev = b.repository.get_revision(revid)
-
- fields = {
- "BZR_REVISION_ID": revid,
- "BZR_REVNO": revno,
- "COMMIT_DATE": osutils.format_date_with_offset_in_original_timezone(rev.timestamp,
- rev.timezone or 0),
- "COMMIT_TIME": int(rev.timestamp),
- "BZR_BRANCH": rev.properties.get("branch-nick", ""),
- }
-
- # If possible, retrieve the git sha
- try:
- from bzrlib.plugins.git.object_store import get_object_store
- except ImportError:
- # No git plugin
- ret = "BZR-%d" % revno
- else:
- store = get_object_store(b.repository)
- store.lock_read()
- try:
- full_rev = store._lookup_revision_sha1(revid)
- finally:
- store.unlock()
- fields["GIT_COMMIT_ABBREV"] = full_rev[:7]
- fields["GIT_COMMIT_FULLREV"] = full_rev
- ret = "GIT-" + fields["GIT_COMMIT_ABBREV"]
-
- if workingtree.WorkingTree.open(path).has_changes():
- fields["COMMIT_IS_CLEAN"] = 0
- ret += "+"
- else:
- fields["COMMIT_IS_CLEAN"] = 1
- return (ret, fields)
-
+from samba_git import find_git
def git_version_summary(path, env=None):
- # Get version from GIT
- if not 'GIT' in env and os.path.exists("/usr/bin/git"):
- # this is useful when doing make dist without configuring
- env.GIT = "/usr/bin/git"
+ git = find_git(env)
- if not 'GIT' in env:
+ if git is None:
return ("GIT-UNKNOWN", {})
+ env.GIT = git
+
environ = dict(os.environ)
environ["GIT_DIR"] = '%s/.git' % path
environ["GIT_WORK_TREE"] = path
@@ -200,8 +148,6 @@ also accepted as dictionary entries here
self.vcs_fields = {}
elif os.path.exists(os.path.join(path, ".git")):
suffix, self.vcs_fields = git_version_summary(path, env=env)
- elif os.path.exists(os.path.join(path, ".bzr")):
- suffix, self.vcs_fields = bzr_version_summary(path)
elif os.path.exists(os.path.join(path, ".distversion")):
suffix, self.vcs_fields = distversion_version_summary(path)
else:
diff --git a/buildtools/wafsamba/wafsamba.py b/buildtools/wafsamba/wafsamba.py
index d7e482c..c27241e 100644
--- a/buildtools/wafsamba/wafsamba.py
+++ b/buildtools/wafsamba/wafsamba.py
@@ -143,6 +143,9 @@ def SAMBA_LIBRARY(bld, libname, source,
enabled=True):
'''define a Samba library'''
+ if pyembed and bld.env['IS_EXTRA_PYTHON']:
+ public_headers = pc_files = None
+
if LIB_MUST_BE_PRIVATE(bld, libname):
private_library=True
@@ -217,10 +220,10 @@ def SAMBA_LIBRARY(bld, libname, source,
if vnum is None and soname is None:
raise Utils.WafError("public library '%s' must have a vnum" %
libname)
- if pc_files is None:
+ if pc_files is None and not bld.env['IS_EXTRA_PYTHON']:
raise Utils.WafError("public library '%s' must have pkg-config file" %
libname)
- if public_headers is None:
+ if public_headers is None and not bld.env['IS_EXTRA_PYTHON']:
raise Utils.WafError("public library '%s' must have header files" %
libname)
@@ -239,6 +242,8 @@ def SAMBA_LIBRARY(bld, libname, source,
bundled_extension, private_library)
ldflags = TO_LIST(ldflags)
+ if bld.env['ENABLE_RELRO'] is True:
+ ldflags.extend(TO_LIST('-Wl,-z,relro,-z,now'))
features = 'cc cshlib symlink_lib install_lib'
if pyext:
diff --git a/buildtools/wafsamba/wscript b/buildtools/wafsamba/wscript
index 694147e..d6bb688 100755
--- a/buildtools/wafsamba/wscript
+++ b/buildtools/wafsamba/wscript
@@ -195,6 +195,12 @@ def set_options(opt):
help='tag release in git at the same time',
type='string', action='store', dest='TAG_RELEASE')
+ opt.add_option('--extra-python', type=str,
+ help=("build selected libraries for the specified "
+ "additional version of Python "
+ "(example: --extra-python=/usr/bin/python3)"),
+ metavar="PYTHON", dest='EXTRA_PYTHON', default=None)
+
@wafsamba.runonce
def configure(conf):
@@ -266,6 +272,8 @@ def configure(conf):
conf.env.AUTOCONF_HOST = Options.options.AUTOCONF_HOST
conf.env.AUTOCONF_PROGRAM_PREFIX = Options.options.AUTOCONF_PROGRAM_PREFIX
+ conf.env.EXTRA_PYTHON = Options.options.EXTRA_PYTHON
+
if (conf.env.AUTOCONF_HOST and
conf.env.AUTOCONF_BUILD and
conf.env.AUTOCONF_BUILD != conf.env.AUTOCONF_HOST):
diff --git a/common/traverse.c b/common/traverse.c
index 618670f..e18e3c3 100644
--- a/common/traverse.c
+++ b/common/traverse.c
@@ -245,13 +245,25 @@ _PUBLIC_ int tdb_traverse(struct tdb_context *tdb,
tdb_traverse_func fn, void *private_data)
{
struct tdb_traverse_lock tl = { NULL, 0, 0, F_WRLCK };
+ enum tdb_lock_flags lock_flags;
int ret;
if (tdb->read_only || tdb->traverse_read) {
return tdb_traverse_read(tdb, fn, private_data);
}
- if (tdb_transaction_lock(tdb, F_WRLCK, TDB_LOCK_WAIT)) {
+ lock_flags = TDB_LOCK_WAIT;
+
+ if (tdb->allrecord_lock.count != 0) {
+ /*
+ * This avoids a deadlock between tdb_lockall() and
+ * tdb_traverse(). See
+ * https://bugzilla.samba.org/show_bug.cgi?id=11381
+ */
+ lock_flags = TDB_LOCK_NOWAIT;
+ }
+
+ if (tdb_transaction_lock(tdb, F_WRLCK, lock_flags)) {
return -1;
}
diff --git a/lib/replace/replace.c b/lib/replace/replace.c
index 9fae44a..dccf514 100644
--- a/lib/replace/replace.c
+++ b/lib/replace/replace.c
@@ -518,11 +518,10 @@ long long int rep_strtoll(const char *str, char **endptr, int base)
}
#else
#ifdef HAVE_BSD_STRTOLL
-#ifdef HAVE_STRTOQ
long long int rep_strtoll(const char *str, char **endptr, int base)
{
- long long int nb = strtoq(str, endptr, base);
- /* In linux EINVAL is only returned if base is not ok */
+ long long int nb = strtoll(str, endptr, base);
+ /* With glibc EINVAL is only returned if base is not ok */
if (errno == EINVAL) {
if (base == 0 || (base >1 && base <37)) {
/* Base was ok so it's because we were not
@@ -534,9 +533,6 @@ long long int rep_strtoll(const char *str, char **endptr, int base)
}
return nb;
}
-#else
-#error "You need the strtoq function"
-#endif /* HAVE_STRTOQ */
#endif /* HAVE_BSD_STRTOLL */
#endif /* HAVE_STRTOLL */
diff --git a/lib/replace/system/threads.h b/lib/replace/system/threads.h
index 25d3502..fe6d0fb 100644
--- a/lib/replace/system/threads.h
+++ b/lib/replace/system/threads.h
@@ -29,15 +29,12 @@
#if defined(HAVE_PTHREAD_MUTEXATTR_SETROBUST_NP) && \
!defined(HAVE_PTHREAD_MUTEXATTR_SETROBUST)
-
#define pthread_mutexattr_setrobust pthread_mutexattr_setrobust_np
+#endif
-/*
- * We assume that PTHREAD_MUTEX_ROBUST_NP goes along with
- * pthread_mutexattr_setrobust_np()
- */
+#if defined(HAVE_DECL_PTHREAD_MUTEX_ROBUST_NP) && \
+ !defined(HAVE_DECL_PTHREAD_MUTEX_ROBUST)
#define PTHREAD_MUTEX_ROBUST PTHREAD_MUTEX_ROBUST_NP
-
#endif
#if defined(HAVE_PTHREAD_MUTEX_CONSISTENT_NP) && \
diff --git a/lib/replace/test/testsuite.c b/lib/replace/test/testsuite.c
index 017b8ed..961b77d 100644
--- a/lib/replace/test/testsuite.c
+++ b/lib/replace/test/testsuite.c
@@ -69,19 +69,23 @@ static int test_ftruncate(void)
}
if (ftruncate(fd, size) != 0) {
printf("failure: ftruncate [\n%s\n]\n", strerror(errno));
+ close(fd);
return false;
}
if (fstat(fd, &st) != 0) {
printf("failure: ftruncate [\nfstat failed - %s\n]\n", strerror(errno));
+ close(fd);
return false;
}
if (st.st_size != size) {
printf("failure: ftruncate [\ngave wrong size %d - expected %d\n]\n",
(int)st.st_size, size);
+ close(fd);
return false;
}
unlink(TESTFILE);
printf("success: ftruncate\n");
+ close(fd);
return true;
}
diff --git a/lib/replace/wscript b/lib/replace/wscript
index 1b156fa..516db2f 100644
--- a/lib/replace/wscript
+++ b/lib/replace/wscript
@@ -136,6 +136,7 @@ def configure(conf):
conf.CHECK_TYPE_IN('sa_family_t', 'sys/socket.h')
conf.CHECK_TYPE_IN('sig_atomic_t', 'signal.h', define='HAVE_SIG_ATOMIC_T_TYPE')
+ conf.CHECK_FUNCS('sigsetmask siggetmask sigprocmask sigblock sigaction sigset')
conf.CHECK_FUNCS_IN('''inet_ntoa inet_aton inet_ntop inet_pton connect gethostbyname
getaddrinfo getnameinfo freeaddrinfo gai_strerror socketpair''',
@@ -447,21 +448,15 @@ removeea setea
if conf.CONFIG_SET('HAVE_PTHREAD'):
- conf.CHECK_DECLS('pthread_mutexattr_setrobust', headers='pthread.h')
- if not conf.CONFIG_SET('HAVE_DECL_PTHREAD_MUTEXATTR_SETROBUST'):
- conf.CHECK_DECLS('pthread_mutexattr_setrobust_np',
- headers='pthread.h')
-
conf.CHECK_FUNCS_IN('pthread_mutexattr_setrobust', 'pthread',
checklibc=True, headers='pthread.h')
if not conf.CONFIG_SET('HAVE_PTHREAD_MUTEXATTR_SETROBUST'):
conf.CHECK_FUNCS_IN('pthread_mutexattr_setrobust_np', 'pthread',
checklibc=True, headers='pthread.h')
- conf.CHECK_DECLS('pthread_mutex_consistent', headers='pthread.h')
- if not conf.CONFIG_SET('HAVE_DECL_PTHREAD_MUTEX_CONSISTENT'):
- conf.CHECK_DECLS('pthread_mutex_consistent_np',
- headers='pthread.h')
+ conf.CHECK_DECLS('PTHREAD_MUTEX_ROBUST', headers='pthread.h')
+ if not conf.CONFIG_SET('HAVE_DECL_PTHREAD_MUTEX_ROBUST'):
+ conf.CHECK_DECLS('PTHREAD_MUTEX_ROBUST_NP', headers='pthread.h')
conf.CHECK_FUNCS_IN('pthread_mutex_consistent', 'pthread',
checklibc=True, headers='pthread.h')
@@ -471,6 +466,8 @@ removeea setea
if ((conf.CONFIG_SET('HAVE_PTHREAD_MUTEXATTR_SETROBUST') or
conf.CONFIG_SET('HAVE_PTHREAD_MUTEXATTR_SETROBUST_NP')) and
+ (conf.CONFIG_SET('HAVE_DECL_PTHREAD_MUTEX_ROBUST') or
+ conf.CONFIG_SET('HAVE_DECL_PTHREAD_MUTEX_ROBUST_NP')) and
(conf.CONFIG_SET('HAVE_PTHREAD_MUTEX_CONSISTENT') or
conf.CONFIG_SET('HAVE_PTHREAD_MUTEX_CONSISTENT_NP'))):
conf.DEFINE('HAVE_ROBUST_MUTEXES', 1)
diff --git a/pytdb.c b/pytdb.c
index 9320799..c9d3a76 100644
--- a/pytdb.c
+++ b/pytdb.c
@@ -31,13 +31,25 @@
/* Include tdb headers */
#include <tdb.h>
+#if PY_MAJOR_VERSION >= 3
+#define PyStr_FromString PyUnicode_FromString
+#define PyStr_FromFormat PyUnicode_FromFormat
+#define PyInt_FromLong PyLong_FromLong
+#define PyInt_Check PyLong_Check
+#define PyInt_AsLong PyLong_AsLong
+#define Py_TPFLAGS_HAVE_ITER 0
+#else
+#define PyStr_FromString PyString_FromString
+#define PyStr_FromFormat PyString_FromFormat
+#endif
+
typedef struct {
PyObject_HEAD
TDB_CONTEXT *ctx;
bool closed;
} PyTdbObject;
-staticforward PyTypeObject PyTdb;
+static PyTypeObject PyTdb;
static void PyErr_SetTDBError(TDB_CONTEXT *tdb)
{
@@ -45,21 +57,21 @@ static void PyErr_SetTDBError(TDB_CONTEXT *tdb)
Py_BuildValue("(i,s)", tdb_error(tdb), tdb_errorstr(tdb)));
}
-static TDB_DATA PyString_AsTDB_DATA(PyObject *data)
+static TDB_DATA PyBytes_AsTDB_DATA(PyObject *data)
{
TDB_DATA ret;
- ret.dptr = (unsigned char *)PyString_AsString(data);
- ret.dsize = PyString_Size(data);
+ ret.dptr = (unsigned char *)PyBytes_AsString(data);
+ ret.dsize = PyBytes_Size(data);
return ret;
}
-static PyObject *PyString_FromTDB_DATA(TDB_DATA data)
+static PyObject *PyBytes_FromTDB_DATA(TDB_DATA data)
{
if (data.dptr == NULL && data.dsize == 0) {
Py_RETURN_NONE;
} else {
- PyObject *ret = PyString_FromStringAndSize((const char *)data.dptr,
- data.dsize);
+ PyObject *ret = PyBytes_FromStringAndSize((const char *)data.dptr,
+ data.dsize);
free(data.dptr);
return ret;
}
@@ -233,11 +245,11 @@ static PyObject *obj_get(PyTdbObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "O", &py_key))
return NULL;
- key = PyString_AsTDB_DATA(py_key);
+ key = PyBytes_AsTDB_DATA(py_key);
if (!key.dptr)
return NULL;
- return PyString_FromTDB_DATA(tdb_fetch(self->ctx, key));
+ return PyBytes_FromTDB_DATA(tdb_fetch(self->ctx, key));
}
static PyObject *obj_append(PyTdbObject *self, PyObject *args)
@@ -251,10 +263,10 @@ static PyObject *obj_append(PyTdbObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "OO", &py_key, &py_data))
return NULL;
- key = PyString_AsTDB_DATA(py_key);
+ key = PyBytes_AsTDB_DATA(py_key);
if (!key.dptr)
return NULL;
- data = PyString_AsTDB_DATA(py_data);
+ data = PyBytes_AsTDB_DATA(py_data);
if (!data.dptr)
return NULL;
@@ -267,7 +279,7 @@ static PyObject *obj_firstkey(PyTdbObject *self)
{
PyErr_TDB_RAISE_IF_CLOSED(self);
- return PyString_FromTDB_DATA(tdb_firstkey(self->ctx));
+ return PyBytes_FromTDB_DATA(tdb_firstkey(self->ctx));
}
static PyObject *obj_nextkey(PyTdbObject *self, PyObject *args)
@@ -279,11 +291,11 @@ static PyObject *obj_nextkey(PyTdbObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "O", &py_key))
return NULL;
- key = PyString_AsTDB_DATA(py_key);
+ key = PyBytes_AsTDB_DATA(py_key);
if (!key.dptr)
return NULL;
- return PyString_FromTDB_DATA(tdb_nextkey(self->ctx, key));
+ return PyBytes_FromTDB_DATA(tdb_nextkey(self->ctx, key));
}
static PyObject *obj_delete(PyTdbObject *self, PyObject *args)
@@ -296,7 +308,7 @@ static PyObject *obj_delete(PyTdbObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "O", &py_key))
return NULL;
- key = PyString_AsTDB_DATA(py_key);
+ key = PyBytes_AsTDB_DATA(py_key);
if (!key.dptr)
return NULL;
ret = tdb_delete(self->ctx, key);
@@ -304,26 +316,42 @@ static PyObject *obj_delete(PyTdbObject *self, PyObject *args)
Py_RETURN_NONE;
}
-static PyObject *obj_has_key(PyTdbObject *self, PyObject *args)
+static int obj_contains(PyTdbObject *self, PyObject *py_key)
{
TDB_DATA key;
int ret;
+ PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self);
+
+ key = PyBytes_AsTDB_DATA(py_key);
+ if (!key.dptr) {
+ PyErr_BadArgument();
+ return -1;
+ }
+ ret = tdb_exists(self->ctx, key);
+ if (ret)
+ return 1;
+ return 0;
+}
+
+#if PY_MAJOR_VERSION < 3
+static PyObject *obj_has_key(PyTdbObject *self, PyObject *args)
+{
+ int ret;
PyObject *py_key;
PyErr_TDB_RAISE_IF_CLOSED(self);
if (!PyArg_ParseTuple(args, "O", &py_key))
return NULL;
- key = PyString_AsTDB_DATA(py_key);
- if (!key.dptr)
+ ret = obj_contains(self, py_key);
+ if (ret == -1)
return NULL;
- ret = tdb_exists(self->ctx, key);
- if (ret != TDB_ERR_NOEXIST) {
- PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
- }
+ if (ret)
+ Py_RETURN_TRUE;
+ Py_RETURN_FALSE;
- return (ret == TDB_ERR_NOEXIST)?Py_False:Py_True;
}
+#endif
static PyObject *obj_store(PyTdbObject *self, PyObject *args)
{
@@ -337,10 +365,10 @@ static PyObject *obj_store(PyTdbObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "OO|i", &py_key, &py_value, &flag))
return NULL;
- key = PyString_AsTDB_DATA(py_key);
+ key = PyBytes_AsTDB_DATA(py_key);
if (!key.dptr)
return NULL;
- value = PyString_AsTDB_DATA(py_value);
+ value = PyBytes_AsTDB_DATA(py_value);
if (!value.dptr)
return NULL;
@@ -389,7 +417,7 @@ static PyObject *tdb_iter_next(PyTdbIteratorObject *self)
return NULL;
current = self->current;
self->current = tdb_nextkey(self->iteratee->ctx, self->current);
- ret = PyString_FromTDB_DATA(current);
+ ret = PyBytes_FromTDB_DATA(current);
return ret;
}
@@ -480,17 +508,23 @@ static PyMethodDef tdb_object_methods[] = {
"Append data to an existing key." },
{ "firstkey", (PyCFunction)obj_firstkey, METH_NOARGS, "S.firstkey() -> data\n"
"Return the first key in this database." },
- { "nextkey", (PyCFunction)obj_nextkey, METH_NOARGS, "S.nextkey(key) -> data\n"
+ { "nextkey", (PyCFunction)obj_nextkey, METH_VARARGS, "S.nextkey(key) -> data\n"
"Return the next key in this database." },
{ "delete", (PyCFunction)obj_delete, METH_VARARGS, "S.delete(key) -> None\n"
"Delete an entry." },
+#if PY_MAJOR_VERSION < 3
{ "has_key", (PyCFunction)obj_has_key, METH_VARARGS, "S.has_key(key) -> None\n"
"Check whether key exists in this database." },
+#endif
{ "store", (PyCFunction)obj_store, METH_VARARGS, "S.store(key, data, flag=REPLACE) -> None"
"Store data." },
{ "add_flags", (PyCFunction)obj_add_flags, METH_VARARGS, "S.add_flags(flags) -> None" },
{ "remove_flags", (PyCFunction)obj_remove_flags, METH_VARARGS, "S.remove_flags(flags) -> None" },
+#if PY_MAJOR_VERSION >= 3
+ { "keys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.iterkeys() -> iterator" },
+#else
{ "iterkeys", (PyCFunction)tdb_object_iter, METH_NOARGS, "S.iterkeys() -> iterator" },
+#endif
{ "clear", (PyCFunction)obj_clear, METH_NOARGS, "S.clear() -> None\n"
"Wipe the entire database." },
{ "repack", (PyCFunction)obj_repack, METH_NOARGS, "S.repack() -> None\n"
@@ -538,7 +572,7 @@ static PyObject *obj_get_flags(PyTdbObject *self, void *closure)
static PyObject *obj_get_filename(PyTdbObject *self, void *closure)
{
PyErr_TDB_RAISE_IF_CLOSED(self);
- return PyString_FromString(tdb_name(self->ctx));
+ return PyBytes_FromString(tdb_name(self->ctx));
}
static PyObject *obj_get_seqnum(PyTdbObject *self, void *closure)
@@ -547,6 +581,22 @@ static PyObject *obj_get_seqnum(PyTdbObject *self, void *closure)
return PyInt_FromLong(tdb_get_seqnum(self->ctx));
}
+static PyObject *obj_get_text(PyTdbObject *self, void *closure)
+{
+ PyObject *mod, *cls, *inst;
+ mod = PyImport_ImportModule("_tdb_text");
+ if (mod == NULL)
+ return NULL;
+ cls = PyObject_GetAttrString(mod, "TdbTextWrapper");
+ if (cls == NULL) {
+ Py_DECREF(mod);
+ return NULL;
+ }
+ inst = PyObject_CallFunction(cls, discard_const_p(char, "O"), self);
+ Py_DECREF(mod);
+ Py_DECREF(cls);
+ return inst;
+}
static PyGetSetDef tdb_object_getsetters[] = {
{ discard_const_p(char, "hash_size"),
@@ -564,6 +614,8 @@ static PyGetSetDef tdb_object_getsetters[] = {
discard_const_p(char, "The filename of this TDB file.") },
{ discard_const_p(char, "seqnum"),
(getter)obj_get_seqnum, NULL, NULL },
+ { discard_const_p(char, "text"),
+ (getter)obj_get_text, NULL, NULL },
{ NULL }
};
@@ -571,9 +623,9 @@ static PyObject *tdb_object_repr(PyTdbObject *self)
{
PyErr_TDB_RAISE_IF_CLOSED(self);
if (tdb_get_flags(self->ctx) & TDB_INTERNAL) {
- return PyString_FromString("Tdb(<internal>)");
+ return PyStr_FromString("Tdb(<internal>)");
} else {
- return PyString_FromFormat("Tdb('%s')", tdb_name(self->ctx));
+ return PyStr_FromFormat("Tdb('%s')", tdb_name(self->ctx));
}
}
@@ -581,27 +633,31 @@ static void tdb_object_dealloc(PyTdbObject *self)
{
if (!self->closed)
tdb_close(self->ctx);
- self->ob_type->tp_free(self);
+ Py_TYPE(self)->tp_free(self);
}
static PyObject *obj_getitem(PyTdbObject *self, PyObject *key)
{
TDB_DATA tkey, val;
PyErr_TDB_RAISE_IF_CLOSED(self);
- if (!PyString_Check(key)) {
- PyErr_SetString(PyExc_TypeError, "Expected string as key");
+ if (!PyBytes_Check(key)) {
+ PyErr_SetString(PyExc_TypeError, "Expected bytestring as key");
return NULL;
}
- tkey.dptr = (unsigned char *)PyString_AsString(key);
- tkey.dsize = PyString_Size(key);
+ tkey.dptr = (unsigned char *)PyBytes_AsString(key);
+ tkey.dsize = PyBytes_Size(key);
val = tdb_fetch(self->ctx, tkey);
if (val.dptr == NULL) {
- PyErr_SetString(PyExc_KeyError, "No such TDB entry");
+ /*
+ * if the key doesn't exist raise KeyError(key) to be
+ * consistent with python dict
+ */
+ PyErr_SetObject(PyExc_KeyError, key);
return NULL;
} else {
- return PyString_FromTDB_DATA(val);
+ return PyBytes_FromTDB_DATA(val);
}
}
@@ -610,22 +666,22 @@ static int obj_setitem(PyTdbObject *self, PyObject *key, PyObject *value)
TDB_DATA tkey, tval;
int ret;
PyErr_TDB_RAISE_RETURN_MINUS_1_IF_CLOSED(self);
- if (!PyString_Check(key)) {
- PyErr_SetString(PyExc_TypeError, "Expected string as key");
+ if (!PyBytes_Check(key)) {
+ PyErr_SetString(PyExc_TypeError, "Expected bytestring as key");
return -1;
}
- tkey = PyString_AsTDB_DATA(key);
+ tkey = PyBytes_AsTDB_DATA(key);
if (value == NULL) {
ret = tdb_delete(self->ctx, tkey);
} else {
- if (!PyString_Check(value)) {
+ if (!PyBytes_Check(value)) {
PyErr_SetString(PyExc_TypeError, "Expected string as value");
return -1;
}
- tval = PyString_AsTDB_DATA(value);
+ tval = PyBytes_AsTDB_DATA(value);
ret = tdb_store(self->ctx, tkey, tval, TDB_REPLACE);
}
@@ -642,6 +698,9 @@ static PyMappingMethods tdb_object_mapping = {
.mp_subscript = (binaryfunc)obj_getitem,
.mp_ass_subscript = (objobjargproc)obj_setitem,
};
+static PySequenceMethods tdb_object_seq = {
+ .sq_contains = (objobjproc)obj_contains,
+};
static PyTypeObject PyTdb = {
.tp_name = "tdb.Tdb",
.tp_basicsize = sizeof(PyTdbObject),
@@ -652,6 +711,7 @@ static PyTypeObject PyTdb = {
.tp_repr = (reprfunc)tdb_object_repr,
.tp_dealloc = (destructor)tdb_object_dealloc,
.tp_as_mapping = &tdb_object_mapping,
+ .tp_as_sequence = &tdb_object_seq,
.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_ITER,
.tp_iter = (getiterfunc)tdb_object_iter,
};
@@ -662,46 +722,78 @@ static PyMethodDef tdb_methods[] = {
{ NULL }
};
-void inittdb(void);
-void inittdb(void)
+#define MODULE_DOC "simple key-value database that supports multiple writers."
+
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "tdb",
+ .m_doc = MODULE_DOC,
+ .m_size = -1,
+ .m_methods = tdb_methods,
+};
+#endif
+
+PyObject* module_init(void);
+PyObject* module_init(void)
{
PyObject *m;
if (PyType_Ready(&PyTdb) < 0)
- return;
+ return NULL;
if (PyType_Ready(&PyTdbIterator) < 0)
- return;
+ return NULL;
- m = Py_InitModule3("tdb", tdb_methods,
- "simple key-value database that supports multiple writers.");
+#if PY_MAJOR_VERSION >= 3
+ m = PyModule_Create(&moduledef);
+#else
+ m = Py_InitModule3("tdb", tdb_methods, MODULE_DOC);
+#endif
if (m == NULL)
- return;
-
- PyModule_AddObject(m, "REPLACE", PyInt_FromLong(TDB_REPLACE));
- PyModule_AddObject(m, "INSERT", PyInt_FromLong(TDB_INSERT));
- PyModule_AddObject(m, "MODIFY", PyInt_FromLong(TDB_MODIFY));
-
- PyModule_AddObject(m, "DEFAULT", PyInt_FromLong(TDB_DEFAULT));
- PyModule_AddObject(m, "CLEAR_IF_FIRST", PyInt_FromLong(TDB_CLEAR_IF_FIRST));
- PyModule_AddObject(m, "INTERNAL", PyInt_FromLong(TDB_INTERNAL));
- PyModule_AddObject(m, "NOLOCK", PyInt_FromLong(TDB_NOLOCK));
- PyModule_AddObject(m, "NOMMAP", PyInt_FromLong(TDB_NOMMAP));
- PyModule_AddObject(m, "CONVERT", PyInt_FromLong(TDB_CONVERT));
- PyModule_AddObject(m, "BIGENDIAN", PyInt_FromLong(TDB_BIGENDIAN));
- PyModule_AddObject(m, "NOSYNC", PyInt_FromLong(TDB_NOSYNC));
- PyModule_AddObject(m, "SEQNUM", PyInt_FromLong(TDB_SEQNUM));
- PyModule_AddObject(m, "VOLATILE", PyInt_FromLong(TDB_VOLATILE));
- PyModule_AddObject(m, "ALLOW_NESTING", PyInt_FromLong(TDB_ALLOW_NESTING));
- PyModule_AddObject(m, "DISALLOW_NESTING", PyInt_FromLong(TDB_DISALLOW_NESTING));
- PyModule_AddObject(m, "INCOMPATIBLE_HASH", PyInt_FromLong(TDB_INCOMPATIBLE_HASH));
-
- PyModule_AddObject(m, "__docformat__", PyString_FromString("restructuredText"));
-
- PyModule_AddObject(m, "__version__", PyString_FromString(PACKAGE_VERSION));
+ return NULL;
+
+ PyModule_AddIntConstant(m, "REPLACE", TDB_REPLACE);
+ PyModule_AddIntConstant(m, "INSERT", TDB_INSERT);
+ PyModule_AddIntConstant(m, "MODIFY", TDB_MODIFY);
+
+ PyModule_AddIntConstant(m, "DEFAULT", TDB_DEFAULT);
+ PyModule_AddIntConstant(m, "CLEAR_IF_FIRST", TDB_CLEAR_IF_FIRST);
+ PyModule_AddIntConstant(m, "INTERNAL", TDB_INTERNAL);
+ PyModule_AddIntConstant(m, "NOLOCK", TDB_NOLOCK);
+ PyModule_AddIntConstant(m, "NOMMAP", TDB_NOMMAP);
+ PyModule_AddIntConstant(m, "CONVERT", TDB_CONVERT);
+ PyModule_AddIntConstant(m, "BIGENDIAN", TDB_BIGENDIAN);
+ PyModule_AddIntConstant(m, "NOSYNC", TDB_NOSYNC);
+ PyModule_AddIntConstant(m, "SEQNUM", TDB_SEQNUM);
+ PyModule_AddIntConstant(m, "VOLATILE", TDB_VOLATILE);
+ PyModule_AddIntConstant(m, "ALLOW_NESTING", TDB_ALLOW_NESTING);
+ PyModule_AddIntConstant(m, "DISALLOW_NESTING", TDB_DISALLOW_NESTING);
+ PyModule_AddIntConstant(m, "INCOMPATIBLE_HASH", TDB_INCOMPATIBLE_HASH);
+
+ PyModule_AddStringConstant(m, "__docformat__", "restructuredText");
+
+ PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION);
Py_INCREF(&PyTdb);
PyModule_AddObject(m, "Tdb", (PyObject *)&PyTdb);
Py_INCREF(&PyTdbIterator);
+
+ return m;
+}
+
+
+#if PY_MAJOR_VERSION >= 3
+PyMODINIT_FUNC PyInit_tdb(void);
+PyMODINIT_FUNC PyInit_tdb(void)
+{
+ return module_init();
+}
+#else
+void inittdb(void);
+void inittdb(void)
+{
+ module_init();
}
+#endif
diff --git a/python/tests/simple.py b/python/tests/simple.py
index 4751f9b..b3136dd 100644
--- a/python/tests/simple.py
+++ b/python/tests/simple.py
@@ -6,9 +6,12 @@
# Copyright (C) 2007-2008 Jelmer Vernooij <jelmer@samba.org>
# Published under the GNU LGPLv3 or later
-import tdb
+import sys
+import os
+import tempfile
from unittest import TestCase
-import os, tempfile
+
+import tdb
class OpenTdbTests(TestCase):
@@ -43,19 +46,18 @@ class InternalTdbTests(TestCase):
self.assertEquals(repr(self.tdb), "Tdb(<internal>)")
-class SimpleTdbTests(TestCase):
+class CommonTdbTests(TestCase):
+ """Tests common to both the text & bytes interfaces"""
+
+ use_text = False
def setUp(self):
- super(SimpleTdbTests, self).setUp()
+ super(CommonTdbTests, self).setUp()
self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT,
os.O_CREAT|os.O_RDWR)
self.assertNotEqual(None, self.tdb)
-
- def tearDown(self):
- del self.tdb
-
- def test_repr(self):
- self.assertTrue(repr(self.tdb).startswith("Tdb('"))
+ if self.use_text:
+ self.tdb = self.tdb.text
def test_lockall(self):
self.tdb.lock_all()
@@ -74,27 +76,6 @@ class SimpleTdbTests(TestCase):
def test_reopen(self):
self.tdb.reopen()
- def test_store(self):
- self.tdb.store("bar", "bla")
- self.assertEquals("bla", self.tdb.get("bar"))
-
- def test_getitem(self):
- self.tdb["bar"] = "foo"
- self.tdb.reopen()
- self.assertEquals("foo", self.tdb["bar"])
-
- def test_delete(self):
- self.tdb["bar"] = "foo"
- del self.tdb["bar"]
- self.assertRaises(KeyError, lambda: self.tdb["bar"])
-
- def test_contains(self):
- self.tdb["bla"] = "bloe"
- self.assertTrue("bla" in self.tdb)
-
- def test_keyerror(self):
- self.assertRaises(KeyError, lambda: self.tdb["bla"])
-
def test_hash_size(self):
self.tdb.hash_size
@@ -107,52 +88,101 @@ class SimpleTdbTests(TestCase):
def test_name(self):
self.tdb.filename
+ def test_add_flags(self):
+ self.tdb.add_flags(tdb.NOMMAP)
+ self.tdb.remove_flags(tdb.NOMMAP)
+
+
+class TextCommonTdbTests(CommonTdbTests):
+
+ use_text = True
+
+
+class SimpleTdbTests(TestCase):
+
+ def setUp(self):
+ super(SimpleTdbTests, self).setUp()
+ self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT,
+ os.O_CREAT|os.O_RDWR)
+ self.assertNotEqual(None, self.tdb)
+
+ def test_repr(self):
+ self.assertTrue(repr(self.tdb).startswith("Tdb('"))
+
+ def test_store(self):
+ self.tdb.store(b"bar", b"bla")
+ self.assertEquals(b"bla", self.tdb.get(b"bar"))
+
+ def test_getitem(self):
+ self.tdb[b"bar"] = b"foo"
+ self.tdb.reopen()
+ self.assertEquals(b"foo", self.tdb[b"bar"])
+
+ def test_delete(self):
+ self.tdb[b"bar"] = b"foo"
+ del self.tdb[b"bar"]
+ self.assertRaises(KeyError, lambda: self.tdb[b"bar"])
+
+ def test_contains(self):
+ self.tdb[b"bla"] = b"bloe"
+ self.assertTrue(b"bla" in self.tdb)
+ self.assertFalse(b"qwertyuiop" in self.tdb)
+ if sys.version_info < (3, 0):
+ self.assertTrue(self.tdb.has_key(b"bla"))
+ self.assertFalse(self.tdb.has_key(b"qwertyuiop"))
+
+ def test_keyerror(self):
+ self.assertRaises(KeyError, lambda: self.tdb[b"bla"])
+
def test_iterator(self):
- self.tdb["bla"] = "1"
- self.tdb["brainslug"] = "2"
+ self.tdb[b"bla"] = b"1"
+ self.tdb[b"brainslug"] = b"2"
l = list(self.tdb)
l.sort()
- self.assertEquals(["bla", "brainslug"], l)
+ self.assertEquals([b"bla", b"brainslug"], l)
def test_transaction_cancel(self):
- self.tdb["bloe"] = "2"
+ self.tdb[b"bloe"] = b"2"
self.tdb.transaction_start()
- self.tdb["bloe"] = "1"
+ self.tdb[b"bloe"] = b"1"
self.tdb.transaction_cancel()
- self.assertEquals("2", self.tdb["bloe"])
+ self.assertEquals(b"2", self.tdb[b"bloe"])
def test_transaction_commit(self):
- self.tdb["bloe"] = "2"
+ self.tdb[b"bloe"] = b"2"
self.tdb.transaction_start()
- self.tdb["bloe"] = "1"
+ self.tdb[b"bloe"] = b"1"
self.tdb.transaction_commit()
- self.assertEquals("1", self.tdb["bloe"])
+ self.assertEquals(b"1", self.tdb[b"bloe"])
def test_transaction_prepare_commit(self):
- self.tdb["bloe"] = "2"
+ self.tdb[b"bloe"] = b"2"
self.tdb.transaction_start()
- self.tdb["bloe"] = "1"
+ self.tdb[b"bloe"] = b"1"
self.tdb.transaction_prepare_commit()
self.tdb.transaction_commit()
- self.assertEquals("1", self.tdb["bloe"])
+ self.assertEquals(b"1", self.tdb[b"bloe"])
def test_iterkeys(self):
- self.tdb["bloe"] = "2"
- self.tdb["bla"] = "25"
- i = self.tdb.iterkeys()
- self.assertEquals(set(["bloe", "bla"]), set([i.next(), i.next()]))
+ self.tdb[b"bloe"] = b"2"
+ self.tdb[b"bla"] = b"25"
+ if sys.version_info >= (3, 0):
+ i = self.tdb.keys()
+ else:
+ i = self.tdb.iterkeys()
+ self.assertEquals(set([b"bloe", b"bla"]), set([next(i), next(i)]))
def test_clear(self):
- self.tdb["bloe"] = "2"
- self.tdb["bla"] = "25"
+ self.tdb[b"bloe"] = b"2"
+ self.tdb[b"bla"] = b"25"
self.assertEquals(2, len(list(self.tdb)))
self.tdb.clear()
self.assertEquals(0, len(list(self.tdb)))
def test_repack(self):
- self.tdb["foo"] = "abc"
- self.tdb["bar"] = "def"
- del self.tdb["foo"]
+ self.tdb[b"foo"] = b"abc"
+ self.tdb[b"bar"] = b"def"
+ del self.tdb[b"foo"]
self.tdb.repack()
def test_seqnum(self):
@@ -164,12 +194,110 @@ class SimpleTdbTests(TestCase):
def test_len(self):
self.assertEquals(0, len(list(self.tdb)))
- self.tdb["entry"] = "value"
+ self.tdb[b"entry"] = b"value"
self.assertEquals(1, len(list(self.tdb)))
- def test_add_flags(self):
- self.tdb.add_flags(tdb.NOMMAP)
- self.tdb.remove_flags(tdb.NOMMAP)
+
+class TdbTextTests(TestCase):
+
+ def setUp(self):
+ super(TdbTextTests, self).setUp()
+ self.tdb = tdb.Tdb(tempfile.mkstemp()[1], 0, tdb.DEFAULT,
+ os.O_CREAT|os.O_RDWR)
+ self.assertNotEqual(None, self.tdb)
+
+ def test_repr(self):
+ self.assertTrue(repr(self.tdb).startswith("Tdb('"))
+
+ def test_store(self):
+ self.tdb.text.store("bar", "bla")
+ self.assertEquals("bla", self.tdb.text.get("bar"))
+
+ def test_getitem(self):
+ self.tdb.text["bar"] = "foo"
+ self.tdb.reopen()
+ self.assertEquals("foo", self.tdb.text["bar"])
+
+ def test_delete(self):
+ self.tdb.text["bar"] = "foo"
+ del self.tdb.text["bar"]
+ self.assertRaises(KeyError, lambda: self.tdb.text["bar"])
+
+ def test_contains(self):
+ self.tdb.text["bla"] = "bloe"
+ self.assertTrue("bla" in self.tdb.text)
+ self.assertFalse("qwertyuiop" in self.tdb.text)
+ if sys.version_info < (3, 0):
+ self.assertTrue(self.tdb.text.has_key("bla"))
+ self.assertFalse(self.tdb.text.has_key("qwertyuiop"))
+
+ def test_keyerror(self):
+ self.assertRaises(KeyError, lambda: self.tdb.text["bla"])
+
+ def test_iterator(self):
+ self.tdb.text["bla"] = "1"
+ self.tdb.text["brainslug"] = "2"
+ l = list(self.tdb.text)
+ l.sort()
+ self.assertEquals(["bla", "brainslug"], l)
+
+ def test_transaction_cancel(self):
+ self.tdb.text["bloe"] = "2"
+ self.tdb.transaction_start()
+ self.tdb.text["bloe"] = "1"
+ self.tdb.transaction_cancel()
+ self.assertEquals("2", self.tdb.text["bloe"])
+
+ def test_transaction_commit(self):
+ self.tdb.text["bloe"] = "2"
+ self.tdb.transaction_start()
+ self.tdb.text["bloe"] = "1"
+ self.tdb.transaction_commit()
+ self.assertEquals("1", self.tdb.text["bloe"])
+
+ def test_transaction_prepare_commit(self):
+ self.tdb.text["bloe"] = "2"
+ self.tdb.transaction_start()
+ self.tdb.text["bloe"] = "1"
+ self.tdb.transaction_prepare_commit()
+ self.tdb.transaction_commit()
+ self.assertEquals("1", self.tdb.text["bloe"])
+
+ def test_iterkeys(self):
+ self.tdb.text["bloe"] = "2"
+ self.tdb.text["bla"] = "25"
+ if sys.version_info >= (3, 0):
+ i = self.tdb.text.keys()
+ else:
+ i = self.tdb.text.iterkeys()
+ self.assertEquals(set(["bloe", "bla"]), set([next(i), next(i)]))
+
+ def test_clear(self):
+ self.tdb.text["bloe"] = "2"
+ self.tdb.text["bla"] = "25"
+ self.assertEquals(2, len(list(self.tdb)))
+ self.tdb.clear()
+ self.assertEquals(0, len(list(self.tdb)))
+
+ def test_repack(self):
+ self.tdb.text["foo"] = "abc"
+ self.tdb.text["bar"] = "def"
+ del self.tdb.text["foo"]
+ self.tdb.repack()
+
+ def test_len(self):
+ self.assertEquals(0, len(list(self.tdb.text)))
+ self.tdb.text["entry"] = "value"
+ self.assertEquals(1, len(list(self.tdb.text)))
+
+ def test_text_and_binary(self):
+ text = u'\xfa\u0148\xef\xe7\xf8\xf0\xea'
+ bytestr = text.encode('utf-8')
+ self.tdb[b"entry"] = bytestr
+ self.tdb.text[u"entry2"] = text
+ self.assertEquals(self.tdb.text["entry"], text)
+ self.assertEquals(self.tdb[b"entry2"], bytestr)
+ assert self.tdb.text.raw == self.tdb
class VersionTests(TestCase):
diff --git a/test/run-allrecord-traverse-deadlock.c b/test/run-allrecord-traverse-deadlock.c
new file mode 100644
index 0000000..2c58206
--- /dev/null
+++ b/test/run-allrecord-traverse-deadlock.c
@@ -0,0 +1,203 @@
+#include "../common/tdb_private.h"
+#include "../common/io.c"
+#include "../common/tdb.c"
+#include "../common/lock.c"
+#include "../common/freelist.c"
+#include "../common/traverse.c"
+#include "../common/transaction.c"
+#include "../common/error.c"
+#include "../common/open.c"
+#include "../common/check.c"
+#include "../common/hash.c"
+#include "../common/mutex.c"
+#include "tap-interface.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdarg.h>
+#include "logging.h"
+
+static void do_allrecord_lock(const char *name, int tdb_flags, int up,
+ int down)
+{
+ struct tdb_context *tdb;
+ int ret;
+ ssize_t nread, nwritten;
+ char c = 0;
+
+ tdb = tdb_open_ex(name, 3, tdb_flags,
+ O_RDWR|O_CREAT, 0755, &taplogctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ ret = tdb_lockall(tdb);
+ ok(ret == 0, "tdb_lockall should succeed");
+
+ nwritten = write(up, &c, sizeof(c));
+ ok(nwritten == sizeof(c), "write should succeed");
+
+ nread = read(down, &c, sizeof(c));
+ ok(nread == sizeof(c), "read should succeed");
+
+ ret = tdb_traverse(tdb, NULL, NULL);
+ ok(ret == -1, "do_allrecord_lock: traverse should fail");
+
+ nwritten = write(up, &c, sizeof(c));
+ ok(nwritten == sizeof(c), "write should succeed");
+
+ exit(0);
+}
+
+static void do_traverse(const char *name, int tdb_flags, int up, int down)
+{
+ struct tdb_context *tdb;
+ int ret;
+ ssize_t nread, nwritten;
+ char c = 0;
+
+ tdb = tdb_open_ex(name, 3, tdb_flags,
+ O_RDWR|O_CREAT, 0755, &taplogctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ ret = tdb_traverse(tdb, NULL, NULL);
+ ok(ret == 1, "do_traverse: tdb_traverse should return 1 record");
+
+ nwritten = write(up, &c, sizeof(c));
+ ok(nwritten == sizeof(c), "write should succeed");
+
+ nread = read(down, &c, sizeof(c));
+ ok(nread == sizeof(c), "read should succeed");
+
+ exit(0);
+}
+
+/*
+ * Process 1: get the allrecord_lock on a tdb.
+ * Process 2: start a traverse, this will stall waiting for the
+ * first chainlock: That is taken by the allrecord_lock
+ * Process 1: start a traverse: This will get EDEADLK in trying to
+ * get the TRANSACTION_LOCK. It will deadlock for mutexes,
+ * which don't have built-in deadlock detection.
+ */
+
+static int do_tests(const char *name, int tdb_flags)
+{
+ struct tdb_context *tdb;
+ int ret;
+ pid_t traverse_child, allrecord_child;
+ int traverse_down[2];
+ int traverse_up[2];
+ int allrecord_down[2];
+ int allrecord_up[2];
+ char c;
+ ssize_t nread, nwritten;
+ TDB_DATA key, data;
+
+ key.dsize = strlen("hi");
+ key.dptr = discard_const_p(uint8_t, "hi");
+ data.dsize = strlen("world");
+ data.dptr = discard_const_p(uint8_t, "world");
+
+ tdb = tdb_open_ex(name, 3, tdb_flags,
+ O_RDWR|O_CREAT, 0755, &taplogctx, NULL);
+ ok(tdb, "tdb_open_ex should succeed");
+
+ ret = tdb_store(tdb, key, data, TDB_INSERT);
+ ok(ret == 0, "tdb_store should succeed");
+
+ ret = pipe(traverse_down);
+ ok(ret == 0, "pipe should succeed");
+
+ ret = pipe(traverse_up);
+ ok(ret == 0, "pipe should succeed");
+
+ ret = pipe(allrecord_down);
+ ok(ret == 0, "pipe should succeed");
+
+ ret = pipe(allrecord_up);
+ ok(ret == 0, "pipe should succeed");
+
+ allrecord_child = fork();
+ ok(allrecord_child != -1, "fork should succeed");
+
+ if (allrecord_child == 0) {
+ tdb_close(tdb);
+ close(traverse_up[0]);
+ close(traverse_up[1]);
+ close(traverse_down[0]);
+ close(traverse_down[1]);
+ close(allrecord_up[0]);
+ close(allrecord_down[1]);
+ do_allrecord_lock(name, tdb_flags,
+ allrecord_up[1], allrecord_down[0]);
+ exit(0);
+ }
+ close(allrecord_up[1]);
+ close(allrecord_down[0]);
+
+ nread = read(allrecord_up[0], &c, sizeof(c));
+ ok(nread == sizeof(c), "read should succeed");
+
+ traverse_child = fork();
+ ok(traverse_child != -1, "fork should succeed");
+
+ if (traverse_child == 0) {
+ tdb_close(tdb);
+ close(traverse_up[0]);
+ close(traverse_down[1]);
+ close(allrecord_up[0]);
+ close(allrecord_down[1]);
+ do_traverse(name, tdb_flags,
+ traverse_up[1], traverse_down[0]);
+ exit(0);
+ }
+ close(traverse_up[1]);
+ close(traverse_down[0]);
+
+ poll(NULL, 0, 1000);
+
+ nwritten = write(allrecord_down[1], &c, sizeof(c));
+ ok(nwritten == sizeof(c), "write should succeed");
+
+ nread = read(traverse_up[0], &c, sizeof(c));
+ ok(nread == sizeof(c), "read should succeed");
+
+ nwritten = write(traverse_down[1], &c, sizeof(c));
+ ok(nwritten == sizeof(c), "write should succeed");
+
+ nread = read(allrecord_up[0], &c, sizeof(c));
+ ok(nread == sizeof(c), "ret should succeed");
+
+ close(traverse_up[0]);
+ close(traverse_down[1]);
+ close(allrecord_up[0]);
+ close(allrecord_down[1]);
+ diag("%s tests done", name);
+ return exit_status();
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+ bool mutex_support;
+
+ mutex_support = tdb_runtime_check_for_robust_mutexes();
+
+ ret = do_tests("marklock-deadlock-fcntl.tdb",
+ TDB_CLEAR_IF_FIRST |
+ TDB_INCOMPATIBLE_HASH);
+ ok(ret == 0, "marklock-deadlock-fcntl.tdb tests should succeed");
+
+ if (!mutex_support) {
+ skip(1, "No robust mutex support, "
+ "skipping marklock-deadlock-mutex.tdb tests");
+ return exit_status();
+ }
+
+ ret = do_tests("marklock-deadlock-mutex.tdb",
+ TDB_CLEAR_IF_FIRST |
+ TDB_MUTEX_LOCKING |
+ TDB_INCOMPATIBLE_HASH);
+ ok(ret == 0, "marklock-deadlock-mutex.tdb tests should succeed");
+
+ return exit_status();
+}
diff --git a/tools/tdbrestore.c b/tools/tdbrestore.c
index f65b36f..81c986c 100644
--- a/tools/tdbrestore.c
+++ b/tools/tdbrestore.c
@@ -17,8 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <assert.h>
#include "replace.h"
+#include <assert.h>
#include "system/locale.h"
#include "system/time.h"
#include "system/filesys.h"
diff --git a/wscript b/wscript
index b960bb9..5845fa0 100644
--- a/wscript
+++ b/wscript
@@ -1,7 +1,7 @@
#!/usr/bin/env python
APPNAME = 'tdb'
-VERSION = '1.3.5'
+VERSION = '1.3.7'
blddir = 'bin'
@@ -41,6 +41,7 @@ tdb1_unit_tests = [
'run-wronghash-fail',
'run-zero-append',
'run-marklock-deadlock',
+ 'run-allrecord-traverse-deadlock',
'run-mutex-openflags2',
'run-mutex-trylock',
'run-mutex-allrecord-bench',
@@ -95,8 +96,7 @@ def configure(conf):
if not conf.env.disable_python:
# also disable if we don't have the python libs installed
- conf.find_program('python', var='PYTHON')
- conf.check_tool('python')
+ conf.SAMBA_CHECK_PYTHON(mandatory=False)
conf.check_python_version((2,4,2))
conf.SAMBA_CHECK_PYTHON_HEADERS(mandatory=False)
if not conf.env.HAVE_PYTHON_H:
@@ -179,12 +179,20 @@ def build(bld):
includes='include', install=False)
if not bld.CONFIG_SET('USING_SYSTEM_PYTDB'):
- bld.SAMBA_PYTHON('pytdb',
- 'pytdb.c',
- deps='tdb',
- enabled=not bld.env.disable_python,
- realname='tdb.so',
- cflags='-DPACKAGE_VERSION=\"%s\"' % VERSION)
+ for env in bld.gen_python_environments(['PKGCONFIGDIR']):
+ bld.SAMBA_PYTHON('pytdb',
+ 'pytdb.c',
+ deps='tdb',
+ enabled=not bld.env.disable_python,
+ realname='tdb.so',
+ cflags='-DPACKAGE_VERSION=\"%s\"' % VERSION)
+
+ for env in bld.gen_python_environments(['PKGCONFIGDIR']):
+ bld.SAMBA_SCRIPT('_tdb_text.py',
+ pattern='_tdb_text.py',
+ installdir='python')
+
+ bld.INSTALL_FILES('${PYTHONARCHDIR}', '_tdb_text.py')
def testonly(ctx):
'''run tdb testsuite'''
@@ -224,7 +232,10 @@ def testonly(ctx):
print("testsuite returned %d" % ret)
if ret != 0:
ecode = ret
- sys.exit(ecode)
+
+ pyret = samba_utils.RUN_PYTHON_TESTS(['python/tests/simple.py'])
+ print("python testsuite returned %d" % pyret)
+ sys.exit(ecode or pyret)
# WAF doesn't build the unit tests for this, maybe because they don't link with tdb?
# This forces it